sammccall updated this revision to Diff 555709.
sammccall added a comment.

regenerate HTML after rebasing on 415d9e8ca39c0b42f351cc532ccfb48b6ac97f7f 
<https://reviews.llvm.org/rG415d9e8ca39c0b42f351cc532ccfb48b6ac97f7f>


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D159309/new/

https://reviews.llvm.org/D159309

Files:
  clang/docs/LibASTMatchersReference.html
  clang/include/clang/ASTMatchers/ASTMatchFinder.h
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/ASTMatchers/ASTMatchFinder.cpp
  clang/lib/ASTMatchers/ASTMatchersInternal.cpp
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/AST/ASTTypeTraitsTest.cpp
  clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -770,6 +770,17 @@
                       cxxCtorInitializer(forField(hasName("i")))));
 }
 
+TEST_P(ASTMatchersTest, Match_ConceptReference) {
+  if (!GetParam().isCXX20OrLater()) {
+    return;
+  }
+  std::string Concept = "template <class> concept C = true;\n";
+  EXPECT_TRUE(matches(Concept + "auto X = C<int>;", conceptReference()));
+  EXPECT_TRUE(matches(Concept + "C auto X = 0;", conceptReference()));
+  EXPECT_TRUE(matches(Concept + "template <C X> int i;", conceptReference()));
+  EXPECT_TRUE(matches(Concept + "void foo(C auto X) {}", conceptReference()));
+}
+
 TEST_P(ASTMatchersTest, Matcher_ThisExpr) {
   if (!GetParam().isCXX()) {
     return;
Index: clang/unittests/AST/ASTTypeTraitsTest.cpp
===================================================================
--- clang/unittests/AST/ASTTypeTraitsTest.cpp
+++ clang/unittests/AST/ASTTypeTraitsTest.cpp
@@ -210,7 +210,13 @@
                              ast_matchers::attr()));
 }
 
-// FIXME: add tests for ConceptReference once we add an ASTMatcher.
+TEST(DynTypedNode, ConceptReferenceSourceRange) {
+  RangeVerifier<ConceptReference> Verifier;
+  Verifier.expectRange(2, 10, 2, 15);
+  EXPECT_TRUE(Verifier.match("template <class> concept C = true;\n"
+                             "auto X = C<int>;",
+                             conceptReference()));
+}
 
 TEST(DynTypedNode, DeclDump) {
   DumpVerifier Verifier;
@@ -224,6 +230,14 @@
   EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
 }
 
+TEST(DynTypedNode, ConceptReferenceDump) {
+  DumpVerifier Verifier;
+  Verifier.expectSubstring("ConceptReference");
+  EXPECT_TRUE(Verifier.match("template <class> concept C = true;\n"
+                             "auto X = C<int>;",
+                             conceptReference()));
+}
+
 TEST(DynTypedNode, DeclPrint) {
   PrintVerifier Verifier;
   Verifier.expectString("void f() {\n}\n");
@@ -236,6 +250,14 @@
   EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
 }
 
