forked from OSchip/llvm-project
[clang] Update `ignoringElidableConstructorCall` matcher to ignore `ExprWithCleanups`.
Summary: The `ExprWithCleanups` node is added to the AST along with the elidable CXXConstructExpr. If it is the outermost node of the node being matched, ignore it as well. Reviewers: gribozavr Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D65944 llvm-svn: 368319
This commit is contained in:
parent
8faf2f3c40
commit
57f471f4ff
|
@ -5805,14 +5805,15 @@ Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
|
|||
|
||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringElidableConstructorCall0')"><a name="ignoringElidableConstructorCall0Anchor">ignoringElidableConstructorCall</a></td><td>ast_matchers::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="ignoringElidableConstructorCall0"><pre>Matches expressions that match InnerMatcher that are possibly wrapped in an
|
||||
elidable constructor.
|
||||
elidable constructor and other corresponding bookkeeping nodes.
|
||||
|
||||
In C++17 copy elidable constructors are no longer being
|
||||
generated in the AST as it is not permitted by the standard. They are
|
||||
however part of the AST in C++14 and earlier. Therefore, to write a matcher
|
||||
that works in all language modes, the matcher has to skip elidable
|
||||
constructor AST nodes if they appear in the AST. This matcher can be used to
|
||||
skip those elidable constructors.
|
||||
In C++17, elidable copy constructors are no longer being generated in the
|
||||
AST as it is not permitted by the standard. They are, however, part of the
|
||||
AST in C++14 and earlier. So, a matcher must abstract over these differences
|
||||
to work in all language modes. This matcher skips elidable constructor-call
|
||||
AST nodes, `ExprWithCleanups` nodes wrapping elidable constructor-calls and
|
||||
various implicit nodes inside the constructor calls, all of which will not
|
||||
appear in the C++17 AST.
|
||||
|
||||
Given
|
||||
|
||||
|
@ -5822,10 +5823,8 @@ void f() {
|
|||
H D = G();
|
||||
}
|
||||
|
||||
``varDecl(hasInitializer(any(
|
||||
ignoringElidableConstructorCall(callExpr()),
|
||||
exprWithCleanups(ignoringElidableConstructorCall(callExpr()))))``
|
||||
matches ``H D = G()``
|
||||
``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))``
|
||||
matches ``H D = G()`` in C++11 through C++17 (and beyond).
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
|
|
|
@ -6533,14 +6533,15 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) {
|
|||
}
|
||||
|
||||
/// Matches expressions that match InnerMatcher that are possibly wrapped in an
|
||||
/// elidable constructor.
|
||||
/// elidable constructor and other corresponding bookkeeping nodes.
|
||||
///
|
||||
/// In C++17 copy elidable constructors are no longer being
|
||||
/// generated in the AST as it is not permitted by the standard. They are
|
||||
/// however part of the AST in C++14 and earlier. Therefore, to write a matcher
|
||||
/// that works in all language modes, the matcher has to skip elidable
|
||||
/// constructor AST nodes if they appear in the AST. This matcher can be used to
|
||||
/// skip those elidable constructors.
|
||||
/// In C++17, elidable copy constructors are no longer being generated in the
|
||||
/// AST as it is not permitted by the standard. They are, however, part of the
|
||||
/// AST in C++14 and earlier. So, a matcher must abstract over these differences
|
||||
/// to work in all language modes. This matcher skips elidable constructor-call
|
||||
/// AST nodes, `ExprWithCleanups` nodes wrapping elidable constructor-calls and
|
||||
/// various implicit nodes inside the constructor calls, all of which will not
|
||||
/// appear in the C++17 AST.
|
||||
///
|
||||
/// Given
|
||||
///
|
||||
|
@ -6552,13 +6553,20 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) {
|
|||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// ``varDecl(hasInitializer(any(
|
||||
/// ignoringElidableConstructorCall(callExpr()),
|
||||
/// exprWithCleanups(ignoringElidableConstructorCall(callExpr()))))``
|
||||
/// matches ``H D = G()``
|
||||
/// ``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))``
|
||||
/// matches ``H D = G()`` in C++11 through C++17 (and beyond).
|
||||
AST_MATCHER_P(Expr, ignoringElidableConstructorCall,
|
||||
ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
|
||||
if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(&Node)) {
|
||||
// E tracks the node that we are examining.
|
||||
const Expr *E = &Node;
|
||||
// If present, remove an outer `ExprWithCleanups` corresponding to the
|
||||
// underlying `CXXConstructExpr`. This check won't cover all cases of added
|
||||
// `ExprWithCleanups` corresponding to `CXXConstructExpr` nodes (because the
|
||||
// EWC is placed on the outermost node of the expression, which this may not
|
||||
// be), but, it still improves the coverage of this matcher.
|
||||
if (const auto *CleanupsExpr = dyn_cast<ExprWithCleanups>(&Node))
|
||||
E = CleanupsExpr->getSubExpr();
|
||||
if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E)) {
|
||||
if (CtorExpr->isElidable()) {
|
||||
if (const auto *MaterializeTemp =
|
||||
dyn_cast<MaterializeTemporaryExpr>(CtorExpr->getArg(0))) {
|
||||
|
|
|
@ -671,6 +671,23 @@ TEST(Matcher, IgnoresElidableDoesNotPreventMatches) {
|
|||
LanguageMode::Cxx11OrLater));
|
||||
}
|
||||
|
||||
TEST(Matcher, IgnoresElidableInVarInit) {
|
||||
auto matcher =
|
||||
varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())));
|
||||
EXPECT_TRUE(matches("struct H {};"
|
||||
"H G();"
|
||||
"void f(H D = G()) {"
|
||||
" return;"
|
||||
"}",
|
||||
matcher, LanguageMode::Cxx11OrLater));
|
||||
EXPECT_TRUE(matches("struct H {};"
|
||||
"H G();"
|
||||
"void f() {"
|
||||
" H D = G();"
|
||||
"}",
|
||||
matcher, LanguageMode::Cxx11OrLater));
|
||||
}
|
||||
|
||||
TEST(Matcher, BindTheSameNameInAlternatives) {
|
||||
StatementMatcher matcher = anyOf(
|
||||
binaryOperator(hasOperatorName("+"),
|
||||
|
|
Loading…
Reference in New Issue