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<<a href="https://clang.llvm.org/doxygen/classclang_1_1ConceptReference.html">ConceptReference</a>></td><td class="name" onclick="toggle('conceptReference0')"><a name="conceptReference0Anchor">conceptReference</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ConceptReference.html">ConceptReference</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="conceptReference0"><pre>Matches concept references. + +Given + template <class> concept C = true; + bool X = C<int>; +conceptReference() + matches 'C<int>'. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('accessSpecDecl0')"><a name="accessSpecDecl0Anchor">accessSpecDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1AccessSpecDecl.html">AccessSpecDecl</a>>...</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