diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -5728,6 +5728,19 @@ +
Matches expressions that match InnerMatcher after any elidable constructor are stripped off. + +Example matches the entire D1 = ... (matcher = cxxOperatorCallExpr(hasArgument(1, callExpr(hasArgument(0, ignoringElidableMoveConstructorCall(ignoringParenImpCasts(callExpr()))))))) +struct H {}; +template<typename T> H B(T A); +void f() { + H D1; + D1 = B(B(1)); +} +
Matches expressions that match InnerMatcher after any implicit casts are stripped off. 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 @@ -6452,6 +6452,31 @@ return false; } +/// Matches expressions that match InnerMatcher after any elidable constructor are stripped off. +/// +/// Example matches the entire D1 = ... (matcher = cxxOperatorCallExpr(hasArgument(1, callExpr(hasArgument(0, ignoringElidableMoveConstructorCall(ignoringParenImpCasts(callExpr()))))))) +/// \code +/// struct H {}; +/// templateH B(T A); +/// void f() { +/// H D1; +/// D1 = B(B(1)); +/// } +/// \endcode +AST_MATCHER_P(Expr, ignoringElidableMoveConstructorCall, + ast_matchers::internal::Matcher , InnerMatcher) { + if (const auto* cxx_construct_expr = dyn_cast (&Node)) { + if (cxx_construct_expr->isElidable()) { + if (const auto* materialize_temp = dyn_cast ( + cxx_construct_expr->getArg(0))) { + return InnerMatcher.matches(*materialize_temp, Finder, Builder); + } + return InnerMatcher.matches(*cxx_construct_expr, Finder, Builder); + } + } + return InnerMatcher.matches(Node, Finder, Builder); +} + //----------------------------------------------------------------------------// // OpenMP handling. //----------------------------------------------------------------------------// 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 @@ -320,6 +320,7 @@ REGISTER_MATCHER(hasUnqualifiedDesugaredType); REGISTER_MATCHER(hasValueType); REGISTER_MATCHER(ifStmt); + REGISTER_MATCHER(ignoringElidableMoveConstructorCall); REGISTER_MATCHER(ignoringImpCasts); REGISTER_MATCHER(ignoringImplicit); REGISTER_MATCHER(ignoringParenCasts); 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 @@ -566,6 +566,71 @@ llvm::make_unique >("x"))); } +TEST(Matcher, IgnoresElidableConstructors) { + StatementMatcher matcher = cxxOperatorCallExpr( + hasArgument(1, callExpr(hasArgument(0, + ignoringElidableMoveConstructorCall( + ignoringParenImpCasts(expr().bind("c"))))))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "struct H {};" + "template H B(T A);" + "void f(){" + "H D1;" + "D1=B(B(1));" + "}" + , matcher, llvm::make_unique >("c"))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "struct H {};" + "template H B(T A);" + "void f(){" + "H D1;" + "D1=B(1);" + "}" + , matcher, llvm::make_unique >("c"))); +} + +TEST(Matcher, IgnoresElidableInReturn) { + auto matcher = expr(ignoringElidableMoveConstructorCall(declRefExpr())); + + EXPECT_TRUE(matches( + "struct H{};" + "H f(){" + "H g;" + "return g;" + "}" + , matcher)); + + EXPECT_FALSE(matches( + "struct H{};" + "H f(){" + "return H();" + "}" + , matcher + )); +} + +TEST(Matcher, IgnoreElidableConstructorDoesNotMatchConstructors) { + auto matcher = varDecl(hasInitializer(ignoringElidableMoveConstructorCall(cxxConstructExpr()))); + EXPECT_TRUE(matches( + "struct H {};" + "void f(){" + "H D;" + "}" + , matcher)); + +}; + +TEST(Matcher, IgnoresElidableDoesNotPreventMatches) { + auto matcher = expr(ignoringElidableMoveConstructorCall(integerLiteral())); + EXPECT_TRUE(matches( + "void f(){" + "int D = 10;" + "}" + , matcher)); +} + TEST(Matcher, BindTheSameNameInAlternatives) { StatementMatcher matcher = anyOf( binaryOperator(hasOperatorName("+"),