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())), _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits