Author: Nathan Ridge Date: 2020-08-10T03:09:18-04:00 New Revision: b1c7f84643ffa63e72733b7089cea89723b82afc
URL: https://github.com/llvm/llvm-project/commit/b1c7f84643ffa63e72733b7089cea89723b82afc DIFF: https://github.com/llvm/llvm-project/commit/b1c7f84643ffa63e72733b7089cea89723b82afc.diff LOG: [clang] Allow DynTypedNode to store a TemplateArgumentLoc The patch also adds a templateArgumentLoc() AST matcher. Differential Revision: https://reviews.llvm.org/D85621 Added: Modified: clang/docs/LibASTMatchersReference.html clang/include/clang/AST/ASTTypeTraits.h clang/include/clang/ASTMatchers/ASTMatchFinder.h clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/AST/ASTTypeTraits.cpp clang/lib/ASTMatchers/ASTMatchFinder.cpp clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Removed: ################################################################################ diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 60ff6ffe6056..eb85e420e7e4 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -679,7 +679,8 @@ <h2 id="decl-matchers">Node Matchers</h2> #pragma omp parallel default(firstprivate) #pragma omp parallel -``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``, and ``default(firstprivate)``. +``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``, and +``default(firstprivate)`` </pre></td></tr> @@ -1625,6 +1626,17 @@ <h2 id="decl-matchers">Node Matchers</h2> </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>></td><td class="name" onclick="toggle('templateArgumentLoc0')"><a name="templateArgumentLoc0Anchor">templateArgumentLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="templateArgumentLoc0"><pre>Matches template arguments (with location info). + +Given + template <typename T> struct C {}; + C<int> c; +templateArgumentLoc() + matches 'int' in C<int>. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('templateArgument0')"><a name="templateArgument0Anchor">templateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>>...</td></tr> <tr><td colspan="4" class="doc" id="templateArgument0"><pre>Matches template arguments. @@ -3776,8 +3788,9 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></td><td class="name" onclick="toggle('isNoneKind0')"><a name="isNoneKind0Anchor">isNoneKind</a></td><td></td></tr> -<tr><td colspan="4" class="doc" id="isNoneKind0"><pre>Matches if the OpenMP ``default`` clause has ``none`` kind specified. +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></td><td class="name" onclick="toggle('isFirstPrivateKind0')"><a name="isFirstPrivateKind0Anchor">isFirstPrivateKind</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isFirstPrivateKind0"><pre>Matches if the OpenMP ``default`` clause has ``firstprivate`` kind +specified. Given @@ -3786,12 +3799,13 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> #pragma omp parallel default(shared) #pragma omp parallel default(firstprivate) -``ompDefaultClause(isNoneKind())`` matches only ``default(none)``. +``ompDefaultClause(isFirstPrivateKind())`` matches only +``default(firstprivate)``. </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></td><td class="name" onclick="toggle('isSharedKind0')"><a name="isSharedKind0Anchor">isSharedKind</a></td><td></td></tr> -<tr><td colspan="4" class="doc" id="isSharedKind0"><pre>Matches if the OpenMP ``default`` clause has ``shared`` kind specified. +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></td><td class="name" onclick="toggle('isNoneKind0')"><a name="isNoneKind0Anchor">isNoneKind</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isNoneKind0"><pre>Matches if the OpenMP ``default`` clause has ``none`` kind specified. Given @@ -3800,12 +3814,12 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> #pragma omp parallel default(shared) #pragma omp parallel default(firstprivate) -``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``. +``ompDefaultClause(isNoneKind())`` matches only ``default(none)``. </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></td><td class="name" onclick="toggle('isFirstPrivateKind0')"><a name="isFirstPrivateKind0Anchor">isSharedKind</a></td><td></td></tr> -<tr><td colspan="4" class="doc" id="isFirstPrivateKind0"><pre>Matches if the OpenMP ``default`` clause has ``firstprivate`` kind specified. +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></td><td class="name" onclick="toggle('isSharedKind0')"><a name="isSharedKind0Anchor">isSharedKind</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isSharedKind0"><pre>Matches if the OpenMP ``default`` clause has ``shared`` kind specified. Given @@ -3814,7 +3828,7 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> #pragma omp parallel default(shared) #pragma omp parallel default(firstprivate) -``ompDefaultClause(isFirstPrivateKind())`` matches only ``default(firstprivate)``. +``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``. </pre></td></tr> diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h index 328b7bce6ba5..bd817b75bb84 100644 --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -132,6 +132,7 @@ class ASTNodeKind { enum NodeKindId { NKI_None, NKI_TemplateArgument, + NKI_TemplateArgumentLoc, NKI_TemplateName, NKI_NestedNameSpecifierLoc, NKI_QualType, @@ -191,6 +192,7 @@ class ASTNodeKind { }; KIND_TO_KIND_ID(CXXCtorInitializer) KIND_TO_KIND_ID(TemplateArgument) +KIND_TO_KIND_ID(TemplateArgumentLoc) KIND_TO_KIND_ID(TemplateName) KIND_TO_KIND_ID(NestedNameSpecifier) KIND_TO_KIND_ID(NestedNameSpecifierLoc) @@ -456,12 +458,13 @@ class DynTypedNode { /// Note that we can store \c Decls, \c Stmts, \c Types, /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are /// guaranteed to be unique pointers pointing to dedicated storage in the AST. - /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and - /// \c TemplateArguments on the other hand do not have storage or unique - /// pointers and thus need to be stored by value. + /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs, + /// \c TemplateArguments and \c TemplateArgumentLocs on the other hand do not + /// have storage or unique pointers and thus need to be stored by value. llvm::AlignedCharArrayUnion<const void *, TemplateArgument, - NestedNameSpecifierLoc, QualType, - TypeLoc> Storage; + TemplateArgumentLoc, NestedNameSpecifierLoc, + QualType, TypeLoc> + Storage; }; template <typename T> @@ -496,6 +499,10 @@ template <> struct DynTypedNode::BaseConverter< TemplateArgument, void> : public ValueConverter<TemplateArgument> {}; +template <> +struct DynTypedNode::BaseConverter<TemplateArgumentLoc, void> + : public ValueConverter<TemplateArgumentLoc> {}; + template <> struct DynTypedNode::BaseConverter< TemplateName, void> : public ValueConverter<TemplateName> {}; diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h index 0af98438ab52..81125ad8d96d 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -159,6 +159,8 @@ class MatchFinder { MatchCallback *Action); void addMatcher(const CXXCtorInitializerMatcher &NodeMatch, MatchCallback *Action); + void addMatcher(const TemplateArgumentLocMatcher &NodeMatch, + MatchCallback *Action); /// @} /// Adds a matcher to execute when running over the AST. @@ -209,6 +211,8 @@ class MatchFinder { NestedNameSpecifierLoc; std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc; std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit; + std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>> + TemplateArgumentLoc; /// All the callbacks in one container to simplify iteration. llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks; }; diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 643419743a11..e37c68a8f156 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -145,6 +145,7 @@ using TypeLocMatcher = internal::Matcher<TypeLoc>; using NestedNameSpecifierMatcher = internal::Matcher<NestedNameSpecifier>; using NestedNameSpecifierLocMatcher = internal::Matcher<NestedNameSpecifierLoc>; using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>; +using TemplateArgumentLocMatcher = internal::Matcher<TemplateArgumentLoc>; /// @} /// Matches any node. @@ -515,6 +516,18 @@ extern const internal::VariadicAllOfMatcher<CXXCtorInitializer> /// matches 'int' in C<int>. extern const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; +/// Matches template arguments (with location info). +/// +/// Given +/// \code +/// template <typename T> struct C {}; +/// C<int> c; +/// \endcode +/// templateArgumentLoc() +/// matches 'int' in C<int>. +extern const internal::VariadicAllOfMatcher<TemplateArgumentLoc> + templateArgumentLoc; + /// Matches template name. /// /// Given diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 3992850c992d..09774b3c912c 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -938,14 +938,13 @@ class HasDeclarationMatcher : public MatcherInterface<T> { 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, 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, CXXCtorInitializer>::value || + std::is_same<T, TemplateArgumentLoc>::value; }; template <typename T> const bool IsBaseType<T>::value; diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp index 34fc587694be..ce8a321a691f 100644 --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -23,6 +23,7 @@ using namespace clang; const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { { NKI_None, "<None>" }, { NKI_None, "TemplateArgument" }, + { NKI_None, "TemplateArgumentLoc" }, { NKI_None, "TemplateName" }, { NKI_None, "NestedNameSpecifierLoc" }, { NKI_None, "QualType" }, @@ -129,6 +130,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const { if (const TemplateArgument *TA = get<TemplateArgument>()) TA->print(PP, OS); + else if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>()) + TAL->getArgument().print(PP, OS); else if (const TemplateName *TN = get<TemplateName>()) TN->print(OS, PP); else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>()) @@ -175,6 +178,8 @@ SourceRange DynTypedNode::getSourceRange() const { return D->getSourceRange(); if (const Stmt *S = get<Stmt>()) return S->getSourceRange(); + if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>()) + return TAL->getSourceRange(); if (const auto *C = get<OMPClause>()) return SourceRange(C->getBeginLoc(), C->getEndLoc()); return SourceRange(); diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index e88da16dd3d4..dc937dde88e3 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -128,6 +128,9 @@ class MatchChildASTVisitor traverse(*T); else if (const auto *C = DynNode.get<CXXCtorInitializer>()) traverse(*C); + else if (const TemplateArgumentLoc *TALoc = + DynNode.get<TemplateArgumentLoc>()) + traverse(*TALoc); // FIXME: Add other base types after adding tests. // It's OK to always overwrite the bound nodes, as if there was @@ -224,6 +227,10 @@ class MatchChildASTVisitor ScopedIncrement ScopedDepth(&CurrentDepth); return traverse(*CtorInit); } + bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) { + ScopedIncrement ScopedDepth(&CurrentDepth); + return traverse(TAL); + } bool TraverseLambdaExpr(LambdaExpr *Node) { if (Finder->getASTContext().getParentMapContext().getTraversalKind() != TK_IgnoreUnlessSpelledInSource) @@ -304,6 +311,9 @@ class MatchChildASTVisitor return VisitorBase::TraverseConstructorInitializer( const_cast<CXXCtorInitializer *>(&CtorInit)); } + bool baseTraverse(TemplateArgumentLoc TAL) { + return VisitorBase::TraverseTemplateArgumentLoc(TAL); + } // Sets 'Matched' to true if 'Matcher' matches 'Node' and: // 0 < CurrentDepth <= MaxDepth. @@ -447,6 +457,7 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit); + bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL); // Matches children or descendants of 'Node' with 'BaseMatcher'. bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx, @@ -557,6 +568,8 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, match(*N); } else if (auto *N = Node.get<CXXCtorInitializer>()) { match(*N); + } else if (auto *N = Node.get<TemplateArgumentLoc>()) { + match(*N); } } @@ -680,6 +693,9 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, void matchDispatch(const CXXCtorInitializer *Node) { matchWithoutFilter(*Node, Matchers->CtorInit); } + void matchDispatch(const TemplateArgumentLoc *Node) { + matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc); + } void matchDispatch(const void *) { /* Do nothing. */ } /// @} @@ -1035,6 +1051,11 @@ bool MatchASTVisitor::TraverseConstructorInitializer( CtorInit); } +bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) { + match(Loc); + return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc); +} + class MatchASTConsumer : public ASTConsumer { public: MatchASTConsumer(MatchFinder *Finder, @@ -1111,6 +1132,12 @@ void MatchFinder::addMatcher(const CXXCtorInitializerMatcher &NodeMatch, Matchers.AllCallbacks.insert(Action); } +void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch, + MatchCallback *Action) { + Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action); + Matchers.AllCallbacks.insert(Action); +} + bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, MatchCallback *Action) { if (NodeMatch.canConvertTo<Decl>()) { @@ -1134,6 +1161,9 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, } else if (NodeMatch.canConvertTo<CXXCtorInitializer>()) { addMatcher(NodeMatch.convertTo<CXXCtorInitializer>(), Action); return true; + } else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) { + addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action); + return true; } return false; } diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 4b9baf7a0e75..5b9476f3098a 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -734,6 +734,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, AccessSpecDecl> accessSpecDecl; const internal::VariadicAllOfMatcher<CXXCtorInitializer> cxxCtorInitializer; const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; +const internal::VariadicAllOfMatcher<TemplateArgumentLoc> templateArgumentLoc; const internal::VariadicAllOfMatcher<TemplateName> templateName; const internal::VariadicDynCastAllOfMatcher<Decl, NonTypeTemplateParmDecl> nonTypeTemplateParmDecl; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index 380538697f46..c7db52b37a50 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -2637,6 +2637,19 @@ TEST(Has, DoesNotDeleteBindings) { std::make_unique<VerifyIdIsBoundTo<Decl>>("x", 1))); } +TEST(TemplateArgumentLoc, Matches) { + EXPECT_TRUE(matchAndVerifyResultTrue( + R"cpp( + template <typename A, int B, template <typename> class C> class X {}; + class A {}; + const int B = 42; + template <typename> class C {}; + X<A, B, C> x; + )cpp", + templateArgumentLoc().bind("x"), + std::make_unique<VerifyIdIsBoundTo<TemplateArgumentLoc>>("x", 3))); +} + TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { // Those matchers cover all the cases where an inner matcher is called // and there is not a 1:1 relationship between the match of the outer _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits