[SyntaxTree] Add support for `CallExpression`

* Generate `CallExpression` syntax node for all semantic nodes inheriting from
`CallExpr` with call-expression syntax - except `CUDAKernelCallExpr`.
* Implement all the accessors
* Arguments of `CallExpression` have their own syntax node which is based on
the `List` base API

Differential Revision: https://reviews.llvm.org/D86544
This commit is contained in:
Eduardo Caldas 2020-08-25 07:47:52 +00:00
parent 1f90d45b9e
commit 2de2ca348d
4 changed files with 703 additions and 103 deletions

View File

@ -57,6 +57,7 @@ enum class NodeKind : uint16_t {
IdExpression,
MemberExpression,
ThisExpression,
CallExpression,
// Statements.
UnknownStatement,
@ -103,7 +104,8 @@ enum class NodeKind : uint16_t {
GlobalNameSpecifier,
DecltypeNameSpecifier,
IdentifierNameSpecifier,
SimpleTemplateNameSpecifier
SimpleTemplateNameSpecifier,
CallArguments
};
/// For debugging purposes.
raw_ostream &operator<<(raw_ostream &OS, NodeKind K);
@ -179,6 +181,8 @@ enum class NodeRole : uint8_t {
MemberExpression_object,
MemberExpression_accessToken,
MemberExpression_member,
CallExpression_callee,
CallExpression_arguments,
};
/// For debugging purposes.
raw_ostream &operator<<(raw_ostream &OS, NodeRole R);
@ -324,6 +328,37 @@ public:
Leaf *thisKeyword();
};
/// Models arguments of a function call.
/// call-arguments:
/// delimited_list(expression, ',')
/// Note: This construct is a simplification of the grammar rule for
/// `expression-list`, that is used in the definition of `call-expression`
class CallArguments final : public List {
public:
CallArguments() : List(NodeKind::CallArguments) {}
static bool classof(const Node *N) {
return N->kind() <= NodeKind::CallArguments;
}
std::vector<Expression *> arguments();
std::vector<List::ElementAndDelimiter<Expression>> argumentsAndCommas();
};
/// A function call. C++ [expr.call]
/// call-expression:
/// expression '(' call-arguments ')'
/// e.g `f(1, '2')` or `this->Base::f()`
class CallExpression final : public Expression {
public:
CallExpression() : Expression(NodeKind::CallExpression) {}
static bool classof(const Node *N) {
return N->kind() == NodeKind::CallExpression;
}
Expression *callee();
Leaf *openParen();
CallArguments *arguments();
Leaf *closeParen();
};
/// Models a parenthesized expression `(E)`. C++ [expr.prim.paren]
/// e.g. `(3 + 2)` in `a = 1 + (3 + 2);`
class ParenExpression final : public Expression {

View File

@ -184,10 +184,11 @@ static syntax::NodeKind getOperatorNodeKind(const CXXOperatorCallExpr &E) {
case OO_Array_New:
case OO_Array_Delete:
case OO_Coawait:
case OO_Call:
case OO_Subscript:
case OO_Arrow:
return syntax::NodeKind::UnknownExpression;
case OO_Call:
return syntax::NodeKind::CallExpression;
case OO_Conditional: // not overloadable
case NUM_OVERLOADED_OPERATORS:
case OO_None:
@ -1042,6 +1043,46 @@ public:
return true;
}
syntax::CallArguments *buildCallArguments(CallExpr::arg_range Args) {
for (const auto &Arg : Args) {
Builder.markExprChild(Arg, syntax::NodeRole::List_element);
const auto *DelimiterToken =
std::next(Builder.findToken(Arg->getEndLoc()));
if (DelimiterToken->kind() == clang::tok::TokenKind::comma)
Builder.markChildToken(DelimiterToken,
syntax::NodeRole::List_delimiter);
}
auto *Arguments = new (allocator()) syntax::CallArguments;
if (!Args.empty())
Builder.foldNode(Builder.getRange((*Args.begin())->getBeginLoc(),
(*(Args.end() - 1))->getEndLoc()),
Arguments, nullptr);
return Arguments;
}
bool WalkUpFromCallExpr(CallExpr *S) {
Builder.markExprChild(S->getCallee(),
syntax::NodeRole::CallExpression_callee);
const auto *LParenToken =
std::next(Builder.findToken(S->getCallee()->getEndLoc()));
// FIXME: Assert that `LParenToken` is indeed a `l_paren` once we have fixed
// the test on decltype desctructors.
if (LParenToken->kind() == clang::tok::l_paren)
Builder.markChildToken(LParenToken, syntax::NodeRole::OpenParen);
Builder.markChild(buildCallArguments(S->arguments()),
syntax::NodeRole::CallExpression_arguments);
Builder.markChildToken(S->getRParenLoc(), syntax::NodeRole::CloseParen);
Builder.foldNode(Builder.getRange(S->getSourceRange()),
new (allocator()) syntax::CallExpression, S);
return true;
}
bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *S) {
// To construct a syntax tree of the same shape for calls to built-in and
// user-defined operators, ignore the `DeclRefExpr` that refers to the
@ -1100,8 +1141,29 @@ public:
new (allocator()) syntax::PostfixUnaryOperatorExpression,
S);
return true;
case syntax::NodeKind::CallExpression: {
Builder.markExprChild(S->getArg(0),
syntax::NodeRole::CallExpression_callee);
const auto *LParenToken =
std::next(Builder.findToken(S->getArg(0)->getEndLoc()));
// FIXME: Assert that `LParenToken` is indeed a `l_paren` once we have
// fixed the test on decltype desctructors.
if (LParenToken->kind() == clang::tok::l_paren)
Builder.markChildToken(LParenToken, syntax::NodeRole::OpenParen);
Builder.markChild(buildCallArguments(CallExpr::arg_range(
S->arg_begin() + 1, S->arg_end())),
syntax::NodeRole::CallExpression_arguments);
Builder.markChildToken(S->getRParenLoc(), syntax::NodeRole::CloseParen);
Builder.foldNode(Builder.getRange(S->getSourceRange()),
new (allocator()) syntax::CallExpression, S);
return true;
}
case syntax::NodeKind::UnknownExpression:
return RecursiveASTVisitor::WalkUpFromCXXOperatorCallExpr(S);
return WalkUpFromExpr(S);
default:
llvm_unreachable("getOperatorNodeKind() does not return this value");
}

