[clang-tools-extra] 4581bf3 - [clangd] Dont index deeply nested symbols

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 27 03:35:25 PDT 2021


Author: Kadir Cetinkaya
Date: 2021-04-27T12:34:56+02:00
New Revision: 4581bf31bb8333dc1372959f7d650ed940eab710

URL: https://github.com/llvm/llvm-project/commit/4581bf31bb8333dc1372959f7d650ed940eab710
DIFF: https://github.com/llvm/llvm-project/commit/4581bf31bb8333dc1372959f7d650ed940eab710.diff

LOG: [clangd] Dont index deeply nested symbols

This is fix for some timeouts and OOM problems faced while indexing an
auto-generated file with thousands of nested lambdas.

Differential Revision: https://reviews.llvm.org/D101066

Added: 
    

Modified: 
    clang-tools-extra/clangd/AST.cpp
    clang-tools-extra/clangd/AST.h
    clang-tools-extra/clangd/index/IndexAction.cpp
    clang-tools-extra/clangd/unittests/ASTTests.cpp
    clang-tools-extra/clangd/unittests/IndexActionTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index abcfc1af848bc..32bae42a07976 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -524,5 +524,14 @@ bool hasUnstableLinkage(const Decl *D) {
   return VD && !VD->getType().isNull() && VD->getType()->isUndeducedType();
 }
 
+bool isDeeplyNested(const Decl *D, unsigned MaxDepth) {
+  size_t ContextDepth = 0;
+  for (auto *Ctx = D->getDeclContext(); Ctx && !Ctx->isTranslationUnit();
+       Ctx = Ctx->getParent()) {
+    if (++ContextDepth == MaxDepth)
+      return true;
+  }
+  return false;
+}
 } // namespace clangd
 } // namespace clang

diff  --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h
index 94984a915422e..7793b6545c0f6 100644
--- a/clang-tools-extra/clangd/AST.h
+++ b/clang-tools-extra/clangd/AST.h
@@ -171,6 +171,12 @@ std::string getQualification(ASTContext &Context,
 /// the cached value is incorrect. (clang catches this with an assertion).
 bool hasUnstableLinkage(const Decl *D);
 
+/// Checks whether \p D is more than \p MaxDepth away from translation unit
+/// scope.
+/// This is useful for limiting traversals to keep operation latencies
+/// reasonable.
+bool isDeeplyNested(const Decl *D, unsigned MaxDepth = 10);
+
 } // namespace clangd
 } // namespace clang
 

diff  --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp
index e5a48df90b4dc..0d8ae93efa4ae 100644
--- a/clang-tools-extra/clangd/index/IndexAction.cpp
+++ b/clang-tools-extra/clangd/index/IndexAction.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "IndexAction.h"
+#include "AST.h"
 #include "Headers.h"
 #include "index/Relation.h"
 #include "index/SymbolOrigin.h"
@@ -21,6 +22,7 @@
 #include "clang/Index/IndexingOptions.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/STLExtras.h"
+#include <cstddef>
 #include <functional>
 #include <memory>
 #include <utility>
@@ -138,6 +140,12 @@ class IndexAction : public ASTFrontendAction {
         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 nested symbols.
+      if (isDeeplyNested(D))
+        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/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp
index 4c52c72d703c7..7b662189eaaf3 100644
--- a/clang-tools-extra/clangd/unittests/ASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp
@@ -351,6 +351,32 @@ TEST(ClangdAST, PrintType) {
     }
   }
 }
+
+TEST(ClangdAST, IsDeeplyNested) {
+  Annotations Test(
+      R"cpp(
+        namespace ns {
+        class Foo {
+          void bar() {
+            class Bar {};
+          }
+        };
+        })cpp");
+  TestTU TU = TestTU::withCode(Test.code());
+  ParsedAST AST = TU.build();
+
+  EXPECT_TRUE(isDeeplyNested(&findUnqualifiedDecl(AST, "Foo"), /*MaxDepth=*/1));
+  EXPECT_FALSE(
+      isDeeplyNested(&findUnqualifiedDecl(AST, "Foo"), /*MaxDepth=*/2));
+
+  EXPECT_TRUE(isDeeplyNested(&findUnqualifiedDecl(AST, "bar"), /*MaxDepth=*/2));
+  EXPECT_FALSE(
+      isDeeplyNested(&findUnqualifiedDecl(AST, "bar"), /*MaxDepth=*/3));
+
+  EXPECT_TRUE(isDeeplyNested(&findUnqualifiedDecl(AST, "Bar"), /*MaxDepth=*/3));
+  EXPECT_FALSE(
+      isDeeplyNested(&findUnqualifiedDecl(AST, "Bar"), /*MaxDepth=*/4));
+}
 } // namespace
 } // namespace clangd
 } // namespace clang

diff  --git a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp
index 31e1bc573290f..99317f4de53d7 100644
--- a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp
@@ -281,6 +281,36 @@ TEST_F(IndexActionTest, SkipFiles) {
       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


        


More information about the cfe-commits mailing list