Skip to content

Commit 15673d7

Browse files
[clangd] Index refs to main-file symbols as well
Summary: This will be needed to support call hierarchy Reviewers: kadircet Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D83536
1 parent a52173a commit 15673d7

File tree

11 files changed

+112
-20
lines changed

11 files changed

+112
-20
lines changed

clang-tools-extra/clangd/ClangdServer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
173173
Callbacks *Callbacks)
174174
: ConfigProvider(Opts.ConfigProvider), TFS(TFS),
175175
DynamicIdx(Opts.BuildDynamicSymbolIndex
176-
? new FileIndex(Opts.HeavyweightDynamicSymbolIndex)
176+
? new FileIndex(Opts.HeavyweightDynamicSymbolIndex,
177+
Opts.CollectMainFileRefs)
177178
: nullptr),
178179
GetClangTidyOptions(Opts.GetClangTidyOptions),
179180
SuggestMissingIncludes(Opts.SuggestMissingIncludes),

clang-tools-extra/clangd/ClangdServer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ class ClangdServer {
111111
/// on background threads. The index is stored in the project root.
112112
bool BackgroundIndex = false;
113113

114+
/// Store refs to main-file symbols in the index.
115+
bool CollectMainFileRefs = false;
116+
114117
/// If set, use this index to augment code completion results.
115118
SymbolIndex *StaticIndex = nullptr;
116119

clang-tools-extra/clangd/index/Background.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ BackgroundIndex::BackgroundIndex(
9595
BackgroundIndexStorage::Factory IndexStorageFactory, Options Opts)
9696
: SwapIndex(std::make_unique<MemIndex>()), TFS(TFS), CDB(CDB),
9797
ContextProvider(std::move(Opts.ContextProvider)),
98+
CollectMainFileRefs(Opts.CollectMainFileRefs),
9899
Rebuilder(this, &IndexedSymbols, Opts.ThreadPoolSize),
99100
IndexStorageFactory(std::move(IndexStorageFactory)),
100101
Queue(std::move(Opts.OnProgress)),
@@ -301,6 +302,7 @@ llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) {
301302
return false; // Skip files that haven't changed, without errors.
302303
return true;
303304
};
305+
IndexOpts.CollectMainFileRefs = CollectMainFileRefs;
304306

