Skip to content

Commit

Permalink
[SyntaxTree] Fix crash on functions with default arguments.
Browse files Browse the repository at this point in the history
* Do not visit `CXXDefaultArgExpr`
* To build `CallArguments` nodes, just go through non-default arguments

Differential Revision: https://reviews.llvm.org/D87249
  • Loading branch information
Eduardo Caldas committed Sep 8, 2020
1 parent 134455a commit f5087d5
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 1 deletion.
15 changes: 14 additions & 1 deletion clang/lib/Tooling/Syntax/BuildTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ struct GetStartLoc : TypeLocVisitor<GetStartLoc, SourceLocation> {
};
} // namespace

static CallExpr::arg_range dropDefaultArgs(CallExpr::arg_range Args) {
auto firstDefaultArg = std::find_if(Args.begin(), Args.end(), [](auto it) {
return isa<CXXDefaultArgExpr>(it);
});
return llvm::make_range(Args.begin(), firstDefaultArg);
}

static syntax::NodeKind getOperatorNodeKind(const CXXOperatorCallExpr &E) {
switch (E.getOperator()) {
// Comparison
Expand Down Expand Up @@ -1111,7 +1118,11 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
return true;
}

syntax::CallArguments *buildCallArguments(CallExpr::arg_range Args) {
/// Builds `CallArguments` syntax node from arguments that appear in source
/// code, i.e. not default arguments.
syntax::CallArguments *
buildCallArguments(CallExpr::arg_range ArgsAndDefaultArgs) {
auto Args = dropDefaultArgs(ArgsAndDefaultArgs);
for (const auto &Arg : Args) {
Builder.markExprChild(Arg, syntax::NodeRole::ListElement);
const auto *DelimiterToken =
Expand Down Expand Up @@ -1233,6 +1244,8 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
}
}

bool WalkUpFromCXXDefaultArgExpr(CXXDefaultArgExpr *S) { return true; }

bool WalkUpFromNamespaceDecl(NamespaceDecl *S) {
auto Tokens = Builder.getDeclarationRange(S);
if (Tokens.front().kind() == tok::coloncolon) {
Expand Down
195 changes: 195 additions & 0 deletions clang/unittests/Tooling/Syntax/BuildTreeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2733,6 +2733,54 @@ CallExpression Expression
)txt"}));
}

TEST_P(SyntaxTreeTest, CallExpression_DefaultArguments) {
if (!GetParam().isCXX11OrLater()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
void f(int i = 1, char c = '2');
void test() {
[[f()]];
[[f(1)]];
[[f(1, '2')]];
}
)cpp",
{R"txt(
CallExpression Expression
|-IdExpression Callee
| `-UnqualifiedId UnqualifiedId
| `-'f'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
CallExpression Expression
|-IdExpression Callee
| `-UnqualifiedId UnqualifiedId
| `-'f'
|-'(' OpenParen
|-CallArguments Arguments
| `-IntegerLiteralExpression ListElement
| `-'1' LiteralToken
`-')' CloseParen
)txt",
R"txt(
CallExpression Expression
|-IdExpression Callee
| `-UnqualifiedId UnqualifiedId
| `-'f'
|-'(' OpenParen
|-CallArguments Arguments
| |-IntegerLiteralExpression ListElement
| | `-'1' LiteralToken
| |-',' ListDelimiter
| `-CharacterLiteralExpression ListElement
| `-''2'' LiteralToken
`-')' CloseParen
)txt"}));
}

TEST_P(SyntaxTreeTest, MultipleDeclaratorsGrouping) {
EXPECT_TRUE(treeDumpEqual(
R"cpp(
Expand Down Expand Up @@ -3986,6 +4034,56 @@ SimpleDeclaration
)txt"}));
}

TEST_P(SyntaxTreeTest, InitDeclarator_Paren_DefaultArguments) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct S {
S(int i = 1, float = 2.);
};
[[S s0;]]
// FIXME: 's...' is a declarator and '(...)' is initializer
[[S s1(1);]]
[[S s2(1, 2.);]]
)cpp",
{R"txt(
SimpleDeclaration
|-'S'
|-SimpleDeclarator Declarator
| `-'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, ImplicitConversion_Argument) {
if (!GetParam().isCXX()) {
return;
Expand Down Expand Up @@ -4114,6 +4212,48 @@ ReturnStatement Statement
)txt"}));
}

TEST_P(SyntaxTreeTest, ConstructorCall_DefaultArguments) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct X {
X(int i = 1, char c = '2');
};
X test() {
auto x0 = [[X()]];
auto x1 = [[X(1)]];
auto x2 = [[X(1, '2')]];
}
)cpp",
{R"txt(
UnknownExpression
|-'X'
|-'('
`-')'
)txt",
R"txt(
UnknownExpression
|-'X'
|-'('
|-IntegerLiteralExpression
| `-'1' LiteralToken
`-')'
)txt",
R"txt(
UnknownExpression
|-'X'
|-'('
|-IntegerLiteralExpression
| `-'1' LiteralToken
|-','
|-CharacterLiteralExpression
| `-''2'' LiteralToken
`-')'
)txt"}));
}

TEST_P(SyntaxTreeTest, TypeConversion_FunctionalNotation) {
if (!GetParam().isCXX()) {
return;
Expand Down Expand Up @@ -4375,6 +4515,61 @@ TranslationUnit Detached
)txt"));
}

TEST_P(SyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Default_One) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
int func1([[int a = 1]]);
)cpp",
{R"txt(
ParameterDeclarationList Parameters
`-SimpleDeclaration ListElement
|-'int'
`-SimpleDeclarator Declarator
|-'a'
|-'='
`-IntegerLiteralExpression
`-'1' LiteralToken
)txt"}));
}

TEST_P(SyntaxTreeTest,
ParametersAndQualifiers_InFreeFunctions_Default_Multiple) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
int func2([[int *ap, int a = 1, char c = '2']]);
)cpp",
{R"txt(
ParameterDeclarationList Parameters
|-SimpleDeclaration ListElement
| |-'int'
| `-SimpleDeclarator Declarator
| |-'*'
| `-'ap'
|-',' ListDelimiter
|-SimpleDeclaration ListElement
| |-'int'
| `-SimpleDeclarator Declarator
| |-'a'
| |-'='
| `-IntegerLiteralExpression
| `-'1' LiteralToken
|-',' ListDelimiter
`-SimpleDeclaration ListElement
|-'char'
`-SimpleDeclarator Declarator
|-'c'
|-'='
`-CharacterLiteralExpression
`-''2'' LiteralToken
)txt"}));
}

TEST_P(SyntaxTreeTest,
ParametersAndQualifiers_InVariadicFunctionTemplate_ParameterPack) {
if (!GetParam().isCXX11OrLater() || GetParam().hasDelayedTemplateParsing()) {
Expand Down

0 comments on commit f5087d5

Please sign in to comment.