diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -573,6 +573,15 @@ Return typeNameParameters +Matcher<CXXBaseSpecifier>cxxBaseSpecifierMatcher<CXXBaseSpecifier>... +
Matches class bases.
+
+Examples matches public virtual B.
+  class B {};
+  class C : public virtual B {};
+
+ + Matcher<CXXCtorInitializer>cxxCtorInitializerMatcher<CXXCtorInitializer>...
Matches constructor initializers.
 
@@ -6144,8 +6153,8 @@
 
-Matcher<CXXBaseSpecifier>hasTypeMatcher<Decl> InnerMatcher -
Overloaded to match the declaration of the expression's or value
+Matcher<CXXBaseSpecifier>hasTypeMatcher<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),
@@ -6157,9 +6166,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"))))))
@@ -6171,6 +6183,24 @@
 
+Matcher<CXXBaseSpecifier>hasTypeMatcher<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>forEachArgumentWithParamMatcher<Expr> ArgMatcher, Matcher<ParmVarDecl> ParamMatcher
Matches all arguments and their respective ParmVarDecl.
 
@@ -7282,8 +7312,8 @@
 
-Matcher<Expr>hasTypeMatcher<Decl> InnerMatcher -
Overloaded to match the declaration of the expression's or value
+Matcher<Expr>hasTypeMatcher<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),
@@ -7295,9 +7325,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"))))))
@@ -7317,10 +7350,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 {};
 
@@ -7493,8 +7529,8 @@
-Matcher<FriendDecl>hasTypeMatcher<Decl> InnerMatcher -
Overloaded to match the declaration of the expression's or value
+Matcher<FriendDecl>hasTypeMatcher<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),
@@ -7506,9 +7542,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"))))))
@@ -7528,10 +7567,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 {};
 
@@ -8750,10 +8792,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 {};
@@ -8896,8 +8941,8 @@ matches using X::b but not using X::a
-Matcher<ValueDecl>hasTypeMatcher<Decl> InnerMatcher -
Overloaded to match the declaration of the expression's or value
+Matcher<ValueDecl>hasTypeMatcher<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),
@@ -8909,9 +8954,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"))))))
@@ -8931,10 +8979,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 {};
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -144,6 +144,7 @@ using TypeLocMatcher = internal::Matcher; 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,15 @@ 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). @@ -3825,16 +3835,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()) @@ -3854,10 +3867,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 diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/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; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -175,6 +175,7 @@ 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 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -4400,6 +4400,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 {}; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/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;", diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp --- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/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",