305307
IndexFileIn Index;
306308
auto Action = createStaticIndexingAction(

clang-tools-extra/clangd/index/Background.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ class BackgroundIndex : public SwapIndex {
137137
// file. Called with the empty string for other tasks.
138138
// (When called, the context from BackgroundIndex construction is active).
139139
std::function<Context(PathRef)> ContextProvider = nullptr;
140+
// Whether to collect references to main-file-only symbols.
141+
bool CollectMainFileRefs = false;
140142
};
141143

142144
/// Creates a new background index and starts its threads.
@@ -188,6 +190,7 @@ class BackgroundIndex : public SwapIndex {
188190
const ThreadsafeFS &TFS;
189191
const GlobalCompilationDatabase &CDB;
190192
std::function<Context(PathRef)> ContextProvider;
193+
bool CollectMainFileRefs;
191194

192195
llvm::Error index(tooling::CompileCommand);
193196

clang-tools-extra/clangd/index/FileIndex.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,13 @@ SlabTuple indexSymbols(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
4747
llvm::ArrayRef<Decl *> DeclsToIndex,
4848
const MainFileMacros *MacroRefsToIndex,
4949
const CanonicalIncludes &Includes, bool IsIndexMainAST,
50-
llvm::StringRef Version) {
50+
llvm::StringRef Version, bool CollectMainFileRefs) {
5151
SymbolCollector::Options CollectorOpts;
5252
CollectorOpts.CollectIncludePath = true;
5353
CollectorOpts.Includes = &Includes;
5454
CollectorOpts.CountReferences = false;
5555
CollectorOpts.Origin = SymbolOrigin::Dynamic;
56+
CollectorOpts.CollectMainFileRefs = CollectMainFileRefs;
5657

5758
index::IndexingOptions IndexOpts;
5859
// We only need declarations, because we don't count references.
@@ -205,11 +206,11 @@ FileShardedIndex::getShard(llvm::StringRef Uri) const {
205206
return std::move(IF);
206207
}
207208

208-
SlabTuple indexMainDecls(ParsedAST &AST) {
209-
return indexSymbols(AST.getASTContext(), AST.getPreprocessorPtr(),
210-
AST.getLocalTopLevelDecls(), &AST.getMacros(),
211-
AST.getCanonicalIncludes(),
212-
/*IsIndexMainAST=*/true, AST.version());
209+
SlabTuple indexMainDecls(ParsedAST &AST, bool CollectMainFileRefs) {
210+
return indexSymbols(
211+
AST.getASTContext(), AST.getPreprocessorPtr(),
212+
AST.getLocalTopLevelDecls(), &AST.getMacros(), AST.getCanonicalIncludes(),
213+
/*IsIndexMainAST=*/true, AST.version(), CollectMainFileRefs);
213214
}
214215

215216
SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
@@ -220,7 +221,8 @@ SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
220221
AST.getTranslationUnitDecl()->decls().end());
221222
return indexSymbols(AST, std::move(PP), DeclsToIndex,
222223
/*MainFileMacros=*/nullptr, Includes,
223-
/*IsIndexMainAST=*/false, Version);
224+
/*IsIndexMainAST=*/false, Version,
225+
/*CollectMainFileRefs=*/false);
224226
}
225227

226228
void FileSymbols::update(llvm::StringRef Key,
@@ -371,8 +373,9 @@ FileSymbols::buildIndex(IndexType Type, DuplicateHandling DuplicateHandle,
371373
llvm_unreachable("Unknown clangd::IndexType");
372374
}
373375

374-
FileIndex::FileIndex(bool UseDex)
376+
FileIndex::FileIndex(bool UseDex, bool CollectMainFileRefs)
375377
: MergedIndex(&MainFileIndex, &PreambleIndex), UseDex(UseDex),
378+
CollectMainFileRefs(CollectMainFileRefs),
376379
PreambleIndex(std::make_unique<MemIndex>()),
377380
MainFileIndex(std::make_unique<MemIndex>()) {}
378381

@@ -415,7 +418,7 @@ void FileIndex::updatePreamble(PathRef Path, llvm::StringRef Version,
415418
}
416419

417420
void FileIndex::updateMain(PathRef Path, ParsedAST &AST) {
418-
auto Contents = indexMainDecls(AST);
421+
auto Contents = indexMainDecls(AST, CollectMainFileRefs);
419422
MainFileSymbols.update(
420423
Path, std::make_unique<SymbolSlab>(std::move(std::get<0>(Contents))),
421424
std::make_unique<RefSlab>(std::move(std::get<1>(Contents))),

clang-tools-extra/clangd/index/FileIndex.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class FileSymbols {
104104
/// FIXME: Expose an interface to remove files that are closed.
105105
class FileIndex : public MergedIndex {
106106
public:
107-
FileIndex(bool UseDex = true);
107+
FileIndex(bool UseDex = true, bool CollectMainFileRefs = false);
108108

109109
/// Update preamble symbols of file \p Path with all declarations in \p AST
110110
/// and macros in \p PP.
@@ -118,6 +118,7 @@ class FileIndex : public MergedIndex {
118118

119119
private:
120120
bool UseDex; // FIXME: this should be always on.
121+
bool CollectMainFileRefs;
121122

122123
// Contains information from each file's preamble only. Symbols and relations
123124
// are sharded per declaration file to deduplicate multiple symbols and reduce
@@ -152,7 +153,7 @@ using SlabTuple = std::tuple<SymbolSlab, RefSlab, RelationSlab>;
152153
/// Retrieves symbols and refs of local top level decls in \p AST (i.e.
153154
/// `AST.getLocalTopLevelDecls()`).
154155
/// Exposed to assist in unit tests.
155-
SlabTuple indexMainDecls(ParsedAST &AST);
156+
SlabTuple indexMainDecls(ParsedAST &AST, bool CollectMainFileRefs = false);
156157

157158
/// Index declarations from \p AST and macros from \p PP that are declared in
158159
/// included headers.

clang-tools-extra/clangd/index/SymbolCollector.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,12 +334,13 @@ bool SymbolCollector::handleDeclOccurrence(
334334
if (IsOnlyRef && !CollectRef)
335335
return true;
336336

337-
// Do not store references to main-file symbols.
338337
// Unlike other fields, e.g. Symbols (which use spelling locations), we use
339338
// file locations for references (as it aligns the behavior of clangd's
340339
// AST-based xref).
341340
// FIXME: we should try to use the file locations for other fields.
342-
if (CollectRef && (!IsMainFileOnly || ND->isExternallyVisible()) &&
341+
if (CollectRef &&
342+
(!IsMainFileOnly || Opts.CollectMainFileRefs ||
343+
ND->isExternallyVisible()) &&
343344
!isa<NamespaceDecl>(ND) &&
344345
(Opts.RefsInHeaders ||
345346
SM.getFileID(SM.getFileLoc(Loc)) == SM.getMainFileID()))

clang-tools-extra/clangd/index/SymbolCollector.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class SymbolCollector : public index::IndexDataConsumer {
7878
/// Collect symbols local to main-files, such as static functions
7979
/// and symbols inside an anonymous namespace.
8080
bool CollectMainFileSymbols = true;
81+
/// Collect references to main-file symbols.
82+
bool CollectMainFileRefs = false;
8183
/// If set to true, SymbolCollector will collect doc for all symbols.
8284
/// Note that documents of symbols being indexed for completion will always
8385
/// be collected regardless of this option.

clang-tools-extra/clangd/tool/ClangdMain.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,13 @@ opt<bool> EnableConfig{
450450
init(true),
451451
};
452452

453+
opt<bool> CollectMainFileRefs{
454+
"collect-main-file-refs",
455+
cat(Misc),
456+
desc("Store references to main-file-only symbols in the index"),
457+
init(false),
458+
};
459+
453460
#if CLANGD_ENABLE_REMOTE
454461
opt<std::string> RemoteIndexAddress{
455462
"remote-index-address",
@@ -682,6 +689,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
682689
if (!ResourceDir.empty())
683690
Opts.ResourceDir = ResourceDir;
684691
Opts.BuildDynamicSymbolIndex = EnableIndex;
692+
Opts.CollectMainFileRefs = CollectMainFileRefs;
685693
std::unique_ptr<SymbolIndex> StaticIdx;
686694
std::future<void> AsyncIndexLoad; // Block exit while loading the index.
687695
if (EnableIndex && !IndexFile.empty()) {

clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,61 @@ TEST_F(BackgroundIndexTest, IndexTwoFiles) {
229229
FileURI("unittest:///root/B.cc")}));
230230
}
231231

232+
TEST_F(BackgroundIndexTest, MainFileRefs) {
233+
MockFS FS;
234+
FS.Files[testPath("root/A.h")] = R"cpp(
235+
void header_sym();
236+
)cpp";
237+
FS.Files[testPath("root/A.cc")] =
238+
"#include \"A.h\"\nstatic void main_sym() { (void)header_sym; }";
239+
240+
// Check the behaviour with CollectMainFileRefs = false (the default).
241+
{
242+
llvm::StringMap<std::string> Storage;
243+
size_t CacheHits = 0;
244+
MemoryShardStorage MSS(Storage, CacheHits);
245+
OverlayCDB CDB(/*Base=*/nullptr);
246+
BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; },
247+
/*Opts=*/{});
248+
249+
tooling::CompileCommand Cmd;
250+
Cmd.Filename = testPath("root/A.cc");
251+
Cmd.Directory = testPath("root");
252+
Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
253+
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
254+
255+
ASSERT_TRUE(Idx.blockUntilIdleForTest());
256+
EXPECT_THAT(
257+
runFuzzyFind(Idx, ""),
258+
UnorderedElementsAre(AllOf(Named("header_sym"), NumReferences(1U)),
259+
AllOf(Named("main_sym"), NumReferences(0U))));
260+
}
261+
262+
// Check the behaviour with CollectMainFileRefs = true.
263+
{
264+
llvm::StringMap<std::string> Storage;
265+
size_t CacheHits = 0;
266+
MemoryShardStorage MSS(Storage, CacheHits);
267+
OverlayCDB CDB(/*Base=*/nullptr);
268+
BackgroundIndex::Options Opts;
269+
Opts.CollectMainFileRefs = true;
270+
BackgroundIndex Idx(
271+
FS, CDB, [&](llvm::StringRef) { return &MSS; }, Opts);
272+
273+
tooling::CompileCommand Cmd;
274+
Cmd.Filename = testPath("root/A.cc");
275+
Cmd.Directory = testPath("root");
276+
Cmd.CommandLine = {"clang++", testPath("root/A.cc")};
277+
CDB.setCompileCommand(testPath("root/A.cc"), Cmd);
278+
279+
ASSERT_TRUE(Idx.blockUntilIdleForTest());
280+
EXPECT_THAT(
281+
runFuzzyFind(Idx, ""),
282+
UnorderedElementsAre(AllOf(Named("header_sym"), NumReferences(1U)),
283+
AllOf(Named("main_sym"), NumReferences(1U))));
284+
}
285+
}
286+
232287
TEST_F(BackgroundIndexTest, ShardStorageTest) {
233288
MockFS FS;
234289
FS.Files[testPath("root/A.h")] = R"cpp(

clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,6 @@ TEST_F(SymbolCollectorTest, Refs) {
714714
EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(Symbols, "NS").ID, _))));
715715
EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "MACRO").ID,
716716
HaveRanges(Main.ranges("macro")))));
717-
// Symbols *only* in the main file:
718717
// - (a, b) externally visible and should have refs.
719718
// - (c, FUNC) externally invisible and had no refs collected.
720719
auto MainSymbols =
@@ -723,6 +722,20 @@ TEST_F(SymbolCollectorTest, Refs) {
723722
EXPECT_THAT(Refs, Contains(Pair(findSymbol(MainSymbols, "b").ID, _)));
724723
EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "c").ID, _))));
725724
EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(MainSymbols, "FUNC").ID, _))));
725+
726+
// Run the collector again with CollectMainFileRefs = true.
727+
// We need to recreate InMemoryFileSystem because runSymbolCollector()
728+
// calls MemoryBuffer::getMemBuffer(), which makes the buffers unusable
729+
// after runSymbolCollector() exits.
730+
InMemoryFileSystem = new llvm::vfs::InMemoryFileSystem();
731+
CollectorOpts.CollectMainFileRefs = true;
732+
runSymbolCollector(Header.code(),
733+
(Main.code() + SymbolsOnlyInMainCode.code()).str());
734+
EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "a").ID, _)));
735+
EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "b").ID, _)));
736+
EXPECT_THAT(Refs, Contains(Pair(findSymbol(Symbols, "c").ID, _)));
737+
// However, references to main-file macros are not collected.
738+
EXPECT_THAT(Refs, Not(Contains(Pair(findSymbol(Symbols, "FUNC").ID, _))));
726739
}
727740

