Exemplo n.º 1
0
void print_completion_string(CXCompletionString completion_string, FILE *file) {
  int I, N;

  N = clang_getNumCompletionChunks(completion_string);
  for (I = 0; I != N; ++I) {
    CXString text;
    const char *cstr;
    enum CXCompletionChunkKind Kind
      = clang_getCompletionChunkKind(completion_string, I);

    if (Kind == CXCompletionChunk_Optional) {
      fprintf(file, "{Optional ");
      print_completion_string(
                clang_getCompletionChunkCompletionString(completion_string, I),
                              file);
      fprintf(file, "}");
      continue;
    }

    text = clang_getCompletionChunkText(completion_string, I);
    cstr = clang_getCString(text);
    fprintf(file, "{%s %s}",
            clang_getCompletionChunkKindSpelling(Kind),
            cstr ? cstr : "");
    clang_disposeString(text);
  }

}
QVector<CodeCompletionChunk> CodeCompletionChunkConverter::optionalChunks(CXCompletionString completionString, uint chunkIndex)
{
    CodeCompletionChunkConverter converter;

    converter.extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex));

    return converter.chunks;
}
void CodeCompletionChunkConverter::extractOptionalCompletionChunks(CXCompletionString completionString)
{
    const uint completionChunkCount = clang_getNumCompletionChunks(completionString);

    for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) {
        const CodeCompletionChunk::Kind kind = chunkKind(completionString, chunkIndex);

        if (kind == CodeCompletionChunk::Optional)
            extractOptionalCompletionChunks(clang_getCompletionChunkCompletionString(completionString, chunkIndex));
        else
            chunks.append(CodeCompletionChunk(kind, chunkText(completionString, chunkIndex)));
    }
}
Exemplo n.º 4
0
std::string
CompletionData::OptionalChunkToString( CXCompletionString completion_string,
                                       size_t chunk_num ) {
  std::string final_string;

  if ( !completion_string )
    return final_string;

  CXCompletionString optional_completion_string =
    clang_getCompletionChunkCompletionString( completion_string, chunk_num );

  if ( !optional_completion_string )
    return final_string;

  size_t optional_num_chunks = clang_getNumCompletionChunks(
                               optional_completion_string );

  for ( size_t j = 0; j < optional_num_chunks; ++j ) {
    CXCompletionChunkKind kind = clang_getCompletionChunkKind(
                                   optional_completion_string, j );

    if ( kind == CXCompletionChunk_Optional ) {
      final_string.append( OptionalChunkToString( optional_completion_string,
                                                  j ) );
    }

    else if ( kind == CXCompletionChunk_Placeholder ) {
      final_string.append(
          "[" + ChunkToString( optional_completion_string, j ) + "]" );
    }

    else if ( kind == CXCompletionChunk_CurrentParameter ) {
      current_arg_ = "[" + ChunkToString( optional_completion_string, j ) + "]";
      final_string.append( "☞  " + current_arg_ );
    }

    else {
      final_string.append( ChunkToString( optional_completion_string, j ) );
    }
  }

  return final_string;
}
/* Print the completion line except the header term (COMPLETION: TypedText),
 * the output format should be identical with the result of clang -cc1
 * -code-completion-at. Here are some sample outputs from the clang code
 * completion process:

     COMPLETION: short
     COMPLETION: signed
     COMPLETION: static
     COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
     COMPLETION: struct

 * However, here we don't handle Pattern explicitly because the emacs
 * script would simply drop those pattern lines with an regexp T T
 */
