Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -2347,7 +2347,7 @@ private: int c; }; fieldDecl(isPrivate()) - matches 'int c;' + matches 'int c;' @@ -2361,7 +2361,7 @@ private: int c; }; fieldDecl(isProtected()) - matches 'int b;' + matches 'int b;' @@ -2375,7 +2375,7 @@ private: int c; }; fieldDecl(isPublic()) - matches 'int a;' + matches 'int a;' @@ -4432,6 +4432,12 @@ +Matcher<Expr>ignoringExprWithCleanupsMatcher<Expr> InnerMatcher +
Matches expressions that match InnerMatcher after ExprWithCleanups
+are stripped off.
+
+ + Matcher<Expr>ignoringImpCastsMatcher<Expr> InnerMatcher
Matches expressions that match InnerMatcher after any implicit casts
 are stripped off.
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -625,6 +625,16 @@
   return InnerMatcher.matches(*Node.IgnoreParenImpCasts(), Finder, Builder);
 }
 
+/// \brief Matches expressions that match InnerMatcher after ExprWithCleanups
+/// are stripped off.
+AST_MATCHER_P(Expr, ignoringExprWithCleanups, internal::Matcher,
+              InnerMatcher) {
+  auto E = &Node;
+  if (auto Cleanups = dyn_cast(E))
+    E = Cleanups->getSubExpr();
+  return InnerMatcher.matches(*E, Finder, Builder);
+}
+
 /// \brief Matches types that match InnerMatcher after any parens are stripped.
 ///
 /// Given
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -265,6 +265,7 @@
   REGISTER_MATCHER(hasUnarySelector);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
+  REGISTER_MATCHER(ignoringExprWithCleanups);
   REGISTER_MATCHER(ignoringImpCasts);
   REGISTER_MATCHER(ignoringParenCasts);
   REGISTER_MATCHER(ignoringParenImpCasts);
Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1997,5 +1997,34 @@
   EXPECT_TRUE(notMatches(CppString2, returnStmt(forFunction(hasName("F")))));
 }
 
+TEST(IgnoringExprWithCleanups, MatchesExprWithCleanups) {
+  EXPECT_TRUE(
+      matches("struct A { ~A(); }; A Foo(); A x = Foo();",
+              varDecl(hasInitializer(ignoringExprWithCleanups(
+                  cxxConstructExpr(has(materializeTemporaryExpr())))))));
+}
+
+TEST(IgnoringExprWithCleanups, MatchesWithoutExprWithCleanups) {
+  EXPECT_TRUE(matches(
+      "int x = 0; const int y = x;",
+      varDecl(hasInitializer(ignoringExprWithCleanups(
+          ignoringParenImpCasts(declRefExpr(to(varDecl(hasName("x"))))))))));
+}
+
+TEST(IgnoringExprWithCleanups, DoesNotMatchIncorrectly) {
+  EXPECT_TRUE(notMatches("char c = ((3));",
+                         varDecl(hasInitializer(ignoringExprWithCleanups(
+                             ignoringParenImpCasts(unless(anything())))))));
+  EXPECT_TRUE(notMatches("float y = (float(0));",
+                         varDecl(hasInitializer(ignoringExprWithCleanups(
+                             ignoringParenImpCasts(integerLiteral()))))));
+  EXPECT_TRUE(notMatches("float y = (float)0;",
+                         varDecl(hasInitializer(ignoringExprWithCleanups(
+                             ignoringParenImpCasts(integerLiteral()))))));
+  EXPECT_TRUE(notMatches("char* p = static_cast(0);",
+                         varDecl(hasInitializer(ignoringExprWithCleanups(
+                             ignoringParenImpCasts(integerLiteral()))))));
+}
+
 } // namespace ast_matchers
 } // namespace clang