From 52ff86d25598175d3304498b14c0f6c780e46ae3 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sun, 21 Jun 2020 13:31:27 +0100 Subject: [PATCH] [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 --- clang/lib/AST/Expr.cpp | 9 +- clang/lib/AST/ParentMapContext.cpp | 7 +- clang/unittests/AST/ASTTraverserTest.cpp | 169 ++++++++++++++++++++- .../ASTMatchers/ASTMatchersTraversalTest.cpp | 109 +++++++++++-- 4 files changed, 281 insertions(+), 13 deletions(-) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index c6b2c47..f55ee20 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(E)) { + auto *SE = Cast->getSubExpr(); + if (SE->getSourceRange() == E->getSourceRange()) + return SE; + } + if (auto *C = dyn_cast(E)) { auto NumArgs = C->getNumArgs(); if (NumArgs == 1 || (NumArgs > 1 && isa(C->getArg(1)))) { Expr *A = C->getArg(0); - if (A->getSourceRange() == E->getSourceRange() || - !isa(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 bae4d01..c80c8bc 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -154,8 +154,13 @@ public: auto SR = Child->getSourceRange(); + if (const auto *C = dyn_cast(E)) { + if (C->getSourceRange() == SR) + return true; + } + if (const auto *C = dyn_cast(E)) { - if (C->getSourceRange() == SR || !isa(C)) + if (C->getSourceRange() == SR || C->isElidable()) return true; } diff --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp index 2f131c3..c24b431 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("varDeclCtor")), + SemanticDump); + + EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, + FN[0].getNodeAs("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 39222fb..ee4fb03 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 @@ -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())); -- 2.7.4