diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -57,6 +57,7 @@ IdExpression, MemberExpression, ThisExpression, + CallExpression, // Statements. UnknownStatement, @@ -103,7 +104,8 @@ GlobalNameSpecifier, DecltypeNameSpecifier, IdentifierNameSpecifier, - SimpleTemplateNameSpecifier + SimpleTemplateNameSpecifier, + CallArguments }; /// For debugging purposes. raw_ostream &operator<<(raw_ostream &OS, NodeKind K); @@ -179,6 +181,8 @@ 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 @@ 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 arguments(); + std::vector> 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 { diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -184,10 +184,11 @@ 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 @@ 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 @@ 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"); } diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -52,6 +52,8 @@ 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 @@ return OS << "NestedNameSpecifier"; case NodeKind::MemberExpression: return OS << "MemberExpression"; + case NodeKind::CallArguments: + return OS << "CallArguments"; } llvm_unreachable("unknown node kind"); } @@ -212,6 +216,10 @@ 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 @@ return Children; } +std::vector syntax::CallArguments::arguments() { + auto ArgumentsAsNodes = getElementsAsNodes(); + std::vector Children; + for (const auto &ArgumentAsNode : ArgumentsAsNodes) { + Children.push_back(llvm::cast(ArgumentAsNode)); + } + return Children; +} + +std::vector> +syntax::CallArguments::argumentsAndCommas() { + auto ArgumentsAsNodesAndCommas = getElementsAsNodesAndDelimiters(); + std::vector> Children; + for (const auto &ArgumentAsNodeAndComma : ArgumentsAsNodesAndCommas) { + Children.push_back( + {llvm::cast(ArgumentAsNodeAndComma.element), + ArgumentAsNodeAndComma.delimiter}); + } + return Children; +} + syntax::Expression *syntax::MemberExpression::object() { return cast_or_null( findChild(syntax::NodeRole::MemberExpression_object)); @@ -322,6 +351,24 @@ findChild(syntax::NodeRole::BinaryOperatorExpression_rightHandSide)); } +syntax::Expression *syntax::CallExpression::callee() { + return cast_or_null( + findChild(syntax::NodeRole::CallExpression_callee)); +} + +syntax::Leaf *syntax::CallExpression::openParen() { + return cast_or_null(findChild(syntax::NodeRole::OpenParen)); +} + +syntax::CallArguments *syntax::CallExpression::arguments() { + return cast_or_null( + findChild(syntax::NodeRole::CallExpression_arguments)); +} + +syntax::Leaf *syntax::CallExpression::closeParen() { + return cast_or_null(findChild(syntax::NodeRole::CloseParen)); +} + syntax::Leaf *syntax::SwitchStatement::switchKeyword() { return cast_or_null( findChild(syntax::NodeRole::IntroducerKeyword)); diff --git a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp --- a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp @@ -316,12 +316,12 @@ `-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 @@ | | `-'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 @@ } )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 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-MemberExpression +CallExpression ExpressionStatement_expression +|-MemberExpression CallExpression_callee | |-IdExpression MemberExpression_object | | `-UnqualifiedId IdExpression_id | | `-'x' @@ -419,8 +420,8 @@ | `-UnqualifiedId IdExpression_id | |-'operator' | `-'int' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -436,16 +437,17 @@ } )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 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-MemberExpression +CallExpression ExpressionStatement_expression +|-MemberExpression CallExpression_callee | |-IdExpression MemberExpression_object | | `-UnqualifiedId IdExpression_id | | `-'x' @@ -471,8 +473,8 @@ | `-UnqualifiedId IdExpression_id | |-'~' | `-'X' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -492,8 +494,8 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-MemberExpression +CallExpression ExpressionStatement_expression +|-MemberExpression CallExpression_callee | |-IdExpression MemberExpression_object | | `-UnqualifiedId IdExpression_id | | `-'x' @@ -506,7 +508,7 @@ |-'x' |-')' |-'(' -`-')' +`-')' CloseParen )txt"})); } @@ -523,15 +525,15 @@ } )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 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-IdExpression +CallExpression ExpressionStatement_expression +|-IdExpression CallExpression_callee | |-NestedNameSpecifier IdExpression_qualifier | | |-DecltypeNameSpecifier List_element | | | |-'decltype' @@ -652,8 +654,8 @@ | | `-'::' List_delimiter | `-UnqualifiedId IdExpression_id | `-'f' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -673,8 +675,8 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-IdExpression +CallExpression ExpressionStatement_expression +|-IdExpression CallExpression_callee | |-NestedNameSpecifier IdExpression_qualifier | | |-IdentifierNameSpecifier List_element | | | `-'S' @@ -684,12 +686,12 @@ | |-'<' | |-'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 @@ | |-'<' | |-'int' | `-'>' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -723,8 +725,8 @@ } )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 @@ | |-'<' | |-'int' | `-'>' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -767,8 +769,8 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-IdExpression +CallExpression ExpressionStatement_expression +|-IdExpression CallExpression_callee | |-NestedNameSpecifier IdExpression_qualifier | | |-IdentifierNameSpecifier List_element | | | `-'T' @@ -782,12 +784,12 @@ | | `-'::' 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 @@ | | `-'::' 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 @@ | |-IntegerLiteralExpression | | `-'0' LiteralToken | `-'>' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -2060,8 +2062,8 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-MemberExpression +CallExpression ExpressionStatement_expression +|-MemberExpression CallExpression_callee | |-IdExpression MemberExpression_object | | `-UnqualifiedId IdExpression_id | | `-'s' @@ -2070,8 +2072,8 @@ | `-UnqualifiedId IdExpression_id | |-'operator' | `-'!' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -2126,8 +2128,8 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-MemberExpression +CallExpression ExpressionStatement_expression +|-MemberExpression CallExpression_callee | |-IdExpression MemberExpression_object | | `-UnqualifiedId IdExpression_id | | `-'sp' @@ -2138,8 +2140,8 @@ | |-'<' | |-'int' | `-'>' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -2158,8 +2160,8 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-MemberExpression +CallExpression ExpressionStatement_expression +|-MemberExpression CallExpression_callee | |-IdExpression MemberExpression_object | | `-UnqualifiedId IdExpression_id | | `-'s' @@ -2171,8 +2173,8 @@ | |-'<' | |-'int' | `-'>' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -2192,8 +2194,8 @@ } )cpp", {R"txt( -UnknownExpression ExpressionStatement_expression -|-MemberExpression +CallExpression ExpressionStatement_expression +|-MemberExpression CallExpression_callee | |-IdExpression MemberExpression_object | | `-UnqualifiedId IdExpression_id | | `-'s' @@ -2205,12 +2207,12 @@ | | `-'::' 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 @@ | `-UnqualifiedId IdExpression_id | |-'~' | `-'S' -|-'(' -`-')' +|-'(' OpenParen +`-')' CloseParen )txt"})); } @@ -2253,10 +2255,10 @@ } )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 @@ | | | `-IdExpression MemberExpression_member | | | `-UnqualifiedId IdExpression_id | | | `-'getU' -| | |-'(' -| | `-')' +| | |-'(' OpenParen +| | `-')' CloseParen | |-'.' MemberExpression_accessToken | `-IdExpression MemberExpression_member | |-NestedNameSpecifier IdExpression_qualifier @@ -2282,8 +2284,462 @@ | |-'<' | |-'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 +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"})); }