[clang-tools-extra] a8c9b9f - [clangd] Support ConceptReference in generic AST wrangling code

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 4 06:09:16 PDT 2023


Author: Sam McCall
Date: 2023-09-04T14:58:25+02:00
New Revision: a8c9b9f1402ccf93955a26d5933cd8c3150c3845

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

LOG: [clangd] Support ConceptReference in generic AST wrangling code

Now we can store it in DynTypedNode, we can target these nodes
(SelectionTree) and resolve them (FindTarget).
This makes Hover, go-to-def etc work in all(?) cases.

Also support it in DumpAST.

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

Added: 
    

Modified: 
    clang-tools-extra/clangd/DumpAST.cpp
    clang-tools-extra/clangd/FindTarget.cpp
    clang-tools-extra/clangd/Selection.cpp
    clang-tools-extra/clangd/unittests/FindTargetTests.cpp
    clang-tools-extra/clangd/unittests/HoverTests.cpp
    clang-tools-extra/clangd/unittests/SelectionTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp
index 2bf75e65a9efb22..85f2592445f2a52 100644
--- a/clang-tools-extra/clangd/DumpAST.cpp
+++ b/clang-tools-extra/clangd/DumpAST.cpp
@@ -205,6 +205,11 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
     // To avoid special cases in the API/UI, use public/private as the kind.
     return getAccessSpelling(CBS.getAccessSpecifier()).str();
   }
+  std::string getKind(const ConceptReference *CR) {
+    // Again there are no variants here.
+    // Kind is "Concept", role is "reference"
+    return "Concept";
+  }
 
   // Detail is the single most important fact about the node.
   // Often this is the name, sometimes a "kind" enum like operators or casts.
@@ -305,6 +310,9 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
   std::string getDetail(const CXXBaseSpecifier &CBS) {
     return CBS.isVirtual() ? "virtual" : "";
   }
+  std::string getDetail(const ConceptReference *CR) {
+    return CR->getNamedConcept()->getNameAsString();
+  }
 
   /// Arcana is produced by TextNodeDumper, for the types it supports.
 
@@ -365,6 +373,10 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
   bool TraverseAttr(Attr *A) {
     return !A || traverseNode("attribute", A, [&] { Base::TraverseAttr(A); });
   }
+  bool TraverseConceptReference(ConceptReference *C) {
+    return !C || traverseNode("reference", C,
+                              [&] { Base::TraverseConceptReference(C); });
+  }
   bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &CBS) {
     return traverseNode("base", CBS,
                         [&] { Base::TraverseCXXBaseSpecifier(CBS); });
@@ -422,6 +434,8 @@ ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens,
     V.TraverseTemplateArgumentLoc(*const_cast<TemplateArgumentLoc *>(TAL));
   else if (const auto *CBS = N.get<CXXBaseSpecifier>())
     V.TraverseCXXBaseSpecifier(*const_cast<CXXBaseSpecifier *>(CBS));
+  else if (const auto *CR = N.get<ConceptReference>())
+    V.TraverseConceptReference(const_cast<ConceptReference *>(CR));
   else
     elog("dumpAST: unhandled DynTypedNode kind {0}",
          N.getNodeKind().asStringRef());

diff  --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index c1ec030275c4f63..a766122ad3deee9 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -10,6 +10,7 @@
 #include "AST.h"
 #include "HeuristicResolver.h"
 #include "support/Logger.h"
+#include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
@@ -257,7 +258,7 @@ struct TargetFinder {
         Outer.add(CE->getCalleeDecl(), Flags);
       }
       void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E) {
-        Outer.add(E->getNamedConcept(), Flags);
+        Outer.add(E->getConceptReference(), Flags);
       }
       void VisitDeclRefExpr(const DeclRefExpr *DRE) {
         const Decl *D = DRE->getDecl();
@@ -532,6 +533,10 @@ struct TargetFinder {
         add(USD, Flags);
     }
   }
+
+  void add(const ConceptReference *CR, RelSet Flags) {
+    add(CR->getNamedConcept(), Flags);
+  }
 };
 
 } // namespace
@@ -561,6 +566,8 @@ allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver) {
     Finder.add(CBS->getTypeSourceInfo()->getType(), Flags);
   else if (const ObjCProtocolLoc *PL = N.get<ObjCProtocolLoc>())
     Finder.add(PL->getProtocol(), Flags);
+  else if (const ConceptReference *CR = N.get<ConceptReference>())
+    Finder.add(CR, Flags);
   return Finder.takeDecls();
 }
 
@@ -1056,11 +1063,8 @@ class ExplicitReferenceCollector
     return RecursiveASTVisitor::TraverseConstructorInitializer(Init);
   }
 
-  bool VisitConceptReference(ConceptReference *ConceptRef) {
-    Out(ReferenceLoc{ConceptRef->getNestedNameSpecifierLoc(),
-                     ConceptRef->getConceptNameLoc(),
-                     /*IsDecl=*/false,
-                     {ConceptRef->getNamedConcept()}});
+  bool VisitConceptReference(const ConceptReference *CR) {
+    visitNode(DynTypedNode::create(*CR));
     return true;
   }
 
@@ -1109,6 +1113,11 @@ class ExplicitReferenceCollector
                            PL->getLocation(),
                            /*IsDecl=*/false,
                            {PL->getProtocol()}}};
+    if (const ConceptReference *CR = N.get<ConceptReference>())
+      return {ReferenceLoc{CR->getNestedNameSpecifierLoc(),
+                           CR->getConceptNameLoc(),
+                           /*IsDecl=*/false,
+                           {CR->getNamedConcept()}}};
 
     // We do not have location information for other nodes (QualType, etc)
     return {};

