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 @@ -212,8 +212,7 @@ index::IndexingOptions IndexOpts; IndexOpts.SystemSymbolFilter = index::IndexingOptions::SystemSymbolFilterKind::All; - // We index function-local classes and its member functions only. - IndexOpts.IndexFunctionLocals = true; + IndexOpts.IndexFunctionLocals = Opts.CollectFunctionLocalClasses; Opts.CollectIncludePath = true; if (Opts.Origin == SymbolOrigin::Unknown) Opts.Origin = SymbolOrigin::Static; diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h --- a/clang-tools-extra/clangd/index/SymbolCollector.h +++ b/clang-tools-extra/clangd/index/SymbolCollector.h @@ -88,6 +88,8 @@ /// If this is set, only collect symbols/references from a file if /// `FileFilter(SM, FID)` is true. If not set, all files are indexed. std::function FileFilter = nullptr; + /// Collect function-local classes and its member functions. + bool CollectFunctionLocalClasses = true; }; SymbolCollector(Options Opts); diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -349,8 +349,9 @@ // For function local symbols, index only classes and its member functions. if (index::isFunctionLocalSymbol(&ND)) - return isa(ND) || - (ND.isCXXInstanceMember() && ND.isFunctionOrFunctionTemplate()); + return Opts.CollectFunctionLocalClasses && + (isa(ND) || + (ND.isCXXInstanceMember() && ND.isFunctionOrFunctionTemplate())); // We want most things but not "local" symbols such as symbols inside // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl. diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -123,8 +123,8 @@ Qualified ? findDecl(*AST, Name) : findUnqualifiedDecl(*AST, Name); const SourceManager &SM = AST->getSourceManager(); bool MainFile = isInsideMainFile(ND.getBeginLoc(), SM); - return SymbolCollector::shouldCollectSymbol( - ND, AST->getASTContext(), SymbolCollector::Options(), MainFile); + return SymbolCollector::shouldCollectSymbol(ND, AST->getASTContext(), Opts, + MainFile); } protected: @@ -132,6 +132,7 @@ std::string FileName = "f.cpp"; TestTU File; llvm::Optional AST; // Initialized after build. + SymbolCollector::Options Opts; }; TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) { @@ -159,17 +160,17 @@ } TEST_F(ShouldCollectSymbolTest, CollectLocalClassesAndVirtualMethods) { - build(R"( + build(/*HeaderCode=*/"", /*Code=*/R"( namespace nx { - auto f() { + void f() { int Local; auto LocalLambda = [&](){ Local++; class ClassInLambda{}; return Local; }; - } // auto ensures function body is parsed. - auto foo() { + } + void foo() { class LocalBase { virtual void LocalVirtual(); void LocalConcrete(); @@ -177,16 +178,22 @@ }; } } // namespace nx - )", - ""); - auto AST = File.build(); - EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false)); - EXPECT_TRUE(shouldCollect("ClassInLambda", /*Qualified=*/false)); - EXPECT_TRUE(shouldCollect("LocalBase", /*Qualified=*/false)); - EXPECT_TRUE(shouldCollect("LocalVirtual", /*Qualified=*/false)); - EXPECT_TRUE(shouldCollect("LocalConcrete", /*Qualified=*/false)); - EXPECT_FALSE(shouldCollect("BaseMember", /*Qualified=*/false)); - EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false)); + )"); + for (bool CollectLocalClasses : {true, false}) { + Opts.CollectFunctionLocalClasses = CollectLocalClasses; + EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false)); + EXPECT_FALSE(shouldCollect("BaseMember", /*Qualified=*/false)); + EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false)); + + EXPECT_EQ(CollectLocalClasses, + shouldCollect("ClassInLambda", /*Qualified=*/false)); + EXPECT_EQ(CollectLocalClasses, + shouldCollect("LocalBase", /*Qualified=*/false)); + EXPECT_EQ(CollectLocalClasses, + shouldCollect("LocalVirtual", /*Qualified=*/false)); + EXPECT_EQ(CollectLocalClasses, + shouldCollect("LocalConcrete", /*Qualified=*/false)); + } } TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {