[clang-tools-extra] 4718ec0 - [clangd] Avoid recursion in TargetFinder::add()
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 12 10:58:03 PST 2021
Author: Nathan Ridge
Date: 2021-01-12T13:57:54-05:00
New Revision: 4718ec01669b01373180f4cd1256c6e2dd6f3999
URL: https://github.com/llvm/llvm-project/commit/4718ec01669b01373180f4cd1256c6e2dd6f3999
DIFF: https://github.com/llvm/llvm-project/commit/4718ec01669b01373180f4cd1256c6e2dd6f3999.diff
LOG: [clangd] Avoid recursion in TargetFinder::add()
Fixes https://github.com/clangd/clangd/issues/633
Differential Revision: https://reviews.llvm.org/D94382
Added:
Modified:
clang-tools-extra/clangd/FindTarget.cpp
clang-tools-extra/clangd/FindTarget.h
clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 9a502a84e36f..84316659daad 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -330,6 +330,7 @@ struct TargetFinder {
llvm::SmallDenseMap<const NamedDecl *,
std::pair<RelSet, /*InsertionOrder*/ size_t>>
Decls;
+ llvm::SmallDenseMap<const Decl *, RelSet> Seen;
RelSet Flags;
template <typename T> void debug(T &Node, RelSet Flags) {
@@ -359,6 +360,15 @@ struct TargetFinder {
if (!D)
return;
debug(*D, Flags);
+
+ // Avoid recursion (which can arise in the presence of heuristic
+ // resolution of dependent names) by exiting early if we have
+ // already seen this decl with all flags in Flags.
+ auto Res = Seen.try_emplace(D);
+ if (!Res.second && Res.first->second.contains(Flags))
+ return;
+ Res.first->second |= Flags;
+
if (const UsingDirectiveDecl *UDD = llvm::dyn_cast<UsingDirectiveDecl>(D))
D = UDD->getNominatedNamespaceAsWritten();
diff --git a/clang-tools-extra/clangd/FindTarget.h b/clang-tools-extra/clangd/FindTarget.h
index 435e4f4ac038..92e4354d1eaa 100644
--- a/clang-tools-extra/clangd/FindTarget.h
+++ b/clang-tools-extra/clangd/FindTarget.h
@@ -194,6 +194,9 @@ class DeclRelationSet {
S &= Other.S;
return *this;
}
+ bool contains(DeclRelationSet Other) const {
+ return (S & Other.S) == Other.S;
+ }
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, DeclRelationSet);
};
// The above operators can't be looked up if both sides are enums.
diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index dd7e9878a6d5..46e17dc053c0 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -787,6 +787,47 @@ TEST_F(TargetDeclTest, DependentTypes) {
"template <typename> struct B");
}
+TEST_F(TargetDeclTest, TypedefCascade) {
+ Code = R"cpp(
+ struct C {
+ using type = int;
+ };
+ struct B {
+ using type = C::type;
+ };
+ struct A {
+ using type = B::type;
+ };
+ A::[[type]] waldo;
+ )cpp";
+ EXPECT_DECLS("TypedefTypeLoc",
+ {"using type = int", Rel::Alias | Rel::Underlying},
+ {"using type = C::type", Rel::Alias | Rel::Underlying},
+ {"using type = B::type", Rel::Alias});
+}
+
+TEST_F(TargetDeclTest, RecursiveTemplate) {
+ Flags.push_back("-std=c++20"); // the test case uses concepts
+
+ Code = R"cpp(
+ template <typename T>
+ concept Leaf = false;
+
+ template <typename Tree>
+ struct descend_left {
+ using type = typename descend_left<typename Tree::left>::[[type]];
+ };
+
+ template <Leaf Tree>
+ struct descend_left<Tree> {
+ using type = typename Tree::value;
+ };
+ )cpp";
+ EXPECT_DECLS("DependentNameTypeLoc",
+ {"using type = typename descend_left<typename Tree::left>::type",
+ Rel::Alias | Rel::Underlying});
+}
+
TEST_F(TargetDeclTest, ObjC) {
Flags = {"-xobjective-c"};
Code = R"cpp(
More information about the cfe-commits
mailing list