Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -4224,6 +4224,11 @@ +Matcher<clang::CXXMemberCallExpr>invokedAtTypeclang::ast_matchers::DeclarationMatcher InnerMatcher +
Overloaded to match the type's declaration.
+
+ + Matcher<internal::Matcher<Decl>>isInstantiated
Matches declarations that are template instantiations or are inside
 template instantiations.
@@ -6956,6 +6961,27 @@
 
+Matcher<clang::CXXMemberCallExpr>invokedAtTypeclang::ast_matchers::Matcher<clang::QualType> InnerMatcher +
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()`.
+
+ + Matcher<internal::BindableMatcher<NestedNameSpecifierLoc>>locMatcher<NestedNameSpecifier> InnerMatcher
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");