diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1226,6 +1226,11 @@ +Matcher<Stmt>fixedPointLiteralMatcher<FixedPointLiteral>... +
Matches fixed point literals
+
+ + Matcher<Stmt>floatLiteralMatcher<FloatingLiteral>...
Matches float literals of all sizes / encodings, e.g.
 1.0, 1.0f, 1.0L and 1e10.
@@ -5219,30 +5224,13 @@
 
-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),
-this resolves one layer of indirection. For example, in the value
-declaration "X x;", cxxRecordDecl(hasName("X")) matches the declaration of
-X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
-declaration of x.
-
-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"))
- class X {};
- void y(X &x) { x; X z; }
- class Y { friend class X; };
+Matcher<CXXBaseSpecifier>hasClassMatcher<CXXRecordDecl> InnerMatcher
+
Matches if the Base specifier refers to the given class matcher.
 
 Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
+(matcher = cxxRecordDecl(hasAnyBase(hasClass(hasName("Base")))))
 class Base {};
 class Derived : Base {};
-
-Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>,
-Matcher<CXXBaseSpecifier>
 
@@ -5632,18 +5620,33 @@ Matcher<CXXRecordDecl>hasAnyBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher
Matches C++ classes that have a direct or indirect base matching BaseSpecMatcher.
 
-Example matches DirectlyDerived, IndirectlyDerived (BaseSpecMatcher ==
-hasType(cxxRecordDecl(hasName("SpecialBase")))) class Foo;
+Example:
+matcher hasAnyBase(hasClass(hasName("SpecialBase")))
+  class Foo;
   class Bar : Foo {};
   class Baz : Bar {};
   class SpecialBase;
-  class DirectlyDerived : SpecialBase {};  // directly derived
-  class IndirectlyDerived : DirectlyDerived {};  // indirectly derived
+  class Proxy : SpecialBase {};  // matches Proxy
+  class IndirectlyDerived : Proxy {};  //matches IndirectlyDerived
 
 FIXME: Refactor this and isDerivedFrom to reuse implementation.
 
+Matcher<CXXRecordDecl>hasDirectBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher +
Matches C++ classes that have a direct base matching BaseSpecMatcher.
+
+Example:
+matcher hasDirectBase(hasClass(hasName("SpecialBase")))
+  class Foo;
+  class Bar : Foo {};
+  class Baz : Bar {};
+  class SpecialBase;
+  class Proxy : SpecialBase {};  // matches Proxy
+  class IndirectlyDerived : Proxy {};  // doesn't match
+
+ + Matcher<CXXRecordDecl>hasMethodMatcher<CXXMethodDecl> InnerMatcher
Matches the first method of a class or struct that satisfies InnerMatcher.
 
@@ -6201,13 +6204,8 @@
  void y(X &x) { x; X z; }
  class Y { friend class X; };
 
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
-class Base {};
-class Derived : Base {};
 
-Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>,
-Matcher<CXXBaseSpecifier>
+Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>
 
