[SyntaxTree] Ignore implicit non-leaf `CXXConstructExpr`

Differential Revision: https://reviews.llvm.org/D86699
This commit is contained in:
Eduardo Caldas 2020-08-27 09:43:14 +00:00
parent 83d82d1fb1
commit 2325d6b42f
2 changed files with 325 additions and 26 deletions

View File

@ -13,6 +13,7 @@
#include "clang/AST/DeclarationName.h" #include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h" #include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprCXX.h"
#include "clang/AST/IgnoreExpr.h"
#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h" #include "clang/AST/Stmt.h"
#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLoc.h"
@ -44,8 +45,28 @@
using namespace clang; using namespace clang;
// Ignores the implicit `CXXConstructExpr` for copy/move constructor calls
// generated by the compiler, as well as in implicit conversions like the one
// wrapping `1` in `X x = 1;`.
static Expr *IgnoreImplicitConstructorSingleStep(Expr *E) {
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 (C->getParenOrBraceRange().isInvalid())
return A;
}
}
return E;
}
static Expr *IgnoreImplicit(Expr *E) {
return IgnoreExprNodes(E, IgnoreImplicitSingleStep,
IgnoreImplicitConstructorSingleStep);
}
LLVM_ATTRIBUTE_UNUSED LLVM_ATTRIBUTE_UNUSED
static bool isImplicitExpr(Expr *E) { return E->IgnoreImplicit() != E; } static bool isImplicitExpr(Expr *E) { return IgnoreImplicit(E) != E; }
namespace { namespace {
/// Get start location of the Declarator from the TypeLoc. /// Get start location of the Declarator from the TypeLoc.
@ -740,7 +761,7 @@ public:
for (auto *D : DS->decls()) for (auto *D : DS->decls())
Builder.noticeDeclWithoutSemicolon(D); Builder.noticeDeclWithoutSemicolon(D);
} else if (auto *E = dyn_cast_or_null<Expr>(S)) { } else if (auto *E = dyn_cast_or_null<Expr>(S)) {
return RecursiveASTVisitor::TraverseStmt(E->IgnoreImplicit()); return RecursiveASTVisitor::TraverseStmt(IgnoreImplicit(E));
} }
return RecursiveASTVisitor::TraverseStmt(S); return RecursiveASTVisitor::TraverseStmt(S);
} }
@ -1579,7 +1600,7 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) { void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) {
if (!Child) if (!Child)
return; return;
Child = Child->IgnoreImplicit(); Child = IgnoreImplicit(Child);
syntax::Tree *ChildNode = Mapping.find(Child); syntax::Tree *ChildNode = Mapping.find(Child);
assert(ChildNode != nullptr); assert(ChildNode != nullptr);

View File

@ -1745,19 +1745,15 @@ TEST_P(SyntaxTreeTest, OverloadedOperator_Plus) {
struct X { struct X {
friend X operator+(X, const 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) { void test(X x, X y) {
[[x + y]]; [[x + y]];
} }
)cpp", )cpp",
{R"txt( {R"txt(
BinaryOperatorExpression Expression BinaryOperatorExpression Expression
|-UnknownExpression LeftHandSide |-IdExpression LeftHandSide
| `-IdExpression | `-UnqualifiedId UnqualifiedId
| `-UnqualifiedId UnqualifiedId | `-'x'
| `-'x'
|-'+' OperatorToken |-'+' OperatorToken
`-IdExpression RightHandSide `-IdExpression RightHandSide
`-UnqualifiedId UnqualifiedId `-UnqualifiedId UnqualifiedId
@ -3821,26 +3817,137 @@ TranslationUnit Detached
)txt")); )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) { TEST_P(SyntaxTreeTest, InitDeclarator_Brace) {
if (!GetParam().isCXX11OrLater()) { if (!GetParam().isCXX11OrLater()) {
return; return;
} }
EXPECT_TRUE(treeDumpEqual( EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp( R"cpp(
int a {}; struct S {
S();
S(int);
S(int, float);
};
void test(){
// FIXME: 's...' is a declarator and '{...}' is initializer
[[S s0{}]];
[[S s1{1}]];
[[S s2{1, 2.}]];
}
)cpp", )cpp",
R"txt( {R"txt(
TranslationUnit Detached SimpleDeclaration
`-SimpleDeclaration |-'S'
|-'int' `-SimpleDeclarator Declarator
|-SimpleDeclarator Declarator `-UnknownExpression
| |-'a' |-'s0'
| `-UnknownExpression |-'{'
| `-UnknownExpression `-'}'
| |-'{' )txt",
| `-'}' R"txt(
`-';' SimpleDeclaration
)txt")); |-'S'
`-SimpleDeclarator Declarator
`-UnknownExpression
|-'s1'
|-'{'
|-IntegerLiteralExpression
| `-'1' LiteralToken
`-'}'
)txt",
R"txt(
SimpleDeclaration
|-'S'
`-SimpleDeclarator Declarator
`-UnknownExpression
|-'s2'
|-'{'
|-IntegerLiteralExpression
| `-'1' LiteralToken
|-','
|-FloatingLiteralExpression
| `-'2.' LiteralToken
`-'}'
)txt"}));
}
TEST_P(SyntaxTreeTest, InitDeclarator_EqualBrace) {
if (!GetParam().isCXX11OrLater()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct S {
S();
S(int);
S(int, float);
};
void test() {
// FIXME: '= {...}' is initializer
[[S s0 = {}]];
[[S s1 = {1}]];
[[S s2 = {1, 2.}]];
}
)cpp",
{R"txt(
SimpleDeclaration
|-'S'
`-SimpleDeclarator Declarator
|-'s0'
|-'='
`-UnknownExpression
|-'{'
`-'}'
)txt",
R"txt(
SimpleDeclaration
|-'S'
`-SimpleDeclarator Declarator
|-'s1'
|-'='
`-UnknownExpression
|-'{'
|-IntegerLiteralExpression
| `-'1' LiteralToken
`-'}'
)txt",
R"txt(
SimpleDeclaration
|-'S'
`-SimpleDeclarator Declarator
|-'s2'
|-'='
`-UnknownExpression
|-'{'
|-IntegerLiteralExpression
| `-'1' LiteralToken
|-','
|-FloatingLiteralExpression
| `-'2.' LiteralToken
`-'}'
)txt"}));
} }
TEST_P(SyntaxTreeTest, InitDeclarator_Paren) { TEST_P(SyntaxTreeTest, InitDeclarator_Paren) {
@ -3851,19 +3958,190 @@ TEST_P(SyntaxTreeTest, InitDeclarator_Paren) {
R"cpp( R"cpp(
struct S { struct S {
S(int); S(int);
S(int, float);
}; };
[[S s(1);]] // FIXME: 's...' is a declarator and '(...)' is initializer
[[S s1(1);]]
[[S s2(1, 2.);]]
)cpp", )cpp",
{R"txt( {R"txt(
SimpleDeclaration SimpleDeclaration
|-'S' |-'S'
|-SimpleDeclarator Declarator |-SimpleDeclarator Declarator
| `-UnknownExpression | `-UnknownExpression
| |-'s' | |-'s1'
| |-'(' | |-'('
| |-IntegerLiteralExpression | |-IntegerLiteralExpression
| | `-'1' LiteralToken | | `-'1' LiteralToken
| `-')' | `-')'
`-';'
)txt",
R"txt(
SimpleDeclaration
|-'S'
|-SimpleDeclarator Declarator
| `-UnknownExpression
| |-'s2'
| |-'('
| |-IntegerLiteralExpression
| | `-'1' LiteralToken
| |-','
| |-FloatingLiteralExpression
| | `-'2.' 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"}));
}
TEST_P(SyntaxTreeTest, ConstructorCall_ZeroArguments) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct X {
X();
};
X test() {
[[return X();]]
}
)cpp",
{R"txt(
ReturnStatement Statement
|-'return' IntroducerKeyword
|-UnknownExpression ReturnValue
| |-'X'
| |-'('
| `-')'
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, ConstructorCall_OneArgument) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct X {
X(int);
};
X test() {
// FIXME: Remove `UnknownExpression` due to implicit `CXXFunctionalCastExpr`
[[return X(1);]]
}
)cpp",
{R"txt(
ReturnStatement Statement
|-'return' IntroducerKeyword
|-UnknownExpression ReturnValue
| `-UnknownExpression
| |-'X'
| |-'('
| |-IntegerLiteralExpression
| | `-'1' LiteralToken
| `-')'
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, ConstructorCall_MultipleArguments) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct X {
X(int, char);
};
X test() {
[[return X(1, '2');]]
}
)cpp",
{R"txt(
ReturnStatement Statement
|-'return' IntroducerKeyword
|-UnknownExpression ReturnValue
| |-'X'
| |-'('
| |-IntegerLiteralExpression
| | `-'1' LiteralToken
| |-','
| |-CharacterLiteralExpression
| | `-''2'' LiteralToken
| `-')'
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, TypeConversion_FunctionalNotation) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
float test() {
[[return float(1);]]
}
)cpp",
{R"txt(
ReturnStatement Statement
|-'return' IntroducerKeyword
|-UnknownExpression ReturnValue
| |-'float'
| |-'('
| |-IntegerLiteralExpression
| | `-'1' LiteralToken
| `-')'
`-';' `-';'
)txt"})); )txt"}));
} }