[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/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,28 @@
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
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 +761,7 @@ public:
for (auto *D : DS->decls())
Builder.noticeDeclWithoutSemicolon(D);
} else if (auto *E = dyn_cast_or_null<Expr>(S)) {
return RecursiveASTVisitor::TraverseStmt(E->IgnoreImplicit());
return RecursiveASTVisitor::TraverseStmt(IgnoreImplicit(E));
}
return RecursiveASTVisitor::TraverseStmt(S);
}
@ -1579,7 +1600,7 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
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);

View File

@ -1745,19 +1745,15 @@ TEST_P(SyntaxTreeTest, OverloadedOperator_Plus) {
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,137 @@ TranslationUnit Detached
)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();
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",
R"txt(
TranslationUnit Detached
`-SimpleDeclaration
|-'int'
|-SimpleDeclarator Declarator
| |-'a'
| `-UnknownExpression
| `-UnknownExpression
| |-'{'
| `-'}'
`-';'
)txt"));
{R"txt(
SimpleDeclaration
|-'S'
`-SimpleDeclarator Declarator
`-UnknownExpression
|-'s0'
|-'{'
`-'}'
)txt",
R"txt(
SimpleDeclaration
|-'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) {
@ -3851,19 +3958,190 @@ TEST_P(SyntaxTreeTest, InitDeclarator_Paren) {
R"cpp(
struct S {
S(int);
S(int, float);
};
[[S s(1);]]
// FIXME: 's...' is a declarator and '(...)' is initializer
[[S s1(1);]]
[[S s2(1, 2.);]]
)cpp",
{R"txt(
SimpleDeclaration
|-'S'
|-SimpleDeclarator Declarator
| `-UnknownExpression
| |-'s'
| |-'s1'
| |-'('
| |-IntegerLiteralExpression
| | `-'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"}));
}