diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -19,6 +19,7 @@ #include "Logger.h" #include "Path.h" #include "Protocol.h" +#include "Quality.h" #include "index/Index.h" #include "index/Symbol.h" #include "index/SymbolOrigin.h" @@ -29,12 +30,14 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include #include namespace clang { class NamedDecl; namespace clangd { struct PreambleData; +struct CodeCompletion; struct CodeCompleteOptions { /// Returns options that can be passed to clang's completion engine. @@ -129,6 +132,16 @@ /// Always use text-based completion. NeverParse, } RunParser = ParseIfReady; + + /// Callback invoked on all CompletionCandidate after they are scored and + /// before they are ranked (by -Score). Thus the results are yielded in + /// arbitrary order. CodeCompletion also contains the computed Score. + /// + /// This callbacks allows capturing various internal structures used by clangd + /// during code completion. Eg: Symbol quality and relevance signals. + std::function + RecordCCResult; }; // Semi-structured representation of a code-complete suggestion for our C++ API. diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1660,6 +1660,13 @@ ? Scores.Total / Relevance.NameMatch : Scores.Quality; + if (Opts.RecordCCResult) { + CodeCompletion Completion = toCodeCompletion(Bundle); + Completion.Score = Scores; + Completion.CompletionTokenRange = ReplacedRange; + Opts.RecordCCResult(Completion, Quality, Relevance); + } + dlog("CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name, llvm::to_string(Origin), Scores.Total, llvm::to_string(Quality), llvm::to_string(Relevance)); diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -29,7 +29,9 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include +#include #include +#include namespace clang { namespace clangd { @@ -69,6 +71,7 @@ MATCHER(InsertInclude, "") { return !arg.Includes.empty() && bool(arg.Includes[0].Insertion); } +MATCHER(Scored, "") { return arg.Score.Total > 0; } MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; } MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; } MATCHER_P(Signature, S, "") { return arg.Signature == S; } @@ -1041,6 +1044,21 @@ EXPECT_THAT(Completions, Contains(Named("TT"))); } +TEST(CompletionTest, EnableInstrumentationMode) { + std::vector RecordedCompletions; + CodeCompleteOptions Opts; + Opts.RecordCCResult = [&RecordedCompletions](const CodeCompletion &CC, + const SymbolQualitySignals &, + const SymbolRelevanceSignals &) { + RecordedCompletions.push_back(CC); + }; + + completions("int xy1, xy2; int a = xy^", /*IndexSymbols=*/{}, Opts); + EXPECT_THAT(RecordedCompletions, + UnorderedElementsAre(AllOf(Named("xy1"), Scored()), + AllOf(Named("xy2"), Scored()))); +} + SignatureHelp signatures(llvm::StringRef Text, Position Point, std::vector IndexSymbols = {}) { std::unique_ptr Index;