Author: Nikita Kniazev Date: 2021-04-09T00:05:36+01:00 New Revision: 2f181086b5cbbe83c4492aa44484a77ed06ec812
URL: https://github.com/llvm/llvm-project/commit/2f181086b5cbbe83c4492aa44484a77ed06ec812 DIFF: https://github.com/llvm/llvm-project/commit/2f181086b5cbbe83c4492aa44484a77ed06ec812.diff LOG: [ASTMatchers] Add `cxxBaseSpecifier` matcher (non-top-level) Required for capturing base specifier in matchers: `cxxRecordDecl(hasDirectBase(cxxBaseSpecifier().bind("base")))` Reviewed By: steveire, aaron.ballman Differential Revision: https://reviews.llvm.org/D69218 Added: Modified: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Removed: ################################################################################ diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index b8fb27b126fc1..ab36402e4bca5 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -573,6 +573,15 @@ <h2 id="decl-matchers">Node Matchers</h2> <tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr> <!-- START_DECL_MATCHERS --> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('cxxBaseSpecifier0')"><a name="cxxBaseSpecifier0Anchor">cxxBaseSpecifier</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="cxxBaseSpecifier0"><pre>Matches class bases. + +Examples matches public virtual B. + class B {}; + class C : public virtual B {}; +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>></td><td class="name" onclick="toggle('cxxCtorInitializer0')"><a name="cxxCtorInitializer0Anchor">cxxCtorInitializer</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXCtorInitializer.html">CXXCtorInitializer</a>>...</td></tr> <tr><td colspan="4" class="doc" id="cxxCtorInitializer0"><pre>Matches constructor initializers. @@ -6144,8 +6153,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasType7')"><a name="hasType7Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="hasType7"><pre>Overloaded to match the declaration of the expression's or value +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasType8')"><a name="hasType8Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType8"><pre>Overloaded to match the declaration of the expression's or value declaration's type. In case of a value declaration (for example a variable declaration), @@ -6157,9 +6166,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; + class Z : public virtual X {}; Example matches class Derived (matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) @@ -6171,6 +6183,24 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasType4')"><a name="hasType4Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType4"><pre>Matches if the expression's or declaration's type matches a type +matcher. + +Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) + and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) + and U (matcher = typedefDecl(hasType(asString("int"))) + and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + asString("class X"))) + class X {}; + void y(X &x) { x; X z; } + typedef int U; + class Y { friend class X; }; + class Z : public virtual X {}; +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('forEachArgumentWithParam1')"><a name="forEachArgumentWithParam1Anchor">forEachArgumentWithParam</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> ArgMatcher, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ParmVarDecl.html">ParmVarDecl</a>> ParamMatcher</td></tr> <tr><td colspan="4" class="doc" id="forEachArgumentWithParam1"><pre>Matches all arguments and their respective ParmVarDecl. @@ -7282,8 +7312,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType4')"><a name="hasType4Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="hasType4"><pre>Overloaded to match the declaration of the expression's or value +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType5')"><a name="hasType5Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType5"><pre>Overloaded to match the declaration of the expression's or value declaration's type. In case of a value declaration (for example a variable declaration), @@ -7295,9 +7325,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; + class Z : public virtual X {}; Example matches class Derived (matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) @@ -7317,10 +7350,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and U (matcher = typedefDecl(hasType(asString("int"))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + asString("class X"))) class X {}; void y(X &x) { x; X z; } typedef int U; class Y { friend class X; }; + class Z : public virtual X {}; </pre></td></tr> @@ -7493,8 +7529,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>></td><td class="name" onclick="toggle('hasType5')"><a name="hasType5Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="hasType5"><pre>Overloaded to match the declaration of the expression's or value +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>></td><td class="name" onclick="toggle('hasType6')"><a name="hasType6Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType6"><pre>Overloaded to match the declaration of the expression's or value declaration's type. In case of a value declaration (for example a variable declaration), @@ -7506,9 +7542,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; + class Z : public virtual X {}; Example matches class Derived (matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) @@ -7528,10 +7567,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and U (matcher = typedefDecl(hasType(asString("int"))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + asString("class X"))) class X {}; void y(X &x) { x; X z; } typedef int U; class Y { friend class X; }; + class Z : public virtual X {}; </pre></td></tr> @@ -8750,10 +8792,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and U (matcher = typedefDecl(hasType(asString("int"))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + asString("class X"))) class X {}; void y(X &x) { x; X z; } typedef int U; class Y { friend class X; }; + class Z : public virtual X {}; </pre></td></tr> @@ -8896,8 +8941,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> matches using X::b but not using X::a </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType6')"><a name="hasType6Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="hasType6"><pre>Overloaded to match the declaration of the expression's or value +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType7')"><a name="hasType7Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType7"><pre>Overloaded to match the declaration of the expression's or value declaration's type. In case of a value declaration (for example a variable declaration), @@ -8909,9 +8954,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + cxxRecordDecl(hasName("X")))) class X {}; void y(X &x) { x; X z; } class Y { friend class X; }; + class Z : public virtual X {}; Example matches class Derived (matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) @@ -8931,10 +8979,13 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) and U (matcher = typedefDecl(hasType(asString("int"))) and friend class X (matcher = friendDecl(hasType("X")) + and public virtual X (matcher = cxxBaseSpecifier(hasType( + asString("class X"))) class X {}; void y(X &x) { x; X z; } typedef int U; class Y { friend class X; }; + class Z : public virtual X {}; </pre></td></tr> diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index fd0e9d6d7c1f7..33f57b755941f 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -144,6 +144,7 @@ using TypeMatcher = internal::Matcher<QualType>; using TypeLocMatcher = internal::Matcher<TypeLoc>; using NestedNameSpecifierMatcher = internal::Matcher<NestedNameSpecifier>; using NestedNameSpecifierLocMatcher = internal::Matcher<NestedNameSpecifierLoc>; +using CXXBaseSpecifierMatcher = internal::Matcher<CXXBaseSpecifier>; using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>; using TemplateArgumentMatcher = internal::Matcher<TemplateArgument>; using TemplateArgumentLocMatcher = internal::Matcher<TemplateArgumentLoc>; @@ -516,6 +517,15 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> extern const internal::VariadicDynCastAllOfMatcher<Decl, AccessSpecDecl> accessSpecDecl; +/// Matches class bases. +/// +/// Examples matches \c public virtual B. +/// \code +/// class B {}; +/// class C : public virtual B {}; +/// \endcode +extern const internal::VariadicAllOfMatcher<CXXBaseSpecifier> cxxBaseSpecifier; + /// Matches constructor initializers. /// /// Examples matches \c i(42). @@ -3825,16 +3835,19 @@ AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher, /// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) /// and U (matcher = typedefDecl(hasType(asString("int"))) /// and friend class X (matcher = friendDecl(hasType("X")) +/// and public virtual X (matcher = cxxBaseSpecifier(hasType( +/// asString("class X"))) /// \code /// class X {}; /// void y(X &x) { x; X z; } /// typedef int U; /// class Y { friend class X; }; +/// class Z : public virtual X {}; /// \endcode AST_POLYMORPHIC_MATCHER_P_OVERLOAD( hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, TypedefNameDecl, - ValueDecl), + ValueDecl, CXXBaseSpecifier), internal::Matcher<QualType>, InnerMatcher, 0) { QualType QT = internal::getUnderlyingType(Node); if (!QT.isNull()) @@ -3854,10 +3867,13 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD( /// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) /// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) /// and friend class X (matcher = friendDecl(hasType("X")) +/// and public virtual X (matcher = cxxBaseSpecifier(hasType( +/// cxxRecordDecl(hasName("X")))) /// \code /// class X {}; /// void y(X &x) { x; X z; } /// class Y { friend class X; }; +/// class Z : public virtual X {}; /// \endcode /// /// Example matches class Derived diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index c2001070de558..7c4eb6dd77ca9 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -756,6 +756,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl> const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl; const internal::VariadicDynCastAllOfMatcher<Decl, AccessSpecDecl> accessSpecDecl; +const internal::VariadicAllOfMatcher<CXXBaseSpecifier> cxxBaseSpecifier; const internal::VariadicAllOfMatcher<CXXCtorInitializer> cxxCtorInitializer; const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument; const internal::VariadicAllOfMatcher<TemplateArgumentLoc> templateArgumentLoc; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 8e595deac2cd1..8c0f688b54417 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -175,6 +175,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(coreturnStmt); REGISTER_MATCHER(coyieldExpr); REGISTER_MATCHER(cudaKernelCallExpr); + REGISTER_MATCHER(cxxBaseSpecifier); REGISTER_MATCHER(cxxBindTemporaryExpr); REGISTER_MATCHER(cxxBoolLiteral); REGISTER_MATCHER(cxxCatchStmt); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index c26e8f8d4d220..877cc6185a4b1 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -4400,6 +4400,13 @@ TEST_P(ASTMatchersTest, HasDirectBase) { return; } + DeclarationMatcher ClassHasAnyDirectBase = + cxxRecordDecl(hasDirectBase(cxxBaseSpecifier())); + EXPECT_TRUE(notMatches("class X {};", ClassHasAnyDirectBase)); + EXPECT_TRUE(matches("class X {}; class Y : X {};", ClassHasAnyDirectBase)); + EXPECT_TRUE(matches("class X {}; class Y : public virtual X {};", + ClassHasAnyDirectBase)); + EXPECT_TRUE(matches( R"cc( class Base {}; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index bf4b0912c6616..ea27178bcc4cc 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -320,6 +320,15 @@ TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) { varDecl(hasType(pointsTo(ClassX))))); } +TEST(HasType, TakesQualTypeMatcherAndMatchesCXXBaseSpecifier) { + TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X"))); + CXXBaseSpecifierMatcher BaseClassX = cxxBaseSpecifier(hasType(ClassX)); + DeclarationMatcher ClassHasBaseClassX = + cxxRecordDecl(hasDirectBase(BaseClassX)); + EXPECT_TRUE(matches("class X {}; class Y : X {};", ClassHasBaseClassX)); + EXPECT_TRUE(notMatches("class Z {}; class Y : Z {};", ClassHasBaseClassX)); +} + TEST(HasType, TakesDeclMatcherAndMatchesExpr) { DeclarationMatcher ClassX = recordDecl(hasName("X")); EXPECT_TRUE( @@ -337,6 +346,15 @@ TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) { notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX)))); } +TEST(HasType, TakesDeclMatcherAndMatchesCXXBaseSpecifier) { + DeclarationMatcher ClassX = recordDecl(hasName("X")); + CXXBaseSpecifierMatcher BaseClassX = cxxBaseSpecifier(hasType(ClassX)); + DeclarationMatcher ClassHasBaseClassX = + cxxRecordDecl(hasDirectBase(BaseClassX)); + EXPECT_TRUE(matches("class X {}; class Y : X {};", ClassHasBaseClassX)); + EXPECT_TRUE(notMatches("class Z {}; class Y : Z {};", ClassHasBaseClassX)); +} + TEST(HasType, MatchesTypedefDecl) { EXPECT_TRUE(matches("typedef int X;", typedefDecl(hasType(asString("int"))))); EXPECT_TRUE(matches("typedef const int T;", diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index a7368d819ccd9..318fd3ad1857e 100644 --- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -297,6 +297,17 @@ TEST_F(RegistryTest, TypeTraversal) { EXPECT_TRUE(matches("int b[7];", M)); } +TEST_F(RegistryTest, CXXBaseSpecifier) { + // TODO: rewrite with top-level cxxBaseSpecifier matcher when available + DeclarationMatcher ClassHasAnyDirectBase = + constructMatcher("cxxRecordDecl", + constructMatcher("hasDirectBase", + constructMatcher("cxxBaseSpecifier"))) + .getTypedMatcher<Decl>(); + EXPECT_TRUE(matches("class X {}; class Y : X {};", ClassHasAnyDirectBase)); + EXPECT_TRUE(notMatches("class X {};", ClassHasAnyDirectBase)); +} + TEST_F(RegistryTest, CXXCtorInitializer) { Matcher<Decl> CtorDecl = constructMatcher( "cxxConstructorDecl", _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits