whisperity created this revision. whisperity added reviewers: aaron.ballman, klimek, hokein, njames93. whisperity added projects: clang, clang-tools-extra. Herald added subscribers: carlosgalvezp, gamesh411, Szelethus, dkrupp, rnkovacs, xazax.hun. Herald added a project: All. whisperity requested review of this revision.
Fixes the `FIXME:` related to adding `forEachTemplateArgument` to the core //AST Matchers// library. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D125383 Files: clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -4971,6 +4971,63 @@ 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())), Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ 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 <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 Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -7391,6 +7391,32 @@ </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 @@ </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 @@ </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 Index: clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ 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<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) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits