Author: Stephen Kelly Date: 2020-10-30T12:14:41Z New Revision: 52ff86d25598175d3304498b14c0f6c780e46ae3
URL: https://github.com/llvm/llvm-project/commit/52ff86d25598175d3304498b14c0f6c780e46ae3 DIFF: https://github.com/llvm/llvm-project/commit/52ff86d25598175d3304498b14c0f6c780e46ae3.diff LOG: [AST] Fix traversal over CXXConstructExpr in Syntactic mode Summary: Skip over elidable nodes, and ensure that intermediate CXXFunctionalCastExpr nodes are also skipped if they are semantic. Reviewers: klimek, ymandel Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D82278 Added: Modified: clang/lib/AST/Expr.cpp clang/lib/AST/ParentMapContext.cpp clang/unittests/AST/ASTTraverserTest.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index c6b2c47a48fb..f55ee20f2476 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2816,13 +2816,18 @@ Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) { Expr *Expr::IgnoreUnlessSpelledInSource() { auto IgnoreImplicitConstructorSingleStep = [](Expr *E) { + if (auto *Cast = dyn_cast<CXXFunctionalCastExpr>(E)) { + auto *SE = Cast->getSubExpr(); + if (SE->getSourceRange() == E->getSourceRange()) + return SE; + } + if (auto *C = dyn_cast<CXXConstructExpr>(E)) { auto NumArgs = C->getNumArgs(); if (NumArgs == 1 || (NumArgs > 1 && isa<CXXDefaultArgExpr>(C->getArg(1)))) { Expr *A = C->getArg(0); - if (A->getSourceRange() == E->getSourceRange() || - !isa<CXXTemporaryObjectExpr>(C)) + if (A->getSourceRange() == E->getSourceRange() || C->isElidable()) return A; } } diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index bae4d016ff6b..c80c8bc23e00 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -154,8 +154,13 @@ class ParentMapContext::ParentMap { auto SR = Child->getSourceRange(); + if (const auto *C = dyn_cast<CXXFunctionalCastExpr>(E)) { + if (C->getSourceRange() == SR) + return true; + } + if (const auto *C = dyn_cast<CXXConstructExpr>(E)) { - if (C->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C)) + if (C->getSourceRange() == SR || C->isElidable()) return true; } diff --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp index 2f131c3fd04f..c24b43164cc8 100644 --- a/clang/unittests/AST/ASTTraverserTest.cpp +++ b/clang/unittests/AST/ASTTraverserTest.cpp @@ -299,6 +299,34 @@ void template_test() { void actual_template_test() { template_test<4>(); } + +struct OneParamCtor { + explicit OneParamCtor(int); +}; +struct TwoParamCtor { + explicit TwoParamCtor(int, int); +}; + +void varDeclCtors() { + { + auto var1 = OneParamCtor(5); + auto var2 = TwoParamCtor(6, 7); + } + { + OneParamCtor var3(5); + TwoParamCtor var4(6, 7); + } + int i = 0; + { + auto var5 = OneParamCtor(i); + auto var6 = TwoParamCtor(i, 7); + } + { + OneParamCtor var7(i); + TwoParamCtor var8(i, 7); + } +} + )cpp"); { @@ -444,6 +472,145 @@ StaticAssertDecl `-StringLiteral )cpp"); } + + auto varChecker = [&AST](StringRef varName, StringRef SemanticDump, + StringRef SyntacticDump) { + auto FN = ast_matchers::match( + functionDecl( + hasName("varDeclCtors"), + forEachDescendant(varDecl(hasName(varName)).bind("varDeclCtor"))), + AST->getASTContext()); + EXPECT_EQ(FN.size(), 1u); + + EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("varDeclCtor")), + SemanticDump); + + EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, + FN[0].getNodeAs<Decl>("varDeclCtor")), + SyntacticDump); + }; + + varChecker("var1", + R"cpp( +VarDecl 'var1' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXFunctionalCastExpr + `-CXXConstructExpr + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var1' +`-CXXConstructExpr + `-IntegerLiteral +)cpp"); + + varChecker("var2", + R"cpp( +VarDecl 'var2' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXTemporaryObjectExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var2' +`-CXXTemporaryObjectExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp"); + + varChecker("var3", + R"cpp( +VarDecl 'var3' +`-CXXConstructExpr + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var3' +`-CXXConstructExpr + `-IntegerLiteral +)cpp"); + + varChecker("var4", + R"cpp( +VarDecl 'var4' +`-CXXConstructExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var4' +`-CXXConstructExpr + |-IntegerLiteral + `-IntegerLiteral +)cpp"); + + varChecker("var5", + R"cpp( +VarDecl 'var5' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXFunctionalCastExpr + `-CXXConstructExpr + `-ImplicitCastExpr + `-DeclRefExpr 'i' +)cpp", + R"cpp( +VarDecl 'var5' +`-CXXConstructExpr + `-DeclRefExpr 'i' +)cpp"); + + varChecker("var6", + R"cpp( +VarDecl 'var6' +`-ExprWithCleanups + `-CXXConstructExpr + `-MaterializeTemporaryExpr + `-CXXTemporaryObjectExpr + |-ImplicitCastExpr + | `-DeclRefExpr 'i' + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var6' +`-CXXTemporaryObjectExpr + |-DeclRefExpr 'i' + `-IntegerLiteral +)cpp"); + + varChecker("var7", + R"cpp( +VarDecl 'var7' +`-CXXConstructExpr + `-ImplicitCastExpr + `-DeclRefExpr 'i' +)cpp", + R"cpp( +VarDecl 'var7' +`-CXXConstructExpr + `-DeclRefExpr 'i' +)cpp"); + + varChecker("var8", + R"cpp( +VarDecl 'var8' +`-CXXConstructExpr + |-ImplicitCastExpr + | `-DeclRefExpr 'i' + `-IntegerLiteral +)cpp", + R"cpp( +VarDecl 'var8' +`-CXXConstructExpr + |-DeclRefExpr 'i' + `-IntegerLiteral +)cpp"); } TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) { @@ -647,7 +814,7 @@ FunctionDecl 'func2' FunctionDecl 'func3' `-CompoundStmt `-ReturnStmt - `-CXXFunctionalCastExpr + `-CXXConstructExpr `-IntegerLiteral )cpp"; EXPECT_EQ( diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index 39222fbe4249..ee4fb032dd51 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -2088,6 +2088,98 @@ void actual_template_test() { EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, staticAssertDecl(has(integerLiteral()))))); + + Code = R"cpp( + +struct OneParamCtor { + explicit OneParamCtor(int); +}; +struct TwoParamCtor { + explicit TwoParamCtor(int, int); +}; + +void varDeclCtors() { + { + auto var1 = OneParamCtor(5); + auto var2 = TwoParamCtor(6, 7); + } + { + OneParamCtor var3(5); + TwoParamCtor var4(6, 7); + } + int i = 0; + { + auto var5 = OneParamCtor(i); + auto var6 = TwoParamCtor(i, 7); + } + { + OneParamCtor var7(i); + TwoParamCtor var8(i, 7); + } +} + +)cpp"; + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var1"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var2"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var3"), + hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var4"), + hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var5"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_AsIs, varDecl(hasName("var6"), hasInitializer(hasDescendant( + cxxConstructExpr())))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var7"), + hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, traverse(TK_AsIs, varDecl(hasName("var8"), + hasInitializer(cxxConstructExpr()))))); + + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var1"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var2"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var3"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var4"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var5"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var6"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var7"), hasInitializer(cxxConstructExpr()))))); + EXPECT_TRUE(matches( + Code, + traverse(TK_IgnoreUnlessSpelledInSource, + varDecl(hasName("var8"), hasInitializer(cxxConstructExpr()))))); } template <typename MatcherT> @@ -2293,21 +2385,20 @@ void func14() { forFunction(functionDecl(hasName("func2"))))))))), langCxx20OrLater())); - EXPECT_TRUE(matches( - Code, - traverse( - TK_IgnoreUnlessSpelledInSource, - returnStmt(forFunction(functionDecl(hasName("func3"))), - hasReturnValue(cxxFunctionalCastExpr( - hasSourceExpression(integerLiteral(equals(42))))))), - langCxx20OrLater())); + EXPECT_TRUE( + matches(Code, + traverse(TK_IgnoreUnlessSpelledInSource, + returnStmt(forFunction(functionDecl(hasName("func3"))), + hasReturnValue(cxxConstructExpr(hasArgument( + 0, integerLiteral(equals(42))))))), + langCxx20OrLater())); EXPECT_TRUE(matches( Code, traverse( TK_IgnoreUnlessSpelledInSource, integerLiteral(equals(42), - hasParent(cxxFunctionalCastExpr(hasParent(returnStmt( + hasParent(cxxConstructExpr(hasParent(returnStmt( forFunction(functionDecl(hasName("func3"))))))))), langCxx20OrLater())); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits