[clang-tools-extra] [clangd] Re-land "support outgoing calls in call hierarchy" (PR #117673)
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 3 00:46:05 PST 2024
https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/117673
>From 65f93cd05d9d792bba9a07bda738503f43221221 Mon Sep 17 00:00:00 2001
From: Quentin Chateau <quentin.chateau at gmail.com>
Date: Mon, 18 Sep 2023 03:01:03 -0400
Subject: [PATCH 1/8] [clangd] Support outgoing calls in call hierarchy
The implementation is very close the the incoming
calls implementation. The results of the outgoing
calls are expected to be the exact symmetry of the
incoming calls.
Differential Revision: https://reviews.llvm.org/D93829
---
clang-tools-extra/clangd/ClangdLSPServer.cpp | 7 +
clang-tools-extra/clangd/ClangdLSPServer.h | 3 +
clang-tools-extra/clangd/ClangdServer.cpp | 9 +
clang-tools-extra/clangd/ClangdServer.h | 4 +
clang-tools-extra/clangd/XRefs.cpp | 63 ++++
clang-tools-extra/clangd/XRefs.h | 3 +
clang-tools-extra/clangd/index/Index.cpp | 5 +
clang-tools-extra/clangd/index/Index.h | 22 ++
clang-tools-extra/clangd/index/MemIndex.cpp | 19 ++
clang-tools-extra/clangd/index/MemIndex.h | 4 +
clang-tools-extra/clangd/index/Merge.cpp | 34 +++
clang-tools-extra/clangd/index/Merge.h | 3 +
.../clangd/index/ProjectAware.cpp | 13 +
clang-tools-extra/clangd/index/dex/Dex.cpp | 25 ++
clang-tools-extra/clangd/index/dex/Dex.h | 18 ++
.../clangd/test/type-hierarchy-ext.test | 2 +
.../clangd/test/type-hierarchy.test | 51 +---
.../clangd/unittests/CallHierarchyTests.cpp | 277 +++++++++++++-----
.../clangd/unittests/CodeCompleteTests.cpp | 6 +
.../clangd/unittests/RenameTests.cpp | 12 +
20 files changed, 457 insertions(+), 123 deletions(-)
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 05dd313d0a0d35..1391dcaa0c81a4 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -1415,6 +1415,12 @@ void ClangdLSPServer::onInlayHint(const InlayHintsParams &Params,
std::move(Reply));
}
+void ClangdLSPServer::onCallHierarchyOutgoingCalls(
+ const CallHierarchyOutgoingCallsParams &Params,
+ Callback<std::vector<CallHierarchyOutgoingCall>> Reply) {
+ Server->outgoingCalls(Params.item, std::move(Reply));
+}
+
void ClangdLSPServer::applyConfiguration(
const ConfigurationSettings &Settings) {
// Per-file update to the compilation database.
@@ -1693,6 +1699,7 @@ void ClangdLSPServer::bindMethods(LSPBinder &Bind,
Bind.method("typeHierarchy/subtypes", this, &ClangdLSPServer::onSubTypes);
Bind.method("textDocument/prepareCallHierarchy", this, &ClangdLSPServer::onPrepareCallHierarchy);
Bind.method("callHierarchy/incomingCalls", this, &ClangdLSPServer::onCallHierarchyIncomingCalls);
+ Bind.method("callHierarchy/outgoingCalls", this, &ClangdLSPServer::onCallHierarchyOutgoingCalls);
Bind.method("textDocument/selectionRange", this, &ClangdLSPServer::onSelectionRange);
Bind.method("textDocument/documentLink", this, &ClangdLSPServer::onDocumentLink);
Bind.method("textDocument/semanticTokens/full", this, &ClangdLSPServer::onSemanticTokens);
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h
index 0b8e4720f53236..597fd9de7ff688 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -156,6 +156,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
void onCallHierarchyIncomingCalls(
const CallHierarchyIncomingCallsParams &,
Callback<std::vector<CallHierarchyIncomingCall>>);
+ void onCallHierarchyOutgoingCalls(
+ const CallHierarchyOutgoingCallsParams &,
+ Callback<std::vector<CallHierarchyOutgoingCall>>);
void onClangdInlayHints(const InlayHintsParams &,
Callback<llvm::json::Value>);
void onInlayHint(const InlayHintsParams &, Callback<std::vector<InlayHint>>);
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index 9b38be04e7ddd7..63f83bc36f0c69 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -912,6 +912,15 @@ void ClangdServer::inlayHints(PathRef File, std::optional<Range> RestrictRange,
WorkScheduler->runWithAST("InlayHints", File, std::move(Action), Transient);
}
+void ClangdServer::outgoingCalls(
+ const CallHierarchyItem &Item,
+ Callback<std::vector<CallHierarchyOutgoingCall>> CB) {
+ WorkScheduler->run("Outgoing Calls", "",
+ [CB = std::move(CB), Item, this]() mutable {
+ CB(clangd::outgoingCalls(Item, Index));
+ });
+}
+
void ClangdServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
// FIXME: Do nothing for now. This will be used for indexing and potentially
// invalidating other caches.
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index a653cdb56b751b..8b6618cf96ccfc 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -292,6 +292,10 @@ class ClangdServer {
void incomingCalls(const CallHierarchyItem &Item,
Callback<std::vector<CallHierarchyIncomingCall>>);
+ /// Resolve outgoing calls for a given call hierarchy item.
+ void outgoingCalls(const CallHierarchyItem &Item,
+ Callback<std::vector<CallHierarchyOutgoingCall>>);
+
/// Resolve inlay hints for a given document.
void inlayHints(PathRef File, std::optional<Range> RestrictRange,
Callback<std::vector<InlayHint>>);
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index 61fa66180376cd..f50c70a4cd4d29 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -1702,6 +1702,7 @@ declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {
HierarchyItem HI;
HI.name = printName(Ctx, ND);
+ // FIXME: Populate HI.detail the way we do in symbolToHierarchyItem?
HI.kind = SK;
HI.range = Range{sourceLocToPosition(SM, DeclRange->getBegin()),
sourceLocToPosition(SM, DeclRange->getEnd())};
@@ -1753,6 +1754,7 @@ static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,
}
HierarchyItem HI;
HI.name = std::string(S.Name);
+ HI.detail = (S.Scope + S.Name).str();
HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
HI.selectionRange = Loc->range;
// FIXME: Populate 'range' correctly
@@ -2319,6 +2321,67 @@ incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
return Results;
}
+std::vector<CallHierarchyOutgoingCall>
+outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
+ std::vector<CallHierarchyOutgoingCall> Results;
+ if (!Index || Item.data.empty())
+ return Results;
+ auto ID = SymbolID::fromStr(Item.data);
+ if (!ID) {
+ elog("outgoingCalls failed to find symbol: {0}", ID.takeError());
+ return Results;
+ }
+ // In this function, we find outgoing calls based on the index only.
+ RefsRequest Request;
+ Request.IDs.insert(*ID);
+ // We could restrict more specifically to calls by introducing a new RefKind,
+ // but non-call references (such as address-of-function) can still be
+ // interesting as they can indicate indirect calls.
+ Request.Filter = RefKind::Reference;
+ // Initially store the ranges in a map keyed by SymbolID of the callee.
+ // This allows us to group different calls to the same function
+ // into the same CallHierarchyOutgoingCall.
+ llvm::DenseMap<SymbolID, std::vector<Range>> CallsOut;
+ // We can populate the ranges based on a refs request only. As we do so, we
+ // also accumulate the callee IDs into a lookup request.
+ LookupRequest CallsOutLookup;
+ Index->refersTo(Request, [&](const auto &R) {
+ auto Loc = indexToLSPLocation(R.Location, Item.uri.file());
+ if (!Loc) {
+ elog("outgoingCalls failed to convert location: {0}", Loc.takeError());
+ return;
+ }
+ auto It = CallsOut.try_emplace(R.Symbol, std::vector<Range>{}).first;
+ It->second.push_back(Loc->range);
+
+ CallsOutLookup.IDs.insert(R.Symbol);
+ });
+ // Perform the lookup request and combine its results with CallsOut to
+ // get complete CallHierarchyOutgoingCall objects.
+ Index->lookup(CallsOutLookup, [&](const Symbol &Callee) {
+ // Filter references to only keep function calls
+ using SK = index::SymbolKind;
+ auto Kind = Callee.SymInfo.Kind;
+ if (Kind != SK::Function && Kind != SK::InstanceMethod &&
+ Kind != SK::ClassMethod && Kind != SK::StaticMethod &&
+ Kind != SK::Constructor && Kind != SK::Destructor &&
+ Kind != SK::ConversionFunction)
+ return;
+
+ auto It = CallsOut.find(Callee.ID);
+ assert(It != CallsOut.end());
+ if (auto CHI = symbolToCallHierarchyItem(Callee, Item.uri.file()))
+ Results.push_back(
+ CallHierarchyOutgoingCall{std::move(*CHI), std::move(It->second)});
+ });
+ // Sort results by name of the callee.
+ llvm::sort(Results, [](const CallHierarchyOutgoingCall &A,
+ const CallHierarchyOutgoingCall &B) {
+ return A.to.name < B.to.name;
+ });
+ return Results;
+}
+
llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
const FunctionDecl *FD) {
if (!FD->hasBody())
diff --git a/clang-tools-extra/clangd/XRefs.h b/clang-tools-extra/clangd/XRefs.h
index df91dd15303c18..247e52314c3f94 100644
--- a/clang-tools-extra/clangd/XRefs.h
+++ b/clang-tools-extra/clangd/XRefs.h
@@ -150,6 +150,9 @@ prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath);
std::vector<CallHierarchyIncomingCall>
incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index);
+std::vector<CallHierarchyOutgoingCall>
+outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index);
+
/// Returns all decls that are referenced in the \p FD except local symbols.
llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,
const FunctionDecl *FD);
diff --git a/clang-tools-extra/clangd/index/Index.cpp b/clang-tools-extra/clangd/index/Index.cpp
index 7a0c23287db225..c2cbfed35c2352 100644
--- a/clang-tools-extra/clangd/index/Index.cpp
+++ b/clang-tools-extra/clangd/index/Index.cpp
@@ -66,6 +66,11 @@ bool SwapIndex::refs(const RefsRequest &R,
llvm::function_ref<void(const Ref &)> CB) const {
return snapshot()->refs(R, CB);
}
+bool SwapIndex::refersTo(
+ const RefsRequest &R,
+ llvm::function_ref<void(const RefersToResult &)> CB) const {
+ return snapshot()->refersTo(R, CB);
+}
void SwapIndex::relations(
const RelationsRequest &R,
llvm::function_ref<void(const SymbolID &, const Symbol &)> CB) const {
diff --git a/clang-tools-extra/clangd/index/Index.h b/clang-tools-extra/clangd/index/Index.h
index 047ce08e93e3ab..4ad066f396f587 100644
--- a/clang-tools-extra/clangd/index/Index.h
+++ b/clang-tools-extra/clangd/index/Index.h
@@ -84,6 +84,14 @@ struct RelationsRequest {
std::optional<uint32_t> Limit;
};
+struct RefersToResult {
+ /// The source location where the symbol is named.
+ SymbolLocation Location;
+ RefKind Kind = RefKind::Unknown;
+ /// The ID of the symbol which is referred to
+ SymbolID Symbol;
+};
+
/// Describes what data is covered by an index.
///
/// Indexes may contain symbols but not references from a file, etc.
@@ -141,6 +149,17 @@ class SymbolIndex {
virtual bool refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const = 0;
+ /// Find all symbols that are referenced by a symbol and apply
+ /// \p Callback on each result.
+ ///
+ /// Results should be returned in arbitrary order.
+ /// The returned result must be deep-copied if it's used outside Callback.
+ ///
+ /// Returns true if there will be more results (limited by Req.Limit);
+ virtual bool
+ refersTo(const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const = 0;
+
/// Finds all relations (S, P, O) stored in the index such that S is among
/// Req.Subjects and P is Req.Predicate, and invokes \p Callback for (S, O) in
/// each.
@@ -175,6 +194,9 @@ class SwapIndex : public SymbolIndex {
llvm::function_ref<void(const Symbol &)>) const override;
bool refs(const RefsRequest &,
llvm::function_ref<void(const Ref &)>) const override;
+ bool
+ refersTo(const RefsRequest &,
+ llvm::function_ref<void(const RefersToResult &)>) const override;
void relations(const RelationsRequest &,
llvm::function_ref<void(const SymbolID &, const Symbol &)>)
const override;
diff --git a/clang-tools-extra/clangd/index/MemIndex.cpp b/clang-tools-extra/clangd/index/MemIndex.cpp
index 2665d46b97d839..2b15d00a6c7f89 100644
--- a/clang-tools-extra/clangd/index/MemIndex.cpp
+++ b/clang-tools-extra/clangd/index/MemIndex.cpp
@@ -85,6 +85,25 @@ bool MemIndex::refs(const RefsRequest &Req,
return false; // We reported all refs.
}
+bool MemIndex::refersTo(
+ const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const {
+ trace::Span Tracer("MemIndex refersTo");
+ uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
+ for (const auto &Pair : Refs) {
+ for (const auto &R : Pair.second) {
+ if (!static_cast<int>(Req.Filter & R.Kind) ||
+ !Req.IDs.contains(R.Container))
+ continue;
+ if (Remaining == 0)
+ return true; // More refs were available.
+ --Remaining;
+ Callback({R.Location, R.Kind, Pair.first});
+ }
+ }
+ return false; // We reported all refs.
+}
+
void MemIndex::relations(
const RelationsRequest &Req,
llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const {
diff --git a/clang-tools-extra/clangd/index/MemIndex.h b/clang-tools-extra/clangd/index/MemIndex.h
index fba2c1a7120a2b..9fd3b2a353b624 100644
--- a/clang-tools-extra/clangd/index/MemIndex.h
+++ b/clang-tools-extra/clangd/index/MemIndex.h
@@ -72,6 +72,10 @@ class MemIndex : public SymbolIndex {
bool refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const override;
+ bool refersTo(
+ const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const override;
+
void relations(const RelationsRequest &Req,
llvm::function_ref<void(const SymbolID &, const Symbol &)>
Callback) const override;
diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp
index 8221d4b1f44405..bedc0bc3f912ab 100644
--- a/clang-tools-extra/clangd/index/Merge.cpp
+++ b/clang-tools-extra/clangd/index/Merge.cpp
@@ -155,6 +155,40 @@ bool MergedIndex::refs(const RefsRequest &Req,
return More || StaticHadMore;
}
+bool MergedIndex::refersTo(
+ const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const {
+ trace::Span Tracer("MergedIndex refersTo");
+ bool More = false;
+ uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
+ // We don't want duplicated refs from the static/dynamic indexes,
+ // and we can't reliably deduplicate them because offsets may differ slightly.
+ // We consider the dynamic index authoritative and report all its refs,
+ // and only report static index refs from other files.
+ More |= Dynamic->refersTo(Req, [&](const auto &O) {
+ Callback(O);
+ assert(Remaining != 0);
+ --Remaining;
+ });
+ if (Remaining == 0 && More)
+ return More;
+ auto DynamicContainsFile = Dynamic->indexedFiles();
+ // We return less than Req.Limit if static index returns more refs for dirty
+ // files.
+ bool StaticHadMore = Static->refersTo(Req, [&](const auto &O) {
+ if ((DynamicContainsFile(O.Location.FileURI) & IndexContents::References) !=
+ IndexContents::None)
+ return; // ignore refs that have been seen from dynamic index.
+ if (Remaining == 0) {
+ More = true;
+ return;
+ }
+ --Remaining;
+ Callback(O);
+ });
+ return More || StaticHadMore;
+}
+
llvm::unique_function<IndexContents(llvm::StringRef) const>
MergedIndex::indexedFiles() const {
return [DynamicContainsFile{Dynamic->indexedFiles()},
diff --git a/clang-tools-extra/clangd/index/Merge.h b/clang-tools-extra/clangd/index/Merge.h
index b8a562b0df5d92..57dd88f34b3cbb 100644
--- a/clang-tools-extra/clangd/index/Merge.h
+++ b/clang-tools-extra/clangd/index/Merge.h
@@ -38,6 +38,9 @@ class MergedIndex : public SymbolIndex {
llvm::function_ref<void(const Symbol &)>) const override;
bool refs(const RefsRequest &,
llvm::function_ref<void(const Ref &)>) const override;
+ bool
+ refersTo(const RefsRequest &,
+ llvm::function_ref<void(const RefersToResult &)>) const override;
void relations(const RelationsRequest &,
llvm::function_ref<void(const SymbolID &, const Symbol &)>)
const override;
diff --git a/clang-tools-extra/clangd/index/ProjectAware.cpp b/clang-tools-extra/clangd/index/ProjectAware.cpp
index 2c6f8273b35d0e..5179a5bd0e4d56 100644
--- a/clang-tools-extra/clangd/index/ProjectAware.cpp
+++ b/clang-tools-extra/clangd/index/ProjectAware.cpp
@@ -35,6 +35,10 @@ class ProjectAwareIndex : public SymbolIndex {
/// Query all indexes while prioritizing the associated one (if any).
bool refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const override;
+ /// Query all indexes while prioritizing the associated one (if any).
+ bool refersTo(
+ const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const override;
/// Queries only the associates index when Req.RestrictForCodeCompletion is
/// set, otherwise queries all.
@@ -94,6 +98,15 @@ bool ProjectAwareIndex::refs(
return false;
}
+bool ProjectAwareIndex::refersTo(
+ const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const {
+ trace::Span Tracer("ProjectAwareIndex::refersTo");
+ if (auto *Idx = getIndex())
+ return Idx->refersTo(Req, Callback);
+ return false;
+}
+
bool ProjectAwareIndex::fuzzyFind(
const FuzzyFindRequest &Req,
llvm::function_ref<void(const Symbol &)> Callback) const {
diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp
index b7d3063e19b499..67851c355a780b 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.cpp
+++ b/clang-tools-extra/clangd/index/dex/Dex.cpp
@@ -147,6 +147,11 @@ void Dex::buildIndex() {
for (DocID SymbolRank = 0; SymbolRank < Symbols.size(); ++SymbolRank)
Builder.add(*Symbols[SymbolRank], SymbolRank);
InvertedIndex = std::move(Builder).build();
+
+ // Build RevRefs
+ for (const auto &Pair : Refs)
+ for (const auto &R : Pair.second)
+ RevRefs[R.Container].emplace_back(R, Pair.first);
}
std::unique_ptr<Iterator> Dex::iterator(const Token &Tok) const {
@@ -314,6 +319,23 @@ bool Dex::refs(const RefsRequest &Req,
return false; // We reported all refs.
}
+bool Dex::refersTo(
+ const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const {
+ trace::Span Tracer("Dex reversed refs");
+ uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
+ for (const auto &ID : Req.IDs)
+ for (const auto &Rev : RevRefs.lookup(ID)) {
+ if (!static_cast<int>(Req.Filter & Rev.ref().Kind))
+ continue;
+ if (Remaining == 0)
+ return true; // More refs were available.
+ --Remaining;
+ Callback(Rev.refersToResult());
+ }
+ return false; // We reported all refs.
+}
+
void Dex::relations(
const RelationsRequest &Req,
llvm::function_ref<void(const SymbolID &, const Symbol &)> Callback) const {
@@ -350,6 +372,9 @@ size_t Dex::estimateMemoryUsage() const {
for (const auto &TokenToPostingList : InvertedIndex)
Bytes += TokenToPostingList.second.bytes();
Bytes += Refs.getMemorySize();
+ Bytes += RevRefs.getMemorySize();
+ for (const auto &Entry : RevRefs)
+ Bytes += Entry.second.size() * sizeof(Entry.second.front());
Bytes += Relations.getMemorySize();
return Bytes + BackingDataSize;
}
diff --git a/clang-tools-extra/clangd/index/dex/Dex.h b/clang-tools-extra/clangd/index/dex/Dex.h
index 69e161d51135b6..86a8d6300d98f9 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.h
+++ b/clang-tools-extra/clangd/index/dex/Dex.h
@@ -85,6 +85,10 @@ class Dex : public SymbolIndex {
bool refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const override;
+ bool refersTo(
+ const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback) const override;
+
void relations(const RelationsRequest &Req,
llvm::function_ref<void(const SymbolID &, const Symbol &)>
Callback) const override;
@@ -95,6 +99,19 @@ class Dex : public SymbolIndex {
size_t estimateMemoryUsage() const override;
private:
+ class RevRef {
+ const Ref &Reference;
+ SymbolID Target;
+
+ public:
+ RevRef(const Ref &Reference, SymbolID Target)
+ : Reference(Reference), Target(Target) {}
+ const Ref &ref() const { return Reference; }
+ RefersToResult refersToResult() const {
+ return {Reference.Location, Reference.Kind, Target};
+ }
+ };
+
void buildIndex();
std::unique_ptr<Iterator> iterator(const Token &Tok) const;
std::unique_ptr<Iterator>
@@ -116,6 +133,7 @@ class Dex : public SymbolIndex {
llvm::DenseMap<Token, PostingList> InvertedIndex;
dex::Corpus Corpus;
llvm::DenseMap<SymbolID, llvm::ArrayRef<Ref>> Refs;
+ llvm::DenseMap<SymbolID, std::vector<RevRef>> RevRefs;
static_assert(sizeof(RelationKind) == sizeof(uint8_t),
"RelationKind should be of same size as a uint8_t");
llvm::DenseMap<std::pair<SymbolID, uint8_t>, std::vector<SymbolID>> Relations;
diff --git a/clang-tools-extra/clangd/test/type-hierarchy-ext.test b/clang-tools-extra/clangd/test/type-hierarchy-ext.test
index ddb9a014be0c72..8d1a5dc31da0f1 100644
--- a/clang-tools-extra/clangd/test/type-hierarchy-ext.test
+++ b/clang-tools-extra/clangd/test/type-hierarchy-ext.test
@@ -12,6 +12,7 @@
# CHECK-NEXT: "data": {
# CHECK-NEXT: "symbolID": "A6576FE083F2949A"
# CHECK-NEXT: },
+# CHECK-NEXT: "detail": "Child3",
# CHECK-NEXT: "kind": 23,
# CHECK-NEXT: "name": "Child3",
# CHECK-NEXT: "range": {
@@ -153,6 +154,7 @@
# CHECK-NEXT: "data": {
# CHECK-NEXT: "symbolID": "5705B382DFC77CBC"
# CHECK-NEXT: },
+# CHECK-NEXT: "detail": "Child4",
# CHECK-NEXT: "kind": 23,
# CHECK-NEXT: "name": "Child4",
# CHECK-NEXT: "range": {
diff --git a/clang-tools-extra/clangd/test/type-hierarchy.test b/clang-tools-extra/clangd/test/type-hierarchy.test
index 69751000a7c6c0..3617c7ef9f5bc2 100644
--- a/clang-tools-extra/clangd/test/type-hierarchy.test
+++ b/clang-tools-extra/clangd/test/type-hierarchy.test
@@ -62,6 +62,7 @@
# CHECK-NEXT: ],
# CHECK-NEXT: "symbolID": "ECDC0C46D75120F4"
# CHECK-NEXT: },
+# CHECK-NEXT: "detail": "Child1",
# CHECK-NEXT: "kind": 23,
# CHECK-NEXT: "name": "Child1",
# CHECK-NEXT: "range": {
@@ -88,56 +89,6 @@
# CHECK-NEXT: }
# CHECK-NEXT: ]
---
-{"jsonrpc":"2.0","id":2,"method":"typeHierarchy/subtypes","params":{"item":{"uri":"test:///main.cpp","data":{"parents":[{"parents":[{"parents":[],"symbolID":"FE546E7B648D69A7"}],"symbolID":"ECDC0C46D75120F4"}],"symbolID":"8A991335E4E67D08"},"name":"Child2","kind":23,"range":{"end":{"character":13,"line":3},"start":{"character":7,"line":3}},"selectionRange":{"end":{"character":13,"line":3},"start":{"character":7,"line":3}}}}}
-# CHECK: "id": 2
-# CHECK-NEXT: "jsonrpc": "2.0",
-# CHECK-NEXT: "result": [
-# CHECK-NEXT: {
-# CHECK-NEXT: "data": {
-# CHECK-NEXT: "parents": [
-# CHECK-NEXT: {
-# CHECK-NEXT: "parents": [
-# CHECK-NEXT: {
-# CHECK-NEXT: "parents": [
-# CHECK-NEXT: {
-# CHECK-NEXT: "parents": [],
-# CHECK-NEXT: "symbolID": "FE546E7B648D69A7"
-# CHECK-NEXT: }
-# CHECK-NEXT: ],
-# CHECK-NEXT: "symbolID": "ECDC0C46D75120F4"
-# CHECK-NEXT: }
-# CHECK-NEXT: ],
-# CHECK-NEXT: "symbolID": "8A991335E4E67D08"
-# CHECK-NEXT: }
-# CHECK-NEXT: ],
-# CHECK-NEXT: "symbolID": "A6576FE083F2949A"
-# CHECK-NEXT: },
-# CHECK-NEXT: "kind": 23,
-# CHECK-NEXT: "name": "Child3",
-# CHECK-NEXT: "range": {
-# CHECK-NEXT: "end": {
-# CHECK-NEXT: "character": 13,
-# CHECK-NEXT: "line": 3
-# CHECK-NEXT: },
-# CHECK-NEXT: "start": {
-# CHECK-NEXT: "character": 7,
-# CHECK-NEXT: "line": 3
-# CHECK-NEXT: }
-# CHECK-NEXT: },
-# CHECK-NEXT: "selectionRange": {
-# CHECK-NEXT: "end": {
-# CHECK-NEXT: "character": 13,
-# CHECK-NEXT: "line": 3
-# CHECK-NEXT: },
-# CHECK-NEXT: "start": {
-# CHECK-NEXT: "character": 7,
-# CHECK-NEXT: "line": 3
-# CHECK-NEXT: }
-# CHECK-NEXT: },
-# CHECK-NEXT: "uri": "file://{{.*}}/clangd-test/main.cpp"
-# CHECK-NEXT: }
-# CHECK-NEXT: ]
----
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
diff --git a/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp b/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp
index 8821d3aad9c784..316b94305c9aeb 100644
--- a/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp
@@ -44,17 +44,27 @@ using ::testing::UnorderedElementsAre;
// Helpers for matching call hierarchy data structures.
MATCHER_P(withName, N, "") { return arg.name == N; }
+MATCHER_P(withDetail, N, "") { return arg.detail == N; }
MATCHER_P(withSelectionRange, R, "") { return arg.selectionRange == R; }
template <class ItemMatcher>
::testing::Matcher<CallHierarchyIncomingCall> from(ItemMatcher M) {
return Field(&CallHierarchyIncomingCall::from, M);
}
+template <class ItemMatcher>
+::testing::Matcher<CallHierarchyOutgoingCall> to(ItemMatcher M) {
+ return Field(&CallHierarchyOutgoingCall::to, M);
+}
template <class... RangeMatchers>
-::testing::Matcher<CallHierarchyIncomingCall> fromRanges(RangeMatchers... M) {
+::testing::Matcher<CallHierarchyIncomingCall> iFromRanges(RangeMatchers... M) {
return Field(&CallHierarchyIncomingCall::fromRanges,
UnorderedElementsAre(M...));
}
+template <class... RangeMatchers>
+::testing::Matcher<CallHierarchyOutgoingCall> oFromRanges(RangeMatchers... M) {
+ return Field(&CallHierarchyOutgoingCall::fromRanges,
+ UnorderedElementsAre(M...));
+}
TEST(CallHierarchy, IncomingOneFileCpp) {
Annotations Source(R"cpp(
@@ -79,21 +89,24 @@ TEST(CallHierarchy, IncomingOneFileCpp) {
prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
ASSERT_THAT(Items, ElementsAre(withName("callee")));
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
- ASSERT_THAT(IncomingLevel1,
- ElementsAre(AllOf(from(withName("caller1")),
- fromRanges(Source.range("Callee")))));
+ ASSERT_THAT(
+ IncomingLevel1,
+ ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))),
+ iFromRanges(Source.range("Callee")))));
auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
- ASSERT_THAT(IncomingLevel2,
- ElementsAre(AllOf(from(withName("caller2")),
- fromRanges(Source.range("Caller1A"),
- Source.range("Caller1B"))),
- AllOf(from(withName("caller3")),
- fromRanges(Source.range("Caller1C")))));
+ ASSERT_THAT(
+ IncomingLevel2,
+ ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))),
+ iFromRanges(Source.range("Caller1A"),
+ Source.range("Caller1B"))),
+ AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))),
+ iFromRanges(Source.range("Caller1C")))));
auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
- ASSERT_THAT(IncomingLevel3,
- ElementsAre(AllOf(from(withName("caller3")),
- fromRanges(Source.range("Caller2")))));
+ ASSERT_THAT(
+ IncomingLevel3,
+ ElementsAre(AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))),
+ iFromRanges(Source.range("Caller2")))));
auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
EXPECT_THAT(IncomingLevel4, IsEmpty());
@@ -125,20 +138,24 @@ TEST(CallHierarchy, IncomingOneFileObjC) {
ASSERT_THAT(Items, ElementsAre(withName("callee")));
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
ASSERT_THAT(IncomingLevel1,
- ElementsAre(AllOf(from(withName("caller1")),
- fromRanges(Source.range("Callee")))));
+ ElementsAre(AllOf(from(AllOf(withName("caller1"),
+ withDetail("MyClass::caller1"))),
+ iFromRanges(Source.range("Callee")))));
auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
ASSERT_THAT(IncomingLevel2,
- ElementsAre(AllOf(from(withName("caller2")),
- fromRanges(Source.range("Caller1A"),
- Source.range("Caller1B"))),
- AllOf(from(withName("caller3")),
- fromRanges(Source.range("Caller1C")))));
+ ElementsAre(AllOf(from(AllOf(withName("caller2"),
+ withDetail("MyClass::caller2"))),
+ iFromRanges(Source.range("Caller1A"),
+ Source.range("Caller1B"))),
+ AllOf(from(AllOf(withName("caller3"),
+ withDetail("MyClass::caller3"))),
+ iFromRanges(Source.range("Caller1C")))));
auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
ASSERT_THAT(IncomingLevel3,
- ElementsAre(AllOf(from(withName("caller3")),
- fromRanges(Source.range("Caller2")))));
+ ElementsAre(AllOf(from(AllOf(withName("caller3"),
+ withDetail("MyClass::caller3"))),
+ iFromRanges(Source.range("Caller2")))));
auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
EXPECT_THAT(IncomingLevel4, IsEmpty());
@@ -167,14 +184,16 @@ TEST(CallHierarchy, MainFileOnlyRef) {
prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
ASSERT_THAT(Items, ElementsAre(withName("callee")));
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
- ASSERT_THAT(IncomingLevel1,
- ElementsAre(AllOf(from(withName("caller1")),
- fromRanges(Source.range("Callee")))));
+ ASSERT_THAT(
+ IncomingLevel1,
+ ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))),
+ iFromRanges(Source.range("Callee")))));
auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
- EXPECT_THAT(IncomingLevel2,
- ElementsAre(AllOf(from(withName("caller2")),
- fromRanges(Source.range("Caller1")))));
+ EXPECT_THAT(
+ IncomingLevel2,
+ ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))),
+ iFromRanges(Source.range("Caller1")))));
}
TEST(CallHierarchy, IncomingQualified) {
@@ -200,14 +219,72 @@ TEST(CallHierarchy, IncomingQualified) {
prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
ASSERT_THAT(Items, ElementsAre(withName("Waldo::find")));
auto Incoming = incomingCalls(Items[0], Index.get());
- EXPECT_THAT(Incoming,
- ElementsAre(AllOf(from(withName("caller1")),
- fromRanges(Source.range("Caller1"))),
- AllOf(from(withName("caller2")),
- fromRanges(Source.range("Caller2")))));
+ EXPECT_THAT(
+ Incoming,
+ ElementsAre(
+ AllOf(from(AllOf(withName("caller1"), withDetail("ns::caller1"))),
+ iFromRanges(Source.range("Caller1"))),
+ AllOf(from(AllOf(withName("caller2"), withDetail("ns::caller2"))),
+ iFromRanges(Source.range("Caller2")))));
}
-TEST(CallHierarchy, IncomingMultiFileCpp) {
+TEST(CallHierarchy, OutgoingOneFile) {
+ // Test outgoing call on the main file, with namespaces and methods
+ Annotations Source(R"cpp(
+ void callee(int);
+ namespace ns {
+ struct Foo {
+ void caller1();
+ };
+ void Foo::caller1() {
+ $Callee[[callee]](42);
+ }
+ }
+ namespace {
+ void caller2(ns::Foo& F) {
+ F.$Caller1A[[caller1]]();
+ F.$Caller1B[[caller1]]();
+ }
+ }
+ void call^er3(ns::Foo& F) {
+ F.$Caller1C[[caller1]]();
+ $Caller2[[caller2]](F);
+ }
+ )cpp");
+ TestTU TU = TestTU::withCode(Source.code());
+ auto AST = TU.build();
+ auto Index = TU.index();
+
+ std::vector<CallHierarchyItem> Items =
+ prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename));
+ ASSERT_THAT(Items, ElementsAre(withName("caller3")));
+ auto OugoingLevel1 = outgoingCalls(Items[0], Index.get());
+ ASSERT_THAT(
+ OugoingLevel1,
+ ElementsAre(
+ AllOf(to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))),
+ oFromRanges(Source.range("Caller1C"))),
+ AllOf(to(AllOf(withName("caller2"), withDetail("caller2"))),
+ oFromRanges(Source.range("Caller2")))));
+
+ auto OutgoingLevel2 = outgoingCalls(OugoingLevel1[1].to, Index.get());
+ ASSERT_THAT(
+ OutgoingLevel2,
+ ElementsAre(AllOf(
+ to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))),
+ oFromRanges(Source.range("Caller1A"), Source.range("Caller1B")))));
+
+ auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get());
+ ASSERT_THAT(
+ OutgoingLevel3,
+ ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))),
+ oFromRanges(Source.range("Callee")))));
+
+ auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get());
+ EXPECT_THAT(OutgoingLevel4, IsEmpty());
+}
+
+TEST(CallHierarchy, MultiFileCpp) {
// The test uses a .hh suffix for header files to get clang
// to parse them in C++ mode. .h files are parsed in C mode
// by default, which causes problems because e.g. symbol
@@ -221,32 +298,47 @@ TEST(CallHierarchy, IncomingMultiFileCpp) {
void calle^e(int) {}
)cpp");
Annotations Caller1H(R"cpp(
- void caller1();
+ namespace nsa {
+ void caller1();
+ }
)cpp");
Annotations Caller1C(R"cpp(
#include "callee.hh"
#include "caller1.hh"
- void caller1() {
- [[calle^e]](42);
+ namespace nsa {
+ void caller1() {
+ [[calle^e]](42);
+ }
}
)cpp");
Annotations Caller2H(R"cpp(
- void caller2();
+ namespace nsb {
+ void caller2();
+ }
)cpp");
Annotations Caller2C(R"cpp(
#include "caller1.hh"
#include "caller2.hh"
- void caller2() {
- $A[[caller1]]();
- $B[[caller1]]();
+ namespace nsb {
+ void caller2() {
+ nsa::$A[[caller1]]();
+ nsa::$B[[caller1]]();
+ }
+ }
+ )cpp");
+ Annotations Caller3H(R"cpp(
+ namespace nsa {
+ void call^er3();
}
)cpp");
Annotations Caller3C(R"cpp(
#include "caller1.hh"
#include "caller2.hh"
- void caller3() {
- $Caller1[[caller1]]();
- $Caller2[[caller2]]();
+ namespace nsa {
+ void call^er3() {
+ $Caller1[[caller1]]();
+ nsb::$Caller2[[caller2]]();
+ }
}
)cpp");
@@ -254,6 +346,7 @@ TEST(CallHierarchy, IncomingMultiFileCpp) {
Workspace.addSource("callee.hh", CalleeH.code());
Workspace.addSource("caller1.hh", Caller1H.code());
Workspace.addSource("caller2.hh", Caller2H.code());
+ Workspace.addSource("caller3.hh", Caller3H.code());
Workspace.addMainFile("callee.cc", CalleeC.code());
Workspace.addMainFile("caller1.cc", Caller1C.code());
Workspace.addMainFile("caller2.cc", Caller2C.code());
@@ -261,46 +354,84 @@ TEST(CallHierarchy, IncomingMultiFileCpp) {
auto Index = Workspace.index();
- auto CheckCallHierarchy = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
+ auto CheckIncomingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
std::vector<CallHierarchyItem> Items =
prepareCallHierarchy(AST, Pos, TUPath);
ASSERT_THAT(Items, ElementsAre(withName("callee")));
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
ASSERT_THAT(IncomingLevel1,
- ElementsAre(AllOf(from(withName("caller1")),
- fromRanges(Caller1C.range()))));
+ ElementsAre(AllOf(from(AllOf(withName("caller1"),
+ withDetail("nsa::caller1"))),
+ iFromRanges(Caller1C.range()))));
auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
ASSERT_THAT(
IncomingLevel2,
- ElementsAre(AllOf(from(withName("caller2")),
- fromRanges(Caller2C.range("A"), Caller2C.range("B"))),
- AllOf(from(withName("caller3")),
- fromRanges(Caller3C.range("Caller1")))));
+ ElementsAre(
+ AllOf(from(AllOf(withName("caller2"), withDetail("nsb::caller2"))),
+ iFromRanges(Caller2C.range("A"), Caller2C.range("B"))),
+ AllOf(from(AllOf(withName("caller3"), withDetail("nsa::caller3"))),
+ iFromRanges(Caller3C.range("Caller1")))));
auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
ASSERT_THAT(IncomingLevel3,
- ElementsAre(AllOf(from(withName("caller3")),
- fromRanges(Caller3C.range("Caller2")))));
+ ElementsAre(AllOf(from(AllOf(withName("caller3"),
+ withDetail("nsa::caller3"))),
+ iFromRanges(Caller3C.range("Caller2")))));
auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
EXPECT_THAT(IncomingLevel4, IsEmpty());
};
+ auto CheckOutgoingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) {
+ std::vector<CallHierarchyItem> Items =
+ prepareCallHierarchy(AST, Pos, TUPath);
+ ASSERT_THAT(Items, ElementsAre(withName("caller3")));
+ auto OutgoingLevel1 = outgoingCalls(Items[0], Index.get());
+ ASSERT_THAT(
+ OutgoingLevel1,
+ ElementsAre(
+ AllOf(to(AllOf(withName("caller1"), withDetail("nsa::caller1"))),
+ oFromRanges(Caller3C.range("Caller1"))),
+ AllOf(to(AllOf(withName("caller2"), withDetail("nsb::caller2"))),
+ oFromRanges(Caller3C.range("Caller2")))));
+
+ auto OutgoingLevel2 = outgoingCalls(OutgoingLevel1[1].to, Index.get());
+ ASSERT_THAT(OutgoingLevel2,
+ ElementsAre(AllOf(
+ to(AllOf(withName("caller1"), withDetail("nsa::caller1"))),
+ oFromRanges(Caller2C.range("A"), Caller2C.range("B")))));
+
+ auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get());
+ ASSERT_THAT(
+ OutgoingLevel3,
+ ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))),
+ oFromRanges(Caller1C.range()))));
+
+ auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get());
+ EXPECT_THAT(OutgoingLevel4, IsEmpty());
+ };
+
// Check that invoking from a call site works.
auto AST = Workspace.openFile("caller1.cc");
ASSERT_TRUE(bool(AST));
- CheckCallHierarchy(*AST, Caller1C.point(), testPath("caller1.cc"));
+ CheckIncomingCalls(*AST, Caller1C.point(), testPath("caller1.cc"));
// Check that invoking from the declaration site works.
AST = Workspace.openFile("callee.hh");
ASSERT_TRUE(bool(AST));
- CheckCallHierarchy(*AST, CalleeH.point(), testPath("callee.hh"));
+ CheckIncomingCalls(*AST, CalleeH.point(), testPath("callee.hh"));
+ AST = Workspace.openFile("caller3.hh");
+ ASSERT_TRUE(bool(AST));
+ CheckOutgoingCalls(*AST, Caller3H.point(), testPath("caller3.hh"));
// Check that invoking from the definition site works.
AST = Workspace.openFile("callee.cc");
ASSERT_TRUE(bool(AST));
- CheckCallHierarchy(*AST, CalleeC.point(), testPath("callee.cc"));
+ CheckIncomingCalls(*AST, CalleeC.point(), testPath("callee.cc"));
+ AST = Workspace.openFile("caller3.cc");
+ ASSERT_TRUE(bool(AST));
+ CheckOutgoingCalls(*AST, Caller3C.point(), testPath("caller3.cc"));
}
TEST(CallHierarchy, IncomingMultiFileObjC) {
@@ -377,20 +508,20 @@ TEST(CallHierarchy, IncomingMultiFileObjC) {
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
ASSERT_THAT(IncomingLevel1,
ElementsAre(AllOf(from(withName("caller1")),
- fromRanges(Caller1C.range()))));
+ iFromRanges(Caller1C.range()))));
auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get());
- ASSERT_THAT(
- IncomingLevel2,
- ElementsAre(AllOf(from(withName("caller2")),
- fromRanges(Caller2C.range("A"), Caller2C.range("B"))),
- AllOf(from(withName("caller3")),
- fromRanges(Caller3C.range("Caller1")))));
+ ASSERT_THAT(IncomingLevel2,
+ ElementsAre(AllOf(from(withName("caller2")),
+ iFromRanges(Caller2C.range("A"),
+ Caller2C.range("B"))),
+ AllOf(from(withName("caller3")),
+ iFromRanges(Caller3C.range("Caller1")))));
auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get());
ASSERT_THAT(IncomingLevel3,
ElementsAre(AllOf(from(withName("caller3")),
- fromRanges(Caller3C.range("Caller2")))));
+ iFromRanges(Caller3C.range("Caller2")))));
auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get());
EXPECT_THAT(IncomingLevel4, IsEmpty());
@@ -438,12 +569,12 @@ TEST(CallHierarchy, CallInLocalVarDecl) {
ASSERT_THAT(Items, ElementsAre(withName("callee")));
auto Incoming = incomingCalls(Items[0], Index.get());
- ASSERT_THAT(
- Incoming,
- ElementsAre(
- AllOf(from(withName("caller1")), fromRanges(Source.range("call1"))),
- AllOf(from(withName("caller2")), fromRanges(Source.range("call2"))),
- AllOf(from(withName("caller3")), fromRanges(Source.range("call3")))));
+ ASSERT_THAT(Incoming, ElementsAre(AllOf(from(withName("caller1")),
+ iFromRanges(Source.range("call1"))),
+ AllOf(from(withName("caller2")),
+ iFromRanges(Source.range("call2"))),
+ AllOf(from(withName("caller3")),
+ iFromRanges(Source.range("call3")))));
}
TEST(CallHierarchy, HierarchyOnField) {
@@ -467,7 +598,7 @@ TEST(CallHierarchy, HierarchyOnField) {
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
ASSERT_THAT(IncomingLevel1,
ElementsAre(AllOf(from(withName("caller")),
- fromRanges(Source.range("Callee")))));
+ iFromRanges(Source.range("Callee")))));
}
TEST(CallHierarchy, HierarchyOnVar) {
@@ -488,7 +619,7 @@ TEST(CallHierarchy, HierarchyOnVar) {
auto IncomingLevel1 = incomingCalls(Items[0], Index.get());
ASSERT_THAT(IncomingLevel1,
ElementsAre(AllOf(from(withName("caller")),
- fromRanges(Source.range("Callee")))));
+ iFromRanges(Source.range("Callee")))));
}
TEST(CallHierarchy, CallInDifferentFileThanCaller) {
@@ -517,7 +648,7 @@ TEST(CallHierarchy, CallInDifferentFileThanCaller) {
// header. The protocol does not allow us to represent such calls, so we drop
// them. (The call hierarchy item itself is kept.)
EXPECT_THAT(Incoming,
- ElementsAre(AllOf(from(withName("caller")), fromRanges())));
+ ElementsAre(AllOf(from(withName("caller")), iFromRanges())));
}
} // namespace
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index a89f4997362265..6b2d7f456b5589 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -1703,6 +1703,12 @@ class IndexRequestCollector : public SymbolIndex {
return false;
}
+ bool
+ refersTo(const RefsRequest &,
+ llvm::function_ref<void(const RefersToResult &)>) const override {
+ return false;
+ }
+
void relations(const RelationsRequest &,
llvm::function_ref<void(const SymbolID &, const Symbol &)>)
const override {}
diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp
index 7d9252110b27df..660b8e61840190 100644
--- a/clang-tools-extra/clangd/unittests/RenameTests.cpp
+++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp
@@ -1601,6 +1601,12 @@ TEST(CrossFileRenameTests, DirtyBuffer) {
return true; // has more references
}
+ bool refersTo(const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback)
+ const override {
+ return false;
+ }
+
bool fuzzyFind(
const FuzzyFindRequest &Req,
llvm::function_ref<void(const Symbol &)> Callback) const override {
@@ -1652,6 +1658,12 @@ TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) {
return false;
}
+ bool refersTo(const RefsRequest &Req,
+ llvm::function_ref<void(const RefersToResult &)> Callback)
+ const override {
+ return false;
+ }
+
bool fuzzyFind(const FuzzyFindRequest &,
llvm::function_ref<void(const Symbol &)>) const override {
return false;
>From f8866c111c07e1a1918d487cf63211ac08a19258 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Tue, 10 Oct 2023 02:28:31 -0400
Subject: [PATCH 2/8] Implement the RefKind::Call optimization
---
clang-tools-extra/clangd/XRefs.cpp | 18 ++++++++---------
clang-tools-extra/clangd/index/Ref.h | 3 +++
.../clangd/index/SymbolCollector.cpp | 20 ++++++++++++++++---
.../clangd/index/SymbolCollector.h | 1 +
clang-tools-extra/clangd/index/dex/Dex.cpp | 3 ++-
5 files changed, 32 insertions(+), 13 deletions(-)
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index f50c70a4cd4d29..bfb83ceaf53996 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -2334,10 +2334,10 @@ outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
// In this function, we find outgoing calls based on the index only.
RefsRequest Request;
Request.IDs.insert(*ID);
- // We could restrict more specifically to calls by introducing a new RefKind,
- // but non-call references (such as address-of-function) can still be
- // interesting as they can indicate indirect calls.
- Request.Filter = RefKind::Reference;
+ // Note that RefKind::Call just restricts the matched SymbolKind to
+ // functions, not the form of the reference (e.g. address-of-function,
+ // which can indicate an indirect call, should still be caught).
+ Request.Filter = RefKind::Call;
// Initially store the ranges in a map keyed by SymbolID of the callee.
// This allows us to group different calls to the same function
// into the same CallHierarchyOutgoingCall.
@@ -2362,11 +2362,11 @@ outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
// Filter references to only keep function calls
using SK = index::SymbolKind;
auto Kind = Callee.SymInfo.Kind;
- if (Kind != SK::Function && Kind != SK::InstanceMethod &&
- Kind != SK::ClassMethod && Kind != SK::StaticMethod &&
- Kind != SK::Constructor && Kind != SK::Destructor &&
- Kind != SK::ConversionFunction)
- return;
+ bool NotCall = (Kind != SK::Function && Kind != SK::InstanceMethod &&
+ Kind != SK::ClassMethod && Kind != SK::StaticMethod &&
+ Kind != SK::Constructor && Kind != SK::Destructor &&
+ Kind != SK::ConversionFunction);
+ assert(!NotCall);
auto It = CallsOut.find(Callee.ID);
assert(It != CallsOut.end());
diff --git a/clang-tools-extra/clangd/index/Ref.h b/clang-tools-extra/clangd/index/Ref.h
index 6e383e2ade3d25..870f77f56e6cb3 100644
--- a/clang-tools-extra/clangd/index/Ref.h
+++ b/clang-tools-extra/clangd/index/Ref.h
@@ -63,6 +63,9 @@ enum class RefKind : uint8_t {
// ^ this references Foo, but does not explicitly spell out its name
// };
Spelled = 1 << 3,
+ // A reference which is a call. Used as a filter for which references
+ // to store in data structures used for computing outgoing calls.
+ Call = 1 << 4,
All = Declaration | Definition | Reference | Spelled,
};
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index 91ae9d3003a971..81125dbb1aeafc 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -18,6 +18,7 @@
#include "clang-include-cleaner/Record.h"
#include "clang-include-cleaner/Types.h"
#include "index/CanonicalIncludes.h"
+#include "index/Ref.h"
#include "index/Relation.h"
#include "index/Symbol.h"
#include "index/SymbolID.h"
@@ -660,7 +661,7 @@ bool SymbolCollector::handleDeclOccurrence(
auto FileLoc = SM.getFileLoc(Loc);
auto FID = SM.getFileID(FileLoc);
if (Opts.RefsInHeaders || FID == SM.getMainFileID()) {
- addRef(ID, SymbolRef{FileLoc, FID, Roles,
+ addRef(ID, SymbolRef{FileLoc, FID, Roles, index::getSymbolInfo(ND).Kind,
getRefContainer(ASTNode.Parent, Opts),
isSpelled(FileLoc, *ND)});
}
@@ -774,8 +775,10 @@ bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name,
// FIXME: Populate container information for macro references.
// FIXME: All MacroRefs are marked as Spelled now, but this should be
// checked.
- addRef(ID, SymbolRef{Loc, SM.getFileID(Loc), Roles, /*Container=*/nullptr,
- /*Spelled=*/true});
+ addRef(ID,
+ SymbolRef{Loc, SM.getFileID(Loc), Roles, index::SymbolKind::Macro,
+ /*Container=*/nullptr,
+ /*Spelled=*/true});
}
// Collect symbols.
@@ -1166,6 +1169,14 @@ bool SymbolCollector::shouldIndexFile(FileID FID) {
return I.first->second;
}
+static bool refIsCall(index::SymbolKind Kind) {
+ using SK = index::SymbolKind;
+ return Kind == SK::Function || Kind == SK::InstanceMethod ||
+ Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
+ Kind == SK::Constructor || Kind == SK::Destructor ||
+ Kind == SK::ConversionFunction;
+}
+
void SymbolCollector::addRef(SymbolID ID, const SymbolRef &SR) {
const auto &SM = ASTCtx->getSourceManager();
// FIXME: use the result to filter out references.
@@ -1177,6 +1188,9 @@ void SymbolCollector::addRef(SymbolID ID, const SymbolRef &SR) {
R.Location.End = Range.second;
R.Location.FileURI = HeaderFileURIs->toURI(*FE).c_str();
R.Kind = toRefKind(SR.Roles, SR.Spelled);
+ if (refIsCall(SR.Kind)) {
+ R.Kind |= RefKind::Call;
+ }
R.Container = getSymbolIDCached(SR.Container);
Refs.insert(ID, R);
}
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h
index 6ff7a0145ff874..e9eb27fd0f6648 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.h
+++ b/clang-tools-extra/clangd/index/SymbolCollector.h
@@ -209,6 +209,7 @@ class SymbolCollector : public index::IndexDataConsumer {
SourceLocation Loc;
FileID FID;
index::SymbolRoleSet Roles;
+ index::SymbolKind Kind;
const Decl *Container;
bool Spelled;
};
diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp
index 67851c355a780b..07318926744516 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.cpp
+++ b/clang-tools-extra/clangd/index/dex/Dex.cpp
@@ -151,7 +151,8 @@ void Dex::buildIndex() {
// Build RevRefs
for (const auto &Pair : Refs)
for (const auto &R : Pair.second)
- RevRefs[R.Container].emplace_back(R, Pair.first);
+ if ((R.Kind & RefKind::Call) != RefKind::Unknown)
+ RevRefs[R.Container].emplace_back(R, Pair.first);
}
std::unique_ptr<Iterator> Dex::iterator(const Token &Tok) const {
>From 3a40e9b2afc10355032599e4c0596351eef2eaf8 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Tue, 17 Oct 2023 04:16:00 -0400
Subject: [PATCH 3/8] Implement the simple lookup optimization
---
clang-tools-extra/clangd/index/dex/Dex.cpp | 31 +++++++++++++++++-----
clang-tools-extra/clangd/index/dex/Dex.h | 12 +++++----
2 files changed, 31 insertions(+), 12 deletions(-)
diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp
index 07318926744516..ce37001124d6b1 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.cpp
+++ b/clang-tools-extra/clangd/index/dex/Dex.cpp
@@ -149,10 +149,14 @@ void Dex::buildIndex() {
InvertedIndex = std::move(Builder).build();
// Build RevRefs
- for (const auto &Pair : Refs)
- for (const auto &R : Pair.second)
+ for (const auto &[ID, RefList] : Refs)
+ for (const auto &R : RefList)
if ((R.Kind & RefKind::Call) != RefKind::Unknown)
- RevRefs[R.Container].emplace_back(R, Pair.first);
+ RevRefs.emplace_back(R, ID);
+ // Sort by container ID so we can use binary search for lookup.
+ llvm::sort(RevRefs, [](const RevRef &A, const RevRef &B) {
+ return A.ref().Container < B.ref().Container;
+ });
}
std::unique_ptr<Iterator> Dex::iterator(const Token &Tok) const {
@@ -320,13 +324,28 @@ bool Dex::refs(const RefsRequest &Req,
return false; // We reported all refs.
}
+llvm::iterator_range<std::vector<Dex::RevRef>::const_iterator>
+Dex::lookupRevRefs(const SymbolID &Container) const {
+ // equal_range() requires an element of the same type as the elements of the
+ // range, so construct a dummy RevRef with the container of interest.
+ Ref QueryRef;
+ QueryRef.Container = Container;
+ RevRef Query(QueryRef, SymbolID{});
+
+ auto ItPair = std::equal_range(RevRefs.cbegin(), RevRefs.cend(), Query,
+ [](const RevRef &A, const RevRef &B) {
+ return A.ref().Container < B.ref().Container;
+ });
+ return {ItPair.first, ItPair.second};
+}
+
bool Dex::refersTo(
const RefsRequest &Req,
llvm::function_ref<void(const RefersToResult &)> Callback) const {
trace::Span Tracer("Dex reversed refs");
uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
for (const auto &ID : Req.IDs)
- for (const auto &Rev : RevRefs.lookup(ID)) {
+ for (const auto &Rev : lookupRevRefs(ID)) {
if (!static_cast<int>(Req.Filter & Rev.ref().Kind))
continue;
if (Remaining == 0)
@@ -373,9 +392,7 @@ size_t Dex::estimateMemoryUsage() const {
for (const auto &TokenToPostingList : InvertedIndex)
Bytes += TokenToPostingList.second.bytes();
Bytes += Refs.getMemorySize();
- Bytes += RevRefs.getMemorySize();
- for (const auto &Entry : RevRefs)
- Bytes += Entry.second.size() * sizeof(Entry.second.front());
+ Bytes += RevRefs.size() * sizeof(RevRef);
Bytes += Relations.getMemorySize();
return Bytes + BackingDataSize;
}
diff --git a/clang-tools-extra/clangd/index/dex/Dex.h b/clang-tools-extra/clangd/index/dex/Dex.h
index 86a8d6300d98f9..12f5afcded3e3b 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.h
+++ b/clang-tools-extra/clangd/index/dex/Dex.h
@@ -100,19 +100,21 @@ class Dex : public SymbolIndex {
private:
class RevRef {
- const Ref &Reference;
+ const Ref *Reference;
SymbolID Target;
public:
RevRef(const Ref &Reference, SymbolID Target)
- : Reference(Reference), Target(Target) {}
- const Ref &ref() const { return Reference; }
+ : Reference(&Reference), Target(Target) {}
+ const Ref &ref() const { return *Reference; }
RefersToResult refersToResult() const {
- return {Reference.Location, Reference.Kind, Target};
+ return {ref().Location, ref().Kind, Target};
}
};
void buildIndex();
+ llvm::iterator_range<std::vector<RevRef>::const_iterator>
+ lookupRevRefs(const SymbolID &Container) const;
std::unique_ptr<Iterator> iterator(const Token &Tok) const;
std::unique_ptr<Iterator>
createFileProximityIterator(llvm::ArrayRef<std::string> ProximityPaths) const;
@@ -133,7 +135,7 @@ class Dex : public SymbolIndex {
llvm::DenseMap<Token, PostingList> InvertedIndex;
dex::Corpus Corpus;
llvm::DenseMap<SymbolID, llvm::ArrayRef<Ref>> Refs;
- llvm::DenseMap<SymbolID, std::vector<RevRef>> RevRefs;
+ std::vector<RevRef> RevRefs; // sorted by container ID
static_assert(sizeof(RelationKind) == sizeof(uint8_t),
"RelationKind should be of same size as a uint8_t");
llvm::DenseMap<std::pair<SymbolID, uint8_t>, std::vector<SymbolID>> Relations;
>From c44fcf5bc2aaf62008bcc69aa2cba6b77d6da165 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Sun, 22 Oct 2023 03:27:55 -0400
Subject: [PATCH 4/8] Address other review comments
---
clang-tools-extra/clangd/XRefs.cpp | 10 +++----
clang-tools-extra/clangd/index/Index.cpp | 8 +++---
clang-tools-extra/clangd/index/Index.h | 27 ++++++++++++++-----
clang-tools-extra/clangd/index/MemIndex.cpp | 11 ++++----
clang-tools-extra/clangd/index/MemIndex.h | 6 ++---
clang-tools-extra/clangd/index/Merge.cpp | 10 +++----
clang-tools-extra/clangd/index/Merge.h | 6 ++---
.../clangd/index/ProjectAware.cpp | 14 +++++-----
clang-tools-extra/clangd/index/dex/Dex.cpp | 25 +++++++++--------
clang-tools-extra/clangd/index/dex/Dex.h | 8 +++---
.../clangd/unittests/CodeCompleteTests.cpp | 6 ++---
.../clangd/unittests/RenameTests.cpp | 12 ++++-----
12 files changed, 76 insertions(+), 67 deletions(-)
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index bfb83ceaf53996..ece9822d5f3377 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -2332,12 +2332,8 @@ outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
return Results;
}
// In this function, we find outgoing calls based on the index only.
- RefsRequest Request;
- Request.IDs.insert(*ID);
- // Note that RefKind::Call just restricts the matched SymbolKind to
- // functions, not the form of the reference (e.g. address-of-function,
- // which can indicate an indirect call, should still be caught).
- Request.Filter = RefKind::Call;
+ ContainedRefsRequest Request;
+ Request.ID = *ID;
// Initially store the ranges in a map keyed by SymbolID of the callee.
// This allows us to group different calls to the same function
// into the same CallHierarchyOutgoingCall.
@@ -2345,7 +2341,7 @@ outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
// We can populate the ranges based on a refs request only. As we do so, we
// also accumulate the callee IDs into a lookup request.
LookupRequest CallsOutLookup;
- Index->refersTo(Request, [&](const auto &R) {
+ Index->containedRefs(Request, [&](const auto &R) {
auto Loc = indexToLSPLocation(R.Location, Item.uri.file());
if (!Loc) {
elog("outgoingCalls failed to convert location: {0}", Loc.takeError());
diff --git a/clang-tools-extra/clangd/index/Index.cpp b/clang-tools-extra/clangd/index/Index.cpp
index c2cbfed35c2352..86dc6ed7633449 100644
--- a/clang-tools-extra/clangd/index/Index.cpp
+++ b/clang-tools-extra/clangd/index/Index.cpp
@@ -66,10 +66,10 @@ bool SwapIndex::refs(const RefsRequest &R,
llvm::function_ref<void(const Ref &)> CB) const {
return snapshot()->refs(R, CB);
}
-bool SwapIndex::refersTo(
- const RefsRequest &R,
- llvm::function_ref<void(const RefersToResult &)> CB) const {
- return snapshot()->refersTo(R, CB);
+bool SwapIndex::containedRefs(
+ const ContainedRefsRequest &R,
+ llvm::function_ref<void(const ContainedRefsResult &)> CB) const {
+ return snapshot()->containedRefs(R, CB);
}
void SwapIndex::relations(
const RelationsRequest &R,
diff --git a/clang-tools-extra/clangd/index/Index.h b/clang-tools-extra/clangd/index/Index.h
index 4ad066f396f587..a193b1a191216a 100644
--- a/clang-tools-extra/clangd/index/Index.h
+++ b/clang-tools-extra/clangd/index/Index.h
@@ -77,6 +77,19 @@ struct RefsRequest {
bool WantContainer = false;
};
+struct ContainedRefsRequest {
+ /// Note that RefKind::Call just restricts the matched SymbolKind to
+ /// functions, not the form of the reference (e.g. address-of-function,
+ /// which can indicate an indirect call, should still be caught).
+ static const RefKind SupportedRefKinds = RefKind::Call;
+
+ SymbolID ID;
+ /// If set, limit the number of refers returned from the index. The index may
+ /// choose to return less than this, e.g. it tries to avoid returning stale
+ /// results.
+ std::optional<uint32_t> Limit;
+};
+
struct RelationsRequest {
llvm::DenseSet<SymbolID> Subjects;
RelationKind Predicate;
@@ -84,7 +97,7 @@ struct RelationsRequest {
std::optional<uint32_t> Limit;
};
-struct RefersToResult {
+struct ContainedRefsResult {
/// The source location where the symbol is named.
SymbolLocation Location;
RefKind Kind = RefKind::Unknown;
@@ -156,9 +169,9 @@ class SymbolIndex {
/// The returned result must be deep-copied if it's used outside Callback.
///
/// Returns true if there will be more results (limited by Req.Limit);
- virtual bool
- refersTo(const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const = 0;
+ virtual bool containedRefs(
+ const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)> Callback) const = 0;
/// Finds all relations (S, P, O) stored in the index such that S is among
/// Req.Subjects and P is Req.Predicate, and invokes \p Callback for (S, O) in
@@ -194,9 +207,9 @@ class SwapIndex : public SymbolIndex {
llvm::function_ref<void(const Symbol &)>) const override;
bool refs(const RefsRequest &,
llvm::function_ref<void(const Ref &)>) const override;
- bool
- refersTo(const RefsRequest &,
- llvm::function_ref<void(const RefersToResult &)>) const override;
+ bool containedRefs(
+ const ContainedRefsRequest &,
+ llvm::function_ref<void(const ContainedRefsResult &)>) const override;
void relations(const RelationsRequest &,
llvm::function_ref<void(const SymbolID &, const Symbol &)>)
const override;
diff --git a/clang-tools-extra/clangd/index/MemIndex.cpp b/clang-tools-extra/clangd/index/MemIndex.cpp
index 2b15d00a6c7f89..9c9d3942bdee63 100644
--- a/clang-tools-extra/clangd/index/MemIndex.cpp
+++ b/clang-tools-extra/clangd/index/MemIndex.cpp
@@ -9,6 +9,7 @@
#include "MemIndex.h"
#include "FuzzyMatch.h"
#include "Quality.h"
+#include "index/Index.h"
#include "support/Trace.h"
namespace clang {
@@ -85,15 +86,15 @@ bool MemIndex::refs(const RefsRequest &Req,
return false; // We reported all refs.
}
-bool MemIndex::refersTo(
- const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const {
+bool MemIndex::containedRefs(
+ const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)> Callback) const {
trace::Span Tracer("MemIndex refersTo");
uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
for (const auto &Pair : Refs) {
for (const auto &R : Pair.second) {
- if (!static_cast<int>(Req.Filter & R.Kind) ||
- !Req.IDs.contains(R.Container))
+ if (!static_cast<int>(ContainedRefsRequest::SupportedRefKinds & R.Kind) ||
+ Req.ID != R.Container)
continue;
if (Remaining == 0)
return true; // More refs were available.
diff --git a/clang-tools-extra/clangd/index/MemIndex.h b/clang-tools-extra/clangd/index/MemIndex.h
index 9fd3b2a353b624..8f390c5028dc4d 100644
--- a/clang-tools-extra/clangd/index/MemIndex.h
+++ b/clang-tools-extra/clangd/index/MemIndex.h
@@ -72,9 +72,9 @@ class MemIndex : public SymbolIndex {
bool refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const override;
- bool refersTo(
- const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const override;
+ bool containedRefs(const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)>
+ Callback) const override;
void relations(const RelationsRequest &Req,
llvm::function_ref<void(const SymbolID &, const Symbol &)>
diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp
index bedc0bc3f912ab..aecca38a885b66 100644
--- a/clang-tools-extra/clangd/index/Merge.cpp
+++ b/clang-tools-extra/clangd/index/Merge.cpp
@@ -155,9 +155,9 @@ bool MergedIndex::refs(const RefsRequest &Req,
return More || StaticHadMore;
}
-bool MergedIndex::refersTo(
- const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const {
+bool MergedIndex::containedRefs(
+ const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)> Callback) const {
trace::Span Tracer("MergedIndex refersTo");
bool More = false;
uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
@@ -165,7 +165,7 @@ bool MergedIndex::refersTo(
// and we can't reliably deduplicate them because offsets may differ slightly.
// We consider the dynamic index authoritative and report all its refs,
// and only report static index refs from other files.
- More |= Dynamic->refersTo(Req, [&](const auto &O) {
+ More |= Dynamic->containedRefs(Req, [&](const auto &O) {
Callback(O);
assert(Remaining != 0);
--Remaining;
@@ -175,7 +175,7 @@ bool MergedIndex::refersTo(
auto DynamicContainsFile = Dynamic->indexedFiles();
// We return less than Req.Limit if static index returns more refs for dirty
// files.
- bool StaticHadMore = Static->refersTo(Req, [&](const auto &O) {
+ bool StaticHadMore = Static->containedRefs(Req, [&](const auto &O) {
if ((DynamicContainsFile(O.Location.FileURI) & IndexContents::References) !=
IndexContents::None)
return; // ignore refs that have been seen from dynamic index.
diff --git a/clang-tools-extra/clangd/index/Merge.h b/clang-tools-extra/clangd/index/Merge.h
index 57dd88f34b3cbb..7441be6e57e854 100644
--- a/clang-tools-extra/clangd/index/Merge.h
+++ b/clang-tools-extra/clangd/index/Merge.h
@@ -38,9 +38,9 @@ class MergedIndex : public SymbolIndex {
llvm::function_ref<void(const Symbol &)>) const override;
bool refs(const RefsRequest &,
llvm::function_ref<void(const Ref &)>) const override;
- bool
- refersTo(const RefsRequest &,
- llvm::function_ref<void(const RefersToResult &)>) const override;
+ bool containedRefs(
+ const ContainedRefsRequest &,
+ llvm::function_ref<void(const ContainedRefsResult &)>) const override;
void relations(const RelationsRequest &,
llvm::function_ref<void(const SymbolID &, const Symbol &)>)
const override;
diff --git a/clang-tools-extra/clangd/index/ProjectAware.cpp b/clang-tools-extra/clangd/index/ProjectAware.cpp
index 5179a5bd0e4d56..9836f0130362a0 100644
--- a/clang-tools-extra/clangd/index/ProjectAware.cpp
+++ b/clang-tools-extra/clangd/index/ProjectAware.cpp
@@ -36,9 +36,9 @@ class ProjectAwareIndex : public SymbolIndex {
bool refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const override;
/// Query all indexes while prioritizing the associated one (if any).
- bool refersTo(
- const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const override;
+ bool containedRefs(const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)>
+ Callback) const override;
/// Queries only the associates index when Req.RestrictForCodeCompletion is
/// set, otherwise queries all.
@@ -98,12 +98,12 @@ bool ProjectAwareIndex::refs(
return false;
}
-bool ProjectAwareIndex::refersTo(
- const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const {
+bool ProjectAwareIndex::containedRefs(
+ const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)> Callback) const {
trace::Span Tracer("ProjectAwareIndex::refersTo");
if (auto *Idx = getIndex())
- return Idx->refersTo(Req, Callback);
+ return Idx->containedRefs(Req, Callback);
return false;
}
diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp
index ce37001124d6b1..9c02e88900b07d 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.cpp
+++ b/clang-tools-extra/clangd/index/dex/Dex.cpp
@@ -151,7 +151,8 @@ void Dex::buildIndex() {
// Build RevRefs
for (const auto &[ID, RefList] : Refs)
for (const auto &R : RefList)
- if ((R.Kind & RefKind::Call) != RefKind::Unknown)
+ if ((R.Kind & ContainedRefsRequest::SupportedRefKinds) !=
+ RefKind::Unknown)
RevRefs.emplace_back(R, ID);
// Sort by container ID so we can use binary search for lookup.
llvm::sort(RevRefs, [](const RevRef &A, const RevRef &B) {
@@ -339,20 +340,18 @@ Dex::lookupRevRefs(const SymbolID &Container) const {
return {ItPair.first, ItPair.second};
}
-bool Dex::refersTo(
- const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const {
+bool Dex::containedRefs(
+ const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)> Callback) const {
trace::Span Tracer("Dex reversed refs");
uint32_t Remaining = Req.Limit.value_or(std::numeric_limits<uint32_t>::max());
- for (const auto &ID : Req.IDs)
- for (const auto &Rev : lookupRevRefs(ID)) {
- if (!static_cast<int>(Req.Filter & Rev.ref().Kind))
- continue;
- if (Remaining == 0)
- return true; // More refs were available.
- --Remaining;
- Callback(Rev.refersToResult());
- }
+ for (const auto &Rev : lookupRevRefs(Req.ID)) {
+ // RevRefs are already filtered to ContainedRefsRequest::SupportedRefKinds
+ if (Remaining == 0)
+ return true; // More refs were available.
+ --Remaining;
+ Callback(Rev.containedRefsResult());
+ }
return false; // We reported all refs.
}
diff --git a/clang-tools-extra/clangd/index/dex/Dex.h b/clang-tools-extra/clangd/index/dex/Dex.h
index 12f5afcded3e3b..b0799ec9bae34e 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.h
+++ b/clang-tools-extra/clangd/index/dex/Dex.h
@@ -85,9 +85,9 @@ class Dex : public SymbolIndex {
bool refs(const RefsRequest &Req,
llvm::function_ref<void(const Ref &)> Callback) const override;
- bool refersTo(
- const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback) const override;
+ bool containedRefs(const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)>
+ Callback) const override;
void relations(const RelationsRequest &Req,
llvm::function_ref<void(const SymbolID &, const Symbol &)>
@@ -107,7 +107,7 @@ class Dex : public SymbolIndex {
RevRef(const Ref &Reference, SymbolID Target)
: Reference(&Reference), Target(Target) {}
const Ref &ref() const { return *Reference; }
- RefersToResult refersToResult() const {
+ ContainedRefsResult containedRefsResult() const {
return {ref().Location, ref().Kind, Target};
}
};
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 6b2d7f456b5589..3acacf496e77f9 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -1703,9 +1703,9 @@ class IndexRequestCollector : public SymbolIndex {
return false;
}
- bool
- refersTo(const RefsRequest &,
- llvm::function_ref<void(const RefersToResult &)>) const override {
+ bool containedRefs(
+ const ContainedRefsRequest &,
+ llvm::function_ref<void(const ContainedRefsResult &)>) const override {
return false;
}
diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp
index 660b8e61840190..a3aa4542bdf751 100644
--- a/clang-tools-extra/clangd/unittests/RenameTests.cpp
+++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp
@@ -1601,9 +1601,9 @@ TEST(CrossFileRenameTests, DirtyBuffer) {
return true; // has more references
}
- bool refersTo(const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback)
- const override {
+ bool containedRefs(const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)>
+ Callback) const override {
return false;
}
@@ -1658,9 +1658,9 @@ TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) {
return false;
}
- bool refersTo(const RefsRequest &Req,
- llvm::function_ref<void(const RefersToResult &)> Callback)
- const override {
+ bool containedRefs(const ContainedRefsRequest &Req,
+ llvm::function_ref<void(const ContainedRefsResult &)>
+ Callback) const override {
return false;
}
>From 247b790f96adf9ef4e24bf0a3609e761384a8019 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Mon, 25 Nov 2024 03:02:58 -0500
Subject: [PATCH 5/8] Address newer review comments
---
clang-tools-extra/clangd/XRefs.cpp | 12 ++---
.../clangd/test/type-hierarchy.test | 51 +++++++++++++++++++
2 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index ece9822d5f3377..d237d95b3eb655 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -2355,14 +2355,14 @@ outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {
// Perform the lookup request and combine its results with CallsOut to
// get complete CallHierarchyOutgoingCall objects.
Index->lookup(CallsOutLookup, [&](const Symbol &Callee) {
- // Filter references to only keep function calls
+ // The containedRefs request should only return symbols which are
+ // function-like, i.e. symbols for which references to them can be "calls".
using SK = index::SymbolKind;
auto Kind = Callee.SymInfo.Kind;
- bool NotCall = (Kind != SK::Function && Kind != SK::InstanceMethod &&
- Kind != SK::ClassMethod && Kind != SK::StaticMethod &&
- Kind != SK::Constructor && Kind != SK::Destructor &&
- Kind != SK::ConversionFunction);
- assert(!NotCall);
+ assert(Kind == SK::Function || Kind == SK::InstanceMethod ||
+ Kind == SK::ClassMethod || Kind == SK::StaticMethod ||
+ Kind == SK::Constructor || Kind == SK::Destructor ||
+ Kind == SK::ConversionFunction);
auto It = CallsOut.find(Callee.ID);
assert(It != CallsOut.end());
diff --git a/clang-tools-extra/clangd/test/type-hierarchy.test b/clang-tools-extra/clangd/test/type-hierarchy.test
index 3617c7ef9f5bc2..a5f13ab13d0b3f 100644
--- a/clang-tools-extra/clangd/test/type-hierarchy.test
+++ b/clang-tools-extra/clangd/test/type-hierarchy.test
@@ -89,6 +89,57 @@
# CHECK-NEXT: }
# CHECK-NEXT: ]
---
+{"jsonrpc":"2.0","id":2,"method":"typeHierarchy/subtypes","params":{"item":{"uri":"test:///main.cpp","data":{"parents":[{"parents":[{"parents":[],"symbolID":"FE546E7B648D69A7"}],"symbolID":"ECDC0C46D75120F4"}],"symbolID":"8A991335E4E67D08"},"name":"Child2","kind":23,"range":{"end":{"character":13,"line":3},"start":{"character":7,"line":3}},"selectionRange":{"end":{"character":13,"line":3},"start":{"character":7,"line":3}}}}}
+# CHECK: "id": 2
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "data": {
+# CHECK-NEXT: "parents": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "parents": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "parents": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "parents": [],
+# CHECK-NEXT: "symbolID": "FE546E7B648D69A7"
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "symbolID": "ECDC0C46D75120F4"
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "symbolID": "8A991335E4E67D08"
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "symbolID": "A6576FE083F2949A"
+# CHECK-NEXT: },
+# CHECK-NEXT: "detail": "Child3",
+# CHECK-NEXT: "kind": 23,
+# CHECK-NEXT: "name": "Child3",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 13,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "selectionRange": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 13,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/clangd-test/main.cpp"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
>From d380984cecf18b53b6e2fdd4266702dcb8ea513a Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Wed, 27 Nov 2024 00:48:54 -0500
Subject: [PATCH 6/8] Implement remote index support for the new containedRefs
request
---
.../clangd/index/remote/Client.cpp | 7 +++
.../clangd/index/remote/Index.proto | 18 +++++++
.../clangd/index/remote/Service.proto | 2 +
.../index/remote/marshalling/Marshalling.cpp | 48 +++++++++++++++++++
.../index/remote/marshalling/Marshalling.h | 7 +++
.../clangd/index/remote/server/Server.cpp | 47 ++++++++++++++++++
6 files changed, 129 insertions(+)
diff --git a/clang-tools-extra/clangd/index/remote/Client.cpp b/clang-tools-extra/clangd/index/remote/Client.cpp
index 391da3916259c6..79b827126b4eff 100644
--- a/clang-tools-extra/clangd/index/remote/Client.cpp
+++ b/clang-tools-extra/clangd/index/remote/Client.cpp
@@ -146,6 +146,13 @@ class IndexClient : public clangd::SymbolIndex {
return streamRPC(Request, &remote::v1::SymbolIndex::Stub::Refs, Callback);
}
+ bool containedRefs(const clangd::ContainedRefsRequest &Request,
+ llvm::function_ref<void(const ContainedRefsResult &)>
+ Callback) const override {
+ return streamRPC(Request, &remote::v1::SymbolIndex::Stub::ContainedRefs,
+ Callback);
+ }
+
void
relations(const clangd::RelationsRequest &Request,
llvm::function_ref<void(const SymbolID &, const clangd::Symbol &)>
diff --git a/clang-tools-extra/clangd/index/remote/Index.proto b/clang-tools-extra/clangd/index/remote/Index.proto
index 3072299d8f345f..689ef9d44ee409 100644
--- a/clang-tools-extra/clangd/index/remote/Index.proto
+++ b/clang-tools-extra/clangd/index/remote/Index.proto
@@ -131,3 +131,21 @@ message Relation {
optional string subject_id = 1;
optional Symbol object = 2;
}
+
+message ContainedRefsRequest {
+ required string id = 1;
+ optional uint32 limit = 2;
+}
+
+message ContainedRefsReply {
+ oneof kind {
+ ContainedRef stream_result = 1;
+ FinalResult final_result = 2;
+ }
+}
+
+message ContainedRef {
+ required SymbolLocation location = 1;
+ required uint32 kind = 2;
+ required string symbol = 3;
+}
diff --git a/clang-tools-extra/clangd/index/remote/Service.proto b/clang-tools-extra/clangd/index/remote/Service.proto
index 7c7efa530200d7..43023321cb9e14 100644
--- a/clang-tools-extra/clangd/index/remote/Service.proto
+++ b/clang-tools-extra/clangd/index/remote/Service.proto
@@ -21,5 +21,7 @@ service SymbolIndex {
rpc Refs(RefsRequest) returns (stream RefsReply) {}
+ rpc ContainedRefs(ContainedRefsRequest) returns (stream ContainedRefsReply) {}
+
rpc Relations(RelationsRequest) returns (stream RelationsReply) {}
}
diff --git a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp
index 7e31ada18a6579..a80d12347d48d2 100644
--- a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp
+++ b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp
@@ -126,6 +126,18 @@ Marshaller::fromProtobuf(const RefsRequest *Message) {
return Req;
}
+llvm::Expected<clangd::ContainedRefsRequest>
+Marshaller::fromProtobuf(const ContainedRefsRequest *Message) {
+ clangd::ContainedRefsRequest Req;
+ auto ID = SymbolID::fromStr(Message->id());
+ if (!ID)
+ return ID.takeError();
+ Req.ID = *ID;
+ if (Message->has_limit())
+ Req.Limit = Message->limit();
+ return Req;
+}
+
llvm::Expected<clangd::RelationsRequest>
Marshaller::fromProtobuf(const RelationsRequest *Message) {
clangd::RelationsRequest Req;
@@ -192,6 +204,21 @@ llvm::Expected<clangd::Ref> Marshaller::fromProtobuf(const Ref &Message) {
return Result;
}
+llvm::Expected<clangd::ContainedRefsResult>
+Marshaller::fromProtobuf(const ContainedRef &Message) {
+ clangd::ContainedRefsResult Result;
+ auto Location = fromProtobuf(Message.location());
+ if (!Location)
+ return Location.takeError();
+ Result.Location = *Location;
+ Result.Kind = static_cast<RefKind>(Message.kind());
+ auto Symbol = SymbolID::fromStr(Message.symbol());
+ if (!Symbol)
+ return Symbol.takeError();
+ Result.Symbol = *Symbol;
+ return Result;
+}
+
llvm::Expected<std::pair<clangd::SymbolID, clangd::Symbol>>
Marshaller::fromProtobuf(const Relation &Message) {
auto SubjectID = SymbolID::fromStr(Message.subject_id());
@@ -244,6 +271,15 @@ RefsRequest Marshaller::toProtobuf(const clangd::RefsRequest &From) {
return RPCRequest;
}
+ContainedRefsRequest
+Marshaller::toProtobuf(const clangd::ContainedRefsRequest &From) {
+ ContainedRefsRequest RPCRequest;
+ RPCRequest.set_id(From.ID.str());
+ if (From.Limit)
+ RPCRequest.set_limit(*From.Limit);
+ return RPCRequest;
+}
+
RelationsRequest Marshaller::toProtobuf(const clangd::RelationsRequest &From) {
RelationsRequest RPCRequest;
for (const auto &ID : From.Subjects)
@@ -299,6 +335,18 @@ llvm::Expected<Ref> Marshaller::toProtobuf(const clangd::Ref &From) {
return Result;
}
+llvm::Expected<ContainedRef>
+Marshaller::toProtobuf(const clangd::ContainedRefsResult &From) {
+ ContainedRef Result;
+ auto Location = toProtobuf(From.Location);
+ if (!Location)
+ return Location.takeError();
+ *Result.mutable_location() = *Location;
+ Result.set_kind(static_cast<uint32_t>(From.Kind));
+ *Result.mutable_symbol() = From.Symbol.str();
+ return Result;
+}
+
llvm::Expected<Relation> Marshaller::toProtobuf(const clangd::SymbolID &Subject,
const clangd::Symbol &Object) {
Relation Result;
diff --git a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h
index e827b4c155a20b..5bee9205aef584 100644
--- a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h
+++ b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h
@@ -40,6 +40,8 @@ class Marshaller {
llvm::Expected<clangd::Symbol> fromProtobuf(const Symbol &Message);
llvm::Expected<clangd::Ref> fromProtobuf(const Ref &Message);
+ llvm::Expected<clangd::ContainedRefsResult>
+ fromProtobuf(const ContainedRef &Message);
llvm::Expected<std::pair<clangd::SymbolID, clangd::Symbol>>
fromProtobuf(const Relation &Message);
@@ -48,6 +50,8 @@ class Marshaller {
llvm::Expected<clangd::FuzzyFindRequest>
fromProtobuf(const FuzzyFindRequest *Message);
llvm::Expected<clangd::RefsRequest> fromProtobuf(const RefsRequest *Message);
+ llvm::Expected<clangd::ContainedRefsRequest>
+ fromProtobuf(const ContainedRefsRequest *Message);
llvm::Expected<clangd::RelationsRequest>
fromProtobuf(const RelationsRequest *Message);
@@ -58,10 +62,13 @@ class Marshaller {
LookupRequest toProtobuf(const clangd::LookupRequest &From);
FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From);
RefsRequest toProtobuf(const clangd::RefsRequest &From);
+ ContainedRefsRequest toProtobuf(const clangd::ContainedRefsRequest &From);
RelationsRequest toProtobuf(const clangd::RelationsRequest &From);
llvm::Expected<Symbol> toProtobuf(const clangd::Symbol &From);
llvm::Expected<Ref> toProtobuf(const clangd::Ref &From);
+ llvm::Expected<ContainedRef>
+ toProtobuf(const clangd::ContainedRefsResult &From);
llvm::Expected<Relation> toProtobuf(const clangd::SymbolID &Subject,
const clangd::Symbol &Object);
diff --git a/clang-tools-extra/clangd/index/remote/server/Server.cpp b/clang-tools-extra/clangd/index/remote/server/Server.cpp
index 52fca53260a167..02d61338f211f0 100644
--- a/clang-tools-extra/clangd/index/remote/server/Server.cpp
+++ b/clang-tools-extra/clangd/index/remote/server/Server.cpp
@@ -258,6 +258,53 @@ class RemoteIndexServer final : public v1::SymbolIndex::Service {
return grpc::Status::OK;
}
+ grpc::Status
+ ContainedRefs(grpc::ServerContext *Context,
+ const ContainedRefsRequest *Request,
+ grpc::ServerWriter<ContainedRefsReply> *Reply) override {
+ auto StartTime = stopwatch::now();
+ WithContextValue WithRequestContext(CurrentRequest, Context);
+ logRequest(*Request);
+ trace::Span Tracer("ContainedRefsRequest");
+ auto Req = ProtobufMarshaller->fromProtobuf(Request);
+ if (!Req) {
+ elog("Can not parse ContainedRefsRequest from protobuf: {0}",
+ Req.takeError());
+ return grpc::Status::CANCELLED;
+ }
+ if (!Req->Limit || *Req->Limit > LimitResults) {
+ log("[public] Limiting result size for ContainedRefs request from {0} to "
+ "{1}.",
+ Req->Limit, LimitResults);
+ Req->Limit = LimitResults;
+ }
+ unsigned Sent = 0;
+ unsigned FailedToSend = 0;
+ bool HasMore =
+ Index.containedRefs(*Req, [&](const clangd::ContainedRefsResult &Item) {
+ auto SerializedItem = ProtobufMarshaller->toProtobuf(Item);
+ if (!SerializedItem) {
+ elog("Unable to convert ContainedRefsResult to protobuf: {0}",
+ SerializedItem.takeError());
+ ++FailedToSend;
+ return;
+ }
+ ContainedRefsReply NextMessage;
+ *NextMessage.mutable_stream_result() = *SerializedItem;
+ logResponse(NextMessage);
+ Reply->Write(NextMessage);
+ ++Sent;
+ });
+ ContainedRefsReply LastMessage;
+ LastMessage.mutable_final_result()->set_has_more(HasMore);
+ logResponse(LastMessage);
+ Reply->Write(LastMessage);
+ SPAN_ATTACH(Tracer, "Sent", Sent);
+ SPAN_ATTACH(Tracer, "Failed to send", FailedToSend);
+ logRequestSummary("v1/ContainedRefs", Sent, StartTime);
+ return grpc::Status::OK;
+ }
+
grpc::Status Relations(grpc::ServerContext *Context,
const RelationsRequest *Request,
grpc::ServerWriter<RelationsReply> *Reply) override {
>From d4ea024e3800c59ef72a12fc1e0fb0283ecda9c4 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Thu, 28 Nov 2024 02:33:19 -0500
Subject: [PATCH 7/8] Bump index version to start storing RefKind::Call
---
.../clangd/index/Serialization.cpp | 2 +-
.../test/index-serialization/Inputs/sample.idx | Bin 470 -> 470 bytes
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp
index 72a4e8b007668f..aad020629942b8 100644
--- a/clang-tools-extra/clangd/index/Serialization.cpp
+++ b/clang-tools-extra/clangd/index/Serialization.cpp
@@ -457,7 +457,7 @@ readCompileCommand(Reader CmdReader, llvm::ArrayRef<llvm::StringRef> Strings) {
// The current versioning scheme is simple - non-current versions are rejected.
// If you make a breaking change, bump this version number to invalidate stored
// data. Later we may want to support some backward compatibility.
-constexpr static uint32_t Version = 19;
+constexpr static uint32_t Version = 20;
llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data,
SymbolOrigin Origin) {
diff --git a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx
index 0c04df86ae1c6cd69ea0f802aff99f8057ffff74..6368e7145b1e4d628708f40d684bc8db1ef7f94d 100644
GIT binary patch
delta 180
zcmV;l089VY1J(nO6n_)|0047za%qbI000O9004NLy^TQ*gD?yP^AtV+zUSCOC7xjt
zx1 at 6HC^m at p^#%10J&d%P!%nzi4<|8(yXwWYHc4R?@0zzn0}l4Ci}Dm6g((8Ss+C|-
zSILlRht~B)$qktI3f2=OMtP2|$~MyB9e*Z+lQ|U0bc{y5AQ+bqdQpK{+IBt|*2XlY
i*8W&q!xsc3U)YhWUjZ4D3jsI*8k0l;QUMy1mjOS#p-G4U
delta 180
zcmV;l089VY1J(nO6n_%{0047za%qbI000UB004NLy^TQ*!Y~X3^OSy|-FuH5kopXh
znl{3Tqu4=(*F(i0IE*x!%Y+NH at MWIERrTbwUSe2^H(h(=fd+f!o5~dKNq7d(twA)B
zU{l?Mv1?{zvPYvAM4lN at sBELFij91DqhDF!Y>re`K1Sn~NEp(aJZZsFYIlQCuEJBS
i^`E;vd;rDTV4jhyUjYe|3jsI*3X?<uQUMB+mjOR>RZcko
>From 0aee7953ef1285bb327f20a01389e554fb44ffa8 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Tue, 3 Dec 2024 03:45:44 -0500
Subject: [PATCH 8/8] Add a ClangdServer option to allow disabling outgoing
calls
---
clang-tools-extra/clangd/ClangdLSPServer.cpp | 3 ++-
clang-tools-extra/clangd/ClangdServer.cpp | 5 ++++-
clang-tools-extra/clangd/ClangdServer.h | 5 +++++
clang-tools-extra/clangd/index/Background.cpp | 2 +-
clang-tools-extra/clangd/index/Background.h | 3 +++
clang-tools-extra/clangd/index/FileIndex.cpp | 13 +++++++------
clang-tools-extra/clangd/index/FileIndex.h | 5 +++--
.../clangd/index/Serialization.cpp | 12 +++++++-----
.../clangd/index/Serialization.h | 3 ++-
clang-tools-extra/clangd/index/dex/Dex.cpp | 12 ++++++++----
clang-tools-extra/clangd/index/dex/Dex.h | 19 +++++++++++--------
clang-tools-extra/clangd/tool/Check.cpp | 2 +-
clang-tools-extra/clangd/tool/ClangdMain.cpp | 14 ++++++++++----
.../clangd/unittests/BackgroundIndexTests.cpp | 3 ++-
14 files changed, 66 insertions(+), 35 deletions(-)
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 1391dcaa0c81a4..1e981825c7c15b 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -1699,7 +1699,8 @@ void ClangdLSPServer::bindMethods(LSPBinder &Bind,
Bind.method("typeHierarchy/subtypes", this, &ClangdLSPServer::onSubTypes);
Bind.method("textDocument/prepareCallHierarchy", this, &ClangdLSPServer::onPrepareCallHierarchy);
Bind.method("callHierarchy/incomingCalls", this, &ClangdLSPServer::onCallHierarchyIncomingCalls);
- Bind.method("callHierarchy/outgoingCalls", this, &ClangdLSPServer::onCallHierarchyOutgoingCalls);
+ if (Opts.EnableOutgoingCalls)
+ Bind.method("callHierarchy/outgoingCalls", this, &ClangdLSPServer::onCallHierarchyOutgoingCalls);
Bind.method("textDocument/selectionRange", this, &ClangdLSPServer::onSelectionRange);
Bind.method("textDocument/documentLink", this, &ClangdLSPServer::onDocumentLink);
Bind.method("textDocument/semanticTokens/full", this, &ClangdLSPServer::onSemanticTokens);
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index 63f83bc36f0c69..52be15d3da936a 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -215,7 +215,9 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
const ThreadsafeFS &TFS, const Options &Opts,
Callbacks *Callbacks)
: FeatureModules(Opts.FeatureModules), CDB(CDB), TFS(TFS),
- DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex() : nullptr),
+ DynamicIdx(Opts.BuildDynamicSymbolIndex
+ ? new FileIndex(Opts.EnableOutgoingCalls)
+ : nullptr),
ModulesManager(Opts.ModulesManager),
ClangTidyProvider(Opts.ClangTidyProvider),
UseDirtyHeaders(Opts.UseDirtyHeaders),
@@ -256,6 +258,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
Callbacks->onBackgroundIndexProgress(S);
};
BGOpts.ContextProvider = Opts.ContextProvider;
+ BGOpts.SupportContainedRefs = Opts.EnableOutgoingCalls;
BackgroundIdx = std::make_unique<BackgroundIndex>(
TFS, CDB,
BackgroundIndexStorage::createDiskBackedStorageFactory(
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index 8b6618cf96ccfc..e030bf04122d5e 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -110,6 +110,11 @@ class ClangdServer {
/// Cached preambles are potentially large. If false, store them on disk.
bool StorePreamblesInMemory = true;
+ /// Call hierarchy's outgoing calls feature requires additional index
+ /// serving structures which increase memory usage. If false, these are
+ /// not created and the feature is not enabled.
+ bool EnableOutgoingCalls = true;
+
/// This throttler controls which preambles may be built at a given time.
clangd::PreambleThrottler *PreambleThrottler = nullptr;
diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp
index 5cde4937fee785..496d1455def4b3 100644
--- a/clang-tools-extra/clangd/index/Background.cpp
+++ b/clang-tools-extra/clangd/index/Background.cpp
@@ -96,7 +96,7 @@ BackgroundIndex::BackgroundIndex(
: SwapIndex(std::make_unique<MemIndex>()), TFS(TFS), CDB(CDB),
IndexingPriority(Opts.IndexingPriority),
ContextProvider(std::move(Opts.ContextProvider)),
- IndexedSymbols(IndexContents::All),
+ IndexedSymbols(IndexContents::All, Opts.SupportContainedRefs),
Rebuilder(this, &IndexedSymbols, Opts.ThreadPoolSize),
IndexStorageFactory(std::move(IndexStorageFactory)),
Queue(std::move(Opts.OnProgress)),
diff --git a/clang-tools-extra/clangd/index/Background.h b/clang-tools-extra/clangd/index/Background.h
index 0d719ffdb957e4..448e911201575f 100644
--- a/clang-tools-extra/clangd/index/Background.h
+++ b/clang-tools-extra/clangd/index/Background.h
@@ -145,6 +145,9 @@ class BackgroundIndex : public SwapIndex {
// file. Called with the empty string for other tasks.
// (When called, the context from BackgroundIndex construction is active).
std::function<Context(PathRef)> ContextProvider = nullptr;
+ // Whether the index needs to support the containedRefs() operation.
+ // May use extra memory.
+ bool SupportContainedRefs = true;
};
/// Creates a new background index and starts its threads.
diff --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-tools-extra/clangd/index/FileIndex.cpp
index eb9562d2b6bf81..aa573e312a756a 100644
--- a/clang-tools-extra/clangd/index/FileIndex.cpp
+++ b/clang-tools-extra/clangd/index/FileIndex.cpp
@@ -239,8 +239,8 @@ SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
/*CollectMainFileRefs=*/false);
}
-FileSymbols::FileSymbols(IndexContents IdxContents)
- : IdxContents(IdxContents) {}
+FileSymbols::FileSymbols(IndexContents IdxContents, bool SupportContainedRefs)
+ : IdxContents(IdxContents), SupportContainedRefs(SupportContainedRefs) {}
void FileSymbols::update(llvm::StringRef Key,
std::unique_ptr<SymbolSlab> Symbols,
@@ -395,7 +395,7 @@ FileSymbols::buildIndex(IndexType Type, DuplicateHandling DuplicateHandle,
std::move(AllRelations), std::move(Files), IdxContents,
std::make_tuple(std::move(SymbolSlabs), std::move(RefSlabs),
std::move(RefsStorage), std::move(SymsStorage)),
- StorageSize);
+ StorageSize, SupportContainedRefs);
}
llvm_unreachable("Unknown clangd::IndexType");
}
@@ -419,11 +419,12 @@ void FileSymbols::profile(MemoryTree &MT) const {
}
}
-FileIndex::FileIndex()
+FileIndex::FileIndex(bool SupportContainedRefs)
: MergedIndex(&MainFileIndex, &PreambleIndex),
- PreambleSymbols(IndexContents::Symbols | IndexContents::Relations),
+ PreambleSymbols(IndexContents::Symbols | IndexContents::Relations,
+ SupportContainedRefs),
PreambleIndex(std::make_unique<MemIndex>()),
- MainFileSymbols(IndexContents::All),
+ MainFileSymbols(IndexContents::All, SupportContainedRefs),
MainFileIndex(std::make_unique<MemIndex>()) {}
void FileIndex::updatePreamble(IndexFileIn IF) {
diff --git a/clang-tools-extra/clangd/index/FileIndex.h b/clang-tools-extra/clangd/index/FileIndex.h
index 44f33e8fbcd51e..304a79fe5ae5c4 100644
--- a/clang-tools-extra/clangd/index/FileIndex.h
+++ b/clang-tools-extra/clangd/index/FileIndex.h
@@ -69,7 +69,7 @@ enum class DuplicateHandling {
/// locking when we swap or obtain references to snapshots.
class FileSymbols {
public:
- FileSymbols(IndexContents IdxContents);
+ FileSymbols(IndexContents IdxContents, bool SupportContainedRefs = true);
/// Updates all slabs associated with the \p Key.
/// If either is nullptr, corresponding data for \p Key will be removed.
/// If CountReferences is true, \p Refs will be used for counting references
@@ -91,6 +91,7 @@ class FileSymbols {
private:
IndexContents IdxContents;
+ bool SupportContainedRefs;
struct RefSlabAndCountReferences {
std::shared_ptr<RefSlab> Slab;
@@ -108,7 +109,7 @@ class FileSymbols {
/// FIXME: Expose an interface to remove files that are closed.
class FileIndex : public MergedIndex {
public:
- FileIndex();
+ FileIndex(bool SupportContainedRefs = true);
/// Update preamble symbols of file \p Path with all declarations in \p AST
/// and macros in \p PP.
diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp
index aad020629942b8..f03839599612c7 100644
--- a/clang-tools-extra/clangd/index/Serialization.cpp
+++ b/clang-tools-extra/clangd/index/Serialization.cpp
@@ -704,7 +704,8 @@ llvm::Expected<IndexFileIn> readIndexFile(llvm::StringRef Data,
}
std::unique_ptr<SymbolIndex> loadIndex(llvm::StringRef SymbolFilename,
- SymbolOrigin Origin, bool UseDex) {
+ SymbolOrigin Origin, bool UseDex,
+ bool SupportContainedRefs) {
trace::Span OverallTracer("LoadIndex");
auto Buffer = llvm::MemoryBuffer::getFile(SymbolFilename);
if (!Buffer) {
@@ -735,10 +736,11 @@ std::unique_ptr<SymbolIndex> loadIndex(llvm::StringRef SymbolFilename,
size_t NumRelations = Relations.size();
trace::Span Tracer("BuildIndex");
- auto Index = UseDex ? dex::Dex::build(std::move(Symbols), std::move(Refs),
- std::move(Relations))
- : MemIndex::build(std::move(Symbols), std::move(Refs),
- std::move(Relations));
+ auto Index = UseDex
+ ? dex::Dex::build(std::move(Symbols), std::move(Refs),
+ std::move(Relations), SupportContainedRefs)
+ : MemIndex::build(std::move(Symbols), std::move(Refs),
+ std::move(Relations));
vlog("Loaded {0} from {1} with estimated memory usage {2} bytes\n"
" - number of symbols: {3}\n"
" - number of refs: {4}\n"
diff --git a/clang-tools-extra/clangd/index/Serialization.h b/clang-tools-extra/clangd/index/Serialization.h
index b6890d63d2c383..d26d193aadd9c7 100644
--- a/clang-tools-extra/clangd/index/Serialization.h
+++ b/clang-tools-extra/clangd/index/Serialization.h
@@ -83,7 +83,8 @@ std::string toYAML(const Ref &);
// Build an in-memory static index from an index file.
// The size should be relatively small, so data can be managed in memory.
std::unique_ptr<SymbolIndex> loadIndex(llvm::StringRef Filename,
- SymbolOrigin Origin, bool UseDex = true);
+ SymbolOrigin Origin, bool UseDex = true,
+ bool SupportContainedRefs = true);
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp
index 9c02e88900b07d..5643ba0c5e4ce8 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.cpp
+++ b/clang-tools-extra/clangd/index/dex/Dex.cpp
@@ -33,13 +33,14 @@ namespace clangd {
namespace dex {
std::unique_ptr<SymbolIndex> Dex::build(SymbolSlab Symbols, RefSlab Refs,
- RelationSlab Rels) {
+ RelationSlab Rels,
+ bool SupportContainedRefs) {
auto Size = Symbols.bytes() + Refs.bytes();
// There is no need to include "Rels" in Data because the relations are self-
// contained, without references into a backing store.
auto Data = std::make_pair(std::move(Symbols), std::move(Refs));
return std::make_unique<Dex>(Data.first, Data.second, Rels, std::move(Data),
- Size);
+ Size, SupportContainedRefs);
}
namespace {
@@ -120,7 +121,7 @@ class IndexBuilder {
} // namespace
-void Dex::buildIndex() {
+void Dex::buildIndex(bool SupportContainedRefs) {
this->Corpus = dex::Corpus(Symbols.size());
std::vector<std::pair<float, const Symbol *>> ScoredSymbols(Symbols.size());
@@ -148,7 +149,10 @@ void Dex::buildIndex() {
Builder.add(*Symbols[SymbolRank], SymbolRank);
InvertedIndex = std::move(Builder).build();
- // Build RevRefs
+ // If the containedRefs() operation is supported, build the RevRefs
+ // data structure used to implement it.
+ if (!SupportContainedRefs)
+ return;
for (const auto &[ID, RefList] : Refs)
for (const auto &R : RefList)
if ((R.Kind & ContainedRefsRequest::SupportedRefKinds) !=
diff --git a/clang-tools-extra/clangd/index/dex/Dex.h b/clang-tools-extra/clangd/index/dex/Dex.h
index b0799ec9bae34e..06977cf3ccdd25 100644
--- a/clang-tools-extra/clangd/index/dex/Dex.h
+++ b/clang-tools-extra/clangd/index/dex/Dex.h
@@ -36,7 +36,8 @@ class Dex : public SymbolIndex {
public:
// All data must outlive this index.
template <typename SymbolRange, typename RefsRange, typename RelationsRange>
- Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations)
+ Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations,
+ bool SupportContainedRefs = true)
: Corpus(0) {
for (auto &&Sym : Symbols)
this->Symbols.push_back(&Sym);
@@ -46,15 +47,15 @@ class Dex : public SymbolIndex {
this->Relations[std::make_pair(Rel.Subject,
static_cast<uint8_t>(Rel.Predicate))]
.push_back(Rel.Object);
- buildIndex();
+ buildIndex(SupportContainedRefs);
}
// Symbols and Refs are owned by BackingData, Index takes ownership.
template <typename SymbolRange, typename RefsRange, typename RelationsRange,
typename Payload>
Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations,
- Payload &&BackingData, size_t BackingDataSize)
+ Payload &&BackingData, size_t BackingDataSize, bool SupportContainedRefs)
: Dex(std::forward<SymbolRange>(Symbols), std::forward<RefsRange>(Refs),
- std::forward<RelationsRange>(Relations)) {
+ std::forward<RelationsRange>(Relations), SupportContainedRefs) {
KeepAlive = std::shared_ptr<void>(
std::make_shared<Payload>(std::move(BackingData)), nullptr);
this->BackingDataSize = BackingDataSize;
@@ -64,16 +65,18 @@ class Dex : public SymbolIndex {
typename FileRange, typename Payload>
Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations,
FileRange &&Files, IndexContents IdxContents, Payload &&BackingData,
- size_t BackingDataSize)
+ size_t BackingDataSize, bool SupportContainedRefs = true)
: Dex(std::forward<SymbolRange>(Symbols), std::forward<RefsRange>(Refs),
std::forward<RelationsRange>(Relations),
- std::forward<Payload>(BackingData), BackingDataSize) {
+ std::forward<Payload>(BackingData), BackingDataSize,
+ SupportContainedRefs) {
this->Files = std::forward<FileRange>(Files);
this->IdxContents = IdxContents;
}
/// Builds an index from slabs. The index takes ownership of the slab.
- static std::unique_ptr<SymbolIndex> build(SymbolSlab, RefSlab, RelationSlab);
+ static std::unique_ptr<SymbolIndex> build(SymbolSlab, RefSlab, RelationSlab,
+ bool SupportContainedRefs = true);
bool
fuzzyFind(const FuzzyFindRequest &Req,
@@ -112,7 +115,7 @@ class Dex : public SymbolIndex {
}
};
- void buildIndex();
+ void buildIndex(bool EnableOutgoingCalls);
llvm::iterator_range<std::vector<RevRef>::const_iterator>
lookupRevRefs(const SymbolID &Container) const;
std::unique_ptr<Iterator> iterator(const Token &Tok) const;
diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp
index bc2eaa77a66eec..35198f1ca37dd0 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -163,7 +163,7 @@ class Checker {
unsigned ErrCount = 0;
Checker(llvm::StringRef File, const ClangdLSPServer::Options &Opts)
- : File(File), Opts(Opts) {}
+ : File(File), Opts(Opts), Index(/*SupportContainedRefs=*/false) {}
// Read compilation database and choose a compile command for the file.
bool buildCommand(const ThreadsafeFS &TFS) {
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index cc061e2d932314..80a0653f8f7404 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -604,7 +604,7 @@ const char TestScheme::TestDir[] = "/clangd-test";
std::unique_ptr<SymbolIndex>
loadExternalIndex(const Config::ExternalIndexSpec &External,
- AsyncTaskRunner *Tasks) {
+ AsyncTaskRunner *Tasks, bool SupportContainedRefs) {
static const trace::Metric RemoteIndexUsed("used_remote_index",
trace::Metric::Value, "address");
switch (External.Kind) {
@@ -620,8 +620,9 @@ loadExternalIndex(const Config::ExternalIndexSpec &External,
External.Location);
auto NewIndex = std::make_unique<SwapIndex>(std::make_unique<MemIndex>());
auto IndexLoadTask = [File = External.Location,
- PlaceHolder = NewIndex.get()] {
- if (auto Idx = loadIndex(File, SymbolOrigin::Static, /*UseDex=*/true))
+ PlaceHolder = NewIndex.get(), SupportContainedRefs] {
+ if (auto Idx = loadIndex(File, SymbolOrigin::Static, /*UseDex=*/true,
+ SupportContainedRefs))
PlaceHolder->reset(std::move(Idx));
};
if (Tasks) {
@@ -909,7 +910,12 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
Opts.BackgroundIndexPriority = BackgroundIndexPriority;
Opts.ReferencesLimit = ReferencesLimit;
Opts.Rename.LimitFiles = RenameFileLimit;
- auto PAI = createProjectAwareIndex(loadExternalIndex, Sync);
+ auto PAI = createProjectAwareIndex(
+ [SupportContainedRefs = Opts.EnableOutgoingCalls](
+ const Config::ExternalIndexSpec &External, AsyncTaskRunner *Tasks) {
+ return loadExternalIndex(External, Tasks, SupportContainedRefs);
+ },
+ Sync);
Opts.StaticIndex = PAI.get();
Opts.AsyncThreadsCount = WorkerThreadsCount;
Opts.MemoryCleanup = getMemoryCleanupFunction();
diff --git a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp
index e51942462fbdf8..ada14c99393186 100644
--- a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp
+++ b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp
@@ -685,7 +685,8 @@ TEST_F(BackgroundIndexTest, Reindex) {
class BackgroundIndexRebuilderTest : public testing::Test {
protected:
BackgroundIndexRebuilderTest()
- : Source(IndexContents::All), Target(std::make_unique<MemIndex>()),
+ : Source(IndexContents::All, /*SupportContainedRefs=*/true),
+ Target(std::make_unique<MemIndex>()),
Rebuilder(&Target, &Source, /*Threads=*/10) {
// Prepare FileSymbols with TestSymbol in it, for checkRebuild.
TestSymbol.ID = SymbolID("foo");
More information about the cfe-commits
mailing list