forked from OSchip/llvm-project
[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
This commit is contained in:
parent
4b13b7581d
commit
4581bf31bb
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 @@ public:
|
|||
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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue