[clang-tools-extra] 9add949 - [ASTMatchers][clang-tidy][NFC] Hoist `forEachTemplateArgument` matcher into the core library
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 13 03:56:33 PDT 2022
Author: Whisperity
Date: 2022-05-13T12:55:48+02:00
New Revision: 9add949557d2cf603b8f541f0dbb83a8fa035d17
URL: https://github.com/llvm/llvm-project/commit/9add949557d2cf603b8f541f0dbb83a8fa035d17
DIFF: https://github.com/llvm/llvm-project/commit/9add949557d2cf603b8f541f0dbb83a8fa035d17.diff
LOG: [ASTMatchers][clang-tidy][NFC] Hoist `forEachTemplateArgument` matcher into the core library
Fixes the `FIXME:` related to adding `forEachTemplateArgument` to the
core AST Matchers library.
Reviewed By: aaron.ballman
Differential Revision: http://reviews.llvm.org/D125383
Added:
Modified:
clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
clang/docs/LibASTMatchersReference.html
clang/docs/ReleaseNotes.rst
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/lib/ASTMatchers/Dynamic/Registry.cpp
clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
index 9265504a7651..1ee757296d93 100644
--- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
@@ -18,26 +18,6 @@ namespace tidy {
namespace misc {
namespace {
-// FIXME: Move ASTMatcher library.
-AST_POLYMORPHIC_MATCHER_P(
- forEachTemplateArgument,
- AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
- TemplateSpecializationType, FunctionDecl),
- clang::ast_matchers::internal::Matcher<TemplateArgument>, InnerMatcher) {
- ArrayRef<TemplateArgument> 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<NamedDecl>, DeclMatcher) {
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 55c4da639a81..b6dc7777f26e 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -7391,6 +7391,32 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('forEachTemplateArgument0')"><a name="forEachTemplateArgument0Anchor">forEachTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachTemplateArgument0"><pre>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'
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument0')"><a name="hasAnyTemplateArgument0Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument0"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl that have at least one TemplateArgument matching the given
@@ -8181,6 +8207,32 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('forEachTemplateArgument1')"><a name="forEachTemplateArgument1Anchor">forEachTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachTemplateArgument1"><pre>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'
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument2')"><a name="hasAnyTemplateArgument2Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument2"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl that have at least one TemplateArgument matching the given
@@ -9405,6 +9457,33 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('forEachTemplateArgument2')"><a name="forEachTemplateArgument2Anchor">forEachTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forEachTemplateArgument2"><pre>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'
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument1')"><a name="hasAnyTemplateArgument1Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument1"><pre>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
index 0b0aba080e12..e52d25960834 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -435,7 +435,10 @@ Build System Changes
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
index 221cab03b0ec..d2bffe8fef49 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5011,6 +5011,49 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
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 <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);
+/// \endcode
+/// 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'
+AST_POLYMORPHIC_MATCHER_P(
+ forEachTemplateArgument,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
+ TemplateSpecializationType, FunctionDecl),
+ clang::ast_matchers::internal::Matcher<TemplateArgument>, InnerMatcher) {
+ ArrayRef<TemplateArgument> 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
index 47db6b51966a..a6f93c8941c7 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -250,6 +250,7 @@ RegistryMaps::RegistryMaps() {
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
index 7f4dc3b05d95..8b3881adc4ce 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -4971,6 +4971,62 @@ TEST(ForEachDescendant, BindsCombinations) {
std::make_unique<VerifyIdIsBoundTo<IfStmt>>("if", 6)));
}
+TEST(ForEachTemplateArgument, OnFunctionDecl) {
+ const std::string Code = R"(
+template <typename T, typename U> 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<VerifyIdIsBoundTo<FunctionDecl>>("FN", 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code, matcher,
+ std::make_unique<VerifyIdIsBoundTo<TemplateArgument>>("TA", 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code, matcher,
+ std::make_unique<VerifyIdIsBoundTo<BuiltinType>>("BT", 2)));
+}
+
+TEST(ForEachTemplateArgument, OnClassTemplateSpecialization) {
+ const std::string Code = R"(
+template <typename T, unsigned N, unsigned M>
+struct Matrix {};
+
+static constexpr unsigned R = 2;
+
+Matrix<int, R * 2, R * 4> 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<VerifyIdIsBoundTo<TemplateSpecializationType>>("TST",
+ 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code, matcher,
+ std::make_unique<VerifyIdIsBoundTo<TemplateArgument>>("TA", 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code, matcher, std::make_unique<VerifyIdIsBoundTo<Expr>>("E", 2)));
+}
+
TEST(Has, DoesNotDeleteBindings) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class X { int a; };", recordDecl(decl().bind("x"), has(fieldDecl())),
More information about the cfe-commits
mailing list