Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -5073,6 +5073,19 @@ unsigned NumResults; } CXCodeCompleteResults; +/** + * \brief Retrieve a cursor corresponding to the completion result at the given index. + * + * \param result The results in which to look for the cursor. + * \param index The index into the CXCompletionResult array in CXCodeCompleteResults. + * + * \returns The cursor that represents the completion result at the given index, + * or a null cursor when the result does not represent a cursor. This + * will happen e.g. for language keywords. + */ +CINDEX_LINKAGE CXCursor +clang_getCompletionCursor(CXCodeCompleteResults *Results, int Index); + /** * \brief Flags that can be passed to \c clang_codeCompleteAt() to * modify its behavior. Index: test/CodeCompletion/templates.cpp =================================================================== --- test/CodeCompletion/templates.cpp +++ test/CodeCompletion/templates.cpp @@ -24,5 +24,8 @@ // CHECK-CC2: foo // CHECK-CC2: in_base // CHECK-CC2: stop - + // RUN: c-index-test -code-completion-at=%s:18:8 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s + // CHECK-CC3: ClassTemplate:{TypedText allocator}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50) (source location: 3:9) + // CHECK-CC3-NEXT: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{Optional {Comma , }{Placeholder typename Alloc}}{RightAngle >} (50) (source location: 9:9) + Index: tools/c-index-test/c-index-test.c =================================================================== --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -2144,13 +2144,21 @@ } static void print_completion_result(CXCompletionResult *completion_result, - FILE *file) { + FILE *file, + CXCodeCompleteResults *all_results, + int index_in_results) { CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind); unsigned annotationCount; enum CXCursorKind ParentKind; CXString ParentName; CXString BriefComment; CXString Annotation; + CXCursor SourceCursor; + CXSourceLocation SourceLocation; + uint SourceLine = 0; + uint SourceColumn = 0; + CXFile SourceFile; + CXString SourceFileName; const char *BriefCommentCString; fprintf(file, "%s:", clang_getCString(ks)); @@ -2212,7 +2220,12 @@ fprintf(file, "(brief comment: %s)", BriefCommentCString); } clang_disposeString(BriefComment); - + + SourceCursor = clang_getCompletionCursor(all_results, index_in_results); + SourceLocation = clang_getCursorLocation(SourceCursor); + clang_getFileLocation(SourceLocation, &SourceFile, &SourceLine, &SourceColumn, 0); + fprintf(file, " (source location: %i:%i)", SourceLine, SourceColumn); + fprintf(file, "\n"); } @@ -2369,7 +2382,7 @@ clang_sortCodeCompletionResults(results->Results, results->NumResults); for (i = 0; i != n; ++i) - print_completion_result(results->Results + i, stdout); + print_completion_result(results->Results + i, stdout, results, i); } n = clang_codeCompleteGetNumDiagnostics(results); for (i = 0; i != n; ++i) { Index: tools/libclang/CIndexCodeCompletion.cpp =================================================================== --- tools/libclang/CIndexCodeCompletion.cpp +++ tools/libclang/CIndexCodeCompletion.cpp @@ -301,6 +301,9 @@ /// \brief A string containing the Objective-C selector entered thus far for a /// message send. std::string Selector; + + /// \brief the list of cursors for the results + SmallVector Cursors; }; } // end anonymous namespace @@ -530,16 +533,36 @@ CodeCompletionResult *Results, unsigned NumResults) override { StoredResults.reserve(StoredResults.size() + NumResults); + AllocatedResults.Cursors.reserve(AllocatedResults.Cursors.size() + NumResults); for (unsigned I = 0; I != NumResults; ++I) { + auto& Result = Results[I]; CodeCompletionString *StoredCompletion - = Results[I].CreateCodeCompletionString(S, Context, getAllocator(), + = Result.CreateCodeCompletionString(S, Context, getAllocator(), getCodeCompletionTUInfo(), includeBriefComments()); CXCompletionResult R; - R.CursorKind = Results[I].CursorKind; + R.CursorKind = Result.CursorKind; R.CompletionString = StoredCompletion; StoredResults.push_back(R); + + CXCursor cursor = clang_getNullCursor(); + switch (Result.Kind) { + case CodeCompletionResult::RK_Pattern: + case CodeCompletionResult::RK_Declaration: + if (auto Declaration = Result.Declaration) + cursor = cxcursor::MakeCXCursor(Declaration, *TU); + break; + case CodeCompletionResult::RK_Macro: + // TODO: build the CXCursor that represents the Resul.Macro + // I have no idea how to get the MacroDefinitionRecord + // corresponding to the IdentifierInfo + break; + case CodeCompletionResult::RK_Keyword: + // not representable by a cursor + break; + } + AllocatedResults.Cursors.push_back(cursor); } enum CodeCompletionContext::Kind contextKind = Context.getKind(); @@ -606,9 +629,11 @@ OverloadCandidate *Candidates, unsigned NumCandidates) override { StoredResults.reserve(StoredResults.size() + NumCandidates); + AllocatedResults.Cursors.reserve(AllocatedResults.Cursors.size() + NumCandidates); for (unsigned I = 0; I != NumCandidates; ++I) { + const auto& Candidate = Candidates[I]; CodeCompletionString *StoredCompletion - = Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(), + = Candidate.CreateSignatureString(CurrentArg, S, getAllocator(), getCodeCompletionTUInfo(), includeBriefComments()); @@ -616,6 +641,10 @@ R.CursorKind = CXCursor_OverloadCandidate; R.CompletionString = StoredCompletion; StoredResults.push_back(R); + + auto FunctionDecl = Candidate.getFunction(); + CXCursor cursor = FunctionDecl ? cxcursor::MakeCXCursor(FunctionDecl, *TU) : clang_getNullCursor(); + AllocatedResults.Cursors.push_back(cursor); } } @@ -977,6 +1006,17 @@ }; } +CXCursor clang_getCompletionCursor(CXCodeCompleteResults *ResultsIn, int Index) +{ + if (!ResultsIn || Index >= ResultsIn->NumResults) + return clang_getNullCursor(); + + AllocatedCXCodeCompleteResults *Results + = static_cast(ResultsIn); + + return Results->Cursors[Index]; +} + void clang_sortCodeCompletionResults(CXCompletionResult *Results, unsigned NumResults) { std::stable_sort(Results, Results + NumResults, OrderCompletionResults()); Index: tools/libclang/libclang.exports =================================================================== --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -161,6 +161,7 @@ clang_getCanonicalType clang_getChildDiagnostics clang_getClangVersion +clang_getCompletionCursor clang_getCompletionAnnotation clang_getCompletionAvailability clang_getCompletionBriefComment