Index: clang-tools-extra/clangd/index/SymbolCollector.h =================================================================== --- clang-tools-extra/clangd/index/SymbolCollector.h +++ clang-tools-extra/clangd/index/SymbolCollector.h @@ -82,7 +82,7 @@ /// Returns true is \p ND should be collected. /// AST matchers require non-const ASTContext. static bool shouldCollectSymbol(const NamedDecl &ND, ASTContext &ASTCtx, - const Options &Opts); + const Options &Opts, bool &IsMainFileSymbol); void initialize(ASTContext &Ctx) override; @@ -106,7 +106,7 @@ void finish() override; private: - const Symbol *addDeclaration(const NamedDecl &, SymbolID); + const Symbol *addDeclaration(const NamedDecl &, SymbolID, bool IsMainFileSymbol); void addDefinition(const NamedDecl &, const Symbol &DeclSymbol); // All Symbols collected from the AST. Index: clang-tools-extra/clangd/index/SymbolCollector.cpp =================================================================== --- clang-tools-extra/clangd/index/SymbolCollector.cpp +++ clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -261,7 +261,8 @@ bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND, ASTContext &ASTCtx, - const Options &Opts) { + const Options &Opts, + bool &IsMainFileSymbol) { if (ND.isImplicit()) return false; // Skip anonymous declarations, e.g (anonymous enum/class/struct). @@ -308,8 +309,7 @@ const auto &SM = ASTCtx.getSourceManager(); // Skip decls in the main file. - if (SM.isInMainFile(SM.getExpansionLoc(ND.getBeginLoc()))) - return false; + IsMainFileSymbol = SM.isInMainFile(SM.getExpansionLoc(ND.getBeginLoc())); // Avoid indexing internal symbols in protobuf generated headers. if (isPrivateProtoDecl(ND)) return false; @@ -356,9 +356,13 @@ if (IsOnlyRef && !CollectRef) return true; - if (!shouldCollectSymbol(*ND, *ASTCtx, Opts)) + bool IsMainFileSymbol = false; + if (!shouldCollectSymbol(*ND, *ASTCtx, Opts, IsMainFileSymbol)) + return true; + // Do not store references to main-file symbols. + if (IsOnlyRef && IsMainFileSymbol) return true; - if (CollectRef && !isa(ND) && + if (CollectRef && !IsMainFileSymbol && !isa(ND) && (Opts.RefsInHeaders || SM.getFileID(SpellingLoc) == SM.getMainFileID())) DeclRefs[ND].emplace_back(SpellingLoc, Roles); // Don't continue indexing if this is a mere reference. @@ -372,13 +376,13 @@ const NamedDecl &OriginalDecl = *cast(ASTNode.OrigD); const Symbol *BasicSymbol = Symbols.find(*ID); if (!BasicSymbol) // Regardless of role, ND is the canonical declaration. - BasicSymbol = addDeclaration(*ND, std::move(*ID)); + BasicSymbol = addDeclaration(*ND, std::move(*ID), IsMainFileSymbol); else if (isPreferredDeclaration(OriginalDecl, Roles)) // If OriginalDecl is preferred, replace the existing canonical // declaration (e.g. a class forward declaration). There should be at most // one duplicate as we expect to see only one preferred declaration per // TU, because in practice they are definitions. - BasicSymbol = addDeclaration(OriginalDecl, std::move(*ID)); + BasicSymbol = addDeclaration(OriginalDecl, std::move(*ID), IsMainFileSymbol); if (Roles & static_cast(index::SymbolRole::Definition)) addDefinition(OriginalDecl, *BasicSymbol); @@ -531,7 +535,8 @@ } const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, - SymbolID ID) { + SymbolID ID, + bool IsMainFileSymbol) { auto &Ctx = ND.getASTContext(); auto &SM = Ctx.getSourceManager(); @@ -542,7 +547,7 @@ // FIXME: this returns foo:bar: for objective-C methods, we prefer only foo: // for consistency with CodeCompletionString and a clean name/signature split. - if (isIndexedForCodeCompletion(ND, Ctx)) + if (!IsMainFileSymbol && isIndexedForCodeCompletion(ND, Ctx)) S.Flags |= Symbol::IndexedForCodeCompletion; if (isImplementationDetail(&ND)) S.Flags |= Symbol::ImplementationDetail; Index: clang-tools-extra/unittests/clangd/BackgroundIndexTests.cpp =================================================================== --- clang-tools-extra/unittests/clangd/BackgroundIndexTests.cpp +++ clang-tools-extra/unittests/clangd/BackgroundIndexTests.cpp @@ -98,7 +98,7 @@ ASSERT_TRUE(Idx.blockUntilIdleForTest()); EXPECT_THAT( runFuzzyFind(Idx, ""), - UnorderedElementsAre(Named("common"), Named("A_CC"), + UnorderedElementsAre(Named("common"), Named("A_CC"), Named("g"), AllOf(Named("f_b"), Declared(), Not(Defined())))); Cmd.Filename = testPath("root/B.cc"); @@ -108,7 +108,7 @@ ASSERT_TRUE(Idx.blockUntilIdleForTest()); // B_CC is dropped as we don't collect symbols from A.h in this compilation. EXPECT_THAT(runFuzzyFind(Idx, ""), - UnorderedElementsAre(Named("common"), Named("A_CC"), + UnorderedElementsAre(Named("common"), Named("A_CC"), Named("g"), AllOf(Named("f_b"), Declared(), Defined()))); auto Syms = runFuzzyFind(Idx, "common"); @@ -161,7 +161,7 @@ auto ShardSource = MSS.loadShard(testPath("root/A.cc")); EXPECT_NE(ShardSource, nullptr); - EXPECT_THAT(*ShardSource->Symbols, UnorderedElementsAre()); + EXPECT_THAT(*ShardSource->Symbols, UnorderedElementsAre(Named("g"))); EXPECT_THAT(*ShardSource->Refs, RefsAre({FileURI("unittest:///root/A.cc")})); } Index: clang-tools-extra/unittests/clangd/FindSymbolsTests.cpp =================================================================== --- clang-tools-extra/unittests/clangd/FindSymbolsTests.cpp +++ clang-tools-extra/unittests/clangd/FindSymbolsTests.cpp @@ -64,6 +64,7 @@ : Server(CDB, FSProvider, DiagConsumer, optsForTests()) { // Make sure the test root directory is created. FSProvider.Files[testPath("unused")] = ""; + CDB.ExtraClangFlags = {"-xc++"}; } protected: @@ -146,7 +147,7 @@ int test() { } )cpp"); - EXPECT_THAT(getSymbols("test"), IsEmpty()); + EXPECT_THAT(getSymbols("test"), ElementsAre(QName("test"))); } TEST_F(WorkspaceSymbolsTest, Namespaces) { Index: clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp =================================================================== --- clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp +++ clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp @@ -114,9 +114,11 @@ // build() must have been called. bool shouldCollect(StringRef Name, bool Qualified = true) { assert(AST.hasValue()); + bool IsMainFileSymbol = false; return SymbolCollector::shouldCollectSymbol( Qualified ? findDecl(*AST, Name) : findUnqualifiedDecl(*AST, Name), - AST->getASTContext(), SymbolCollector::Options()); + AST->getASTContext(), SymbolCollector::Options(), + IsMainFileSymbol); } protected: @@ -140,8 +142,8 @@ EXPECT_TRUE(shouldCollect("nx")); EXPECT_TRUE(shouldCollect("nx::X")); EXPECT_TRUE(shouldCollect("nx::f")); + EXPECT_TRUE(shouldCollect("InMain")); - EXPECT_FALSE(shouldCollect("InMain")); EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false)); EXPECT_FALSE(shouldCollect("InAnonymous", /*Qualified=*/false)); } @@ -419,7 +421,7 @@ void $printdef[[print]]() {} // Declared/defined in main only. - int Y; + int $ydecl[[Y]]; )cpp"); runSymbolCollector(Header.code(), Main.code()); EXPECT_THAT( @@ -432,7 +434,8 @@ AllOf(QName("print"), DeclRange(Header.range("printdecl")), DefRange(Main.range("printdef"))), AllOf(QName("Z"), DeclRange(Header.range("zdecl"))), - AllOf(QName("foo"), DeclRange(Header.range("foodecl"))) + AllOf(QName("foo"), DeclRange(Header.range("foodecl"))), + AllOf(QName("Y"), DeclRange(Main.range("ydecl"))) )); } @@ -502,18 +505,17 @@ const std::string Header = R"( class W; class X {}; - class Y; class Z {}; // not used anywhere - Y* y = nullptr; // used in header doesn't count + W* w = nullptr; // used in header doesn't count #define GLOBAL_Z(name) Z name; )"; const std::string Main = R"( - W* w = nullptr; + W* w1 = nullptr; W* w2 = nullptr; // only one usage counts X x(); class V; - V* v = nullptr; // Used, but not eligible for indexing. - class Y{}; // definition doesn't count as a reference + V* v = nullptr; + class W{}; // definition doesn't count as a reference GLOBAL_Z(z); // Not a reference to Z, we don't spell the type. )"; CollectorOpts.CountReferences = true; @@ -521,8 +523,14 @@ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("W"), RefCount(1)), AllOf(QName("X"), RefCount(1)), - AllOf(QName("Y"), RefCount(0)), - AllOf(QName("Z"), RefCount(0)), QName("y"))); + AllOf(QName("Z"), RefCount(0)), + AllOf(QName("z"), RefCount(0)), + AllOf(QName("x"), RefCount(0)), + AllOf(QName("w"), RefCount(0)), + AllOf(QName("w1"), RefCount(0)), + AllOf(QName("w2"), RefCount(0)), + AllOf(QName("V"), RefCount(1)), + AllOf(QName("v"), RefCount(0)))); } TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) { @@ -614,7 +622,7 @@ DeclURI(TestHeaderURI)))); } -TEST_F(SymbolCollectorTest, IgnoreSymbolsInMainFile) { +TEST_F(SymbolCollectorTest, SymbolsInMainFile) { const std::string Header = R"( class Foo {}; void f1(); @@ -622,14 +630,15 @@ )"; const std::string Main = R"( namespace { - void ff() {} // ignore + void ff() {} // ignored (in anonymous namespace) } - void main_f() {} // ignore + void main_f() {} void f1() {} )"; runSymbolCollector(Header, Main); EXPECT_THAT(Symbols, - UnorderedElementsAre(QName("Foo"), QName("f1"), QName("f2"))); + UnorderedElementsAre(QName("Foo"), QName("f1"), QName("f2"), + QName("main_f"))); } TEST_F(SymbolCollectorTest, ClassMembers) { @@ -966,7 +975,8 @@ CollectorOpts.CountReferences = true; runSymbolCollector(Header, Main); EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), RefCount(1)), - AllOf(QName("Y"), RefCount(1)))); + AllOf(QName("Y"), RefCount(1)), + AllOf(QName("C"), RefCount(0)))); } TEST_F(SymbolCollectorTest, Origin) { @@ -993,7 +1003,7 @@ CollectorOpts.CollectMacro = true; runSymbolCollector(Header.code(), Main); EXPECT_THAT(Symbols, - UnorderedElementsAre(QName("p"), + UnorderedElementsAre(QName("p"), QName("t"), AllOf(QName("X"), DeclURI(TestHeaderURI), IncludeHeader(TestHeaderURI)), AllOf(Labeled("MAC(x)"), RefCount(0),