Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -4224,6 +4224,11 @@ +
Overloaded to match the type's declaration. +
Matches declarations that are template instantiations or are inside template instantiations. @@ -6956,6 +6961,27 @@
Matches if the type of the object expression (as written, without any
+implicit casts) either matches the InnerMatcher, or is a pointer to a
+type that matches the InnerMatcher. Differs from `thisPointerType` in that
+it matches against the type of the written object expression, which could be
+a subclass of the thisPointerType (like when the invoked member is
+inherited).
+
+Given
+ class Y { public: void m(); };
+ class X : public Y {};
+ void z() { Y y; y.m(); X x; x.m(); X *p; p->m(); }
+cxxMemberCallExpr(invokedAtType(hasDeclaration(
+ cxxRecordDecl(hasName("Y")))))
+ matches `y.m()`.
+cxxMemberCallExpr(invokedAtType(hasDeclaration(
+ cxxRecordDecl(hasName("X")))))
+ matches `x.m()` and `p->m()`.
+Matches NestedNameSpecifierLocs for which the given inner
NestedNameSpecifier-matcher matches.
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3278,6 +3278,40 @@
.matches(Node, Finder, Builder);
}
+/// Matches if the type of the object expression (as written, without any
+/// implicit casts) either matches the InnerMatcher, or is a pointer to a
+/// type that matches the InnerMatcher. Differs from `thisPointerType` in that
+/// it matches against the type of the written object expression, which could be
+/// a subclass of the thisPointerType (like when the invoked member is
+/// inherited).
+///
+/// Given
+/// \code
+/// class Y { public: void m(); };
+/// class X : public Y {};
+/// void z() { Y y; y.m(); X x; x.m(); X *p; p->m(); }
+/// \endcode
+/// cxxMemberCallExpr(invokedAtType(hasDeclaration(
+/// cxxRecordDecl(hasName("Y")))))
+/// matches `y.m()` (while `thisPointerType` would match all three calls.)
+///
+/// cxxMemberCallExpr(invokedAtType(hasDeclaration(
+/// cxxRecordDecl(hasName("X")))))
+/// matches `x.m()` and `p->m()` (while `thisPointerType` would not match any
+/// of the calls, because `this`'s type is `Y` in those calls).
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, invokedAtType,
+ internal::Matcher, InnerMatcher, 0) {
+ return on(anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
+}
+
+/// Overloaded to match the type's declaration.
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, invokedAtType, DeclarationMatcher,
+ InnerMatcher, 1) {
+ return on(anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
+}
+
/// Matches a DeclRefExpr that refers to a declaration that matches the
/// specified matcher.
///
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -470,6 +470,35 @@
}
+TEST(MatcherCXXMemberCallExpr, InvokedAtType) {
+ auto M = cxxMemberCallExpr(invokedAtType(cxxRecordDecl(hasName("Y"))));
+ EXPECT_TRUE(matches(
+ R"cc(
+ struct Y {
+ void m();
+ };
+ void z(Y y) { y.m(); }
+ )cc",
+ M));
+ EXPECT_TRUE(matches(
+ R"cc(
+ struct Y {
+ void m();
+ };
+ void z(Y *y) { y->m(); }
+ )cc",
+ M));
+ EXPECT_TRUE(notMatches(
+ R"cc(
+ struct Y {
+ void m();
+ };
+ struct X : public Y {};
+ void z(X x) { x.m(); }
+ )cc",
+ M));
+}
+
TEST(ForEachArgumentWithParam, ReportsNoFalsePositives) {
StatementMatcher ArgumentY =
declRefExpr(to(varDecl(hasName("y")))).bind("arg");