diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp --- a/clang-tools-extra/clangd/index/Background.cpp +++ b/clang-tools-extra/clangd/index/Background.cpp @@ -276,6 +276,7 @@ struct File { llvm::DenseSet Symbols; llvm::DenseSet Refs; + llvm::DenseSet Relations; FileDigest Digest; }; llvm::StringMap Files; @@ -325,12 +326,14 @@ llvm::StringRef Path = FileIt.getKey(); SymbolSlab::Builder Syms; RefSlab::Builder Refs; + RelationSlab::Builder Relations; // TODO: Populate. for (const auto *S : FileIt.second.Symbols) Syms.insert(*S); for (const auto *R : FileIt.second.Refs) Refs.insert(RefToIDs[R], *R); auto SS = llvm::make_unique(std::move(Syms).build()); auto RS = llvm::make_unique(std::move(Refs).build()); + auto RelS = llvm::make_unique(std::move(Relations).build()); auto IG = llvm::make_unique( getSubGraph(URI::create(Path), Index.Sources.getValue())); // We need to store shards before updating the index, since the latter @@ -339,6 +342,7 @@ IndexFileOut Shard; Shard.Symbols = SS.get(); Shard.Refs = RS.get(); + Shard.Relations = RelS.get(); Shard.Sources = IG.get(); if (auto Error = IndexStorage->storeShard(Path, Shard)) @@ -356,7 +360,7 @@ // This can override a newer version that is added in another thread, if // this thread sees the older version but finishes later. This should be // rare in practice. - IndexedSymbols.update(Path, std::move(SS), std::move(RS), + IndexedSymbols.update(Path, std::move(SS), std::move(RS), std::move(RelS), Path == MainFile); } } @@ -429,6 +433,7 @@ auto Action = createStaticIndexingAction( IndexOpts, [&](SymbolSlab S) { Index.Symbols = std::move(S); }, [&](RefSlab R) { Index.Refs = std::move(R); }, + [&](RelationSlab R) { Index.Relations = std::move(R); }, [&](IncludeGraph IG) { Index.Sources = std::move(IG); }); // We're going to run clang here, and it could potentially crash. @@ -570,9 +575,13 @@ auto RS = SI.Shard->Refs ? llvm::make_unique(std::move(*SI.Shard->Refs)) : nullptr; + auto RelS = + SI.Shard->Relations + ? llvm::make_unique(std::move(*SI.Shard->Relations)) + : nullptr; IndexedFileDigests[SI.AbsolutePath] = SI.Digest; IndexedSymbols.update(SI.AbsolutePath, std::move(SS), std::move(RS), - SI.CountReferences); + std::move(RelS), SI.CountReferences); } } diff --git a/clang-tools-extra/clangd/index/FileIndex.h b/clang-tools-extra/clangd/index/FileIndex.h --- a/clang-tools-extra/clangd/index/FileIndex.h +++ b/clang-tools-extra/clangd/index/FileIndex.h @@ -63,7 +63,8 @@ /// If CountReferences is true, \p Refs will be used for counting References /// during merging. void update(PathRef Path, std::unique_ptr Slab, - std::unique_ptr Refs, bool CountReferences); + std::unique_ptr Refs, + std::unique_ptr Relations, bool CountReferences); /// The index keeps the symbols alive. /// Will count Symbol::References based on number of references in the main @@ -83,6 +84,8 @@ llvm::StringMap> FileToSymbols; /// Stores the latest ref snapshots for all active files. llvm::StringMap FileToRefs; + /// Stores the latest relation snapshots for all active files. + llvm::StringMap> FileToRelations; }; /// This manages symbols from files and an in-memory index on all symbols. @@ -128,10 +131,12 @@ SwapIndex MainFileIndex; }; +using SlabTuple = std::tuple; + /// Retrieves symbols and refs of local top level decls in \p AST (i.e. /// `AST.getLocalTopLevelDecls()`). /// Exposed to assist in unit tests. -std::pair indexMainDecls(ParsedAST &AST); +SlabTuple indexMainDecls(ParsedAST &AST); /// Idex declarations from \p AST and macros from \p PP that are declared in /// included headers. diff --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-tools-extra/clangd/index/FileIndex.cpp --- a/clang-tools-extra/clangd/index/FileIndex.cpp +++ b/clang-tools-extra/clangd/index/FileIndex.cpp @@ -28,10 +28,10 @@ namespace clang { namespace clangd { -static std::pair -indexSymbols(ASTContext &AST, std::shared_ptr PP, - llvm::ArrayRef DeclsToIndex, - const CanonicalIncludes &Includes, bool IsIndexMainAST) { +static SlabTuple indexSymbols(ASTContext &AST, std::shared_ptr PP, + llvm::ArrayRef DeclsToIndex, + const CanonicalIncludes &Includes, + bool IsIndexMainAST) { SymbolCollector::Options CollectorOpts; CollectorOpts.CollectIncludePath = true; CollectorOpts.Includes = &Includes; @@ -65,15 +65,17 @@ auto Syms = Collector.takeSymbols(); auto Refs = Collector.takeRefs(); + auto Relations = Collector.takeRelations(); vlog("index AST for {0} (main={1}): \n" " symbol slab: {2} symbols, {3} bytes\n" - " ref slab: {4} symbols, {5} refs, {6} bytes", + " ref slab: {4} symbols, {5} refs, {6} bytes\n" + " relations slab: {7} relations, {8} bytes", FileName, IsIndexMainAST, Syms.size(), Syms.bytes(), Refs.size(), - Refs.numRefs(), Refs.bytes()); - return {std::move(Syms), std::move(Refs)}; + Refs.numRefs(), Refs.bytes(), Relations.size(), Relations.bytes()); + return {std::move(Syms), std::move(Refs), std::move(Relations)}; } -std::pair indexMainDecls(ParsedAST &AST) { +SlabTuple indexMainDecls(ParsedAST &AST) { return indexSymbols(AST.getASTContext(), AST.getPreprocessorPtr(), AST.getLocalTopLevelDecls(), AST.getCanonicalIncludes(), /*IsIndexMainAST=*/true); @@ -84,13 +86,14 @@ std::vector DeclsToIndex( AST.getTranslationUnitDecl()->decls().begin(), AST.getTranslationUnitDecl()->decls().end()); - return indexSymbols(AST, std::move(PP), DeclsToIndex, Includes, - /*IsIndexMainAST=*/false) - .first; + return std::get<0>(indexSymbols(AST, std::move(PP), DeclsToIndex, Includes, + /*IsIndexMainAST=*/false)); } void FileSymbols::update(PathRef Path, std::unique_ptr Symbols, - std::unique_ptr Refs, bool CountReferences) { + std::unique_ptr Refs, + std::unique_ptr Relations, + bool CountReferences) { std::lock_guard Lock(Mutex); if (!Symbols) FileToSymbols.erase(Path); @@ -98,18 +101,23 @@ FileToSymbols[Path] = std::move(Symbols); if (!Refs) { FileToRefs.erase(Path); - return; + } else { + RefSlabAndCountReferences Item; + Item.CountReferences = CountReferences; + Item.Slab = std::move(Refs); + FileToRefs[Path] = std::move(Item); } - RefSlabAndCountReferences Item; - Item.CountReferences = CountReferences; - Item.Slab = std::move(Refs); - FileToRefs[Path] = std::move(Item); + if (!Relations) + FileToRelations.erase(Path); + else + FileToRelations[Path] = std::move(Relations); } std::unique_ptr FileSymbols::buildIndex(IndexType Type, DuplicateHandling DuplicateHandle) { std::vector> SymbolSlabs; std::vector> RefSlabs; + std::vector> RelationSlabs; std::vector MainFileRefs; { std::lock_guard Lock(Mutex); @@ -120,6 +128,8 @@ if (FileAndRefs.second.CountReferences) MainFileRefs.push_back(RefSlabs.back().get()); } + for (const auto &FileAndRelations : FileToRelations) + RelationSlabs.push_back(FileAndRelations.second); } std::vector AllSymbols; std::vector SymsStorage; @@ -187,20 +197,33 @@ } } + std::vector AllRelations; + { + for (const auto &RelationSlab : RelationSlabs) { + for (const auto &R : *RelationSlab) { + AllRelations.push_back(R); + } + } + } + size_t StorageSize = RefsStorage.size() * sizeof(Ref) + SymsStorage.size() * sizeof(Symbol); for (const auto &Slab : SymbolSlabs) StorageSize += Slab->bytes(); for (const auto &RefSlab : RefSlabs) StorageSize += RefSlab->bytes(); + for (const auto &RelationSlab : RelationSlabs) + StorageSize += RelationSlab->bytes(); // Index must keep the slabs and contiguous ranges alive. switch (Type) { case IndexType::Light: return llvm::make_unique( llvm::make_pointee_range(AllSymbols), std::move(AllRefs), + std::move(AllRelations), std::make_tuple(std::move(SymbolSlabs), std::move(RefSlabs), - std::move(RefsStorage), std::move(SymsStorage)), + std::move(RelationSlabs), std::move(RefsStorage), + std::move(SymsStorage)), StorageSize); case IndexType::Heavy: return llvm::make_unique( @@ -223,7 +246,8 @@ auto Symbols = indexHeaderSymbols(AST, std::move(PP), Includes); PreambleSymbols.update( Path, llvm::make_unique(std::move(Symbols)), - llvm::make_unique(), /*CountReferences=*/false); + llvm::make_unique(), llvm::make_unique(), + /*CountReferences=*/false); PreambleIndex.reset( PreambleSymbols.buildIndex(UseDex ? IndexType::Heavy : IndexType::Light, DuplicateHandling::PickOne)); @@ -232,8 +256,9 @@ void FileIndex::updateMain(PathRef Path, ParsedAST &AST) { auto Contents = indexMainDecls(AST); MainFileSymbols.update( - Path, llvm::make_unique(std::move(Contents.first)), - llvm::make_unique(std::move(Contents.second)), + Path, llvm::make_unique(std::move(std::get<0>(Contents))), + llvm::make_unique(std::move(std::get<1>(Contents))), + llvm::make_unique(std::move(std::get<2>(Contents))), /*CountReferences=*/true); MainFileIndex.reset( MainFileSymbols.buildIndex(IndexType::Light, DuplicateHandling::PickOne)); diff --git a/clang-tools-extra/clangd/index/Index.h b/clang-tools-extra/clangd/index/Index.h --- a/clang-tools-extra/clangd/index/Index.h +++ b/clang-tools-extra/clangd/index/Index.h @@ -103,6 +103,10 @@ virtual void refs(const RefsRequest &Req, llvm::function_ref Callback) const = 0; + virtual void + relations(const SymbolID &Subject, index::SymbolRole Predicate, + llvm::function_ref Callback) const = 0; + /// Returns estimated size of index (in bytes). virtual size_t estimateMemoryUsage() const = 0; }; @@ -123,6 +127,9 @@ llvm::function_ref) const override; void refs(const RefsRequest &, llvm::function_ref) const override; + void relations(const SymbolID &, index::SymbolRole, + llvm::function_ref) const override; + size_t estimateMemoryUsage() const override; private: diff --git a/clang-tools-extra/clangd/index/Index.cpp b/clang-tools-extra/clangd/index/Index.cpp --- a/clang-tools-extra/clangd/index/Index.cpp +++ b/clang-tools-extra/clangd/index/Index.cpp @@ -69,6 +69,11 @@ llvm::function_ref CB) const { return snapshot()->refs(R, CB); } +void SwapIndex::relations(const SymbolID &Subject, index::SymbolRole Predicate, + llvm::function_ref CB) const { + return snapshot()->relations(Subject, Predicate, CB); +} + size_t SwapIndex::estimateMemoryUsage() const { return snapshot()->estimateMemoryUsage(); } diff --git a/clang-tools-extra/clangd/index/IndexAction.h b/clang-tools-extra/clangd/index/IndexAction.h --- a/clang-tools-extra/clangd/index/IndexAction.h +++ b/clang-tools-extra/clangd/index/IndexAction.h @@ -27,6 +27,7 @@ SymbolCollector::Options Opts, std::function SymbolsCallback, std::function RefsCallback, + std::function RelationsCallback, std::function IncludeGraphCallback); } // namespace clangd diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -116,9 +116,11 @@ const index::IndexingOptions &Opts, std::function SymbolsCallback, std::function RefsCallback, + std::function RelationsCallback, std::function IncludeGraphCallback) : WrapperFrontendAction(index::createIndexingAction(C, Opts, nullptr)), SymbolsCallback(SymbolsCallback), RefsCallback(RefsCallback), + RelationsCallback(RelationsCallback), IncludeGraphCallback(IncludeGraphCallback), Collector(C), Includes(std::move(Includes)), PragmaHandler(collectIWYUHeaderMaps(this->Includes.get())) {} @@ -155,6 +157,8 @@ SymbolsCallback(Collector->takeSymbols()); if (RefsCallback != nullptr) RefsCallback(Collector->takeRefs()); + if (RelationsCallback != nullptr) + RelationsCallback(Collector->takeRelations()); if (IncludeGraphCallback != nullptr) { #ifndef NDEBUG // This checks if all nodes are initialized. @@ -168,6 +172,7 @@ private: std::function SymbolsCallback; std::function RefsCallback; + std::function RelationsCallback; std::function IncludeGraphCallback; std::shared_ptr Collector; std::unique_ptr Includes; @@ -181,6 +186,7 @@ SymbolCollector::Options Opts, std::function SymbolsCallback, std::function RefsCallback, + std::function RelationsCallback, std::function IncludeGraphCallback) { index::IndexingOptions IndexOpts; IndexOpts.SystemSymbolFilter = @@ -198,7 +204,8 @@ Opts.Includes = Includes.get(); return llvm::make_unique( std::make_shared(std::move(Opts)), std::move(Includes), - IndexOpts, SymbolsCallback, RefsCallback, IncludeGraphCallback); + IndexOpts, SymbolsCallback, RefsCallback, RelationsCallback, + IncludeGraphCallback); } } // namespace clangd diff --git a/clang-tools-extra/clangd/index/MemIndex.h b/clang-tools-extra/clangd/index/MemIndex.h --- a/clang-tools-extra/clangd/index/MemIndex.h +++ b/clang-tools-extra/clangd/index/MemIndex.h @@ -20,26 +20,33 @@ public: MemIndex() = default; // All symbols and refs must outlive this index. - template - MemIndex(SymbolRange &&Symbols, RefRange &&Refs) { + template + MemIndex(SymbolRange &&Symbols, RefRange &&Refs, RelationRange &&Relations) { for (const Symbol &S : Symbols) Index[S.ID] = &S; for (const std::pair> &R : Refs) this->Refs.try_emplace(R.first, R.second.begin(), R.second.end()); + RelationSlab::Builder Builder; + for (const Relation &R : Relations) + Builder.insert(R); + this->Relations = std::move(Builder).build(); } // Symbols are owned by BackingData, Index takes ownership. - template - MemIndex(SymbolRange &&Symbols, RefRange &&Refs, Payload &&BackingData, - size_t BackingDataSize) + template + MemIndex(SymbolRange &&Symbols, RefRange &&Refs, RelationRange &&Relations, + Payload &&BackingData, size_t BackingDataSize) : MemIndex(std::forward(Symbols), - std::forward(Refs)) { + std::forward(Refs), + std::forward(Relations)) { KeepAlive = std::shared_ptr( std::make_shared(std::move(BackingData)), nullptr); this->BackingDataSize = BackingDataSize; } /// Builds an index from slabs. The index takes ownership of the data. - static std::unique_ptr build(SymbolSlab Symbols, RefSlab Refs); + static std::unique_ptr build(SymbolSlab Symbols, RefSlab Refs, + RelationSlab Relations); bool fuzzyFind(const FuzzyFindRequest &Req, @@ -51,6 +58,10 @@ void refs(const RefsRequest &Req, llvm::function_ref Callback) const override; + void + relations(const SymbolID &Subject, index::SymbolRole Predicate, + llvm::function_ref Callback) const override; + size_t estimateMemoryUsage() const override; private: @@ -58,6 +69,7 @@ llvm::DenseMap Index; // A map from symbol ID to symbol refs, support query by IDs. llvm::DenseMap> Refs; + RelationSlab Relations; std::shared_ptr KeepAlive; // poor man's move-only std::any // Size of memory retained by KeepAlive. size_t BackingDataSize = 0; diff --git a/clang-tools-extra/clangd/index/MemIndex.cpp b/clang-tools-extra/clangd/index/MemIndex.cpp --- a/clang-tools-extra/clangd/index/MemIndex.cpp +++ b/clang-tools-extra/clangd/index/MemIndex.cpp @@ -16,11 +16,14 @@ namespace clang { namespace clangd { -std::unique_ptr MemIndex::build(SymbolSlab Slab, RefSlab Refs) { +std::unique_ptr MemIndex::build(SymbolSlab Slab, RefSlab Refs, + RelationSlab Relations) { // Store Slab size before it is moved. const auto BackingDataSize = Slab.bytes() + Refs.bytes(); - auto Data = std::make_pair(std::move(Slab), std::move(Refs)); - return llvm::make_unique(Data.first, Data.second, std::move(Data), + auto Data = + std::make_tuple(std::move(Slab), std::move(Refs), std::move(Relations)); + return llvm::make_unique(std::get<0>(Data), std::get<1>(Data), + std::get<2>(Data), std::move(Data), BackingDataSize); } @@ -84,8 +87,18 @@ } } +void MemIndex::relations( + const SymbolID &Subject, index::SymbolRole Predicate, + llvm::function_ref Callback) const { + auto Rels = Relations.lookup(Subject, Predicate); + for (const auto &R : Rels) { + Callback(R.Object); + } +} + size_t MemIndex::estimateMemoryUsage() const { - return Index.getMemorySize() + Refs.getMemorySize() + BackingDataSize; + return Index.getMemorySize() + Refs.getMemorySize() + Relations.bytes() + + BackingDataSize; } } // namespace clangd diff --git a/clang-tools-extra/clangd/index/Merge.h b/clang-tools-extra/clangd/index/Merge.h --- a/clang-tools-extra/clangd/index/Merge.h +++ b/clang-tools-extra/clangd/index/Merge.h @@ -42,6 +42,8 @@ llvm::function_ref) const override; void refs(const RefsRequest &, llvm::function_ref) const override; + void relations(const SymbolID &, index::SymbolRole, + llvm::function_ref) const override; size_t estimateMemoryUsage() const override { return Dynamic->estimateMemoryUsage() + Static->estimateMemoryUsage(); } diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp --- a/clang-tools-extra/clangd/index/Merge.cpp +++ b/clang-tools-extra/clangd/index/Merge.cpp @@ -120,6 +120,22 @@ }); } +void MergedIndex::relations( + const SymbolID &Subject, index::SymbolRole Predicate, + llvm::function_ref Callback) const { + // Return results from both indexes but avoid duplicates. + llvm::DenseSet SeenObjects; + Dynamic->relations(Subject, Predicate, [&](const SymbolID &ObjectID) { + Callback(ObjectID); + SeenObjects.insert(ObjectID); + }); + Static->relations(Subject, Predicate, [&](const SymbolID &ObjectID) { + if (!SeenObjects.count(ObjectID)) { + Callback(ObjectID); + } + }); +} + // Returns true if \p L is (strictly) preferred to \p R (e.g. by file paths). If // neither is preferred, this returns false. bool prefer(const SymbolLocation &L, const SymbolLocation &R) { diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -657,7 +657,8 @@ trace::Span Tracer("BuildIndex"); auto Index = UseDex ? dex::Dex::build(std::move(Symbols), std::move(Refs)) - : MemIndex::build(std::move(Symbols), std::move(Refs)); + : 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/dex/Dex.h b/clang-tools-extra/clangd/index/dex/Dex.h --- a/clang-tools-extra/clangd/index/dex/Dex.h +++ b/clang-tools-extra/clangd/index/dex/Dex.h @@ -72,6 +72,10 @@ void refs(const RefsRequest &Req, llvm::function_ref Callback) const override; + void + relations(const SymbolID &Subject, index::SymbolRole Predicate, + llvm::function_ref Callback) const override; + size_t estimateMemoryUsage() const override; private: diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp --- a/clang-tools-extra/clangd/index/dex/Dex.cpp +++ b/clang-tools-extra/clangd/index/dex/Dex.cpp @@ -259,6 +259,11 @@ } } +void Dex::relations(const SymbolID &Subject, index::SymbolRole Predicate, + llvm::function_ref Callback) const { + // TODO: Implement. +} + size_t Dex::estimateMemoryUsage() const { size_t Bytes = Symbols.size() * sizeof(const Symbol *); Bytes += SymbolQuality.size() * sizeof(float); diff --git a/clang-tools-extra/clangd/indexer/IndexerMain.cpp b/clang-tools-extra/clangd/indexer/IndexerMain.cpp --- a/clang-tools-extra/clangd/indexer/IndexerMain.cpp +++ b/clang-tools-extra/clangd/indexer/IndexerMain.cpp @@ -62,6 +62,12 @@ Refs.insert(Sym.first, Ref); } }, + [&](RelationSlab S) { + std::lock_guard Lock(SymbolsMu); + for (const auto &R : S) { + Relations.insert(R); + } + }, /*IncludeGraphCallback=*/nullptr) .release(); } @@ -71,6 +77,7 @@ ~IndexActionFactory() { Result.Symbols = std::move(Symbols).build(); Result.Refs = std::move(Refs).build(); + Result.Relations = std::move(Relations).build(); } private: @@ -78,6 +85,7 @@ std::mutex SymbolsMu; SymbolSlab::Builder Symbols; RefSlab::Builder Refs; + RelationSlab::Builder Relations; }; } // namespace diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -90,7 +90,7 @@ SymbolSlab::Builder Slab; for (const auto &Sym : Symbols) Slab.insert(Sym); - return MemIndex::build(std::move(Slab).build(), RefSlab()); + return MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab()); } CodeCompleteResult completions(ClangdServer &Server, llvm::StringRef TestCode, @@ -1093,6 +1093,9 @@ void refs(const RefsRequest &, llvm::function_ref) const override {} + void relations(const SymbolID &, index::SymbolRole, + llvm::function_ref) const override {} + // This is incorrect, but IndexRequestCollector is not an actual index and it // isn't used in production code. size_t estimateMemoryUsage() const override { return 0; } diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -469,7 +469,7 @@ Sym.IncludeHeaders.emplace_back(S.IncludeHeader, 1); Slab.insert(Sym); } - return MemIndex::build(std::move(Slab).build(), RefSlab()); + return MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab()); } TEST(IncludeFixerTest, IncompleteType) { @@ -525,7 +525,8 @@ SymbolSlab::Builder Slab; Slab.insert(Sym); - auto Index = MemIndex::build(std::move(Slab).build(), RefSlab()); + auto Index = + MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab()); TU.ExternalIndex = Index.get(); EXPECT_THAT(TU.build().getDiagnostics(), diff --git a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp --- a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp @@ -82,7 +82,8 @@ FileSymbols FS; EXPECT_THAT(runFuzzyFind(*FS.buildIndex(IndexType::Light), ""), IsEmpty()); - FS.update("f1", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cc"), false); + FS.update("f1", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cc"), nullptr, + false); EXPECT_THAT(runFuzzyFind(*FS.buildIndex(IndexType::Light), ""), UnorderedElementsAre(QName("1"), QName("2"), QName("3"))); EXPECT_THAT(getRefs(*FS.buildIndex(IndexType::Light), SymbolID("1")), @@ -91,8 +92,8 @@ TEST(FileSymbolsTest, Overlap) { FileSymbols FS; - FS.update("f1", numSlab(1, 3), nullptr, false); - FS.update("f2", numSlab(3, 5), nullptr, false); + FS.update("f1", numSlab(1, 3), nullptr, nullptr, false); + FS.update("f2", numSlab(3, 5), nullptr, nullptr, false); for (auto Type : {IndexType::Light, IndexType::Heavy}) EXPECT_THAT(runFuzzyFind(*FS.buildIndex(Type), ""), UnorderedElementsAre(QName("1"), QName("2"), QName("3"), @@ -111,8 +112,8 @@ auto X2 = symbol("x"); X2.Definition.FileURI = "file:///x2"; - FS.update("f1", OneSymboSlab(X1), nullptr, false); - FS.update("f2", OneSymboSlab(X2), nullptr, false); + FS.update("f1", OneSymboSlab(X1), nullptr, nullptr, false); + FS.update("f2", OneSymboSlab(X2), nullptr, nullptr, false); for (auto Type : {IndexType::Light, IndexType::Heavy}) EXPECT_THAT( runFuzzyFind(*FS.buildIndex(Type, DuplicateHandling::Merge), "x"), @@ -124,14 +125,14 @@ FileSymbols FS; SymbolID ID("1"); - FS.update("f1", numSlab(1, 3), refSlab(ID, "f1.cc"), false); + FS.update("f1", numSlab(1, 3), refSlab(ID, "f1.cc"), nullptr, false); auto Symbols = FS.buildIndex(IndexType::Light); EXPECT_THAT(runFuzzyFind(*Symbols, ""), UnorderedElementsAre(QName("1"), QName("2"), QName("3"))); EXPECT_THAT(getRefs(*Symbols, ID), RefsAre({FileURI("f1.cc")})); - FS.update("f1", nullptr, nullptr, false); + FS.update("f1", nullptr, nullptr, nullptr, false); auto Empty = FS.buildIndex(IndexType::Light); EXPECT_THAT(runFuzzyFind(*Empty, ""), IsEmpty()); EXPECT_THAT(getRefs(*Empty, ID), ElementsAre()); @@ -369,8 +370,8 @@ TEST(FileSymbolsTest, CountReferencesNoRefSlabs) { FileSymbols FS; - FS.update("f1", numSlab(1, 3), nullptr, true); - FS.update("f2", numSlab(1, 3), nullptr, false); + FS.update("f1", numSlab(1, 3), nullptr, nullptr, true); + FS.update("f2", numSlab(1, 3), nullptr, nullptr, false); EXPECT_THAT( runFuzzyFind(*FS.buildIndex(IndexType::Light, DuplicateHandling::Merge), ""), @@ -381,12 +382,18 @@ TEST(FileSymbolsTest, CountReferencesWithRefSlabs) { FileSymbols FS; - FS.update("f1cpp", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cpp"), true); - FS.update("f1h", numSlab(1, 3), refSlab(SymbolID("1"), "f1.h"), false); - FS.update("f2cpp", numSlab(1, 3), refSlab(SymbolID("2"), "f2.cpp"), true); - FS.update("f2h", numSlab(1, 3), refSlab(SymbolID("2"), "f2.h"), false); - FS.update("f3cpp", numSlab(1, 3), refSlab(SymbolID("3"), "f3.cpp"), true); - FS.update("f3h", numSlab(1, 3), refSlab(SymbolID("3"), "f3.h"), false); + FS.update("f1cpp", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cpp"), nullptr, + true); + FS.update("f1h", numSlab(1, 3), refSlab(SymbolID("1"), "f1.h"), nullptr, + false); + FS.update("f2cpp", numSlab(1, 3), refSlab(SymbolID("2"), "f2.cpp"), nullptr, + true); + FS.update("f2h", numSlab(1, 3), refSlab(SymbolID("2"), "f2.h"), nullptr, + false); + FS.update("f3cpp", numSlab(1, 3), refSlab(SymbolID("3"), "f3.cpp"), nullptr, + true); + FS.update("f3h", numSlab(1, 3), refSlab(SymbolID("3"), "f3.h"), nullptr, + false); EXPECT_THAT( runFuzzyFind(*FS.buildIndex(IndexType::Light, DuplicateHandling::Merge), ""), diff --git a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp --- a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp +++ b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp @@ -77,6 +77,7 @@ SymbolCollector::Options(), [&](SymbolSlab S) { IndexFile.Symbols = std::move(S); }, [&](RefSlab R) { IndexFile.Refs = std::move(R); }, + [&](RelationSlab R) { IndexFile.Relations = std::move(R); }, [&](IncludeGraph IG) { IndexFile.Sources = std::move(IG); }); std::vector Args = {"index_action", "-fsyntax-only", diff --git a/clang-tools-extra/clangd/unittests/IndexTests.cpp b/clang-tools-extra/clangd/unittests/IndexTests.cpp --- a/clang-tools-extra/clangd/unittests/IndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/IndexTests.cpp @@ -119,8 +119,9 @@ auto Token = std::make_shared(); std::weak_ptr WeakToken = Token; - SwapIndex S(llvm::make_unique( - SymbolSlab(), RefSlab(), std::move(Token), /*BackingDataSize=*/0)); + SwapIndex S(llvm::make_unique(SymbolSlab(), RefSlab(), + RelationSlab(), std::move(Token), + /*BackingDataSize=*/0)); EXPECT_FALSE(WeakToken.expired()); // Current MemIndex keeps it alive. S.reset(llvm::make_unique()); // Now the MemIndex is destroyed. EXPECT_TRUE(WeakToken.expired()); // So the token is too. @@ -132,12 +133,13 @@ FuzzyFindRequest Req; Req.Query = "2"; Req.AnyScope = true; - MemIndex I(Symbols, RefSlab()); + MemIndex I(Symbols, RefSlab(), RelationSlab()); EXPECT_THAT(match(I, Req), ElementsAre("2")); } TEST(MemIndexTest, MemIndexLimitedNumMatches) { - auto I = MemIndex::build(generateNumSymbols(0, 100), RefSlab()); + auto I = + MemIndex::build(generateNumSymbols(0, 100), RefSlab(), RelationSlab()); FuzzyFindRequest Req; Req.Query = "5"; Req.AnyScope = true; @@ -152,7 +154,7 @@ TEST(MemIndexTest, FuzzyMatch) { auto I = MemIndex::build( generateSymbols({"LaughingOutLoud", "LionPopulation", "LittleOldLady"}), - RefSlab()); + RefSlab(), RelationSlab()); FuzzyFindRequest Req; Req.Query = "lol"; Req.AnyScope = true; @@ -162,8 +164,8 @@ } TEST(MemIndexTest, MatchQualifiedNamesWithoutSpecificScope) { - auto I = - MemIndex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab()); + auto I = MemIndex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab(), + RelationSlab()); FuzzyFindRequest Req; Req.Query = "y"; Req.AnyScope = true; @@ -171,8 +173,8 @@ } TEST(MemIndexTest, MatchQualifiedNamesWithGlobalScope) { - auto I = - MemIndex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab()); + auto I = MemIndex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab(), + RelationSlab()); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {""}; @@ -181,7 +183,8 @@ TEST(MemIndexTest, MatchQualifiedNamesWithOneScope) { auto I = MemIndex::build( - generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"}), RefSlab()); + generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"}), RefSlab(), + RelationSlab()); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {"a::"}; @@ -190,7 +193,8 @@ TEST(MemIndexTest, MatchQualifiedNamesWithMultipleScopes) { auto I = MemIndex::build( - generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"}), RefSlab()); + generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"}), RefSlab(), + RelationSlab()); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {"a::", "b::"}; @@ -198,7 +202,8 @@ } TEST(MemIndexTest, NoMatchNestedScopes) { - auto I = MemIndex::build(generateSymbols({"a::y1", "a::b::y2"}), RefSlab()); + auto I = MemIndex::build(generateSymbols({"a::y1", "a::b::y2"}), RefSlab(), + RelationSlab()); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {"a::"}; @@ -206,7 +211,8 @@ } TEST(MemIndexTest, IgnoreCases) { - auto I = MemIndex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab()); + auto I = MemIndex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab(), + RelationSlab()); FuzzyFindRequest Req; Req.Query = "AB"; Req.Scopes = {"ns::"}; @@ -214,7 +220,8 @@ } TEST(MemIndexTest, Lookup) { - auto I = MemIndex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab()); + auto I = MemIndex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab(), + RelationSlab()); EXPECT_THAT(lookup(*I, SymbolID("ns::abc")), UnorderedElementsAre("ns::abc")); EXPECT_THAT(lookup(*I, {SymbolID("ns::abc"), SymbolID("ns::xyz")}), UnorderedElementsAre("ns::abc", "ns::xyz")); @@ -244,7 +251,7 @@ index::SymbolProperty::TemplatePartialSpecialization); B.insert(S); - auto I = MemIndex::build(std::move(B).build(), RefSlab()); + auto I = MemIndex::build(std::move(B).build(), RefSlab(), RelationSlab()); FuzzyFindRequest Req; Req.AnyScope = true; @@ -259,8 +266,10 @@ } TEST(MergeIndexTest, Lookup) { - auto I = MemIndex::build(generateSymbols({"ns::A", "ns::B"}), RefSlab()), - J = MemIndex::build(generateSymbols({"ns::B", "ns::C"}), RefSlab()); + auto I = MemIndex::build(generateSymbols({"ns::A", "ns::B"}), RefSlab(), + RelationSlab()), + J = MemIndex::build(generateSymbols({"ns::B", "ns::C"}), RefSlab(), + RelationSlab()); MergedIndex M(I.get(), J.get()); EXPECT_THAT(lookup(M, SymbolID("ns::A")), UnorderedElementsAre("ns::A")); EXPECT_THAT(lookup(M, SymbolID("ns::B")), UnorderedElementsAre("ns::B")); @@ -274,8 +283,10 @@ } TEST(MergeIndexTest, FuzzyFind) { - auto I = MemIndex::build(generateSymbols({"ns::A", "ns::B"}), RefSlab()), - J = MemIndex::build(generateSymbols({"ns::B", "ns::C"}), RefSlab()); + auto I = MemIndex::build(generateSymbols({"ns::A", "ns::B"}), RefSlab(), + RelationSlab()), + J = MemIndex::build(generateSymbols({"ns::B", "ns::C"}), RefSlab(), + RelationSlab()); FuzzyFindRequest Req; Req.Scopes = {"ns::"}; EXPECT_THAT(match(MergedIndex(I.get(), J.get()), Req), diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp --- a/clang-tools-extra/clangd/unittests/TestTU.cpp +++ b/clang-tools-extra/clangd/unittests/TestTU.cpp @@ -75,7 +75,9 @@ std::unique_ptr TestTU::index() const { auto AST = build(); - auto Idx = llvm::make_unique(/*UseDex=*/true); + // UseDex is temporarily set to false so we can test subtypes support + // before implementing it in Dex. + auto Idx = llvm::make_unique(/*UseDex=*/false); Idx->updatePreamble(Filename, AST.getASTContext(), AST.getPreprocessorPtr(), AST.getCanonicalIncludes()); Idx->updateMain(Filename, AST);