diff  --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp
index 233a3c7cd313df7..8c6d5750ecefdba 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -635,8 +635,12 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
     if (llvm::isa_and_nonnull<TranslationUnitDecl>(X))
       return Base::TraverseDecl(X); // Already pushed by constructor.
     // Base::TraverseDecl will suppress children, but not this node itself.
-    if (X && X->isImplicit())
-      return true;
+    if (X && X->isImplicit()) {
+      // Most implicit nodes have only implicit children and can be skipped.
+      // However there are exceptions (`void foo(Concept auto x)`), and
+      // the base implementation knows how to find them.
+      return Base::TraverseDecl(X);
+    }
     return traverseNode(X, [&] { return Base::TraverseDecl(X); });
   }
   bool TraverseTypeLoc(TypeLoc X) {
@@ -660,6 +664,9 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
   bool TraverseAttr(Attr *X) {
     return traverseNode(X, [&] { return Base::TraverseAttr(X); });
   }
+  bool TraverseConceptReference(ConceptReference *X) {
+    return traverseNode(X, [&] { return Base::TraverseConceptReference(X); });
+  }
   // Stmt is the same, but this form allows the data recursion optimization.
   bool dataTraverseStmtPre(Stmt *X) {
     if (!X || isImplicit(X))

diff  --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 19e80658de063ce..fbd10c4a47a793d 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -537,7 +537,7 @@ TEST_F(TargetDeclTest, Concept) {
     }
   )cpp";
   EXPECT_DECLS(
-      "ConceptSpecializationExpr",
+      "ConceptReference",
       {"template <typename T> concept Fooable = requires (T t) { t.foo(); }"});
 
   // trailing requires clause
@@ -548,7 +548,7 @@ TEST_F(TargetDeclTest, Concept) {
       template <typename T>
       void foo() requires [[Fooable]]<T>;
   )cpp";
-  EXPECT_DECLS("ConceptSpecializationExpr",
+  EXPECT_DECLS("ConceptReference",
                {"template <typename T> concept Fooable = true"});
 
   // constrained-parameter
@@ -559,7 +559,7 @@ TEST_F(TargetDeclTest, Concept) {
     template <[[Fooable]] T>
     void bar(T t);
   )cpp";
-  EXPECT_DECLS("ConceptSpecializationExpr",
+  EXPECT_DECLS("ConceptReference",
                {"template <typename T> concept Fooable = true"});
 
   // partial-concept-id
@@ -570,7 +570,7 @@ TEST_F(TargetDeclTest, Concept) {
     template <[[Fooable]]<int> T>
     void bar(T t);
   )cpp";
-  EXPECT_DECLS("ConceptSpecializationExpr",
+  EXPECT_DECLS("ConceptReference",
                {"template <typename T, typename U> concept Fooable = true"});
 }
 

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index c26bda898687cb1..8c88cd52574536c 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -487,6 +487,16 @@ class Foo final {})cpp";
          HI.Kind = index::SymbolKind::TypeAlias;
          HI.Definition = "int";
        }},
+      {R"cpp(
+        template <class T> concept F = true;
+        [[^F]] auto x = 1;
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "F";
+         HI.Kind = index::SymbolKind::Concept;
+         HI.Definition = "template <class T>\nconcept F = true";
+       }},
       // auto on lambda
       {R"cpp(
         void foo() {
@@ -535,7 +545,7 @@ class Foo final {})cpp";
          HI.Kind = index::SymbolKind::Concept;
          HI.Definition = "template <class T>\nconcept Fooable = true";
        }},
-       {R"cpp(
+      {R"cpp(
         template<class T> concept Fooable = true;
         template<Fooable [[T^T]]>
         void bar(TT t) {}
@@ -549,6 +559,28 @@ class Foo final {})cpp";
          HI.Kind = index::SymbolKind::TemplateTypeParm;
          HI.Definition = "Fooable TT";
        }},
+      {R"cpp(
+        template<class T> concept Fooable = true;
+        void bar([[Foo^able]] auto t) {}
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "Fooable";
+         HI.Kind = index::SymbolKind::Concept;
+         HI.Definition = "template <class T>\nconcept Fooable = true";
+       }},
+      // concept reference
+      {R"cpp(
+        template<class T> concept Fooable = true;
+        auto X = [[Fooa^ble]]<int>;
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.NamespaceScope = "";
+         HI.Name = "Fooable";
+         HI.Kind = index::SymbolKind::Concept;
+         HI.Definition = "template <class T>\nconcept Fooable = true";
+         HI.Value = "true";
+       }},
 
       // empty macro
       {R"cpp(

diff  --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
index 422a89a49630d33..4c019a1524f3c39 100644
--- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -561,6 +561,33 @@ TEST(SelectionTest, CommonAncestor) {
         [[^using enum ns::A]];
         )cpp",
        "UsingEnumDecl"},
+
+      // concepts
+      {R"cpp(
+        template <class> concept C = true;
+        auto x = [[^C<int>]];
+      )cpp",
+       "ConceptReference"},
+      {R"cpp(
+        template <class> concept C = true;
+        [[^C]] auto x = 0;
+      )cpp",
+       "ConceptReference"},
+      {R"cpp(
+        template <class> concept C = true;
+        void foo([[^C]] auto x) {}
+      )cpp",
+       "ConceptReference"},
+      {R"cpp(
+        template <class> concept C = true;
+        template <[[^C]] x> int i = 0;
+      )cpp",
+       "ConceptReference"},
+      {R"cpp(
+        namespace ns { template <class> concept C = true; }
+        auto x = [[ns::^C<int>]];
+      )cpp",
+       "ConceptReference"},
   };
 
   for (const Case &C : Cases) {


        


More information about the cfe-commits mailing list