+TEST(DynTypedNode, ConceptReferencePrint) {
+  PrintVerifier Verifier;
+  Verifier.expectString("C<int>");
+  EXPECT_TRUE(Verifier.match("template <class> concept C = true;\n"
+                             "auto X = C<int>;",
+                             conceptReference()));
+}
+
 TEST(DynTypedNode, QualType) {
   QualType Q;
   DynTypedNode Node = DynTypedNode::create(Q);
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -173,6 +173,7 @@
   REGISTER_MATCHER(compoundStmt);
   REGISTER_MATCHER(coawaitExpr);
   REGISTER_MATCHER(conceptDecl);
+  REGISTER_MATCHER(conceptReference);
   REGISTER_MATCHER(conditionalOperator);
   REGISTER_MATCHER(constantArrayType);
   REGISTER_MATCHER(constantExpr);
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -768,6 +768,7 @@
     templateTypeParmDecl;
 const internal::VariadicDynCastAllOfMatcher<Decl, TemplateTemplateParmDecl>
     templateTemplateParmDecl;
+const internal::VariadicAllOfMatcher<ConceptReference> conceptReference;
 
 const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture;
 const internal::VariadicAllOfMatcher<QualType> qualType;
Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -26,6 +26,7 @@
 #include <deque>
 #include <memory>
 #include <set>
+#include <variant>
 
 namespace clang {
 namespace ast_matchers {
@@ -136,6 +137,8 @@
       traverse(*TALoc);
     else if (const Attr *A = DynNode.get<Attr>())
       traverse(*A);
+    else if (const ConceptReference *CR = DynNode.get<ConceptReference>())
+      traverse(*CR);
     // FIXME: Add other base types after adding tests.
 
     // It's OK to always overwrite the bound nodes, as if there was
@@ -275,6 +278,12 @@
     ScopedIncrement ScopedDepth(&CurrentDepth);
     return traverse(*A);
   }
+  bool TraverseConceptReference(ConceptReference *CR) {
+    if (CR == nullptr)
+      return true;
+    ScopedIncrement ScopedDepth(&CurrentDepth);
+    return traverse(*CR);
+  }
   bool TraverseLambdaExpr(LambdaExpr *Node) {
     if (!Finder->isTraversalIgnoringImplicitNodes())
       return VisitorBase::TraverseLambdaExpr(Node);
@@ -360,6 +369,10 @@
   bool baseTraverse(const Attr &AttrNode) {
     return VisitorBase::TraverseAttr(const_cast<Attr *>(&AttrNode));
   }
+  bool baseTraverse(const ConceptReference &CR) {
+    return VisitorBase::TraverseConceptReference(
+        const_cast<ConceptReference *>(&CR));
+  }
 
   // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
   //   0 < CurrentDepth <= MaxDepth.
@@ -505,6 +518,7 @@
   bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
   bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
   bool TraverseAttr(Attr *AttrNode);
+  bool TraverseConceptReference(ConceptReference *);
 
   bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
     if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
@@ -712,6 +726,8 @@
       match(*N);
     } else if (auto *N = Node.get<Attr>()) {
       match(*N);
+    } else if (auto *N = Node.get<ConceptReference>()) {
+      match(*N);
     }
   }
 
@@ -766,85 +782,14 @@
   bool TraversingASTNodeNotAsIs = false;
   bool TraversingASTChildrenNotSpelledInSource = false;
 
-  class CurMatchData {
-// We don't have enough free low bits in 32bit builds to discriminate 8 pointer
-// types in PointerUnion. so split the union in 2 using a free bit from the
-// callback pointer.
-#define CMD_TYPES_0                                                            \
-  const QualType *, const TypeLoc *, const NestedNameSpecifier *,              \
-      const NestedNameSpecifierLoc *
-#define CMD_TYPES_1                                                            \
-  const CXXCtorInitializer *, const TemplateArgumentLoc *, const Attr *,       \
-      const DynTypedNode *
-
-#define IMPL(Index)                                                            \
-  template <typename NodeType>                                                 \
-  std::enable_if_t<                                                            \
-      llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value>             \
-  SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) {          \
-    assertEmpty();                                                             \
-    Callback.setPointerAndInt(CB, Index);                                      \
-    Node##Index = &N;                                                          \
-  }                                                                            \
-                                                                               \
-  template <typename T>                                                        \
-  std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value,       \
-                   const T *>                                                  \
-  getNode() const {                                                            \
-    assertHoldsState();                                                        \
-    return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>()    \
-                                        : nullptr;                             \
-  }
-
-  public:
-    CurMatchData() : Node0(nullptr) {}
-
-    IMPL(0)
-    IMPL(1)
-
-    const MatchCallback *getCallback() const { return Callback.getPointer(); }
-
-    void SetBoundNodes(const BoundNodes &BN) {
-      assertHoldsState();
-      BNodes = &BN;
-    }
-
-    void clearBoundNodes() {
-      assertHoldsState();
-      BNodes = nullptr;
-    }
-
-    const BoundNodes *getBoundNodes() const {
-      assertHoldsState();
-      return BNodes;
-    }
-
-    void reset() {
-      assertHoldsState();
-      Callback.setPointerAndInt(nullptr, 0);
-      Node0 = nullptr;
-    }
-
-  private:
-    void assertHoldsState() const {
-      assert(Callback.getPointer() != nullptr && !Node0.isNull());
-    }
-
-    void assertEmpty() const {
-      assert(Callback.getPointer() == nullptr && Node0.isNull() &&
-             BNodes == nullptr);
-    }
-
-    llvm::PointerIntPair<const MatchCallback *, 1> Callback;
-    union {
-      llvm::PointerUnion<CMD_TYPES_0> Node0;
-      llvm::PointerUnion<CMD_TYPES_1> Node1;
-    };
+  struct CurMatchData {
+    const MatchCallback *Callback = nullptr;
     const BoundNodes *BNodes = nullptr;
-
-#undef CMD_TYPES_0
-#undef CMD_TYPES_1
-#undef IMPL
+    std::variant<std::monostate, const QualType *, const TypeLoc *,
+                 const NestedNameSpecifier *, const NestedNameSpecifierLoc *,
+                 const CXXCtorInitializer *, const TemplateArgumentLoc *,
+                 const Attr *, const DynTypedNode *, const ConceptReference *>
+        Node;
   } CurMatchState;
 
   struct CurMatchRAII {
@@ -852,10 +797,17 @@
     CurMatchRAII(MatchASTVisitor &MV, const MatchCallback *CB,
                  const NodeType &NT)
         : MV(MV) {
-      MV.CurMatchState.SetCallbackAndRawNode(CB, NT);
+      assert(MV.CurMatchState.Callback == nullptr &&
+             std::holds_alternative<std::monostate>(MV.CurMatchState.Node) &&
+             MV.CurMatchState.BNodes == nullptr);
+      MV.CurMatchState.Callback = CB;
+      MV.CurMatchState.Node = &NT;
     }
 
-    ~CurMatchRAII() { MV.CurMatchState.reset(); }
+    ~CurMatchRAII() {
+      MV.CurMatchState.Callback = nullptr;
+      MV.CurMatchState.Node = std::monostate{};
+    }
 
   private:
     MatchASTVisitor &MV;
@@ -890,30 +842,22 @@
 
     static void dumpNodeFromState(const ASTContext &Ctx,
                                   const CurMatchData &State, raw_ostream &OS) {
-      if (const DynTypedNode *MatchNode = State.getNode<DynTypedNode>()) {
-        dumpNode(Ctx, *MatchNode, OS);
-      } else if (const auto *QT = State.getNode<QualType>()) {
-        dumpNode(Ctx, DynTypedNode::create(*QT), OS);
-      } else if (const auto *TL = State.getNode<TypeLoc>()) {
-        dumpNode(Ctx, DynTypedNode::create(*TL), OS);
-      } else if (const auto *NNS = State.getNode<NestedNameSpecifier>()) {
-        dumpNode(Ctx, DynTypedNode::create(*NNS), OS);
-      } else if (const auto *NNSL = State.getNode<NestedNameSpecifierLoc>()) {
-        dumpNode(Ctx, DynTypedNode::create(*NNSL), OS);
-      } else if (const auto *CtorInit = State.getNode<CXXCtorInitializer>()) {
-        dumpNode(Ctx, DynTypedNode::create(*CtorInit), OS);
-      } else if (const auto *TAL = State.getNode<TemplateArgumentLoc>()) {
-        dumpNode(Ctx, DynTypedNode::create(*TAL), OS);
-      } else if (const auto *At = State.getNode<Attr>()) {
-        dumpNode(Ctx, DynTypedNode::create(*At), OS);
-      }
+      std::visit(llvm::makeVisitor([&](std::monostate) {},
+                                   [&](const DynTypedNode *Node) {
+                                     dumpNode(Ctx, *Node, OS);
+                                   },
+                                   [&](const auto *Node) {
+                                     dumpNode(Ctx, DynTypedNode::create(*Node),
+                                              OS);
+                                   }),
+                 State.Node);
     }
 
   public:
     TraceReporter(const MatchASTVisitor &MV) : MV(MV) {}
     void print(raw_ostream &OS) const override {
       const CurMatchData &State = MV.CurMatchState;
-      const MatchCallback *CB = State.getCallback();
+      const MatchCallback *CB = State.Callback;
       if (!CB) {
         OS << "ASTMatcher: Not currently matching\n";
         return;
@@ -924,7 +868,7 @@
 
       ASTContext &Ctx = MV.getASTContext();
 
-      if (const BoundNodes *Nodes = State.getBoundNodes()) {
+      if (const BoundNodes *Nodes = State.BNodes) {
         OS << "ASTMatcher: Processing '" << CB->getID() << "' against:\n\t";
         dumpNodeFromState(Ctx, State, OS);
         const BoundNodes::IDToNodeMap &Map = Nodes->getMap();
@@ -1102,6 +1046,9 @@
   void matchDispatch(const Attr *Node) {
     matchWithoutFilter(*Node, Matchers->Attr);
   }
+  void matchDispatch(const ConceptReference *Node) {
+    matchWithoutFilter(*Node, Matchers->ConceptReference);
+  }
   void matchDispatch(const void *) { /* Do nothing. */ }
   /// @}
 
@@ -1240,10 +1187,11 @@
     struct CurBoundScope {
       CurBoundScope(MatchASTVisitor::CurMatchData &State, const BoundNodes &BN)
           : State(State) {
-        State.SetBoundNodes(BN);
+        assert(State.BNodes == nullptr);
+        State.BNodes = &BN;
       }
 
-      ~CurBoundScope() { State.clearBoundNodes(); }
+      ~CurBoundScope() { State.BNodes = nullptr; }
 
     private:
       MatchASTVisitor::CurMatchData &State;
@@ -1526,6 +1474,11 @@
   return RecursiveASTVisitor<MatchASTVisitor>::TraverseAttr(AttrNode);
 }
 
+bool MatchASTVisitor::TraverseConceptReference(ConceptReference *CR) {
+  match(*CR);
+  return RecursiveASTVisitor::TraverseConceptReference(CR);
+}
+
 class MatchASTConsumer : public ASTConsumer {
 public:
   MatchASTConsumer(MatchFinder *Finder,
@@ -1626,6 +1579,12 @@
   Matchers.AllCallbacks.insert(Action);
 }
 
+void MatchFinder::addMatcher(const ConceptReferenceMatcher &AttrMatch,
+                             MatchCallback *Action) {
+  Matchers.ConceptReference.emplace_back(AttrMatch, Action);
+  Matchers.AllCallbacks.insert(Action);
+}
+
 bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
                                     MatchCallback *Action) {
   if (NodeMatch.canConvertTo<Decl>()) {
@@ -1655,6 +1614,9 @@
   } else if (NodeMatch.canConvertTo<Attr>()) {
     addMatcher(NodeMatch.convertTo<Attr>(), Action);
     return true;
+  } else if (NodeMatch.canConvertTo<ConceptReference>()) {
+    addMatcher(NodeMatch.convertTo<ConceptReference>(), Action);
+    return true;
   }
   return false;
 }
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1163,19 +1163,10 @@
 /// IsBaseType<T>::value is true if T is a "base" type in the AST
 /// node class hierarchies.
 template <typename T>
-struct IsBaseType {
-  static const bool value =
-      std::is_same<T, Decl>::value || std::is_same<T, Stmt>::value ||
-      std::is_same<T, QualType>::value || std::is_same<T, Type>::value ||
-      std::is_same<T, TypeLoc>::value ||
-      std::is_same<T, NestedNameSpecifier>::value ||
-      std::is_same<T, NestedNameSpecifierLoc>::value ||
-      std::is_same<T, CXXCtorInitializer>::value ||
-      std::is_same<T, TemplateArgumentLoc>::value ||
-      std::is_same<T, Attr>::value;
-};
-template <typename T>
-const bool IsBaseType<T>::value;
+using IsBaseType =
+    llvm::is_one_of<T, Decl, Stmt, QualType, Type, TypeLoc, NestedNameSpecifier,
+                    NestedNameSpecifierLoc, CXXCtorInitializer,
+                    TemplateArgumentLoc, Attr, ConceptReference>;
 
 /// A "type list" that contains all types.
 ///
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -152,6 +152,7 @@
 using TemplateArgumentLocMatcher = internal::Matcher<TemplateArgumentLoc>;
 using LambdaCaptureMatcher = internal::Matcher<LambdaCapture>;
 using AttrMatcher = internal::Matcher<Attr>;
+using ConceptReferenceMatcher = internal::Matcher<ConceptReference>;
 /// @}
 
 /// Matches any node.
@@ -611,6 +612,18 @@
                                                    TemplateTemplateParmDecl>
     templateTemplateParmDecl;
 
+/// Matches concept references.
+///
+/// Given
+/// \code
+///   template <class> concept C = true;
+///   bool X = C<int>;
+/// \endcode
+/// conceptReference()
+///   matches 'C<int>'.
+extern const internal::VariadicAllOfMatcher<ConceptReference> conceptReference;
+
+
 /// Matches public C++ declarations and C++ base specifers that specify public
 /// inheritance.
 ///
Index: clang/include/clang/ASTMatchers/ASTMatchFinder.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchFinder.h
+++ clang/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -169,6 +169,8 @@
   void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
                   MatchCallback *Action);
   void addMatcher(const AttrMatcher &NodeMatch, MatchCallback *Action);
+  void addMatcher(const ConceptReferenceMatcher &NodeMatch,
+                  MatchCallback *Action);
   /// @}
 
   /// Adds a matcher to execute when running over the AST.
@@ -222,6 +224,8 @@
     std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>>
         TemplateArgumentLoc;
     std::vector<std::pair<AttrMatcher, MatchCallback *>> Attr;
+    std::vector<std::pair<ConceptReferenceMatcher, MatchCallback *>>
+        ConceptReference;
     /// All the callbacks in one container to simplify iteration.
     llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
   };
Index: clang/docs/LibASTMatchersReference.html
===================================================================
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -611,6 +611,17 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ConceptReference.html";>ConceptReference</a>&gt;</td><td class="name" onclick="toggle('conceptReference0')"><a name="conceptReference0Anchor">conceptReference</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ConceptReference.html";>ConceptReference</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="conceptReference0"><pre>Matches concept references.
+
+Given
+  template &lt;class&gt; concept C = true;
+  bool X = C&lt;int&gt;;
+conceptReference()
+  matches 'C&lt;int&gt;'.
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html";>Decl</a>&gt;</td><td class="name" onclick="toggle('accessSpecDecl0')"><a name="accessSpecDecl0Anchor">accessSpecDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1AccessSpecDecl.html";>AccessSpecDecl</a>&gt;...</td></tr>
 <tr><td colspan="4" class="doc" id="accessSpecDecl0"><pre>Matches C++ access specifier declarations.
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to