728741
TEST_F(SymbolCollectorTest, MacroRefInHeader) {
@@ -908,8 +921,9 @@ TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
908921
$Foo[[Foo]] fo;
909922
}
910923
)");
911-
// The main file is normal .cpp file, we should collect the refs
912-
// for externally visible symbols.
924+
// We should collect refs to main-file symbols in all cases:
925+
926+
// 1. The main file is normal .cpp file.
913927
TestFileName = testPath("foo.cpp");
914928
runSymbolCollector("", Header.code());
915929
EXPECT_THAT(Refs,
@@ -918,7 +932,7 @@ TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
918932
Pair(findSymbol(Symbols, "Func").ID,
919933
HaveRanges(Header.ranges("Func")))));
920934

921-
// Run the .h file as main file, we should collect the refs.
935+
// 2. Run the .h file as main file.
922936
TestFileName = testPath("foo.h");
923937
runSymbolCollector("", Header.code(),
924938
/*ExtraArgs=*/{"-xobjective-c++-header"});
@@ -929,8 +943,7 @@ TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
929943
Pair(findSymbol(Symbols, "Func").ID,
930944
HaveRanges(Header.ranges("Func")))));
931945

932-
// Run the .hh file as main file (without "-x c++-header"), we should collect
933-
// the refs as well.
946+
// 3. Run the .hh file as main file (without "-x c++-header").
934947
TestFileName = testPath("foo.hh");
935948
runSymbolCollector("", Header.code());
936949
EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"), QName("Func")));

0 commit comments

Comments
 (0)