[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