forked from OSchip/llvm-project
[SyntaxTree] Ignore implicit non-leaf `CXXConstructExpr`
Differential Revision: https://reviews.llvm.org/D86699
This commit is contained in:
parent
83d82d1fb1
commit
2325d6b42f
|
@ -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);
|
||||||
|
|
|
@ -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"}));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue