sammccall created this revision.
sammccall added a reviewer: ioeric.
Herald added subscribers: cfe-commits, jkorous, MaskRay, ilya-biryukov.
Surface it in the completion items C++ API, and when a flag is set.
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D48938
Files:
clangd/CodeComplete.cpp
clangd/CodeComplete.h
clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
clangd/index/FileIndex.cpp
clangd/index/Index.cpp
clangd/index/Index.h
clangd/index/Merge.cpp
clangd/index/SymbolCollector.cpp
clangd/index/SymbolCollector.h
clangd/tool/ClangdMain.cpp
unittests/clangd/CodeCompleteTests.cpp
unittests/clangd/IndexTests.cpp
Index: unittests/clangd/IndexTests.cpp
===================================================================
--- unittests/clangd/IndexTests.cpp
+++ unittests/clangd/IndexTests.cpp
@@ -282,6 +282,8 @@
DetR.Documentation = "--doc--";
L.Detail = &DetL;
R.Detail = &DetR;
+ L.Origin = SymbolOrigin::Dynamic;
+ R.Origin = SymbolOrigin::Static;
Symbol::Details Scratch;
Symbol M = mergeSymbol(L, R, &Scratch);
@@ -293,6 +295,8 @@
ASSERT_TRUE(M.Detail);
EXPECT_EQ(M.Detail->ReturnType, "DetL");
EXPECT_EQ(M.Detail->Documentation, "--doc--");
+ EXPECT_EQ(M.Origin,
+ SymbolOrigin::Dynamic | SymbolOrigin::Static | SymbolOrigin::Merge);
}
TEST(MergeTest, PreferSymbolWithDefn) {
Index: unittests/clangd/CodeCompleteTests.cpp
===================================================================
--- unittests/clangd/CodeCompleteTests.cpp
+++ unittests/clangd/CodeCompleteTests.cpp
@@ -59,6 +59,7 @@
}
MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); }
MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; }
+MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; }
// Shorthand for Contains(Named(Name)).
Matcher<const std::vector<CodeCompletion> &> Has(std::string Name) {
@@ -137,6 +138,7 @@
Sym.ID = SymbolID(USR);
Sym.SymInfo.Kind = Kind;
Sym.IsIndexedForCodeCompletion = true;
+ Sym.Origin = SymbolOrigin::Static;
return Sym;
}
Symbol func(StringRef Name) { // Assumes the function has no args.
@@ -511,9 +513,12 @@
)cpp",
{func("ns::both"), cls("ns::Index")});
// We get results from both index and sema, with no duplicates.
- EXPECT_THAT(
- Results.Completions,
- UnorderedElementsAre(Named("local"), Named("Index"), Named("both")));
+ EXPECT_THAT(Results.Completions,
+ UnorderedElementsAre(
+ AllOf(Named("local"), Origin(SymbolOrigin::AST)),
+ AllOf(Named("Index"), Origin(SymbolOrigin::Static)),
+ AllOf(Named("both"),
+ Origin(SymbolOrigin::AST | SymbolOrigin::Static))));
}
TEST(CompletionTest, SemaIndexMergeWithLimit) {
@@ -1252,6 +1257,8 @@
C.Header = "\"foo.h\"";
C.Kind = CompletionItemKind::Method;
C.Score.Total = 1.0;
+ C.Origin =
+ static_cast<SymbolOrigin>(SymbolOrigin::AST | SymbolOrigin::Static);
CodeCompleteOptions Opts;
Opts.IncludeIndicator.Insert = "^";
@@ -1278,6 +1285,10 @@
EXPECT_EQ(R.label, "^Foo::x(bool) const");
EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
+ Opts.ShowOrigins = true;
+ R = C.render(Opts);
+ EXPECT_EQ(R.label, "^[AS]Foo::x(bool) const");
+
C.BundleSize = 2;
R = C.render(Opts);
EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -143,6 +143,11 @@
"Clang uses an index built from symbols in opened files"),
llvm::cl::init(true));
+static llvm::cl::opt<bool> ShowOrigins(
+ "debug-origin", llvm::cl::desc("Show origins of completion items"),
+ llvm::cl::init(clangd::CodeCompleteOptions().ShowOrigins),
+ llvm::cl::Hidden);
+
static llvm::cl::opt<Path> YamlSymbolFile(
"yaml-symbol-file",
llvm::cl::desc(
@@ -261,6 +266,7 @@
CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
CCOpts.Limit = LimitResults;
CCOpts.BundleOverloads = CompletionStyle != Detailed;
+ CCOpts.ShowOrigins = ShowOrigins;
// Initialize and run ClangdLSPServer.
ClangdLSPServer LSPServer(Out, CCOpts, CompileCommandsDirPath, Opts);
Index: clangd/index/SymbolCollector.h
===================================================================
--- clangd/index/SymbolCollector.h
+++ clangd/index/SymbolCollector.h
@@ -52,6 +52,8 @@
const CanonicalIncludes *Includes = nullptr;
// Populate the Symbol.References field.
bool CountReferences = false;
+ // Every symbol collected will be stamped with this origin.
+ SymbolOrigin Origin = SymbolOrigin::Unknown;
};
SymbolCollector(Options Opts);
Index: clangd/index/SymbolCollector.cpp
===================================================================
--- clangd/index/SymbolCollector.cpp
+++ clangd/index/SymbolCollector.cpp
@@ -411,6 +411,7 @@
Detail.IncludeHeader = Include;
S.Detail = &Detail;
+ S.Origin = Opts.Origin;
Symbols.insert(S);
return Symbols.find(S.ID);
}
Index: clangd/index/Merge.cpp
===================================================================
--- clangd/index/Merge.cpp
+++ clangd/index/Merge.cpp
@@ -115,6 +115,9 @@
} else
S.Detail = O.Detail;
}
+
+ S.Origin =
+ static_cast<SymbolOrigin>(S.Origin | O.Origin | SymbolOrigin::Merge);
return S;
}
Index: clangd/index/Index.h
===================================================================
--- clangd/index/Index.h
+++ clangd/index/Index.h
@@ -117,6 +117,19 @@
namespace clang {
namespace clangd {
+// Describes the source of information about a symbol.
+// Mainly useful for debugging, e.g. understanding code completion reuslts.
+// This is a bitfield as information can be combined from several sources.
+enum SymbolOrigin : uint8_t {
+ Unknown = 0,
+ AST = 1 << 0, // Directly from the AST (indexes should not set this).
+ Dynamic = 1 << 1, // From the dynamic index of opened files.
+ Static = 1 << 2, // From the static, externally-built index.
+ Merge = 1 << 3, // A non-trivial index merge was performed.
+ // Remaining bits reserved for index implementations.
+};
+raw_ostream &operator<<(raw_ostream&, SymbolOrigin);
+
// The class presents a C++ symbol, e.g. class, function.
//
// WARNING: Symbols do not own much of their underlying data - typically strings
@@ -157,6 +170,8 @@
/// Whether or not this symbol is meant to be used for the code completion.
/// See also isIndexedForCodeCompletion().
bool IsIndexedForCodeCompletion = false;
+ /// Where this symbol came from. Usually an index provides a constant value.
+ SymbolOrigin Origin = Unknown;
/// A brief description of the symbol that can be appended in the completion
/// candidate list. For example, "(X x, Y y) const" is a function signature.
llvm::StringRef Signature;
Index: clangd/index/Index.cpp
===================================================================
--- clangd/index/Index.cpp
+++ clangd/index/Index.cpp
@@ -44,6 +44,16 @@
std::copy(HexString.begin(), HexString.end(), ID.HashValue.begin());
}
+raw_ostream &operator<<(raw_ostream &OS, SymbolOrigin O) {
+ if (O == SymbolOrigin::Unknown)
+ return OS << "unknown";
+ static char Sigils[] = "ADSM4567";
+ for (unsigned I = 0; I < sizeof(Sigils); ++I)
+ if (O & static_cast<SymbolOrigin>(1 << I))
+ OS << Sigils[I];
+ return OS;
+}
+
raw_ostream &operator<<(raw_ostream &OS, const Symbol &S) {
return OS << S.Scope << S.Name;
}
Index: clangd/index/FileIndex.cpp
===================================================================
--- clangd/index/FileIndex.cpp
+++ clangd/index/FileIndex.cpp
@@ -27,6 +27,7 @@
CollectorOpts.CountReferences = false;
if (!URISchemes.empty())
CollectorOpts.URISchemes = URISchemes;
+ CollectorOpts.Origin = SymbolOrigin::Dynamic;
SymbolCollector Collector(std::move(CollectorOpts));
Collector.setPreprocessor(PP);
Index: clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
===================================================================
--- clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
+++ clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
@@ -112,6 +112,7 @@
CollectorOpts.FallbackDir = AssumedHeaderDir;
CollectorOpts.CollectIncludePath = true;
CollectorOpts.CountReferences = true;
+ CollectorOpts.Origin = Origin::Static;
auto Includes = llvm::make_unique<CanonicalIncludes>();
addSystemHeadersMapping(Includes.get());
CollectorOpts.Includes = Includes.get();
Index: clangd/CodeComplete.h
===================================================================
--- clangd/CodeComplete.h
+++ clangd/CodeComplete.h
@@ -67,6 +67,9 @@
std::string NoInsert = " ";
} IncludeIndicator;
+ /// Expose origins of completion items in the label (for debugging).
+ bool ShowOrigins = false;
+
// Populated internally by clangd, do not set.
/// If `Index` is set, it is used to augment the code completion
/// results.
@@ -103,6 +106,7 @@
// - Documentation may be from one symbol, or a combination of several
// Other fields should apply equally to all bundled completions.
unsigned BundleSize = 1;
+ SymbolOrigin Origin = SymbolOrigin::Unknown;
// The header through which this symbol could be included.
// Quoted string as expected by an #include directive, e.g. "<memory>".
// Empty for non-symbol completions, or when not known.
Index: clangd/CodeComplete.cpp
===================================================================
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -41,6 +41,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/ScopedPrinter.h"
#include <queue>
// We log detailed candidate here if you run with -debug-only=codecomplete.
@@ -266,6 +267,8 @@
: ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments) {
add(C, SemaCCS);
if (C.SemaResult) {
+ Completion.Origin =
+ static_cast<SymbolOrigin>(Completion.Origin | SymbolOrigin::AST);
Completion.Name = llvm::StringRef(SemaCCS->getTypedText());
if (Completion.Scope.empty())
if (C.SemaResult->Kind == CodeCompletionResult::RK_Declaration)
@@ -277,6 +280,8 @@
toCompletionItemKind(C.SemaResult->Kind, C.SemaResult->Declaration);
}
if (C.IndexResult) {
+ Completion.Origin =
+ static_cast<SymbolOrigin>(Completion.Origin | C.IndexResult->Origin);
if (Completion.Scope.empty())
Completion.Scope = C.IndexResult->Scope;
if (Completion.Kind == CompletionItemKind::Missing)
@@ -1144,17 +1149,18 @@
Relevance.NameMatch = *FuzzyScore;
else
return;
- unsigned SemaResult = 0, IndexResult = 0;
+ SymbolOrigin Origin = SymbolOrigin::Unknown;
for (const auto &Candidate : Bundle) {
if (Candidate.IndexResult) {
Quality.merge(*Candidate.IndexResult);
Relevance.merge(*Candidate.IndexResult);
- ++IndexResult;
+ Origin =
+ static_cast<SymbolOrigin>(Origin | Candidate.IndexResult->Origin);
}
if (Candidate.SemaResult) {
Quality.merge(*Candidate.SemaResult);
Relevance.merge(*Candidate.SemaResult);
- ++SemaResult;
+ Origin = static_cast<SymbolOrigin>(Origin | SymbolOrigin::AST);
}
}
@@ -1167,15 +1173,14 @@
? Scores.Total / Relevance.NameMatch
: Scores.Quality;
- LLVM_DEBUG(llvm::dbgs() << "CodeComplete: " << First.Name << "("
- << IndexResult << " index) "
- << "(" << SemaResult << " sema)"
- << " = " << Scores.Total << "\n"
- << Quality << Relevance << "\n");
+ LLVM_DEBUG(llvm::dbgs()
+ << "CodeComplete: " << First.Name << "(" << Origin << ")"
+ << " = " << Scores.Total << "\n"
+ << Quality << Relevance << "\n");
- NSema += bool(SemaResult);
- NIndex += bool(IndexResult);
- NBoth += SemaResult && IndexResult;
+ NSema += bool(Origin & SymbolOrigin::AST);
+ NIndex += bool(Origin & ~SymbolOrigin::AST);
+ NBoth += (Origin & SymbolOrigin::AST) && (Origin & ~SymbolOrigin::AST);
if (Candidates.push({std::move(Bundle), Scores}))
Incomplete = true;
}
@@ -1243,7 +1248,9 @@
CompletionItem LSP;
LSP.label = (HeaderInsertion ? Opts.IncludeIndicator.Insert
: Opts.IncludeIndicator.NoInsert) +
+ (Opts.ShowOrigins ? "[" + llvm::to_string(Origin) + "]" : "") +
RequiredQualifier + Name + Signature;
+
LSP.kind = Kind;
LSP.detail = BundleSize > 1 ? llvm::formatv("[{0} overloads]", BundleSize)
: ReturnType;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits