diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -679,7 +679,8 @@ #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)`` @@ -1625,6 +1626,17 @@ +Matcher<TemplateArgumentLoc>templateArgumentLocMatcher<TemplateArgumentLoc>... +
Matches template arguments (with location info).
+
+Given
+  template <typename T> struct C {};
+  C<int> c;
+templateArgumentLoc()
+  matches 'int' in C<int>.
+
+ + Matcher<TemplateArgument>templateArgumentMatcher<TemplateArgument>...
Matches template arguments.
 
@@ -3776,8 +3788,9 @@
 
-Matcher<OMPDefaultClause>isNoneKind -
Matches if the OpenMP ``default`` clause has ``none`` kind specified.
+Matcher<OMPDefaultClause>isFirstPrivateKind
+
Matches if the OpenMP ``default`` clause has ``firstprivate`` kind
+specified.
 
 Given
 
@@ -3786,12 +3799,13 @@
   #pragma omp parallel default(shared)
   #pragma omp parallel default(firstprivate)
 
-``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
+``ompDefaultClause(isFirstPrivateKind())`` matches only
+``default(firstprivate)``.
 
-Matcher<OMPDefaultClause>isSharedKind -
Matches if the OpenMP ``default`` clause has ``shared`` kind specified.
+Matcher<OMPDefaultClause>isNoneKind
+
Matches if the OpenMP ``default`` clause has ``none`` kind specified.
 
 Given
 
@@ -3800,12 +3814,12 @@
   #pragma omp parallel default(shared)
   #pragma omp parallel default(firstprivate)
 
-``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``.
+``ompDefaultClause(isNoneKind())`` matches only ``default(none)``.
 
-Matcher<OMPDefaultClause>isSharedKind -
Matches if the OpenMP ``default`` clause has ``firstprivate`` kind specified.
+Matcher<OMPDefaultClause>isSharedKind
+
Matches if the OpenMP ``default`` clause has ``shared`` kind specified.
 
 Given
 
@@ -3814,7 +3828,7 @@
   #pragma omp parallel default(shared)
   #pragma omp parallel default(firstprivate)
 
-``ompDefaultClause(isFirstPrivateKind())`` matches only ``default(firstprivate)``.
+``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``.
 
diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -132,6 +132,7 @@ enum NodeKindId { NKI_None, NKI_TemplateArgument, + NKI_TemplateArgumentLoc, NKI_TemplateName, NKI_NestedNameSpecifierLoc, NKI_QualType, @@ -191,6 +192,7 @@ }; 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 @@ /// 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 Storage; + TemplateArgumentLoc, NestedNameSpecifierLoc, + QualType, TypeLoc> + Storage; }; template @@ -496,6 +499,10 @@ struct DynTypedNode::BaseConverter< TemplateArgument, void> : public ValueConverter {}; +template <> +struct DynTypedNode::BaseConverter + : public ValueConverter {}; + template <> struct DynTypedNode::BaseConverter< TemplateName, void> : public ValueConverter {}; diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h --- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -159,6 +159,8 @@ 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 @@ NestedNameSpecifierLoc; std::vector> TypeLoc; std::vector> CtorInit; + std::vector> + TemplateArgumentLoc; /// All the callbacks in one container to simplify iteration. llvm::SmallPtrSet AllCallbacks; }; diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -145,6 +145,7 @@ using NestedNameSpecifierMatcher = internal::Matcher; using NestedNameSpecifierLocMatcher = internal::Matcher; using CXXCtorInitializerMatcher = internal::Matcher; +using TemplateArgumentLocMatcher = internal::Matcher; /// @} /// Matches any node. @@ -515,6 +516,18 @@ /// matches 'int' in C. extern const internal::VariadicAllOfMatcher templateArgument; +/// Matches template arguments (with location info). +/// +/// Given +/// \code +/// template struct C {}; +/// C c; +/// \endcode +/// templateArgumentLoc() +/// matches 'int' in C. +extern const internal::VariadicAllOfMatcher + templateArgumentLoc; + /// Matches template name. /// /// Given diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -938,14 +938,13 @@ template struct IsBaseType { static const bool value = - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || + std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value; + std::is_same::value || + std::is_same::value; }; template const bool IsBaseType::value; diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -23,6 +23,7 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { { NKI_None, "" }, { NKI_None, "TemplateArgument" }, + { NKI_None, "TemplateArgumentLoc" }, { NKI_None, "TemplateName" }, { NKI_None, "NestedNameSpecifierLoc" }, { NKI_None, "QualType" }, @@ -129,6 +130,8 @@ const PrintingPolicy &PP) const { if (const TemplateArgument *TA = get()) TA->print(PP, OS); + else if (const TemplateArgumentLoc *TAL = get()) + TAL->getArgument().print(PP, OS); else if (const TemplateName *TN = get()) TN->print(OS, PP); else if (const NestedNameSpecifier *NNS = get()) @@ -175,6 +178,8 @@ return D->getSourceRange(); if (const Stmt *S = get()) return S->getSourceRange(); + if (const TemplateArgumentLoc *TAL = get()) + return TAL->getSourceRange(); if (const auto *C = get()) return SourceRange(C->getBeginLoc(), C->getEndLoc()); return SourceRange(); diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -128,6 +128,9 @@ traverse(*T); else if (const auto *C = DynNode.get()) traverse(*C); + else if (const TemplateArgumentLoc *TALoc = + DynNode.get()) + 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 @@ 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 @@ return VisitorBase::TraverseConstructorInitializer( const_cast(&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 @@ 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 @@ match(*N); } else if (auto *N = Node.get()) { match(*N); + } else if (auto *N = Node.get()) { + match(*N); } } @@ -680,6 +693,9 @@ 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 @@ CtorInit); } +bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) { + match(Loc); + return RecursiveASTVisitor::TraverseTemplateArgumentLoc(Loc); +} + class MatchASTConsumer : public ASTConsumer { public: MatchASTConsumer(MatchFinder *Finder, @@ -1111,6 +1132,12 @@ 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()) { @@ -1134,6 +1161,9 @@ } else if (NodeMatch.canConvertTo()) { addMatcher(NodeMatch.convertTo(), Action); return true; + } else if (NodeMatch.canConvertTo()) { + addMatcher(NodeMatch.convertTo(), Action); + return true; } return false; } diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -734,6 +734,7 @@ accessSpecDecl; const internal::VariadicAllOfMatcher cxxCtorInitializer; const internal::VariadicAllOfMatcher templateArgument; +const internal::VariadicAllOfMatcher templateArgumentLoc; const internal::VariadicAllOfMatcher templateName; const internal::VariadicDynCastAllOfMatcher nonTypeTemplateParmDecl; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -2637,6 +2637,19 @@ std::make_unique>("x", 1))); } +TEST(TemplateArgumentLoc, Matches) { + EXPECT_TRUE(matchAndVerifyResultTrue( + R"cpp( + template class C> class X {}; + class A {}; + const int B = 42; + template class C {}; + X x; + )cpp", + templateArgumentLoc().bind("x"), + std::make_unique>("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