@@ -6421,13 +6419,8 @@ void y(X &x) { x; X z; } class Y { friend class X; }; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) -class Base {}; -class Derived : Base {}; -Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, -Matcher<CXXBaseSpecifier> +Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>
@@ -7815,13 +7808,8 @@ void y(X &x) { x; X z; } class Y { friend class X; }; -Example matches class Derived -(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) -class Base {}; -class Derived : Base {}; -Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>, -Matcher<CXXBaseSpecifier> +Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl> 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 @@ -2864,7 +2864,7 @@ /// BaseSpecMatcher. /// /// Example: -/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))) +/// matcher hasAnyBase(hasClass(hasName("SpecialBase"))) /// \code /// class Foo; /// class Bar : Foo {}; @@ -2880,6 +2880,27 @@ return internal::matchesAnyBase(Node, BaseSpecMatcher, Finder, Builder); } +/// Matches C++ classes that have a direct base matching \p BaseSpecMatcher. +/// +/// Example: +/// matcher hasDirectBase(hasClass(hasName("SpecialBase"))) +/// \code +/// class Foo; +/// class Bar : Foo {}; +/// class Baz : Bar {}; +/// class SpecialBase; +/// class Proxy : SpecialBase {}; // matches Proxy +/// class IndirectlyDerived : Proxy {}; // doesn't match +/// \endcode +AST_MATCHER_P(CXXRecordDecl, hasDirectBase, internal::Matcher, + BaseSpecMatcher) { + + return Node.hasDefinition() && + llvm::any_of(Node.bases(), [&](const CXXBaseSpecifier &Base) { + return BaseSpecMatcher.matches(Base, Finder, Builder); + }); +} + /// Similar to \c isDerivedFrom(), but also matches classes that directly /// match \c Base. AST_POLYMORPHIC_MATCHER_P_OVERLOAD( @@ -3510,19 +3531,10 @@ /// class Y { friend class X; }; /// \endcode /// -/// Example matches class Derived -/// (matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))) -/// \code -/// class Base {}; -/// class Derived : Base {}; -/// \endcode /// -/// Usable as: Matcher, Matcher, Matcher, -/// Matcher +/// Usable as: Matcher, Matcher, Matcher AST_POLYMORPHIC_MATCHER_P_OVERLOAD( - hasType, - AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl, - CXXBaseSpecifier), + hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl), internal::Matcher, InnerMatcher, 1) { QualType QT = internal::getUnderlyingType(Node); if (!QT.isNull()) @@ -3530,6 +3542,23 @@ return false; } +/// Matches if the Base specifier refers to the given class matcher. +/// +/// Example matches class Derived +/// (matcher = cxxRecordDecl(hasAnyBase(hasClass(hasName("Base"))))) +/// \code +/// class Base {}; +/// class Derived : Base {}; +/// \endcode +AST_MATCHER_P(CXXBaseSpecifier, hasClass, internal::Matcher, + InnerMatcher) { + QualType QT = Node.getType(); + assert(!QT.isNull() && "CXXBaseSpecifier shouldn't have a null type"); + const CXXRecordDecl *RD = QT->getAsCXXRecordDecl(); + assert(RD && "CXXBaseSpecifier should refer to a CXXRecordDecl"); + return InnerMatcher.matches(*RD, Finder, Builder); +} + /// Matches if the type location of the declarator decl's type matches /// the inner matcher. /// diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -130,9 +130,6 @@ return TSI->getType(); return QualType(); } -inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) { - return Node.getType(); -} /// Unifies obtaining the FunctionProtoType pointer from both /// FunctionProtoType and FunctionDecl nodes.. 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 @@ -261,6 +261,7 @@ REGISTER_MATCHER(hasCanonicalType); REGISTER_MATCHER(hasCaseConstant); REGISTER_MATCHER(hasCastKind); + REGISTER_MATCHER(hasClass); REGISTER_MATCHER(hasCondition); REGISTER_MATCHER(hasConditionVariableStatement); REGISTER_MATCHER(hasDecayedType); @@ -271,6 +272,7 @@ REGISTER_MATCHER(hasDefinition); REGISTER_MATCHER(hasDescendant); REGISTER_MATCHER(hasDestinationType); + REGISTER_MATCHER(hasDirectBase); REGISTER_MATCHER(hasDynamicExceptionSpec); REGISTER_MATCHER(hasEitherOperand); REGISTER_MATCHER(hasElementType); 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 @@ -2997,26 +2997,24 @@ } TEST(HasAnyBase, DirectBase) { - EXPECT_TRUE(matches( - "struct Base {};" - "struct ExpectedMatch : Base {};", - cxxRecordDecl(hasName("ExpectedMatch"), - hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))); + EXPECT_TRUE(matches("struct Base {};" + "struct ExpectedMatch : Base {};", + cxxRecordDecl(hasName("ExpectedMatch"), + hasAnyBase(hasClass(hasName("Base")))))); } TEST(HasAnyBase, IndirectBase) { - EXPECT_TRUE(matches( - "struct Base {};" - "struct Intermediate : Base {};" - "struct ExpectedMatch : Intermediate {};", - cxxRecordDecl(hasName("ExpectedMatch"), - hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))); + EXPECT_TRUE(matches("struct Base {};" + "struct Intermediate : Base {};" + "struct ExpectedMatch : Intermediate {};", + cxxRecordDecl(hasName("ExpectedMatch"), + hasAnyBase(hasClass(hasName("Base")))))); } TEST(HasAnyBase, NoBase) { EXPECT_TRUE(notMatches("struct Foo {};" "struct Bar {};", - cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl()))))); + cxxRecordDecl(hasAnyBase(hasClass(cxxRecordDecl()))))); } TEST(IsPublicBase, Public) { @@ -3117,5 +3115,57 @@ cxxRecordDecl(hasAnyBase(isVirtual())))); } +TEST(BaseSpecifier, hasDirectBase) { + EXPECT_TRUE(matches( + R"cc( + class Base {}; + class Derived : Base{}; + )cc", + cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasClass(hasName("Base")))))); + + StringRef MultiDerived = R"cc( + class Base {}; + class Base2 {}; + class Derived : Base, Base2{}; + )cc"; + + EXPECT_TRUE(matches(MultiDerived, + cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasClass(hasName("Base")))))); + EXPECT_TRUE(matches( + MultiDerived, cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasClass(hasName("Base2")))))); + + StringRef Indirect = R"cc( + class Base {}; + class Intermediate : Base {}; + class Derived : Intermediate{}; + )cc"; + + EXPECT_TRUE( + matches(Indirect, + cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasClass(hasName("Intermediate")))))); + EXPECT_TRUE(notMatches( + Indirect, cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasClass(hasName("Base")))))); + + // Only really here to make sure the asserts don't fire + EXPECT_FALSE( + matches(R"cc( + class Base {}; + class Derived : BAse {}; + )cc", + cxxRecordDecl(hasDirectBase(hasClass(hasName("Base")))))); + + EXPECT_FALSE( + matches(R"cc( + using Base = int; + class Derived : Base {}; + )cc", + cxxRecordDecl(hasDirectBase(hasClass(hasName("Base")))))); +} + } // namespace ast_matchers } // namespace clang