View File

@ -52,6 +52,8 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeKind K) {
return OS << "UnqualifiedId";
case NodeKind::IdExpression:
return OS << "IdExpression";
case NodeKind::CallExpression:
return OS << "CallExpression";
case NodeKind::UnknownStatement:
return OS << "UnknownStatement";
case NodeKind::DeclarationStatement:
@ -130,6 +132,8 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeKind K) {
return OS << "NestedNameSpecifier";
case NodeKind::MemberExpression:
return OS << "MemberExpression";
case NodeKind::CallArguments:
return OS << "CallArguments";
}
llvm_unreachable("unknown node kind");
}
@ -212,6 +216,10 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeRole R) {
return OS << "MemberExpression_accessToken";
case syntax::NodeRole::MemberExpression_member:
return OS << "MemberExpression_member";
case syntax::NodeRole::CallExpression_callee:
return OS << "CallExpression_callee";
case syntax::NodeRole::CallExpression_arguments:
return OS << "CallExpression_arguments";
}
llvm_unreachable("invalid role");
}
@ -240,6 +248,27 @@ syntax::NestedNameSpecifier::specifiersAndDoubleColons() {
return Children;
}
std::vector<syntax::Expression *> syntax::CallArguments::arguments() {
auto ArgumentsAsNodes = getElementsAsNodes();
std::vector<syntax::Expression *> Children;
for (const auto &ArgumentAsNode : ArgumentsAsNodes) {
Children.push_back(llvm::cast<syntax::Expression>(ArgumentAsNode));
}
return Children;
}
std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>>
syntax::CallArguments::argumentsAndCommas() {
auto ArgumentsAsNodesAndCommas = getElementsAsNodesAndDelimiters();
std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>> Children;
for (const auto &ArgumentAsNodeAndComma : ArgumentsAsNodesAndCommas) {
Children.push_back(
{llvm::cast<syntax::Expression>(ArgumentAsNodeAndComma.element),
ArgumentAsNodeAndComma.delimiter});
}
return Children;
}
syntax::Expression *syntax::MemberExpression::object() {
return cast_or_null<syntax::Expression>(
findChild(syntax::NodeRole::MemberExpression_object));
@ -322,6 +351,24 @@ syntax::Expression *syntax::BinaryOperatorExpression::rhs() {
findChild(syntax::NodeRole::BinaryOperatorExpression_rightHandSide));
}
syntax::Expression *syntax::CallExpression::callee() {
return cast_or_null<syntax::Expression>(
findChild(syntax::NodeRole::CallExpression_callee));
}
syntax::Leaf *syntax::CallExpression::openParen() {
return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::OpenParen));
}
syntax::CallArguments *syntax::CallExpression::arguments() {
return cast_or_null<syntax::CallArguments>(
findChild(syntax::NodeRole::CallExpression_arguments));
}
syntax::Leaf *syntax::CallExpression::closeParen() {
return cast_or_null<syntax::Leaf>(findChild(syntax::NodeRole::CloseParen));
}
syntax::Leaf *syntax::SwitchStatement::switchKeyword() {
return cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));

