[clang] Add 'refersToPack' AST matcher (PR #86228)

June Rhodes via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 21 19:03:11 PDT 2024


https://github.com/hach-que created https://github.com/llvm/llvm-project/pull/86228

This adds a 'refersToPack' AST matcher, which can be used to match against template arguments that are inside parameter packs. The inner matcher is evaluated against each argument in the parameter pack, such that given:

```cpp
template<typename T, typename... Params> class A {};
A<int, double> a;
A<double, int> b;
A<double, int, long> c;
```

The matcher `classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToPack(refersToType(...))))` would evaluate the `refersToType` against:

- For `a`, the `double` template argument. 
- For `b`, the `int` template argument.
- For `c`, the `int` template argument, then the `long` template argument.

If the inner matcher matches against any argument of the parameter pack, then `refersToPack` matches.

>From e298ea2437dfdd3d44e7d53ef2a5e41bf17bd329 Mon Sep 17 00:00:00 2001
From: June Rhodes <jrhodes at redpoint.games>
Date: Fri, 22 Mar 2024 12:51:40 +1100
Subject: [PATCH] Add 'refersToPack' AST matcher

---
 clang/include/clang/ASTMatchers/ASTMatchers.h | 29 +++++++++++++++++++
 clang/lib/ASTMatchers/Dynamic/Registry.cpp    |  1 +
 2 files changed, 30 insertions(+)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 2f71053d030f68..df30d4c85c22c6 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -1151,6 +1151,35 @@ AST_MATCHER_P(TemplateArgument, refersToDeclaration,
   return false;
 }
 
+/// Matches template arguments within a pack template argument; the inner
+/// matcher is compared against each argument of the parameter pack.
+///
+/// Given
+/// \code
+///   template<typename T, typename... Params> class A {};
+///   A<int, double> a;
+///   A<double, int> b;
+/// \endcode
+///
+/// \endcode
+/// classTemplateSpecializationDecl(hasAnyTemplateArgument(
+///     refersToPack(refersToType(asString("double")))))
+///   matches the specialization \c A<int, double>
+///   but does not match the specialization \c A<double, int>
+AST_MATCHER_P(TemplateArgument, refersToPack,
+              internal::Matcher<TemplateArgument>, InnerMatcher) {
+  if (Node.getKind() == TemplateArgument::Pack) {
+    for (const TemplateArgument &Arg : Node.pack_elements()) {
+      BoundNodesTreeBuilder Result(*Builder);
+      if (InnerMatcher.matches(Arg, Finder, &Result)) {
+        *Builder = std::move(Result);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 /// Matches a sugar TemplateArgument that refers to a certain expression.
 ///
 /// Given
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 2c75e6beb74301..732d49e850288a 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -551,6 +551,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(referenceType);
   REGISTER_MATCHER(referenceTypeLoc);
   REGISTER_MATCHER(refersToDeclaration);
+  REGISTER_MATCHER(refersToPack);
   REGISTER_MATCHER(refersToIntegralType);
   REGISTER_MATCHER(refersToTemplate);
   REGISTER_MATCHER(refersToType);



More information about the cfe-commits mailing list