diff --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp --- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -18,26 +18,6 @@ namespace misc { namespace { -// FIXME: Move ASTMatcher library. -AST_POLYMORPHIC_MATCHER_P( - forEachTemplateArgument, - AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl, - TemplateSpecializationType, FunctionDecl), - clang::ast_matchers::internal::Matcher, InnerMatcher) { - ArrayRef TemplateArgs = - clang::ast_matchers::internal::getTemplateSpecializationArgs(Node); - clang::ast_matchers::internal::BoundNodesTreeBuilder Result; - bool Matched = false; - for (const auto &Arg : TemplateArgs) { - clang::ast_matchers::internal::BoundNodesTreeBuilder ArgBuilder(*Builder); - if (InnerMatcher.matches(Arg, Finder, &ArgBuilder)) { - Matched = true; - Result.addMatch(ArgBuilder); - } - } - *Builder = std::move(Result); - return Matched; -} AST_MATCHER_P(DeducedTemplateSpecializationType, refsToTemplatedDecl, clang::ast_matchers::internal::Matcher, DeclMatcher) { diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -7391,6 +7391,32 @@ +Matcher<ClassTemplateSpecializationDecl>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher +
Matches classTemplateSpecialization, templateSpecializationType and functionDecl nodes where the template argument matches the inner matcher.
+This matcher may produce multiple matches.
+
+Given
+  template <typename T, unsigned N, unsigned M>
+  struct Matrix {};
+
+  constexpr unsigned R = 2;
+  Matrix<int, R * 2, R * 4> M;
+
+  template <typename T, typename U>
+  void f(T&& t, U&& u) {}
+
+  bool B = false;
+  f(R, B);
+
+templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
+  matches twice, with expr() matching 'R * 2' and 'R * 4'
+
+functionDecl(forEachTemplateArgument(refersToType(builtinType())))
+  matches the specialization f<unsigned, bool> twice, for 'unsigned'
+  and 'bool'
+
+ + Matcher<ClassTemplateSpecializationDecl>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher
Matches classTemplateSpecializations, templateSpecializationType and
 functionDecl that have at least one TemplateArgument matching the given
@@ -8181,6 +8207,32 @@
 
+Matcher<FunctionDecl>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher +
Matches classTemplateSpecialization, templateSpecializationType and functionDecl nodes where the template argument matches the inner matcher.
+This matcher may produce multiple matches.
+
+Given
+  template <typename T, unsigned N, unsigned M>
+  struct Matrix {};
+
+  constexpr unsigned R = 2;
+  Matrix<int, R * 2, R * 4> M;
+
+  template <typename T, typename U>
+  void f(T&& t, U&& u) {}
+
+  bool B = false;
+  f(R, B);
+
+templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
+  matches twice, with expr() matching 'R * 2' and 'R * 4'
+
+functionDecl(forEachTemplateArgument(refersToType(builtinType())))
+  matches the specialization f<unsigned, bool> twice, for 'unsigned'
+  and 'bool'
+
+ + Matcher<FunctionDecl>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher
Matches classTemplateSpecializations, templateSpecializationType and
 functionDecl that have at least one TemplateArgument matching the given
@@ -9405,6 +9457,33 @@
 
+Matcher<TemplateSpecializationType>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher +
Matches classTemplateSpecialization, templateSpecializationType and functionDecl nodes where the template argument matches the inner matcher.
+This matcher may produce multiple matches.
+
+
+Given
+  template <typename T, unsigned N, unsigned M>
+  struct Matrix {};
+
+  constexpr unsigned R = 2;
+  Matrix<int, R * 2, R * 4> M;
+
+  template <typename T, typename U>
+  void f(T&& t, U&& u) {}
+
+  bool B = false;
+  f(R, B);
+
+templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
+  matches twice, with expr() matching 'R * 2' and 'R * 4'
+
+functionDecl(forEachTemplateArgument(refersToType(builtinType())))
+  matches the specialization f<unsigned, bool> twice, for 'unsigned'
+  and 'bool'
+
+ + Matcher<TemplateSpecializationType>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher
Matches classTemplateSpecializations, templateSpecializationType and
 functionDecl that have at least one TemplateArgument matching the given
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -435,7 +435,10 @@
 AST Matchers
 ------------
 
-- Expanded ``isInline`` narrowing matcher to support c++17 inline variables.
+- Expanded ``isInline`` narrowing matcher to support C++17 inline variables.
+
+- Added ``forEachTemplateArgument`` matcher which creates a match every
+  time a ``templateArgument`` matches the matcher supplied to it.
 
 clang-format
 ------------
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
@@ -5011,6 +5011,49 @@
   return Node.getNumParams() == N;
 }
 
+/// Matches classTemplateSpecialization, templateSpecializationType and
+/// functionDecl nodes where the template argument matches the inner matcher.
+/// This matcher may produce multiple matches.
+///
+/// Given
+/// \code
+///   template 
+///   struct Matrix {};
+///
+///   constexpr unsigned R = 2;
+///   Matrix M;
+///
+///   template 
+///   void f(T&& t, U&& u) {}
+///
+///   bool B = false;
+///   f(R, B);
+/// \endcode
+/// templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
+///   matches twice, with expr() matching 'R * 2' and 'R * 4'
+/// functionDecl(forEachTemplateArgument(refersToType(builtinType())))
+///   matches the specialization f twice, for 'unsigned'
+///   and 'bool'
+AST_POLYMORPHIC_MATCHER_P(
+    forEachTemplateArgument,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
+                                    TemplateSpecializationType, FunctionDecl),
+    clang::ast_matchers::internal::Matcher, InnerMatcher) {
+  ArrayRef TemplateArgs =
+      clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
+  clang::ast_matchers::internal::BoundNodesTreeBuilder Result;
+  bool Matched = false;
+  for (const auto &Arg : TemplateArgs) {
+    clang::ast_matchers::internal::BoundNodesTreeBuilder ArgBuilder(*Builder);
+    if (InnerMatcher.matches(Arg, Finder, &ArgBuilder)) {
+      Matched = true;
+      Result.addMatch(ArgBuilder);
+    }
+  }
+  *Builder = std::move(Result);
+  return Matched;
+}
+
 /// Matches \c FunctionDecls that have a noreturn attribute.
 ///
 /// Given
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -250,6 +250,7 @@
   REGISTER_MATCHER(forEachLambdaCapture);
   REGISTER_MATCHER(forEachOverridden);
   REGISTER_MATCHER(forEachSwitchCase);