View File

@ -316,12 +316,12 @@ TranslationUnit Detached
`-CompoundStatement
|-'{' OpenParen
|-ExpressionStatement CompoundStatement_statement
| |-UnknownExpression ExpressionStatement_expression
| | |-IdExpression
| |-CallExpression ExpressionStatement_expression
| | |-IdExpression CallExpression_callee
| | | `-UnqualifiedId IdExpression_id
| | | `-'test'
| | |-'('
| | `-')'
| | |-'(' OpenParen
| | `-')' CloseParen
| `-';'
|-IfStatement CompoundStatement_statement
| |-'if' IntroducerKeyword
@ -330,21 +330,21 @@ TranslationUnit Detached
| | `-'1' LiteralToken
| |-')'
| |-ExpressionStatement IfStatement_thenStatement
| | |-UnknownExpression ExpressionStatement_expression
| | | |-IdExpression
| | |-CallExpression ExpressionStatement_expression
| | | |-IdExpression CallExpression_callee
| | | | `-UnqualifiedId IdExpression_id
| | | | `-'test'
| | | |-'('
| | | `-')'
| | | |-'(' OpenParen
| | | `-')' CloseParen
| | `-';'
| |-'else' IfStatement_elseKeyword
| `-ExpressionStatement IfStatement_elseStatement
| |-UnknownExpression ExpressionStatement_expression
| | |-IdExpression
| |-CallExpression ExpressionStatement_expression
| | |-IdExpression CallExpression_callee
| | | `-UnqualifiedId IdExpression_id
| | | `-'test'
| | |-'('
| | `-')'
| | |-'(' OpenParen
| | `-')' CloseParen
| `-';'
`-'}' CloseParen
)txt"));
@ -378,20 +378,21 @@ void test(X x) {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| `-UnqualifiedId IdExpression_id
| |-'operator'
| `-'+'
|-'('
|-IdExpression
| `-UnqualifiedId IdExpression_id
| `-'x'
|-','
|-IdExpression
| `-UnqualifiedId IdExpression_id
| `-'x'
`-')'
|-'(' OpenParen
|-CallArguments CallExpression_arguments
| |-IdExpression List_element
| | `-UnqualifiedId IdExpression_id
| | `-'x'
| |-',' List_delimiter
| `-IdExpression List_element
| `-UnqualifiedId IdExpression_id
| `-'x'
`-')' CloseParen
)txt"}));
}
@ -409,8 +410,8 @@ void test(X x) {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'x'
@ -419,8 +420,8 @@ UnknownExpression ExpressionStatement_expression
| `-UnqualifiedId IdExpression_id
| |-'operator'
| `-'int'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -436,16 +437,17 @@ void test() {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| `-UnqualifiedId IdExpression_id
| |-'operator'
| |-'""'
| `-'_w'
|-'('
|-CharacterLiteralExpression
| `-''1'' LiteralToken
`-')'
|-'(' OpenParen
|-CallArguments CallExpression_arguments
| `-CharacterLiteralExpression List_element
| `-''1'' LiteralToken
`-')' CloseParen
)txt"}));
}
@ -461,8 +463,8 @@ void test(X x) {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'x'
@ -471,8 +473,8 @@ UnknownExpression ExpressionStatement_expression
| `-UnqualifiedId IdExpression_id
| |-'~'
| `-'X'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -492,8 +494,8 @@ void test(X x) {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'x'
@ -506,7 +508,7 @@ UnknownExpression ExpressionStatement_expression
|-'x'
|-')'
|-'('
`-')'
`-')' CloseParen
)txt"}));
}
@ -523,15 +525,15 @@ void test() {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| `-UnqualifiedId IdExpression_id
| |-'f'
| |-'<'
| |-'int'
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -639,8 +641,8 @@ void test(S s) {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| |-NestedNameSpecifier IdExpression_qualifier
| | |-DecltypeNameSpecifier List_element
| | | |-'decltype'
@ -652,8 +654,8 @@ UnknownExpression ExpressionStatement_expression
| | `-'::' List_delimiter
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -673,8 +675,8 @@ void test() {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| |-NestedNameSpecifier IdExpression_qualifier
| | |-IdentifierNameSpecifier List_element
| | | `-'S'
@ -684,12 +686,12 @@ UnknownExpression ExpressionStatement_expression
| |-'<'
| |-'int'
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| |-NestedNameSpecifier IdExpression_qualifier
| | |-IdentifierNameSpecifier List_element
| | | `-'S'
@ -700,8 +702,8 @@ UnknownExpression ExpressionStatement_expression
| |-'<'
| |-'int'
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -723,8 +725,8 @@ void test() {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| |-NestedNameSpecifier IdExpression_qualifier
| | |-'::' List_delimiter
| | |-IdentifierNameSpecifier List_element
@ -743,8 +745,8 @@ UnknownExpression ExpressionStatement_expression
| |-'<'
| |-'int'
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -767,8 +769,8 @@ void test() {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| |-NestedNameSpecifier IdExpression_qualifier
| | |-IdentifierNameSpecifier List_element
| | | `-'T'
@ -782,12 +784,12 @@ UnknownExpression ExpressionStatement_expression
| | `-'::' List_delimiter
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| |-NestedNameSpecifier IdExpression_qualifier
| | |-IdentifierNameSpecifier List_element
| | | `-'T'
@ -797,12 +799,12 @@ UnknownExpression ExpressionStatement_expression
| | `-'::' List_delimiter
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
UnknownExpression ExpressionStatement_expression
|-IdExpression
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| |-NestedNameSpecifier IdExpression_qualifier
| | |-IdentifierNameSpecifier List_element
| | | `-'T'
@ -814,8 +816,8 @@ UnknownExpression ExpressionStatement_expression
| |-IntegerLiteralExpression
| | `-'0' LiteralToken
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -2060,8 +2062,8 @@ void test(S s) {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'s'
@ -2070,8 +2072,8 @@ UnknownExpression ExpressionStatement_expression
| `-UnqualifiedId IdExpression_id
| |-'operator'
| `-'!'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -2126,8 +2128,8 @@ void test(S* sp){
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'sp'
@ -2138,8 +2140,8 @@ UnknownExpression ExpressionStatement_expression
| |-'<'
| |-'int'
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -2158,8 +2160,8 @@ void test(S s){
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'s'
@ -2171,8 +2173,8 @@ UnknownExpression ExpressionStatement_expression
| |-'<'
| |-'int'
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -2192,8 +2194,8 @@ void test(S s){
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'s'
@ -2205,12 +2207,12 @@ UnknownExpression ExpressionStatement_expression
| | `-'::' List_delimiter
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'s'
@ -2224,8 +2226,8 @@ UnknownExpression ExpressionStatement_expression
| `-UnqualifiedId IdExpression_id
| |-'~'
| `-'S'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
@ -2253,10 +2255,10 @@ void test(S* sp) {
}
)cpp",
{R"txt(
UnknownExpression ExpressionStatement_expression
|-MemberExpression
| |-UnknownExpression MemberExpression_object
| | |-MemberExpression
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-CallExpression MemberExpression_object
| | |-MemberExpression CallExpression_callee
| | | |-IdExpression MemberExpression_object
| | | | `-UnqualifiedId IdExpression_id
| | | | `-'sp'
@ -2264,8 +2266,8 @@ UnknownExpression ExpressionStatement_expression
| | | `-IdExpression MemberExpression_member
| | | `-UnqualifiedId IdExpression_id
| | | `-'getU'
| | |-'('
| | `-')'
| | |-'(' OpenParen
| | `-')' CloseParen
| |-'.' MemberExpression_accessToken
| `-IdExpression MemberExpression_member
| |-NestedNameSpecifier IdExpression_qualifier
@ -2282,8 +2284,462 @@ UnknownExpression ExpressionStatement_expression
| |-'<'
| |-'int'
| `-'>'
|-'('
`-')'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Callee_Member) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct S{
void f();
};
void test(S s) {
[[s.f()]];
}
)cpp",
{R"txt(
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-IdExpression MemberExpression_object
| | `-UnqualifiedId IdExpression_id
| | `-'s'
| |-'.' MemberExpression_accessToken
| `-IdExpression MemberExpression_member
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Callee_OperatorParens) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct S {
void operator()();
};
void test(S s) {
[[s()]];
}
)cpp",
{R"txt(
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| `-UnqualifiedId IdExpression_id
| `-'s'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Callee_OperatorParensChaining) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct S {
S operator()();
};
void test(S s) {
[[s()()]];
}
)cpp",
{R"txt(
CallExpression ExpressionStatement_expression
|-CallExpression CallExpression_callee
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'s'
| |-'(' OpenParen
| `-')' CloseParen
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Callee_MemberWithThis) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct Base {
void f();
};
struct S: public Base {
void f();
void test() {
[[this->f()]];
[[f()]];
[[this->Base::f()]];
}
};
)cpp",
{R"txt(
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-ThisExpression MemberExpression_object
| | `-'this' IntroducerKeyword
| |-'->' MemberExpression_accessToken
| `-IdExpression MemberExpression_member
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
CallExpression ExpressionStatement_expression
|-MemberExpression CallExpression_callee
| |-ThisExpression MemberExpression_object
| | `-'this' IntroducerKeyword
| |-'->' MemberExpression_accessToken
| `-IdExpression MemberExpression_member
| |-NestedNameSpecifier IdExpression_qualifier
| | |-IdentifierNameSpecifier List_element
| | | `-'Base'
| | `-'::' List_delimiter
| `-UnqualifiedId IdExpression_id
| `-'f'
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Callee_FunctionPointer) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
void (*pf)();
void test() {
[[pf()]];
[[(*pf)()]];
}
)cpp",
{R"txt(
CallExpression ExpressionStatement_expression
|-IdExpression CallExpression_callee
| `-UnqualifiedId IdExpression_id
| `-'pf'
|-'(' OpenParen
`-')' CloseParen
)txt",
R"txt(
CallExpression ExpressionStatement_expression
|-ParenExpression CallExpression_callee
| |-'(' OpenParen
| |-PrefixUnaryOperatorExpression ParenExpression_subExpression
| | |-'*' OperatorExpression_operatorToken
| | `-IdExpression UnaryOperatorExpression_operand
| | `-UnqualifiedId IdExpression_id
| | `-'pf'
| `-')' CloseParen
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Callee_MemberFunctionPointer) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct S {
void f();
};
void test(S s) {
void (S::*pmf)();
pmf = &S::f;
[[(s.*pmf)()]];
}
)cpp",
{R"txt(
CallExpression ExpressionStatement_expression
|-ParenExpression CallExpression_callee
| |-'(' OpenParen
| |-BinaryOperatorExpression ParenExpression_subExpression
| | |-IdExpression BinaryOperatorExpression_leftHandSide
| | | `-UnqualifiedId IdExpression_id
| | | `-'s'
| | |-'.*' OperatorExpression_operatorToken
| | `-IdExpression BinaryOperatorExpression_rightHandSide
| | `-UnqualifiedId IdExpression_id
| | `-'pmf'
| `-')' CloseParen
|-'(' OpenParen
`-')' CloseParen
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_Zero) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
void f();
void test() {
[[f();]]
}
)cpp",
{R"txt(
ExpressionStatement CompoundStatement_statement
|-CallExpression ExpressionStatement_expression
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'f'
| |-'(' OpenParen
| `-')' CloseParen
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_One) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
void f(int);
void test() {
[[f(1);]]
}
)cpp",
{R"txt(
ExpressionStatement CompoundStatement_statement
|-CallExpression ExpressionStatement_expression
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'f'
| |-'(' OpenParen
| |-CallArguments CallExpression_arguments
| | `-IntegerLiteralExpression List_element
| | `-'1' LiteralToken
| `-')' CloseParen
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_Multiple) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
void f(int, char, float);
void test() {
[[f(1, '2', 3.);]]
}
)cpp",
{R"txt(
ExpressionStatement CompoundStatement_statement
|-CallExpression ExpressionStatement_expression
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'f'
| |-'(' OpenParen
| |-CallArguments CallExpression_arguments
| | |-IntegerLiteralExpression List_element
| | | `-'1' LiteralToken
| | |-',' List_delimiter
| | |-CharacterLiteralExpression List_element
| | | `-''2'' LiteralToken
| | |-',' List_delimiter
| | `-FloatingLiteralExpression List_element
| | `-'3.' LiteralToken
| `-')' CloseParen
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_Assignment) {
if (!GetParam().isCXX()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
void f(int);
void test(int a) {
[[f(a = 1);]]
}
)cpp",
{R"txt(
ExpressionStatement CompoundStatement_statement
|-CallExpression ExpressionStatement_expression
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'f'
| |-'(' OpenParen
| |-CallArguments CallExpression_arguments
| | `-BinaryOperatorExpression List_element
| | |-IdExpression BinaryOperatorExpression_leftHandSide
| | | `-UnqualifiedId IdExpression_id
| | | `-'a'
| | |-'=' OperatorExpression_operatorToken
| | `-IntegerLiteralExpression BinaryOperatorExpression_rightHandSide
| | `-'1' LiteralToken
| `-')' CloseParen
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_BracedInitList_Empty) {
if (!GetParam().isCXX11OrLater()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
void f(int[]);
void test() {
[[f({});]]
}
)cpp",
{R"txt(
ExpressionStatement CompoundStatement_statement
|-CallExpression ExpressionStatement_expression
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'f'
| |-'(' OpenParen
| |-CallArguments CallExpression_arguments
| | `-UnknownExpression List_element
| | `-UnknownExpression
| | |-'{'
| | `-'}'
| `-')' CloseParen
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_BracedInitList_Simple) {
if (!GetParam().isCXX11OrLater()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct TT {};
struct T{
int a;
TT b;
};
void f(T);
void test() {
[[f({1, {}});]]
}
)cpp",
{R"txt(
ExpressionStatement CompoundStatement_statement
|-CallExpression ExpressionStatement_expression
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'f'
| |-'(' OpenParen
| |-CallArguments CallExpression_arguments
| | `-UnknownExpression List_element
| | `-UnknownExpression
| | |-'{'
| | |-IntegerLiteralExpression
| | | `-'1' LiteralToken
| | |-','
| | |-UnknownExpression
| | | `-UnknownExpression
| | | |-'{'
| | | `-'}'
| | `-'}'
| `-')' CloseParen
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_BracedInitList_Designated) {
if (!GetParam().isCXX11OrLater()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
struct TT {};
struct T{
int a;
TT b;
};
void f(T);
void test() {
[[f({.a = 1, .b {}});]]
}
)cpp",
{R"txt(
ExpressionStatement CompoundStatement_statement
|-CallExpression ExpressionStatement_expression
| |-IdExpression CallExpression_callee
| | `-UnqualifiedId IdExpression_id
| | `-'f'
| |-'(' OpenParen
| |-CallArguments CallExpression_arguments
| | `-UnknownExpression List_element
| | `-UnknownExpression
| | |-'{'
| | |-UnknownExpression
| | | |-'.'
| | | |-'a'
| | | |-'='
| | | `-IntegerLiteralExpression
| | | `-'1' LiteralToken
| | |-','
| | |-UnknownExpression
| | | |-'.'
| | | |-'b'
| | | `-UnknownExpression
| | | `-UnknownExpression
| | | |-'{'
| | | `-'}'
| | `-'}'
| `-')' CloseParen
`-';'
)txt"}));
}
TEST_P(SyntaxTreeTest, CallExpression_Arguments_ParameterPack) {
if (!GetParam().isCXX11OrLater() || GetParam().hasDelayedTemplateParsing()) {
return;
}
EXPECT_TRUE(treeDumpEqualOnAnnotations(
R"cpp(
template<typename T, typename... Args>
void test(T t, Args... args) {
[[test(args...)]];
}
)cpp",
{R"txt(
CallExpression ExpressionStatement_expression
|-UnknownExpression CallExpression_callee
| `-'test'
|-'(' OpenParen
|-CallArguments CallExpression_arguments
| `-UnknownExpression List_element
| |-IdExpression
| | `-UnqualifiedId IdExpression_id
| | `-'args'
| `-'...'
`-')' CloseParen
)txt"}));
}