static void completion_printAllCompletionTerms(
    CXCompletionString completion_string, FILE *fp)
{
    int i_chunk  = 0;
    int n_chunks = clang_getNumCompletionChunks(completion_string);

    CXString chk_text;
    enum CXCompletionChunkKind chk_kind;

    for ( ; i_chunk < n_chunks; i_chunk++)
    {
        /* get the type and completion text of this chunk */
        chk_kind = clang_getCompletionChunkKind(completion_string, i_chunk);
        chk_text = clang_getCompletionChunkText(completion_string, i_chunk);
        
        /* differenct kinds of chunks has various output formats */
        switch (chk_kind)
        {
        case CXCompletionChunk_Placeholder:
            fprintf(fp, "<#%s#>", clang_getCString(chk_text));
            break;
                
        case CXCompletionChunk_ResultType:
            fprintf(fp, "[#%s#]", clang_getCString(chk_text));
            break;

        case CXCompletionChunk_Optional:
            /* print optional term in a recursive way */
            fprintf(fp, "{#");
            completion_printAllCompletionTerms(
                clang_getCompletionChunkCompletionString(completion_string, i_chunk),
                fp);
            fprintf(fp, "#}");
            break;
                
        default:
            fprintf(fp, "%s", clang_getCString(chk_text));
        }

        clang_disposeString(chk_text);
    }
}
Exemplo n.º 6
0
code_completion_string code_completion_string::chunkCompletionString(unsigned idx) const
{
    return { clang_getCompletionChunkCompletionString(str, idx) };
}
QList<ClangCodeCompletionItem> TranslationUnit::completeAt(
    const int line
  , const int column
  , const unsigned completion_flags
  , const clang::unsaved_files_list& unsaved_files
  , const PluginConfiguration::sanitize_rules_list_type& sanitize_rules
  )
{
    auto files = unsaved_files.get();
#ifndef NDEBUG
    for (auto& item : files)
        assert(
            "Sanity check"
          && item.Filename
          && std::strlen(item.Filename)
          && item.Contents
          && item.Length
          );
#endif

    clang::DCXCodeCompleteResults res = {
        clang_codeCompleteAt(
            m_unit
          , m_filename.constData()
          , unsigned(line)
          , unsigned(column)
          , files.data()
          , files.size()
          , completion_flags
          )
      };
    if (!res)
    {
        throw Exception::CompletionFailure(
            i18nc("@item:intext", "Unable to perform code completion").toAscii().constData()
          );
    }

#if 0
    clang_sortCodeCompletionResults(res->Results, res->NumResults);
#endif

    // Collect some diagnostic SPAM
    for (auto i = 0u; i < clang_codeCompleteGetNumDiagnostics(res); ++i)
    {
        clang::DCXDiagnostic diag = {clang_codeCompleteGetDiagnostic(res, i)};
        appendDiagnostic(diag);
    }

    QList<ClangCodeCompletionItem> completions;
    completions.reserve(res->NumResults);                   // Peallocate enough space for completion results

    // Lets look what we've got...
    for (auto i = 0u; i < res->NumResults; ++i)
    {
        const auto str = res->Results[i].CompletionString;
        const auto priority = clang_getCompletionPriority(str);
        const auto cursor_kind = res->Results[i].CursorKind;
        debugShowCompletionResult(i, priority, str, cursor_kind);

        // Skip unusable completions
        // 0) check availability
        const auto availability = clang_getCompletionAvailability(str);
        if (availability != CXAvailability_Available && availability != CXAvailability_Deprecated)
        {
            kDebug(DEBUG_AREA) << "!! Skip result" << i << "as not available";
            continue;
        }
        // 1) check usefulness
        /// \todo Make it configurable
        if (cursor_kind == CXCursor_NotImplemented)
            continue;

        // Collect all completion chunks and from a format string
        QString text_before;
        QString typed_text;
        QString text_after;
        QStringList placeholders;
        int optional_placeholers_start_position = -1;
        // A lambda to append given text to different parts
        // of future completion string, depending on already processed text
        auto appender = [&](const QString& text)
        {
            if (typed_text.isEmpty())
                text_before += text;
            else
                text_after += text;
        };
        auto skip_this_item = false;
        for (
            auto j = 0u
          , chunks = clang_getNumCompletionChunks(str)
          ; j < chunks && !skip_this_item
          ; ++j
          )
        {
            auto kind = clang_getCompletionChunkKind(str, j);
            auto text = toString(clang::DCXString{clang_getCompletionChunkText(str, j)});
            switch (kind)
            {
                // Text that a user would be expected to type to get this code-completion result
                case CXCompletionChunk_TypedText:
                // Text that should be inserted as part of a code-completion result
                case CXCompletionChunk_Text:
                {
                    auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer
                    if (p.first)
                        typed_text += p.second;
                    else                                    // Go for next completion item
                        skip_this_item = true;
                    break;
                }
                // Placeholder text that should be replaced by the user
                case CXCompletionChunk_Placeholder:
                {
                    auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer
                    if (p.first)
                    {
                        appender(
                            QLatin1String{"%"}
                          + QString::number(placeholders.size() + 1)
                          + QLatin1String{"%"}
                          );
                        placeholders.push_back(p.second);
                    }
                    else                                    // Go for next completion item
                        skip_this_item = true;
                    break;
                }
                // A code-completion string that describes "optional" text that
                // could be a part of the template (but is not required)
                case CXCompletionChunk_Optional:
                {
                    auto ostr = clang_getCompletionChunkCompletionString(str, j);
                    for (
                        auto oci = 0u
                      , ocn = clang_getNumCompletionChunks(ostr)
                      ; oci < ocn
                      ; ++oci
                      )
                    {
                        auto otext = toString(clang::DCXString{clang_getCompletionChunkText(ostr, oci)});
                        // Pipe given piece of text through sanitizer
                        auto p = sanitize(otext, sanitize_rules);
                        if (p.first)
                        {
                            auto okind = clang::kind_of(ostr, oci);
                            if (okind == CXCompletionChunk_Placeholder)
                            {
                                appender(
                                    QLatin1String{"%"}
                                  + QString::number(placeholders.size() + 1)
                                  + QLatin1String{"%"}
                                  );
                                placeholders.push_back(p.second);
                                optional_placeholers_start_position = placeholders.size();
                            }
                            else appender(p.second);
                        }
                        else
                        {
                            skip_this_item = true;
                            break;
                        }
                    }
                    break;
                }
                case CXCompletionChunk_ResultType:
                case CXCompletionChunk_LeftParen:
                case CXCompletionChunk_RightParen:
                case CXCompletionChunk_LeftBracket:
                case CXCompletionChunk_RightBracket:
                case CXCompletionChunk_LeftBrace:
                case CXCompletionChunk_RightBrace:
                case CXCompletionChunk_LeftAngle:
                case CXCompletionChunk_RightAngle:
                case CXCompletionChunk_Comma:
                case CXCompletionChunk_Colon:
                case CXCompletionChunk_SemiColon:
                case CXCompletionChunk_Equal:
                case CXCompletionChunk_CurrentParameter:
                case CXCompletionChunk_HorizontalSpace:
                /// \todo Kate can't handle \c '\n' well in completions list
                case CXCompletionChunk_VerticalSpace:
                {
                    auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer
                    if (p.first)
                        appender(p.second);
                    else                                    // Go for next completion item
                        skip_this_item = true;
                    break;
                }
                // Informative text that should be displayed but never inserted
                // as part of the template
                case CXCompletionChunk_Informative:
                    // Informative text before CXCompletionChunk_TypedText usually
                    // just a method scope (i.e. long name of an owner class)
                    // and it's useless for completer cuz it can group items
                    // by parent already...
                    if (!typed_text.isEmpty())
                    {
                        // Pipe given piece of text through sanitizer
                        auto p = sanitize(text, sanitize_rules);
                        if (p.first)
                            appender(p.second);
                        else                                // Go for next completion item
                            skip_this_item = true;
                    }
                    break;
                default:
                    break;
            }
        }
        // Does it pass the completion items sanitizer?
        if (skip_this_item) continue;                       // No! Skip it!

        assert("Priority expected to be less than 100" && priority < 101u);

        const auto comment = toString(clang::DCXString{clang_getCompletionBriefComment(str)});
        //
        completions.push_back({
            makeParentText(str, cursor_kind)
          , text_before
          , typed_text
          , text_after
          , placeholders
          , optional_placeholers_start_position
          , priority
          , cursor_kind
          , comment
          , availability == CXAvailability_Deprecated
          });
    }

    return completions;
}
Exemplo n.º 8
0
void ClangDriver::DoParseCompletionString(CXCompletionString str,
                                          int depth,
                                          wxString& entryName,
                                          wxString& signature,
                                          wxString& completeString,
                                          wxString& returnValue)
{

    bool collectingSignature = false;
    int numOfChunks = clang_getNumCompletionChunks(str);
    for(int j = 0; j < numOfChunks; j++) {

        CXString chunkText = clang_getCompletionChunkText(str, j);
        CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(str, j);

        switch(chunkKind) {
        case CXCompletionChunk_TypedText:
            entryName = wxString(clang_getCString(chunkText), wxConvUTF8);
            completeString += entryName;
            break;

        case CXCompletionChunk_ResultType:
            completeString += wxString(clang_getCString(chunkText), wxConvUTF8);
            completeString += wxT(" ");
            returnValue = wxString(clang_getCString(chunkText), wxConvUTF8);
            break;

        case CXCompletionChunk_Optional: {
            // Optional argument
            CXCompletionString optStr = clang_getCompletionChunkCompletionString(str, j);
            wxString optionalString;
            wxString dummy;
            // Once we hit the 'Optional Chunk' only the 'completeString' is matter
            DoParseCompletionString(optStr, depth + 1, dummy, dummy, optionalString, dummy);
            if(collectingSignature) {
                signature += optionalString;
            }
            completeString += optionalString;
        } break;
        case CXCompletionChunk_LeftParen:
            collectingSignature = true;
            signature += wxT("(");
            completeString += wxT("(");
            break;

        case CXCompletionChunk_RightParen:
            collectingSignature = true;
            signature += wxT(")");
            completeString += wxT(")");
            break;

        default:
            if(collectingSignature) {
                signature += wxString(clang_getCString(chunkText), wxConvUTF8);
            }
            completeString += wxString(clang_getCString(chunkText), wxConvUTF8);
            break;
        }
        clang_disposeString(chunkText);
    }

    // To make this tag compatible with ctags one, we need to place
    // a /^ and $/ in the pattern string (we add this only to the top level completionString)
    if(depth == 0) {
        completeString.Prepend(wxT("/^ "));
        completeString.Append(wxT(" $/"));
    }
}