[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