+  REGISTER_MATCHER(forEachTemplateArgument);
   REGISTER_MATCHER(forField);
   REGISTER_MATCHER(forFunction);
   REGISTER_MATCHER(forStmt);
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
@@ -4971,6 +4971,62 @@
     std::make_unique>("if", 6)));
 }
 
+TEST(ForEachTemplateArgument, OnFunctionDecl) {
+  const std::string Code = R"(
+template  void f(T, U) {}
+void test() {
+  int I = 1;
+  bool B = false;
+  f(I, B);
+})";
+  EXPECT_TRUE(matches(
+      Code, functionDecl(forEachTemplateArgument(refersToType(builtinType()))),
+      langCxx11OrLater()));
+  auto matcher =
+      functionDecl(forEachTemplateArgument(
+                       templateArgument(refersToType(builtinType().bind("BT")))
+                           .bind("TA")))
+          .bind("FN");
+
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code, matcher,
+      std::make_unique>("FN", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code, matcher,
+      std::make_unique>("TA", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code, matcher,
+      std::make_unique>("BT", 2)));
+}
+
+TEST(ForEachTemplateArgument, OnClassTemplateSpecialization) {
+  const std::string Code = R"(
+template 
+struct Matrix {};
+
+static constexpr unsigned R = 2;
+
+Matrix M;
+)";
+  EXPECT_TRUE(matches(
+      Code, templateSpecializationType(forEachTemplateArgument(isExpr(expr()))),
+      langCxx11OrLater()));
+  auto matcher = templateSpecializationType(
+                     forEachTemplateArgument(
+                         templateArgument(isExpr(expr().bind("E"))).bind("TA")))
+                     .bind("TST");
+
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code, matcher,
+      std::make_unique>("TST",
+                                                                      2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code, matcher,
+      std::make_unique>("TA", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code, matcher, std::make_unique>("E", 2)));
+}
+
 TEST(Has, DoesNotDeleteBindings) {
   EXPECT_TRUE(matchAndVerifyResultTrue(
     "class X { int a; };", recordDecl(decl().bind("x"), has(fieldDecl())),