Skip to content

Commit 9add949

Browse files
committed
[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
1 parent 7b323af commit 9add949

File tree

6 files changed

+183
-21
lines changed

6 files changed

+183
-21
lines changed

clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,6 @@ namespace tidy {
1818
namespace misc {
1919

2020
namespace {
21-
// FIXME: Move ASTMatcher library.
22-
AST_POLYMORPHIC_MATCHER_P(
23-
forEachTemplateArgument,
24-
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
25-
TemplateSpecializationType, FunctionDecl),
26-
clang::ast_matchers::internal::Matcher<TemplateArgument>, InnerMatcher) {
27-
ArrayRef<TemplateArgument> TemplateArgs =
28-
clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
29-
clang::ast_matchers::internal::BoundNodesTreeBuilder Result;
30-
bool Matched = false;
31-
for (const auto &Arg : TemplateArgs) {
32-
clang::ast_matchers::internal::BoundNodesTreeBuilder ArgBuilder(*Builder);
33-
if (InnerMatcher.matches(Arg, Finder, &ArgBuilder)) {
34-
Matched = true;
35-
Result.addMatch(ArgBuilder);
36-
}
37-
}
38-
*Builder = std::move(Result);
39-
return Matched;
40-
}
4121

4222
AST_MATCHER_P(DeducedTemplateSpecializationType, refsToTemplatedDecl,
4323
clang::ast_matchers::internal::Matcher<NamedDecl>, DeclMatcher) {

clang/docs/LibASTMatchersReference.html

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7391,6 +7391,32 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
73917391
</pre></td></tr>
73927392

73937393

7394+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('forEachTemplateArgument0')"><a name="forEachTemplateArgument0Anchor">forEachTemplateArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
7395+
<tr><td colspan="4" class="doc" id="forEachTemplateArgument0"><pre>Matches classTemplateSpecialization, templateSpecializationType and functionDecl nodes where the template argument matches the inner matcher.
7396+
This matcher may produce multiple matches.
7397+
7398+
Given
7399+
template &lt;typename T, unsigned N, unsigned M&gt;
7400+
struct Matrix {};
7401+
7402+
constexpr unsigned R = 2;
7403+
Matrix&lt;int, R * 2, R * 4&gt; M;
7404+
7405+
template &lt;typename T, typename U&gt;
7406+
void f(T&amp;&amp; t, U&amp;&amp; u) {}
7407+
7408+
bool B = false;
7409+
f(R, B);
7410+
7411+
templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
7412+
matches twice, with expr() matching 'R * 2' and 'R * 4'
7413+
7414+
functionDecl(forEachTemplateArgument(refersToType(builtinType())))
7415+
matches the specialization f&lt;unsigned, bool&gt; twice, for 'unsigned'
7416+
and 'bool'
7417+
</pre></td></tr>
7418+
7419+
73947420
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>&gt;</td><td class="name" onclick="toggle('hasAnyTemplateArgument0')"><a name="hasAnyTemplateArgument0Anchor">hasAnyTemplateArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
73957421
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument0"><pre>Matches classTemplateSpecializations, templateSpecializationType and
73967422
functionDecl that have at least one TemplateArgument matching the given
@@ -8181,6 +8207,32 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
81818207
</pre></td></tr>
81828208

81838209

8210+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('forEachTemplateArgument1')"><a name="forEachTemplateArgument1Anchor">forEachTemplateArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
8211+
<tr><td colspan="4" class="doc" id="forEachTemplateArgument1"><pre>Matches classTemplateSpecialization, templateSpecializationType and functionDecl nodes where the template argument matches the inner matcher.
8212+
This matcher may produce multiple matches.
8213+
8214+
Given
8215+
template &lt;typename T, unsigned N, unsigned M&gt;
8216+
struct Matrix {};
8217+
8218+
constexpr unsigned R = 2;
8219+
Matrix&lt;int, R * 2, R * 4&gt; M;
8220+
8221+
template &lt;typename T, typename U&gt;
8222+
void f(T&amp;&amp; t, U&amp;&amp; u) {}
8223+
8224+
bool B = false;
8225+
f(R, B);
8226+
8227+
templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
8228+
matches twice, with expr() matching 'R * 2' and 'R * 4'
8229+
8230+
functionDecl(forEachTemplateArgument(refersToType(builtinType())))
8231+
matches the specialization f&lt;unsigned, bool&gt; twice, for 'unsigned'
8232+
and 'bool'
8233+
</pre></td></tr>
8234+
8235+
81848236
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('hasAnyTemplateArgument2')"><a name="hasAnyTemplateArgument2Anchor">hasAnyTemplateArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
81858237
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument2"><pre>Matches classTemplateSpecializations, templateSpecializationType and
81868238
functionDecl that have at least one TemplateArgument matching the given
@@ -9405,6 +9457,33 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
94059457
</pre></td></tr>
94069458

94079459

9460+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;</td><td class="name" onclick="toggle('forEachTemplateArgument2')"><a name="forEachTemplateArgument2Anchor">forEachTemplateArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
9461+
<tr><td colspan="4" class="doc" id="forEachTemplateArgument2"><pre>Matches classTemplateSpecialization, templateSpecializationType and functionDecl nodes where the template argument matches the inner matcher.
9462+
This matcher may produce multiple matches.
9463+
9464+
9465+
Given
9466+
template &lt;typename T, unsigned N, unsigned M&gt;
9467+
struct Matrix {};
9468+
9469+
constexpr unsigned R = 2;
9470+
Matrix&lt;int, R * 2, R * 4&gt; M;
9471+
9472+
template &lt;typename T, typename U&gt;
9473+
void f(T&amp;&amp; t, U&amp;&amp; u) {}
9474+
9475+
bool B = false;
9476+
f(R, B);
9477+
9478+
templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
9479+
matches twice, with expr() matching 'R * 2' and 'R * 4'
9480+
9481+
functionDecl(forEachTemplateArgument(refersToType(builtinType())))
9482+
matches the specialization f&lt;unsigned, bool&gt; twice, for 'unsigned'
9483+
and 'bool'
9484+
</pre></td></tr>
9485+
9486+
94089487
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;</td><td class="name" onclick="toggle('hasAnyTemplateArgument1')"><a name="hasAnyTemplateArgument1Anchor">hasAnyTemplateArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt; InnerMatcher</td></tr>
94099488
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument1"><pre>Matches classTemplateSpecializations, templateSpecializationType and
94109489
functionDecl that have at least one TemplateArgument matching the given

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,10 @@ Build System Changes
435435
AST Matchers
436436
------------
437437

438-
- Expanded ``isInline`` narrowing matcher to support c++17 inline variables.
438+
- Expanded ``isInline`` narrowing matcher to support C++17 inline variables.
439+
440+
- Added ``forEachTemplateArgument`` matcher which creates a match every
441+
time a ``templateArgument`` matches the matcher supplied to it.
439442

440443
clang-format
441444
------------

clang/include/clang/ASTMatchers/ASTMatchers.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5011,6 +5011,49 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
50115011
return Node.getNumParams() == N;
50125012
}
50135013

5014+
/// Matches classTemplateSpecialization, templateSpecializationType and
5015+
/// functionDecl nodes where the template argument matches the inner matcher.
5016+
/// This matcher may produce multiple matches.
5017+
///
5018+
/// Given
5019+
/// \code
5020+
/// template <typename T, unsigned N, unsigned M>
5021+
/// struct Matrix {};
5022+
///
5023+
/// constexpr unsigned R = 2;
5024+
/// Matrix<int, R * 2, R * 4> M;
5025+
///
5026+
/// template <typename T, typename U>
5027+
/// void f(T&& t, U&& u) {}
5028+
///
5029+
/// bool B = false;
5030+
/// f(R, B);
5031+
/// \endcode
5032+
/// templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
5033+
/// matches twice, with expr() matching 'R * 2' and 'R * 4'
5034+
/// functionDecl(forEachTemplateArgument(refersToType(builtinType())))
5035+
/// matches the specialization f<unsigned, bool> twice, for 'unsigned'
5036+
/// and 'bool'
5037+
AST_POLYMORPHIC_MATCHER_P(
5038+
forEachTemplateArgument,
5039+
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
5040+
TemplateSpecializationType, FunctionDecl),
5041+
clang::ast_matchers::internal::Matcher<TemplateArgument>, InnerMatcher) {
5042+
ArrayRef<TemplateArgument> TemplateArgs =
5043+
clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
5044+
clang::ast_matchers::internal::BoundNodesTreeBuilder Result;
5045+
bool Matched = false;
5046+
for (const auto &Arg : TemplateArgs) {
5047+
clang::ast_matchers::internal::BoundNodesTreeBuilder ArgBuilder(*Builder);
5048+
if (InnerMatcher.matches(Arg, Finder, &ArgBuilder)) {
5049+
Matched = true;
5050+
Result.addMatch(ArgBuilder);
5051+
}
5052+
}
5053+
*Builder = std::move(Result);
5054+
return Matched;
5055+
}
5056+
50145057
/// Matches \c FunctionDecls that have a noreturn attribute.
50155058
///
50165059
/// Given

clang/lib/ASTMatchers/Dynamic/Registry.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ RegistryMaps::RegistryMaps() {
250250
REGISTER_MATCHER(forEachLambdaCapture);
251251
REGISTER_MATCHER(forEachOverridden);
252252
REGISTER_MATCHER(forEachSwitchCase);
253+
REGISTER_MATCHER(forEachTemplateArgument);
253254
REGISTER_MATCHER(forField);
254255
REGISTER_MATCHER(forFunction);
255256
REGISTER_MATCHER(forStmt);

clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4971,6 +4971,62 @@ TEST(ForEachDescendant, BindsCombinations) {
49714971
std::make_unique<VerifyIdIsBoundTo<IfStmt>>("if", 6)));
49724972
}
49734973

4974+
TEST(ForEachTemplateArgument, OnFunctionDecl) {
4975+
const std::string Code = R"(
4976+
template <typename T, typename U> void f(T, U) {}
4977+
void test() {
4978+
int I = 1;
4979+
bool B = false;
4980+
f(I, B);
4981+
})";
4982+
EXPECT_TRUE(matches(
4983+
Code, functionDecl(forEachTemplateArgument(refersToType(builtinType()))),
4984+
langCxx11OrLater()));
4985+
auto matcher =
4986+
functionDecl(forEachTemplateArgument(
4987+
templateArgument(refersToType(builtinType().bind("BT")))
4988+
.bind("TA")))
4989+
.bind("FN");
4990+
4991+
EXPECT_TRUE(matchAndVerifyResultTrue(
4992+
Code, matcher,
4993+
std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("FN", 2)));
4994+
EXPECT_TRUE(matchAndVerifyResultTrue(
4995+
Code, matcher,
4996+
std::make_unique<VerifyIdIsBoundTo<TemplateArgument>>("TA", 2)));
4997+
EXPECT_TRUE(matchAndVerifyResultTrue(
4998+
Code, matcher,
4999+
std::make_unique<VerifyIdIsBoundTo<BuiltinType>>("BT", 2)));
5000+
}
5001+
5002+
TEST(ForEachTemplateArgument, OnClassTemplateSpecialization) {
5003+
const std::string Code = R"(
5004+
template <typename T, unsigned N, unsigned M>
5005+
struct Matrix {};
5006+
5007+
static constexpr unsigned R = 2;
5008+
5009+
Matrix<int, R * 2, R * 4> M;
5010+
)";
5011+
EXPECT_TRUE(matches(
5012+
Code, templateSpecializationType(forEachTemplateArgument(isExpr(expr()))),
5013+
langCxx11OrLater()));
5014+
auto matcher = templateSpecializationType(
5015+
forEachTemplateArgument(
5016+
templateArgument(isExpr(expr().bind("E"))).bind("TA")))
5017+
.bind("TST");
5018+
5019+
EXPECT_TRUE(matchAndVerifyResultTrue(
5020+
Code, matcher,
5021+
std::make_unique<VerifyIdIsBoundTo<TemplateSpecializationType>>("TST",
5022+
2)));
5023+
EXPECT_TRUE(matchAndVerifyResultTrue(
5024+
Code, matcher,
5025+
std::make_unique<VerifyIdIsBoundTo<TemplateArgument>>("TA", 2)));
5026+
EXPECT_TRUE(matchAndVerifyResultTrue(
5027+
Code, matcher, std::make_unique<VerifyIdIsBoundTo<Expr>>("E", 2)));
5028+
}
5029+
49745030
TEST(Has, DoesNotDeleteBindings) {
49755031
EXPECT_TRUE(matchAndVerifyResultTrue(
49765032
"class X { int a; };", recordDecl(decl().bind("x"), has(fieldDecl())),

0 commit comments

Comments
 (0)