CompletionData::CompletionData( const CXCompletionResult &completion_result ) { CXCompletionString completion_string = completion_result.CompletionString; if ( !completion_string ) return; uint num_chunks = clang_getNumCompletionChunks( completion_string ); bool saw_left_paren = false; bool saw_function_params = false; bool saw_placeholder = false; for ( uint j = 0; j < num_chunks; ++j ) { ExtractDataFromChunk( completion_string, j, saw_left_paren, saw_function_params, saw_placeholder ); } original_string_ = RemoveTrailingParens( boost::move( original_string_ ) ); kind_ = CursorKindToCompletionKind( completion_result.CursorKind ); detailed_info_.append( return_type_ ) .append( " " ) .append( everything_except_return_type_ ) .append( "\n" ); doc_string_ = YouCompleteMe::CXStringToString( clang_getCompletionBriefComment( completion_string ) ); }
CompletionData::CompletionData( CXCompletionString completion_string, CXCursorKind kind, CXCodeCompleteResults *results, size_t index ) { size_t num_chunks = clang_getNumCompletionChunks( completion_string ); bool saw_left_paren = false; bool saw_function_params = false; bool saw_placeholder = false; for ( size_t j = 0; j < num_chunks; ++j ) { ExtractDataFromChunk( completion_string, j, saw_left_paren, saw_function_params, saw_placeholder ); } original_string_ = RemoveTrailingParens( std::move( original_string_ ) ); kind_ = CursorKindToCompletionKind( kind ); detailed_info_.append( return_type_ ) .append( " " ) .append( everything_except_return_type_ ) .append( "\n" ); doc_string_ = CXStringToString( clang_getCompletionBriefComment( completion_string ) ); BuildCompletionFixIt( results, index ); }
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); } }
CompletionData::CompletionData( const CXCompletionResult &completion_result ) { CXCompletionString completion_string = completion_result.CompletionString; if ( !completion_string ) return; uint num_chunks = clang_getNumCompletionChunks( completion_string ); bool saw_left_paren = false; bool saw_function_params = false; for ( uint j = 0; j < num_chunks; ++j ) { ExtractDataFromChunk( completion_string, j, saw_left_paren, saw_function_params ); } kind_ = CursorKindToVimKind( completion_result.CursorKind ); // We remove any two consecutive underscores from the function definition // since identifiers with them are ugly, compiler-reserved names. Functions // from the standard library use parameter names like "__pos" and we want to // show them as just "pos". This will never interfere with client code since // ANY C++ identifier with two consecutive underscores in it is // compiler-reserved. everything_except_return_type_ = RemoveTwoConsecutiveUnderscores( boost::move( everything_except_return_type_ ) ); detailed_info_.append( return_type_ ) .append( " " ) .append( everything_except_return_type_ ) .append( "\n" ); }
void CodeCompletionsExtractor::extractText() { const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString); for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex); if (chunkKind == CXCompletionChunk_TypedText) { currentCodeCompletion_.setText(CodeCompletionChunkConverter::chunkText(currentCxCodeCompleteResult.CompletionString, chunkIndex)); break; } } }
void CodeCompletionsExtractor::extractHasParameters() { const uint completionChunkCount = clang_getNumCompletionChunks(currentCxCodeCompleteResult.CompletionString); for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex); if (chunkKind == CXCompletionChunk_LeftParen) { const CXCompletionChunkKind nextChunkKind = clang_getCompletionChunkKind(currentCxCodeCompleteResult.CompletionString, chunkIndex + 1); currentCodeCompletion_.setHasParameters(nextChunkKind != CXCompletionChunk_RightParen); return; } } }
CompletionData::CompletionData( const CXCompletionResult &completion_result, bool is_argument_hint ) { CXCompletionString completion_string = completion_result.CompletionString; if ( !completion_string ) return; uint num_chunks = clang_getNumCompletionChunks( completion_string ); bool saw_left_paren = false; bool saw_function_params = false; bool saw_placeholder = false; for ( uint j = 0; j < num_chunks; ++j ) { ExtractDataFromChunk( completion_string, j, saw_left_paren, saw_function_params, saw_placeholder ); } original_string_ = RemoveTrailingParens( boost::move( original_string_ ) ); kind_ = CursorKindToCompletionKind( completion_result.CursorKind ); // We trim any underscores from the function definition since identifiers // with them are ugly, in most cases compiler-reserved names. Functions // from the standard library use parameter names like "__pos" and we want to // show them as just "pos". This will never interfere with client code since // ANY C++ identifier with two consecutive underscores in it is // compiler-reserved. everything_except_return_type_ = TrimUnderscores( everything_except_return_type_ ); detailed_info_.append( return_type_ ) .append( " " ) .append( everything_except_return_type_ ) .append( "\n" ); doc_string_ = YouCompleteMe::CXStringToString( clang_getCompletionBriefComment( completion_string ) ); // This address issue #1287 if ( kind_ == YouCompleteMe::FUNCTION || kind_ == YouCompleteMe::UNKNOWN ) everything_except_return_type_ = original_string_; if ( is_argument_hint ) { kind_ = NONE; return_type_ = ""; original_string_ = ""; everything_except_return_type_ = TrimUnderscores( current_arg_ ); if ( everything_except_return_type_.empty() ) everything_except_return_type_ = "void"; } }
static CXString get_result_typed_text(CXCompletionResult *r) { unsigned int chunks_n = clang_getNumCompletionChunks(r->CompletionString); for (unsigned int i = 0; i < chunks_n; ++i) { enum CXCompletionChunkKind kind; kind = clang_getCompletionChunkKind(r->CompletionString, i); if (kind == CXCompletionChunk_TypedText) return clang_getCompletionChunkText(r->CompletionString, i); } CXString empty = {0,0}; return empty; }
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))); } }
bool CodeCompletionsExtractor::hasText(const Utf8String &text, CXCompletionString cxCompletionString) const { const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString); for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex); if (chunkKind == CXCompletionChunk_TypedText) { const ClangString currentText(clang_getCompletionChunkText(cxCompletionString, chunkIndex)); return text == currentText; } } return false; }
static size_t count_type_chars(CXCompletionResult *r) { unsigned int chars = 0; unsigned int chunks_n = clang_getNumCompletionChunks(r->CompletionString); for (unsigned int i = 0; i < chunks_n; ++i) { enum CXCompletionChunkKind kind; kind = clang_getCompletionChunkKind(r->CompletionString, i); if (kind == CXCompletionChunk_ResultType) { CXString s = clang_getCompletionChunkText(r->CompletionString, i); chars += strlen(clang_getCString(s)); clang_disposeString(s); } } return chars; }
void CodeCompletionsExtractor::extractMacroCompletionKind() { CXCompletionString cxCompletionString = cxCodeCompleteResults->Results[cxCodeCompleteResultIndex].CompletionString; const uint completionChunkCount = clang_getNumCompletionChunks(cxCompletionString); for (uint chunkIndex = 0; chunkIndex < completionChunkCount; ++chunkIndex) { CXCompletionChunkKind kind = clang_getCompletionChunkKind(cxCompletionString, chunkIndex); if (kind == CXCompletionChunk_Placeholder) { currentCodeCompletion_.setCompletionKind(CodeCompletion::FunctionCompletionKind); return; } } currentCodeCompletion_.setCompletionKind(CodeCompletion::PreProcessorCompletionKind); }
const char* cc_result_entryname(CXCompletionString cs) { int num = clang_getNumCompletionChunks(cs); if(clang_getCompletionAvailability(cs) == CXAvailability_Available && num >= 1) { int i; for(i=0; i<num; i++) { int type = clang_getCompletionChunkKind(cs, i); if(type == CXCompletionChunk_TypedText){ CXString str = clang_getCompletionChunkText(cs, i); return clang_getCString(str); } } return NULL; }else { return NULL; } }
CompletionData::CompletionData( const CXCompletionResult &completion_result, bool is_argument_hint ) { CXCompletionString completion_string = completion_result.CompletionString; if ( !completion_string ) return; size_t num_chunks = clang_getNumCompletionChunks( completion_string ); bool saw_left_paren = false; bool saw_function_params = false; bool saw_placeholder = false; for ( size_t j = 0; j < num_chunks; ++j ) { ExtractDataFromChunk( completion_string, j, saw_left_paren, saw_function_params, saw_placeholder ); } original_string_ = RemoveTrailingParens( std::move( original_string_ ) ); kind_ = CursorKindToCompletionKind( completion_result.CursorKind ); detailed_info_.append( return_type_ ) .append( " " ) .append( everything_except_return_type_ ) .append( "\n" ); doc_string_ = YouCompleteMe::CXStringToString( clang_getCompletionBriefComment( completion_string ) ); // This address issue #1287 if ( kind_ == YouCompleteMe::FUNCTION || kind_ == YouCompleteMe::UNKNOWN ) everything_except_return_type_ = original_string_; if ( is_argument_hint ) { kind_ = NONE; return_type_ = ""; original_string_ = ""; everything_except_return_type_ = current_arg_; if ( everything_except_return_type_.empty() ) everything_except_return_type_ = "void"; } }
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); } }
OovStringVec Tokenizer::codeComplete(size_t offset) { CLangAutoLock lock(mCLangLock, __LINE__, this); OovStringVec strs; unsigned options = 0; // This gets more than we want. // unsigned options = clang_defaultCodeCompleteOptions(); unsigned int line; unsigned int column; getLineColumn(offset, line, column); CXCodeCompleteResults *results = clang_codeCompleteAt(mTransUnit, mSourceFilename.getStr(), line, column, nullptr, 0, options); if(results) { clang_sortCodeCompletionResults(&results->Results[0], results->NumResults); for(size_t ri=0; ri<results->NumResults /*&& ri < 50*/; ri++) { OovString str; CXCompletionString compStr = results->Results[ri].CompletionString; size_t numChunks = clang_getNumCompletionChunks(compStr); for(size_t ci=0; ci<numChunks && ci < 30; ci++) { CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(compStr, ci); // We will discard return values from functions, so the first // chunk returned will be the identifier or function name. Function // arguments will be returned after a space, so they can be // discarded easily. if(chunkKind == CXCompletionChunk_TypedText || str.length()) { std::string chunkStr = getDisposedString(clang_getCompletionChunkText(compStr, ci)); if(str.length() != 0) str += ' '; str += chunkStr; } } strs.push_back(str); } clang_disposeCodeCompleteResults(results); } return strs; }
void GmacsPreprocessor::codeCompletion(const QTextCursor &cursor) { int line = cursor.blockNumber(); int column = cursor.columnNumber(); //const char *name = filename->toLocal8Bit().data(); const char *name = clang_getCString(clang_getTranslationUnitSpelling(unit)); //qDebug() << cursor.document()->toPlainText(); //qDebug() << cursor.document()->toPlainText().size(); QString document = cursor.document()->toPlainText(); QString text = cursor.block().text(); QRegExp exp("\t"); int tab_count = text.count(exp); fprintf(stderr, "column = [%d]\n", cursor.positionInBlock()); //unsaved_file->Filename = name; //unsaved_file->Contents = document.toLocal8Bit().data(); //unsaved_file->Length = document.size(); if (!unit) return; CLANG_REPARSE(unit, NULL);//unsaved_file); fprintf(stderr, "line = [%d], column = [%d]\n", line+1, column + tab_count); fprintf(stderr, "name = [%s]\n", name); CXCodeCompleteResults *res = CLANG_CODE_COMPLETION(unit, name, line+1, column + tab_count); if (!res) fprintf(stderr, "ERROR: could not complete\n"); for (size_t i = 0; i < clang_codeCompleteGetNumDiagnostics(res); i++) { const CXDiagnostic &diag = clang_codeCompleteGetDiagnostic(res, i); const CXString &s = clang_getDiagnosticSpelling(diag); fprintf(stderr, "%s\n", clang_getCString(s)); } unsigned num_results = res->NumResults; fprintf(stderr, "num_results = [%d]\n"); for (unsigned i = 0; i < num_results; i++) { const CXCompletionString& str = res->Results[i].CompletionString; unsigned chunks = clang_getNumCompletionChunks(str); for (unsigned j = 0; j < chunks; j++) { const CXString& out = clang_getCompletionChunkText(str, j); //std::cout << clang_getCString(out) << " "; if (clang_getCompletionChunkKind(str, j) != CXCompletionChunk_TypedText) continue; } //std::cout << std::endl; } clang_disposeCodeCompleteResults(res); }
static int make_ac_proposal(struct make_ac_ctx *ctx, struct ac_proposal *p, CXCompletionResult *r, str_t *fmt) { unsigned int chunks_n; chunks_n = clang_getNumCompletionChunks(r->CompletionString); str_clear(ctx->word); str_clear(ctx->abbr); str_clear(ctx->type); str_clear(ctx->text); for (unsigned int i = 0; i < chunks_n; ++i) { enum CXCompletionChunkKind kind; CXString s; kind = clang_getCompletionChunkKind(r->CompletionString, i); s = clang_getCompletionChunkText(r->CompletionString, i); switch (kind) { case CXCompletionChunk_ResultType: str_add_printf(&ctx->type, "%s", clang_getCString(s)); break; case CXCompletionChunk_TypedText: str_add_cstr(&ctx->word, clang_getCString(s)); default: str_add_cstr(&ctx->text, clang_getCString(s)); break; } clang_disposeString(s); } if (ctx->type->len > MAX_TYPE_CHARS) { ctx->type->len = MAX_TYPE_CHARS-1; str_add_cstr(&ctx->type, "…"); } str_add_printf(&ctx->abbr, fmt->data, ctx->type->data, ctx->text->data); p->abbr = strdup(ctx->abbr->data); p->word = strdup(ctx->word->data); return 1; }
static int completion_printCompletionHeadTerm( CXCompletionString completion_string, FILE *fp) { int i_chunk = 0; int n_chunks = clang_getNumCompletionChunks(completion_string); CXString ac_string; /* inspect all chunks only to find the TypedText chunk */ for ( ; i_chunk < n_chunks; i_chunk++) { if (clang_getCompletionChunkKind(completion_string, i_chunk) == CXCompletionChunk_TypedText) { /* We got it, just dump it to fp */ ac_string = clang_getCompletionChunkText(completion_string, i_chunk); fprintf(fp, "COMPLETION: %s", clang_getCString(ac_string)); clang_disposeString(ac_string); return n_chunks; /* care package on the way */ } } return -1; /* We haven't found TypedText chunk in completion_string */ }
/* Print "COMPLETION: " followed by the TypedText chunk of the completion * string to fp, that's the text that a user would be expected to type to get * this code-completion result. TypedText is the keyword for the client program * (emacs script in this case) to filter completion results. * * Only prints a completion if it matches the given prefix. * * This function returns the number of matching completion chunks on success, or it * would return an -1 if no matching TypedText chunk was found. */ static int completion_printCompletionHeadTerm( CXCompletionString completion_string, FILE *fp, char *prefix) { int i_chunk = 0; int n_chunks = clang_getNumCompletionChunks(completion_string); CXString ac_string; /* inspect all chunks only to find the TypedText chunk */ for ( ; i_chunk < n_chunks; i_chunk++) { if (clang_getCompletionChunkKind(completion_string, i_chunk) == CXCompletionChunk_TypedText) { /* We got it, dump it to fp if it matches the prefix */ ac_string = clang_getCompletionChunkText(completion_string, i_chunk); char *cstring = (char *)clang_getCString(ac_string); if (isPrefix(prefix, cstring) > 0) { return -1; } fprintf(fp, "COMPLETION: %s", cstring); clang_disposeString(ac_string); return n_chunks; /* care package on the way */ } } return -1; /* We haven't found TypedText chunk in completion_string */ }
static void ide_clang_completion_item_lazy_init (IdeClangCompletionItem *self) { CXCompletionResult *result; g_autoptr(IdeSourceSnippet) snippet = NULL; GdkPixbuf *icon = NULL; GString *markup = NULL; unsigned num_chunks; unsigned i; guint tab_stop = 0; g_assert (IDE_IS_CLANG_COMPLETION_ITEM (self)); if (G_LIKELY (self->initialized)) return; result = ide_clang_completion_item_get_result (self); num_chunks = clang_getNumCompletionChunks (result); snippet = ide_source_snippet_new (NULL, NULL); markup = g_string_new (NULL); g_assert (result); g_assert (num_chunks); g_assert (IDE_IS_SOURCE_SNIPPET (snippet)); g_assert (markup); /* * Try to determine the icon to use for this result. */ switch ((int)result->CursorKind) { case CXCursor_CXXMethod: case CXCursor_Constructor: case CXCursor_Destructor: case CXCursor_MemberRef: case CXCursor_MemberRefExpr: case CXCursor_ObjCClassMethodDecl: case CXCursor_ObjCInstanceMethodDecl: icon = get_icon ("lang-method-symbolic"); break; case CXCursor_ConversionFunction: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: icon = get_icon ("lang-function-symbolic"); break; case CXCursor_FieldDecl: icon = get_icon ("struct-field-symbolic"); break; case CXCursor_VarDecl: /* local? */ case CXCursor_ParmDecl: case CXCursor_ObjCIvarDecl: case CXCursor_ObjCPropertyDecl: case CXCursor_ObjCSynthesizeDecl: case CXCursor_NonTypeTemplateParameter: case CXCursor_Namespace: case CXCursor_NamespaceAlias: case CXCursor_NamespaceRef: break; case CXCursor_StructDecl: icon = get_icon ("lang-struct-symbolic"); break; case CXCursor_UnionDecl: case CXCursor_ClassDecl: case CXCursor_TypeRef: case CXCursor_TemplateRef: case CXCursor_TypedefDecl: case CXCursor_ClassTemplate: case CXCursor_ClassTemplatePartialSpecialization: case CXCursor_ObjCClassRef: case CXCursor_ObjCInterfaceDecl: case CXCursor_ObjCImplementationDecl: case CXCursor_ObjCCategoryDecl: case CXCursor_ObjCCategoryImplDecl: case CXCursor_ObjCProtocolDecl: case CXCursor_ObjCProtocolRef: case CXCursor_TemplateTypeParameter: case CXCursor_TemplateTemplateParameter: icon = get_icon ("lang-class-symbolic"); break; case CXCursor_EnumConstantDecl: icon = get_icon ("lang-enum-value-symbolic"); break; case CXCursor_EnumDecl: icon = get_icon ("lang-enum-symbolic"); break; case CXCursor_NotImplemented: default: break; } /* * Walk the chunks, creating our snippet for insertion as well as our markup * for the row in the completion window. */ for (i = 0; i < num_chunks; i++) { enum CXCompletionChunkKind kind; IdeSourceSnippetChunk *chunk; const gchar *text; g_autofree gchar *escaped = NULL; CXString cxstr; kind = clang_getCompletionChunkKind (result->CompletionString, i); cxstr = clang_getCompletionChunkText (result->CompletionString, i); text = clang_getCString (cxstr); if (text) escaped = g_markup_escape_text (text, -1); else escaped = g_strdup (""); switch (kind) { case CXCompletionChunk_Optional: break; case CXCompletionChunk_TypedText: g_string_append_printf (markup, "<b>%s</b>", escaped); chunk = ide_source_snippet_chunk_new (); ide_source_snippet_chunk_set_text (chunk, text); ide_source_snippet_chunk_set_text_set (chunk, TRUE); ide_source_snippet_add_chunk (snippet, chunk); g_clear_object (&chunk); break; case CXCompletionChunk_Text: g_string_append (markup, escaped); chunk = ide_source_snippet_chunk_new (); ide_source_snippet_chunk_set_text (chunk, text); ide_source_snippet_chunk_set_text_set (chunk, TRUE); ide_source_snippet_add_chunk (snippet, chunk); g_clear_object (&chunk); break; case CXCompletionChunk_Placeholder: g_string_append (markup, escaped); chunk = ide_source_snippet_chunk_new (); ide_source_snippet_chunk_set_text (chunk, text); ide_source_snippet_chunk_set_text_set (chunk, TRUE); ide_source_snippet_chunk_set_tab_stop (chunk, ++tab_stop); ide_source_snippet_add_chunk (snippet, chunk); g_clear_object (&chunk); break; case CXCompletionChunk_Informative: if (0 == g_strcmp0 (text, "const ")) g_string_append (markup, text); break; case CXCompletionChunk_CurrentParameter: break; case CXCompletionChunk_LeftParen: g_string_append (markup, " "); chunk = ide_source_snippet_chunk_new (); ide_source_snippet_chunk_set_text (chunk, " "); ide_source_snippet_chunk_set_text_set (chunk, TRUE); ide_source_snippet_add_chunk (snippet, chunk); g_clear_object (&chunk); /* fall through */ 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_HorizontalSpace: g_string_append (markup, escaped); chunk = ide_source_snippet_chunk_new (); ide_source_snippet_chunk_set_text (chunk, text); ide_source_snippet_chunk_set_text_set (chunk, TRUE); ide_source_snippet_add_chunk (snippet, chunk); g_clear_object (&chunk); break; case CXCompletionChunk_VerticalSpace: g_string_append (markup, escaped); /* insert the vertical space */ chunk = ide_source_snippet_chunk_new (); ide_source_snippet_chunk_set_text (chunk, text); ide_source_snippet_chunk_set_text_set (chunk, TRUE); ide_source_snippet_add_chunk (snippet, chunk); g_clear_object (&chunk); /* now perform indentation */ chunk = ide_source_snippet_chunk_new (); ide_source_snippet_chunk_set_text (chunk, "\t"); ide_source_snippet_chunk_set_text_set (chunk, TRUE); ide_source_snippet_add_chunk (snippet, chunk); g_clear_object (&chunk); break; case CXCompletionChunk_ResultType: g_string_append_printf (markup, "%s ", escaped); break; default: break; } } self->snippet = g_object_ref (snippet); self->markup = g_string_free (markup, FALSE); self->icon = icon ? g_object_ref (icon) : NULL; }
void CompletionThread::process(Request *request) { // if (!request->unsaved.isEmpty()) { // int line = request->location.line(); // int pos = 0; // while (line > 1) { // int p = request->unsaved.indexOf('\n', pos); // if (p == -1) { // pos = -1; // break; // } // pos = p + 1; // --line; // } // if (pos != -1) { // int end = request->unsaved.indexOf('\n', pos); // if (end == -1) // end = request->unsaved.size(); // error("Completing at %s:%d:%d line: [%s]\n", // request->location.path().constData(), // request->location.line(), // request->location.column(), // request->unsaved.mid(pos, end - pos).constData()); // } // } StopWatch sw; int parseTime = 0; int reparseTime = 0; int completeTime = 0; int processTime = 0; SourceFile *&cache = mCacheMap[request->source.fileId]; if (cache && cache->source != request->source) { delete cache; cache = 0; } if (!cache) { cache = new SourceFile; mCacheList.append(cache); while (mCacheMap.size() > mCacheSize) { SourceFile *c = mCacheList.removeFirst(); mCacheMap.remove(c->source.fileId); delete c; } } else { mCacheList.moveToEnd(cache); } const bool sendDebug = testLog(LogLevel::Debug); if (cache->translationUnit && cache->source != request->source) { clang_disposeTranslationUnit(cache->translationUnit); cache->translationUnit = 0; cache->source = request->source; } else if (!cache->translationUnit) { cache->source = request->source; } const Path sourceFile = request->source.sourceFile(); CXUnsavedFile unsaved = { sourceFile.constData(), request->unsaved.constData(), static_cast<unsigned long>(request->unsaved.size()) }; size_t hash = 0; uint64_t lastModified = 0; if (request->unsaved.size()) { std::hash<String> h; hash = h(request->unsaved); } else { lastModified = sourceFile.lastModifiedMs(); } const auto &options = Server::instance()->options(); if (!cache->translationUnit) { cache->completionsMap.clear(); cache->completionsList.deleteAll(); sw.restart(); Flags<CXTranslationUnit_Flags> flags = static_cast<CXTranslationUnit_Flags>(clang_defaultEditingTranslationUnitOptions()); flags |= CXTranslationUnit_PrecompiledPreamble; flags |= CXTranslationUnit_CacheCompletionResults; flags |= CXTranslationUnit_SkipFunctionBodies; for (const auto &inc : options.includePaths) { request->source.includePaths << inc; } request->source.defines << options.defines; String clangLine; RTags::parseTranslationUnit(sourceFile, request->source.toCommandLine(Source::Default|Source::ExcludeDefaultArguments), cache->translationUnit, mIndex, &unsaved, request->unsaved.size() ? 1 : 0, flags, &clangLine); // error() << "PARSING" << clangLine; parseTime = sw.restart(); if (cache->translationUnit) { RTags::reparseTranslationUnit(cache->translationUnit, &unsaved, request->unsaved.size() ? 1 : 0); } reparseTime = sw.elapsed(); if (!cache->translationUnit) return; cache->unsavedHash = hash; cache->lastModified = lastModified; } else if (cache->unsavedHash != hash || cache->lastModified != lastModified) { cache->completionsMap.clear(); cache->completionsList.deleteAll(); cache->unsavedHash = hash; cache->lastModified = lastModified; } else if (!(request->flags & Refresh)) { const auto it = cache->completionsMap.find(request->location); if (it != cache->completionsMap.end()) { cache->completionsList.moveToEnd(it->second); error("Found completions (%d) in cache %s:%d:%d", it->second->candidates.size(), sourceFile.constData(), request->location.line(), request->location.column()); printCompletions(it->second->candidates, request); return; } } sw.restart(); const unsigned int completionFlags = (CXCodeComplete_IncludeMacros|CXCodeComplete_IncludeCodePatterns); CXCodeCompleteResults *results = clang_codeCompleteAt(cache->translationUnit, sourceFile.constData(), request->location.line(), request->location.column(), &unsaved, unsaved.Length ? 1 : 0, completionFlags); completeTime = sw.restart(); if (results) { std::vector<Completions::Candidate> nodes; nodes.reserve(results->NumResults); int nodeCount = 0; Map<Token, int> tokens; if (!request->unsaved.isEmpty()) { tokens = Token::tokenize(request->unsaved.constData(), request->unsaved.size()); // for (Map<Token, int>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { // error() << String(it->first.data, it->first.length) << it->second; // } } for (unsigned int i = 0; i < results->NumResults; ++i) { const CXCursorKind kind = results->Results[i].CursorKind; if (!(options.options & Server::CompletionsNoFilter) && kind == CXCursor_Destructor) continue; const CXCompletionString &string = results->Results[i].CompletionString; const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string); if (!(options.options & Server::CompletionsNoFilter) && availabilityKind != CXAvailability_Available) continue; const int priority = clang_getCompletionPriority(string); if (size_t(nodeCount) == nodes.size()) nodes.emplace_back(); Completions::Candidate &node = nodes.back(); node.cursorKind = kind; node.priority = priority; node.signature.reserve(256); const int chunkCount = clang_getNumCompletionChunks(string); bool ok = true; for (int j=0; j<chunkCount; ++j) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j); if (chunkKind == CXCompletionChunk_TypedText) { node.completion = RTags::eatString(clang_getCompletionChunkText(string, j)); if (node.completion.size() > 8 && node.completion.startsWith("operator") && !isPartOfSymbol(node.completion.at(8))) { ok = false; break; } node.signature.append(node.completion); } else { node.signature.append(RTags::eatString(clang_getCompletionChunkText(string, j))); if (chunkKind == CXCompletionChunk_ResultType) node.signature.append(' '); } } if (ok) { int ws = node.completion.size() - 1; while (ws >= 0 && isspace(node.completion.at(ws))) --ws; if (ws >= 0) { node.completion.truncate(ws + 1); node.signature.replace("\n", ""); node.distance = tokens.value(Token(node.completion.constData(), node.completion.size()), -1); if (sendDebug) debug() << node.signature << node.priority << kind << node.distance << clang_getCompletionAvailability(string); ++nodeCount; continue; } } node.completion.clear(); node.signature.clear(); } if (nodeCount) { // Sort pointers instead of shuffling candidates around std::vector<Completions::Candidate*> nodesPtr; nodesPtr.reserve(nodeCount); for (auto& n : nodes) nodesPtr.push_back(&n); std::sort(nodesPtr.begin(), nodesPtr.end(), compareCompletionCandidates); Completions *&c = cache->completionsMap[request->location]; if (c) { cache->completionsList.moveToEnd(c); } else { enum { MaxCompletionCache = 10 }; // ### configurable? c = new Completions(request->location); cache->completionsList.append(c); while (cache->completionsMap.size() > MaxCompletionCache) { Completions *cc = cache->completionsList.takeFirst(); cache->completionsMap.remove(cc->location); delete cc; } } c->candidates.resize(nodeCount); for (int i=0; i<nodeCount; ++i) c->candidates[i] = std::move(*nodesPtr[i]); printCompletions(c->candidates, request); processTime = sw.elapsed(); warning("Processed %s, parse %d/%d, complete %d, process %d => %d completions (unsaved %d)", sourceFile.constData(), parseTime, reparseTime, completeTime, processTime, nodeCount, request->unsaved.size()); } else { printCompletions(List<Completions::Candidate>(), request); error() << "No completion results available" << request->location << results->NumResults; } clang_disposeCodeCompleteResults(results); } }
void CompletionJob::execute() { CXUnsavedFile unsavedFile = { mUnsaved.isEmpty() ? 0 : mPath.constData(), mUnsaved.isEmpty() ? 0 : mUnsaved.constData(), static_cast<unsigned long>(mUnsaved.size()) }; CXCodeCompleteResults *results = clang_codeCompleteAt(mUnit, mPath.constData(), mLine, mColumn, &unsavedFile, mUnsaved.isEmpty() ? 0 : 1, CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns); if (results) { CompletionNode *nodes = new CompletionNode[results->NumResults]; int nodeCount = 0; Map<Token, int> tokens; if (!mUnsaved.isEmpty()) { tokenize(mUnsaved.constData(), mUnsaved.size(), tokens); // for (Map<Token, int>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { // error() << ByteArray(it->first.data, it->first.length) << it->second; // } } for (unsigned i = 0; i < results->NumResults; ++i) { const CXCursorKind kind = results->Results[i].CursorKind; if (kind == CXCursor_Destructor) continue; const CXCompletionString &string = results->Results[i].CompletionString; const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string); if (availabilityKind != CXAvailability_Available) continue; const int priority = clang_getCompletionPriority(string); if (priority >= 75) continue; CompletionNode &node = nodes[nodeCount]; node.priority = priority; node.signature.reserve(256); const int chunkCount = clang_getNumCompletionChunks(string); bool ok = true; for (int j=0; j<chunkCount; ++j) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j); if (chunkKind == CXCompletionChunk_TypedText) { node.completion = RTags::eatString(clang_getCompletionChunkText(string, j)); if (node.completion.size() > 8 && node.completion.startsWith("operator") && !isPartOfSymbol(node.completion.at(8))) { ok = false; break; } node.signature.append(node.completion); } else { node.signature.append(RTags::eatString(clang_getCompletionChunkText(string, j))); if (chunkKind == CXCompletionChunk_ResultType) node.signature.append(' '); } } if (ok) { int ws = node.completion.size() - 1; while (ws >= 0 && isspace(node.completion.at(ws))) --ws; if (ws >= 0) { node.completion.truncate(ws + 1); node.signature.replace("\n", ""); node.distance = tokens.value(Token(node.completion.constData(), node.completion.size()), -1); ++nodeCount; continue; } } node.completion.clear(); node.signature.clear(); } if (nodeCount) { qsort(nodes, nodeCount, sizeof(CompletionNode), compareCompletionNode); write<128>("`%s %s", nodes[0].completion.constData(), nodes[0].signature.constData()); for (int i=1; i<nodeCount; ++i) { write<128>("%s %s", nodes[i].completion.constData(), nodes[i].signature.constData()); } } delete[] nodes; //processDiagnostics(results); clang_disposeCodeCompleteResults(results); shared_ptr<Project> proj = project(); if (proj) proj->addToCache(mPath, mArgs, mIndex, mUnit); } mFinished(mPath); }
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(" $/")); } }
/** * ide_clang_completion_item_get_typed_text: * @self: An #IdeClangCompletionItem. * * Gets the text that would be expected to be typed to insert this completion * item into the text editor. * * Returns: A string which should not be modified or freed. */ const gchar * ide_clang_completion_item_get_typed_text (IdeClangCompletionItem *self) { CXCompletionResult *result; CXString cxstr; g_return_val_if_fail (IDE_IS_CLANG_COMPLETION_ITEM (self), NULL); if (self->typed_text) return self->typed_text; result = ide_clang_completion_item_get_result (self); /* * Determine the index of the typed text. Each completion result should have * exaction one of these. */ if (G_UNLIKELY (self->typed_text_index == -1)) { guint num_chunks; guint i; num_chunks = clang_getNumCompletionChunks (result); for (i = 0; i < num_chunks; i++) { enum CXCompletionChunkKind kind; kind = clang_getCompletionChunkKind (result->CompletionString, i); if (kind == CXCompletionChunk_TypedText) { self->typed_text_index = i; break; } } } if (self->typed_text_index == -1) { /* * FIXME: * * This seems like an implausible result, but we are definitely * hitting it occasionally. */ return g_strdup (""); } #ifdef IDE_ENABLE_TRACE { enum CXCompletionChunkKind kind; unsigned num_chunks; g_assert (self->typed_text_index >= 0); num_chunks = clang_getNumCompletionChunks (result->CompletionString); g_assert (num_chunks > self->typed_text_index); kind = clang_getCompletionChunkKind (result->CompletionString, self->typed_text_index); g_assert (kind == CXCompletionChunk_TypedText); } #endif cxstr = clang_getCompletionChunkText (result->CompletionString, self->typed_text_index); self->typed_text = g_strdup (clang_getCString (cxstr)); clang_disposeString (cxstr); return self->typed_text; }
unsigned code_completion_string::chunks() const { return clang_getNumCompletionChunks(str); }
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; }
completion_list translation_unit::complete_at(uint32_t row, uint32_t col) { completion_list ret; CXCodeCompleteResults *res; if (mCxUnsaved) { res = clang_codeCompleteAt(mUnit, mName.c_str(), row, col, mCxUnsaved, 1, 0); } else res = clang_codeCompleteAt(mUnit, mName.c_str(), row, col, nullptr, 0, 0); for (uint32_t i = 0; i < res->NumResults; ++i) { // skip all private members if (clang_getCompletionAvailability(res->Results[i].CompletionString) == CXAvailability_NotAccessible) continue; // number of completion chunks for the current result completion_result r; uint32_t nChunks = clang_getNumCompletionChunks(res->Results[i].CompletionString); // function to handle a single chunk auto handle_chunk = [&](CXCompletionChunkKind k, uint32_t num) { CXString txt = clang_getCompletionChunkText(res->Results[i].CompletionString, num); switch (k) { case CXCompletionChunk_ResultType: r.return_type = cx2std(txt); break; case CXCompletionChunk_TypedText: r.name = cx2std(txt); break; case CXCompletionChunk_Placeholder: r.args.push_back(cx2std(txt)); break; case CXCompletionChunk_Optional: case CXCompletionChunk_LeftParen: case CXCompletionChunk_RightParen: case CXCompletionChunk_RightBracket: case CXCompletionChunk_LeftBracket: case CXCompletionChunk_LeftBrace: case CXCompletionChunk_RightBrace: case CXCompletionChunk_RightAngle: case CXCompletionChunk_LeftAngle: case CXCompletionChunk_Comma: case CXCompletionChunk_Colon: case CXCompletionChunk_SemiColon: case CXCompletionChunk_Equal: case CXCompletionChunk_Informative: case CXCompletionChunk_HorizontalSpace: break; default: break; } }; for (uint32_t k = 0; k < nChunks; ++k) { handle_chunk(clang_getCompletionChunkKind(res->Results[i].CompletionString, k), k); } // fill additional info and append to result set r.brief = cx2std(clang_getCompletionBriefComment(res->Results[i].CompletionString)); r.priority = clang_getCompletionPriority(res->Results[i].CompletionString); r.type = cursor2completion(res->Results[i].CursorKind); // @todo: once clang forwards the CXCursor of a completion result, we should get // the full documentation for each entry ret.push_back(r); } clang_disposeCodeCompleteResults(res); return ret; }
void CompletionJob::execute() { StopWatch timer; CXUnsavedFile unsavedFile = { mUnsaved.isEmpty() ? 0 : mPath.constData(), mUnsaved.isEmpty() ? 0 : mUnsaved.constData(), static_cast<unsigned long>(mUnsaved.size()) }; if (!mUnit) { String clangLine; RTags::parseTranslationUnit(mPath, mArgs, mUnit, Server::instance()->clangIndex(), clangLine, 0, 0, &unsavedFile, 1); mParseCount = 1; if (!mUnit) { error() << "Failed to parse" << mPath << "Can't complete"; return; } } // error() << "Completing" << mPath << mParseCount; assert(mParseCount >= 1 && mParseCount <= 2); if (mParseCount == 1) { RTags::reparseTranslationUnit(mUnit, &unsavedFile, 1); if (!mUnit) { mFinished(mPath, id()); return; } else { ++mParseCount; } } CXCodeCompleteResults *results = clang_codeCompleteAt(mUnit, mPath.constData(), mLine, mColumn, &unsavedFile, mUnsaved.isEmpty() ? 0 : 1, CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns); if (results) { CompletionNode *nodes = new CompletionNode[results->NumResults]; int nodeCount = 0; Map<Token, int> tokens; if (!mUnsaved.isEmpty()) { tokenize(mUnsaved.constData(), mUnsaved.size(), tokens); // for (Map<Token, int>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { // error() << String(it->first.data, it->first.length) << it->second; // } } for (unsigned i = 0; i < results->NumResults; ++i) { const CXCursorKind kind = results->Results[i].CursorKind; if (kind == CXCursor_Destructor) continue; const CXCompletionString &string = results->Results[i].CompletionString; const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string); if (availabilityKind != CXAvailability_Available) continue; const int priority = clang_getCompletionPriority(string); if (priority >= 75) continue; CompletionNode &node = nodes[nodeCount]; node.priority = priority; node.signature.reserve(256); const int chunkCount = clang_getNumCompletionChunks(string); bool ok = true; for (int j=0; j<chunkCount; ++j) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j); if (chunkKind == CXCompletionChunk_TypedText) { node.completion = RTags::eatString(clang_getCompletionChunkText(string, j)); if (node.completion.size() > 8 && node.completion.startsWith("operator") && !isPartOfSymbol(node.completion.at(8))) { ok = false; break; } node.signature.append(node.completion); } else { node.signature.append(RTags::eatString(clang_getCompletionChunkText(string, j))); if (chunkKind == CXCompletionChunk_ResultType) node.signature.append(' '); } } if (ok) { int ws = node.completion.size() - 1; while (ws >= 0 && isspace(node.completion.at(ws))) --ws; if (ws >= 0) { node.completion.truncate(ws + 1); node.signature.replace("\n", ""); node.distance = tokens.value(Token(node.completion.constData(), node.completion.size()), -1); ++nodeCount; continue; } } node.completion.clear(); node.signature.clear(); } if (nodeCount) { if (nodeCount > SendThreshold) { write("`"); } else { qsort(nodes, nodeCount, sizeof(CompletionNode), compareCompletionNode); if (mType == Stream) { write<128>("`%s %s", nodes[0].completion.constData(), nodes[0].signature.constData()); } else { write<128>("%s %s", nodes[0].completion.constData(), nodes[0].signature.constData()); } for (int i=1; i<nodeCount; ++i) { write<128>("%s %s", nodes[i].completion.constData(), nodes[i].signature.constData()); } } } warning() << "Wrote" << ((nodeCount > SendThreshold) ? -1 : nodeCount) << "completions for" << String::format<128>("%s:%d:%d", mPath.constData(), mLine, mColumn) << "in" << timer.elapsed() << "ms" << mArgs; // const unsigned diagnosticCount = clang_getNumDiagnostics(mUnit); // for (unsigned i=0; i<diagnosticCount; ++i) { // CXDiagnostic diagnostic = clang_getDiagnostic(mUnit, i); // const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(diagnostic); // const String msg = RTags::eatString(clang_getDiagnosticSpelling(diagnostic)); // CXFile file; // unsigned line, col; // clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file, &line, &col, 0); // error() << i << diagnosticCount << severity << msg // << String::format<128>("%s:%d:%d", RTags::eatString(clang_getFileName(file)).constData(), // line, col); // clang_disposeDiagnostic(diagnostic); // } delete[] nodes; //processDiagnostics(results); clang_disposeCodeCompleteResults(results); std::shared_ptr<Project> proj = project(); if (proj) { // error() << "Adding to cache" << mParseCount << mPath; proj->addToCache(mPath, mArgs, mUnit, mParseCount); } } mFinished(mPath, id()); }