Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -573,6 +573,15 @@
Matches class bases. + +Examples matches public virtual B. + class B {}; + class C : public virtual B {}; +
Matches constructor initializers. @@ -6109,8 +6118,8 @@
Overloaded to match the declaration of the expression's or value ++ Matcher<CXXBaseSpecifier> hasType Matcher<Decl> InnerMatcher + 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), @@ -6122,9 +6131,12 @@ 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")))))) @@ -6136,6 +6148,24 @@+ Matcher<CXXBaseSpecifier> hasType Matcher<QualType> InnerMatcher + + 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 {}; +Matcher<CXXConstructExpr> forEachArgumentWithParam Matcher<Expr> ArgMatcher, Matcher<ParmVarDecl> ParamMatcher - Matches all arguments and their respective ParmVarDecl. @@ -7247,8 +7277,8 @@- Matcher<Expr> hasType Matcher<Decl> InnerMatcher - Overloaded to match the declaration of the expression's or value ++ Matcher<Expr> hasType Matcher<Decl> InnerMatcher @@ -7458,8 +7494,8 @@ 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), @@ -7260,9 +7290,12 @@ 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")))))) @@ -7282,10 +7315,13 @@ 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 {};- Matcher<FriendDecl> hasType Matcher<Decl> InnerMatcher @@ -8861,8 +8906,8 @@ matches using X::b but not using X::a Overloaded to match the declaration of the expression's or value ++ Matcher<FriendDecl> hasType Matcher<Decl> InnerMatcher @@ -8715,10 +8757,13 @@ 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 {}; 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), @@ -7471,9 +7507,12 @@ 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")))))) @@ -7493,10 +7532,13 @@ 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 {};
Overloaded to match the declaration of the expression's or value ++ Matcher<ValueDecl> hasType Matcher<Decl> InnerMatcher Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -144,6 +144,7 @@ using TypeLocMatcher = internal::Matcher 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), @@ -8874,9 +8919,12 @@ 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")))))) @@ -8896,10 +8944,13 @@ 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 {};; using NestedNameSpecifierMatcher = internal::Matcher ; using NestedNameSpecifierLocMatcher = internal::Matcher ; +using CXXBaseSpecifierMatcher = internal::Matcher ; using CXXCtorInitializerMatcher = internal::Matcher ; using TemplateArgumentMatcher = internal::Matcher ; using TemplateArgumentLocMatcher = internal::Matcher ; @@ -516,6 +517,16 @@ extern const internal::VariadicDynCastAllOfMatcher accessSpecDecl; +/// Matches class bases. +/// +/// Examples matches \c public virtual B. +/// \code +/// class B {}; +/// class C : public virtual B {}; +/// \endcode +extern const internal::VariadicAllOfMatcher + cxxBaseSpecifier; + /// Matches constructor initializers. /// /// Examples matches \c i(42). @@ -3790,16 +3801,19 @@ /// 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 , InnerMatcher, 0) { QualType QT = internal::getUnderlyingType(Node); if (!QT.isNull()) @@ -3819,10 +3833,13 @@ /// 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 Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -756,6 +756,7 @@ const internal::VariadicDynCastAllOfMatcher parmVarDecl; const internal::VariadicDynCastAllOfMatcher accessSpecDecl; +const internal::VariadicAllOfMatcher cxxBaseSpecifier; const internal::VariadicAllOfMatcher cxxCtorInitializer; const internal::VariadicAllOfMatcher templateArgument; const internal::VariadicAllOfMatcher templateArgumentLoc; Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -179,6 +179,7 @@ REGISTER_MATCHER(cxxConstructExpr); REGISTER_MATCHER(cxxConstructorDecl); REGISTER_MATCHER(cxxConversionDecl); + REGISTER_MATCHER(cxxBaseSpecifier); REGISTER_MATCHER(cxxCtorInitializer); REGISTER_MATCHER(cxxDeductionGuideDecl); REGISTER_MATCHER(cxxDefaultArgExpr); Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1278,6 +1278,35 @@ ZIsDirectlyDerivedFromX)); } +TEST_P(ASTMatchersTest, ClassHasBase) { + if (!GetParam().isCXX()) { + 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)); + + TypeMatcher ClassX = asString("class X"); + CXXBaseSpecifierMatcher BaseClassX = cxxBaseSpecifier(hasType(ClassX)); + DeclarationMatcher ClassHasBaseClassX = + cxxRecordDecl(hasDirectBase(BaseClassX)); + EXPECT_TRUE(matches("class X {}; class Y {}; class Z : X, Y {};", + ClassHasBaseClassX)); + EXPECT_TRUE(matches("class X {}; class Y {}; class Z : Y, X {};", + ClassHasBaseClassX)); + EXPECT_TRUE(notMatches("class W {}; class Y {}; class Z : W, Y {};", + ClassHasBaseClassX)); + DeclarationMatcher ClassZHasBaseClassX = + cxxRecordDecl(hasName("Z"), hasDirectBase(BaseClassX)); + EXPECT_TRUE(matches("class X {}; class Y : X {}; class Z : X {};", + ClassZHasBaseClassX)); + EXPECT_TRUE(notMatches("class X {}; class Y : X {}; class Z : Y {};", + ClassZHasBaseClassX)); +} + TEST_P(ASTMatchersTest, IsLambda) { if (!GetParam().isCXX11OrLater()) { return; @@ -4400,6 +4429,13 @@ 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 {}; Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -320,6 +320,15 @@ 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 @@ 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;", Index: clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp =================================================================== --- clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -297,6 +297,17 @@ 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 (); + EXPECT_TRUE(matches("class X {}; class Y : X {};", ClassHasAnyDirectBase)); + EXPECT_TRUE(notMatches("class X {};", ClassHasAnyDirectBase)); +} + TEST_F(RegistryTest, CXXCtorInitializer) { Matcher CtorDecl = constructMatcher( "cxxConstructorDecl",