Skip to content

Commit

Permalink
[ASTMatchers][clang-tidy][NFC] Hoist forEachTemplateArgument matche…
Browse files Browse the repository at this point in the history
…r 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
  • Loading branch information
whisperity committed May 13, 2022
1 parent 7b323af commit 9add949
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 21 deletions.
20 changes: 0 additions & 20 deletions clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
Expand Up @@ -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) {
Expand Down
79 changes: 79 additions & 0 deletions clang/docs/LibASTMatchersReference.html
Expand Up @@ -7391,6 +7391,32 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>


<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>
<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 &lt;typename T, unsigned N, unsigned M&gt;
struct Matrix {};

constexpr unsigned R = 2;
Matrix&lt;int, R * 2, R * 4&gt; M;

template &lt;typename T, typename U&gt;
void f(T&amp;&amp; t, U&amp;&amp; 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&lt;unsigned, bool&gt; twice, for 'unsigned'
and 'bool'
</pre></td></tr>


<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>
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument0"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl that have at least one TemplateArgument matching the given
Expand Down Expand Up @@ -8181,6 +8207,32 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>


<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>
<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 &lt;typename T, unsigned N, unsigned M&gt;
struct Matrix {};

constexpr unsigned R = 2;
Matrix&lt;int, R * 2, R * 4&gt; M;

template &lt;typename T, typename U&gt;
void f(T&amp;&amp; t, U&amp;&amp; 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&lt;unsigned, bool&gt; twice, for 'unsigned'
and 'bool'
</pre></td></tr>


<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>
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument2"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl that have at least one TemplateArgument matching the given
Expand Down Expand Up @@ -9405,6 +9457,33 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>


<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>
<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 &lt;typename T, unsigned N, unsigned M&gt;
struct Matrix {};

constexpr unsigned R = 2;
Matrix&lt;int, R * 2, R * 4&gt; M;

template &lt;typename T, typename U&gt;
void f(T&amp;&amp; t, U&amp;&amp; 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&lt;unsigned, bool&gt; twice, for 'unsigned'
and 'bool'
</pre></td></tr>


<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>
<tr><td colspan="4" class="doc" id="hasAnyTemplateArgument1"><pre>Matches classTemplateSpecializations, templateSpecializationType and
functionDecl that have at least one TemplateArgument matching the given
Expand Down
5 changes: 4 additions & 1 deletion clang/docs/ReleaseNotes.rst
Expand Up @@ -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
------------
Expand Down
43 changes: 43 additions & 0 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/Dynamic/Registry.cpp
Expand Up @@ -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);
Expand Down
56 changes: 56 additions & 0 deletions clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Expand Up @@ -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())),
Expand Down

0 comments on commit 9add949

Please sign in to comment.