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 @@ -21,6 +21,7 @@ #include "clang/Index/IndexingOptions.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/STLExtras.h" +#include #include #include #include @@ -138,6 +139,19 @@ Includes(std::move(Includes)), Opts(Opts), PragmaHandler(collectIWYUHeaderMaps(this->Includes.get())) { this->Opts.ShouldTraverseDecl = [this](const Decl *D) { + // Many operations performed during indexing is linear in terms of depth + // of the decl (USR generation, name lookups, figuring out role of a + // reference are some examples). Since we index all the decls nested + // inside, it becomes quadratic. + // So we give up on symbols nested more than a certain level to keep + // indexing time reasonable. + static constexpr size_t MaxContextDepth = 10; + size_t ContextDepth = 0; + for (auto *Ctx = D->getDeclContext(); Ctx && !Ctx->isTranslationUnit(); + Ctx = Ctx->getParent()) { + if (++ContextDepth == MaxContextDepth) + return false; + } auto &SM = D->getASTContext().getSourceManager(); auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation())); if (!FID.isValid()) 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 @@ -281,6 +281,36 @@ EXPECT_THAT(Ref.Location.FileURI, EndsWith("good.h")); } +TEST_F(IndexActionTest, SkipNestedSymbols) { + std::string MainFilePath = testPath("main.cpp"); + addFile(MainFilePath, R"cpp( + namespace ns1 { + namespace ns2 { + namespace ns3 { + namespace ns4 { + namespace ns5 { + namespace ns6 { + namespace ns7 { + namespace ns8 { + namespace ns9 { + class Bar {}; + void foo() { + class Baz {}; + } + } + } + } + } + } + } + } + } + })cpp"); + IndexFileIn IndexFile = runIndexingAction(MainFilePath, {"-std=c++14"}); + EXPECT_THAT(*IndexFile.Symbols, testing::Contains(HasName("foo"))); + EXPECT_THAT(*IndexFile.Symbols, testing::Contains(HasName("Bar"))); + EXPECT_THAT(*IndexFile.Symbols, Not(testing::Contains(HasName("Baz")))); +} } // namespace } // namespace clangd } // namespace clang