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,15 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include #include +#include namespace clang { class NamedDecl; namespace clangd { struct PreambleData; +struct CodeCompleteResult; struct CodeCompleteOptions { /// Returns options that can be passed to clang's completion engine. @@ -129,6 +133,13 @@ /// Always use text-based completion. NeverParse, } RunParser = ParseIfReady; + + /// Enables special instrumentation mode that allows capturing various + /// internal structures used by clangd during code completion. Eg: Symbol + /// quality and relevance signals of all the candidates in the output. + /// Ideally this must be disabled when being used by ClangdLSPServer. + bool EnableInstrumentationMode = false; + std::function *RecordCCResults; }; // Semi-structured representation of a code-complete suggestion for our C++ API. @@ -202,6 +213,10 @@ // Relevance describes how well this candidate matched the query. // e.g. symbols from nearby files have higher relevance. float Relevance = 0.f; + + // Signals captured when instrumentation is enabled during code completion. + std::shared_ptr QualitySignals; + std::shared_ptr RelevanceSignals; }; Scores Score; 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 @@ -65,7 +65,9 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" #include +#include #include +#include // We log detailed candidate here if you run with -debug-only=codecomplete. #define DEBUG_TYPE "CodeComplete" @@ -1458,6 +1460,10 @@ // Merge Sema and Index results, score them, and pick the winners. auto Top = mergeResults(Recorder->Results, IndexResults, /*Identifiers*/ {}); + + if (Opts.EnableInstrumentationMode) + (*Opts.RecordCCResults)(toCodeCompleteResult(Top)); + return toCodeCompleteResult(Top); } @@ -1660,6 +1666,12 @@ ? Scores.Total / Relevance.NameMatch : Scores.Quality; + if (Opts.EnableInstrumentationMode) { + Scores.QualitySignals = std::make_shared(Quality); + Scores.RelevanceSignals = + std::make_shared(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,6 +29,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include +#include #include namespace clang { @@ -1041,6 +1042,31 @@ EXPECT_THAT(Completions, Contains(Named("TT"))); } +TEST(CompletionTest, EnableInstrumentationMode) { + CodeCompleteResult CapturedResult; + std::function ResultRecorder = + [&CapturedResult](const CodeCompleteResult &Result) -> void { + CapturedResult = Result; + }; + CodeCompleteOptions Opts; + Opts.EnableInstrumentationMode = true; + Opts.RecordCCResults = &ResultRecorder; + + auto Results = + completions("int xyz; int a = xy^", /*IndexSymbols=*/{}, Opts); + EXPECT_EQ(Results.Completions.size(), CapturedResult.Completions.size()); + ASSERT_GT(CapturedResult.Completions.size(), 0); + EXPECT_TRUE(CapturedResult.Completions.front().Score.QualitySignals); + EXPECT_TRUE(CapturedResult.Completions.front().Score.RelevanceSignals); +} + +TEST(CompletionTest, DisableInstrumentationModeByDefault) { + auto Results = completions("int xyz; int a = xy^"); + ASSERT_GT(Results.Completions.size(), 0); + EXPECT_FALSE(Results.Completions.front().Score.QualitySignals); + EXPECT_FALSE(Results.Completions.front().Score.RelevanceSignals); +} + SignatureHelp signatures(llvm::StringRef Text, Position Point, std::vector IndexSymbols = {}) { std::unique_ptr Index;