diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h --- a/clang/include/clang/AST/IgnoreExpr.h +++ b/clang/include/clang/AST/IgnoreExpr.h @@ -56,6 +56,8 @@ Expr *IgnoreParensSingleStep(Expr *E); +Expr *IgnoreImplicitConstructorSingleStep(Expr *E); + } // namespace clang #endif // LLVM_CLANG_AST_IGNOREEXPR_H diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2854,19 +2854,6 @@ } Expr *Expr::IgnoreUnlessSpelledInSource() { - auto IgnoreImplicitConstructorSingleStep = [](Expr *E) { - 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)) - return A; - } - } - return E; - }; auto IgnoreImplicitMemberCallSingleStep = [](Expr *E) { if (auto *C = dyn_cast(E)) { Expr *ExprNode = C->getImplicitObjectArgument(); diff --git a/clang/lib/AST/IgnoreExpr.cpp b/clang/lib/AST/IgnoreExpr.cpp --- a/clang/lib/AST/IgnoreExpr.cpp +++ b/clang/lib/AST/IgnoreExpr.cpp @@ -127,3 +127,16 @@ return E; } + +Expr *clang::IgnoreImplicitConstructorSingleStep(Expr *E) { + 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)) + return A; + } + } + return E; +} diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -13,6 +13,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/IgnoreExpr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/TypeLoc.h" @@ -44,8 +45,13 @@ using namespace clang; +static Expr *IgnoreImplicit(Expr *E) { + return IgnoreExprNodes(E, IgnoreImplicitSingleStep, + IgnoreImplicitConstructorSingleStep); +} + LLVM_ATTRIBUTE_UNUSED -static bool isImplicitExpr(Expr *E) { return E->IgnoreImplicit() != E; } +static bool isImplicitExpr(Expr *E) { return IgnoreImplicit(E) != E; } namespace { /// Get start location of the Declarator from the TypeLoc. @@ -740,7 +746,7 @@ for (auto *D : DS->decls()) Builder.noticeDeclWithoutSemicolon(D); } else if (auto *E = dyn_cast_or_null(S)) { - return RecursiveASTVisitor::TraverseStmt(E->IgnoreImplicit()); + return RecursiveASTVisitor::TraverseStmt(IgnoreImplicit(E)); } return RecursiveASTVisitor::TraverseStmt(S); } @@ -1579,7 +1585,7 @@ void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) { if (!Child) return; - Child = Child->IgnoreImplicit(); + Child = IgnoreImplicit(Child); syntax::Tree *ChildNode = Mapping.find(Child); assert(ChildNode != nullptr); diff --git a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp --- a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp @@ -1745,19 +1745,15 @@ struct X { friend X operator+(X, const X&); }; -// FIXME: Remove additional `UnknownExpression` wrapping `x`. For that, ignore -// implicit copy constructor called on `x`. This should've been ignored already, -// as we `IgnoreImplicit` when traversing an `Stmt`. void test(X x, X y) { [[x + y]]; } )cpp", {R"txt( BinaryOperatorExpression Expression -|-UnknownExpression LeftHandSide -| `-IdExpression -| `-UnqualifiedId UnqualifiedId -| `-'x' +|-IdExpression LeftHandSide +| `-UnqualifiedId UnqualifiedId +| `-'x' |-'+' OperatorToken `-IdExpression RightHandSide `-UnqualifiedId UnqualifiedId @@ -3821,26 +3817,73 @@ )txt")); } +TEST_P(SyntaxTreeTest, InitDeclarator_Equal) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { S(int);}; +void test() { + [[S s = 1]]; +} +)cpp", + {R"txt( +SimpleDeclaration +|-'S' +`-SimpleDeclarator Declarator + |-'s' + |-'=' + `-IntegerLiteralExpression + `-'1' LiteralToken +)txt"})); +} + TEST_P(SyntaxTreeTest, InitDeclarator_Brace) { if (!GetParam().isCXX11OrLater()) { return; } - EXPECT_TRUE(treeDumpEqual( + EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( -int a {}; +struct S { S(int);}; +void test(){ + [[S s{1}]]; +} )cpp", - R"txt( -TranslationUnit Detached -`-SimpleDeclaration - |-'int' - |-SimpleDeclarator Declarator - | |-'a' - | `-UnknownExpression - | `-UnknownExpression - | |-'{' - | `-'}' - `-';' -)txt")); + {R"txt( +SimpleDeclaration +|-'S' +`-SimpleDeclarator Declarator + |-'s' + |-'{' + |-IntegerLiteralExpression + | `-'1' LiteralToken + `-'}' +)txt"})); +} + +TEST_P(SyntaxTreeTest, InitDeclarator_EqualBrace) { + if (!GetParam().isCXX11OrLater()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { S(int);}; +void test() { + [[S s = {1}]]; +} +)cpp", + {R"txt( +SimpleDeclaration +|-'S' +`-SimpleDeclarator Declarator + |-'s' + |-'=' + |-'{' + |-IntegerLiteralExpression + | `-'1' LiteralToken + `-'}' +)txt"})); } TEST_P(SyntaxTreeTest, InitDeclarator_Paren) { @@ -3858,12 +3901,60 @@ SimpleDeclaration |-'S' |-SimpleDeclarator Declarator -| `-UnknownExpression -| |-'s' -| |-'(' -| |-IntegerLiteralExpression -| | `-'1' LiteralToken -| `-')' +| |-'s' +| |-'(' +| |-IntegerLiteralExpression +| | `-'1' LiteralToken +| `-')' +`-';' +)txt"})); +} + +TEST_P(SyntaxTreeTest, ImplicitConversion_Argument) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct X { + X(int); +}; +void TakeX(const X&); +void test() { + [[TakeX(1)]]; +} +)cpp", + {R"txt( +CallExpression Expression +|-IdExpression Callee +| `-UnqualifiedId UnqualifiedId +| `-'TakeX' +|-'(' OpenParen +|-CallArguments Arguments +| `-IntegerLiteralExpression ListElement +| `-'1' LiteralToken +`-')' CloseParen +)txt"})); +} + +TEST_P(SyntaxTreeTest, ImplicitConversion_Return) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct X { + X(int); +}; +X CreateX(){ + [[return 1;]] +} +)cpp", + {R"txt( +ReturnStatement Statement +|-'return' IntroducerKeyword +|-IntegerLiteralExpression ReturnValue +| `-'1' LiteralToken `-';' )txt"})); }