Index: clang-tools-extra/trunk/clangd/index/FileIndex.h =================================================================== --- clang-tools-extra/trunk/clangd/index/FileIndex.h +++ clang-tools-extra/trunk/clangd/index/FileIndex.h @@ -63,6 +63,9 @@ fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref Callback) const override; + void lookup(const LookupRequest &Req, + llvm::function_ref Callback) const override; + private: FileSymbols FSymbols; MemIndex Index; Index: clang-tools-extra/trunk/clangd/index/FileIndex.cpp =================================================================== --- clang-tools-extra/trunk/clangd/index/FileIndex.cpp +++ clang-tools-extra/trunk/clangd/index/FileIndex.cpp @@ -93,5 +93,11 @@ return Index.fuzzyFind(Req, Callback); } +void FileIndex::lookup( + const LookupRequest &Req, + llvm::function_ref Callback) const { + Index.lookup(Req, Callback); +} + } // namespace clangd } // namespace clang Index: clang-tools-extra/trunk/clangd/index/Index.h =================================================================== --- clang-tools-extra/trunk/clangd/index/Index.h +++ clang-tools-extra/trunk/clangd/index/Index.h @@ -248,6 +248,10 @@ size_t MaxCandidateCount = UINT_MAX; }; +struct LookupRequest { + llvm::DenseSet IDs; +}; + /// \brief Interface for symbol indexes that can be used for searching or /// matching symbols among a set of symbols based on names or unique IDs. class SymbolIndex { @@ -263,8 +267,14 @@ fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref Callback) const = 0; + /// Looks up symbols with any of the given symbol IDs and applies \p Callback + /// on each matched symbol. + /// The returned symbol must be deep-copied if it's used outside Callback. + virtual void + lookup(const LookupRequest &Req, + llvm::function_ref Callback) const = 0; + // FIXME: add interfaces for more index use cases: - // - Symbol getSymbolInfo(SymbolID); // - getAllOccurrences(SymbolID); }; Index: clang-tools-extra/trunk/clangd/index/MemIndex.h =================================================================== --- clang-tools-extra/trunk/clangd/index/MemIndex.h +++ clang-tools-extra/trunk/clangd/index/MemIndex.h @@ -31,6 +31,10 @@ fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref Callback) const override; + virtual void + lookup(const LookupRequest &Req, + llvm::function_ref Callback) const override; + private: std::shared_ptr> Symbols; // Index is a set of symbols that are deduplicated by symbol IDs. Index: clang-tools-extra/trunk/clangd/index/MemIndex.cpp =================================================================== --- clang-tools-extra/trunk/clangd/index/MemIndex.cpp +++ clang-tools-extra/trunk/clangd/index/MemIndex.cpp @@ -60,6 +60,15 @@ return More; } +void MemIndex::lookup(const LookupRequest &Req, + llvm::function_ref Callback) const { + for (const auto &ID : Req.IDs) { + auto I = Index.find(ID); + if (I != Index.end()) + Callback(*I->second); + } +} + std::unique_ptr MemIndex::build(SymbolSlab Slab) { struct Snapshot { SymbolSlab Slab; Index: clang-tools-extra/trunk/clangd/index/Merge.cpp =================================================================== --- clang-tools-extra/trunk/clangd/index/Merge.cpp +++ clang-tools-extra/trunk/clangd/index/Merge.cpp @@ -52,6 +52,28 @@ return More; } + void + lookup(const LookupRequest &Req, + llvm::function_ref Callback) const override { + SymbolSlab::Builder B; + + Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); }); + + auto RemainingIDs = Req.IDs; + Symbol::Details Scratch; + Static->lookup(Req, [&](const Symbol &S) { + const Symbol *Sym = B.find(S.ID); + RemainingIDs.erase(S.ID); + if (!Sym) + Callback(S); + else + Callback(mergeSymbol(*Sym, S, &Scratch)); + }); + for (const auto &ID : RemainingIDs) + if (const Symbol *Sym = B.find(ID)) + Callback(*Sym); + } + private: const SymbolIndex *Dynamic, *Static; }; Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -689,6 +689,9 @@ return true; } + void lookup(const LookupRequest &, + llvm::function_ref) const override {} + const std::vector allRequests() const { return Requests; } private: Index: clang-tools-extra/trunk/unittests/clangd/IndexTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/IndexTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/IndexTests.cpp @@ -29,7 +29,7 @@ Sym.Scope = ""; } else { Sym.Name = QName.substr(Pos + 2); - Sym.Scope = QName.substr(0, Pos); + Sym.Scope = QName.substr(0, Pos + 2); } return Sym; } @@ -89,13 +89,16 @@ return generateSymbols(Names, WeakSymbols); } +std::string getQualifiedName(const Symbol &Sym) { + return (Sym.Scope + Sym.Name).str(); +} + std::vector match(const SymbolIndex &I, const FuzzyFindRequest &Req, bool *Incomplete = nullptr) { std::vector Matches; bool IsIncomplete = I.fuzzyFind(Req, [&](const Symbol &Sym) { - Matches.push_back( - (Sym.Scope + (Sym.Scope.empty() ? "" : "::") + Sym.Name).str()); + Matches.push_back(getQualifiedName(Sym)); }); if (Incomplete) *Incomplete = IsIncomplete; @@ -178,7 +181,7 @@ I.build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"})); FuzzyFindRequest Req; Req.Query = "y"; - Req.Scopes = {"a"}; + Req.Scopes = {"a::"}; EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1", "a::y2")); } @@ -187,7 +190,7 @@ I.build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"})); FuzzyFindRequest Req; Req.Query = "y"; - Req.Scopes = {"a", "b"}; + Req.Scopes = {"a::", "b::"}; EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1", "a::y2", "b::y3")); } @@ -196,7 +199,7 @@ I.build(generateSymbols({"a::y1", "a::b::y2"})); FuzzyFindRequest Req; Req.Query = "y"; - Req.Scopes = {"a"}; + Req.Scopes = {"a::"}; EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1")); } @@ -205,16 +208,60 @@ I.build(generateSymbols({"ns::ABC", "ns::abc"})); FuzzyFindRequest Req; Req.Query = "AB"; - Req.Scopes = {"ns"}; + Req.Scopes = {"ns::"}; EXPECT_THAT(match(I, Req), UnorderedElementsAre("ns::ABC", "ns::abc")); } -TEST(MergeTest, MergeIndex) { +// Returns qualified names of symbols with any of IDs in the index. +std::vector lookup(const SymbolIndex &I, + llvm::ArrayRef IDs) { + LookupRequest Req; + Req.IDs.insert(IDs.begin(), IDs.end()); + std::vector Results; + I.lookup(Req, [&](const Symbol &Sym) { + Results.push_back(getQualifiedName(Sym)); + }); + return Results; +} + +TEST(MemIndexTest, Lookup) { + MemIndex I; + I.build(generateSymbols({"ns::abc", "ns::xyz"})); + 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")); + EXPECT_THAT(lookup(I, {SymbolID("ns::nonono"), SymbolID("ns::xyz")}), + UnorderedElementsAre("ns::xyz")); + EXPECT_THAT(lookup(I, SymbolID("ns::nonono")), UnorderedElementsAre()); +} + +TEST(MergeIndexTest, Lookup) { + MemIndex I, J; + I.build(generateSymbols({"ns::A", "ns::B"})); + J.build(generateSymbols({"ns::B", "ns::C"})); + EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::A")), + UnorderedElementsAre("ns::A")); + EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::B")), + UnorderedElementsAre("ns::B")); + EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::C")), + UnorderedElementsAre("ns::C")); + EXPECT_THAT( + lookup(*mergeIndex(&I, &J), {SymbolID("ns::A"), SymbolID("ns::B")}), + UnorderedElementsAre("ns::A", "ns::B")); + EXPECT_THAT( + lookup(*mergeIndex(&I, &J), {SymbolID("ns::A"), SymbolID("ns::C")}), + UnorderedElementsAre("ns::A", "ns::C")); + EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::D")), + UnorderedElementsAre()); + EXPECT_THAT(lookup(*mergeIndex(&I, &J), {}), UnorderedElementsAre()); +} + +TEST(MergeIndexTest, FuzzyFind) { MemIndex I, J; I.build(generateSymbols({"ns::A", "ns::B"})); J.build(generateSymbols({"ns::B", "ns::C"})); FuzzyFindRequest Req; - Req.Scopes = {"ns"}; + Req.Scopes = {"ns::"}; EXPECT_THAT(match(*mergeIndex(&I, &J), Req), UnorderedElementsAre("ns::A", "ns::B", "ns::C")); }