[clang] 2de2ca3 - [SyntaxTree] Add support for `CallExpression`

Eduardo Caldas via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 26 00:04:01 PDT 2020


Author: Eduardo Caldas
Date: 2020-08-26T07:03:49Z
New Revision: 2de2ca348dfa09963eb33ddf71c9cbb59612c16a

URL: https://github.com/llvm/llvm-project/commit/2de2ca348dfa09963eb33ddf71c9cbb59612c16a
DIFF: https://github.com/llvm/llvm-project/commit/2de2ca348dfa09963eb33ddf71c9cbb59612c16a.diff

LOG: [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

Added: 
    

Modified: 
    clang/include/clang/Tooling/Syntax/Nodes.h
    clang/lib/Tooling/Syntax/BuildTree.cpp
    clang/lib/Tooling/Syntax/Nodes.cpp
    clang/unittests/Tooling/Syntax/BuildTreeTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h
index 0b3991768008..9a14aac130b4 100644
--- a/clang/include/clang/Tooling/Syntax/Nodes.h
+++ b/clang/include/clang/Tooling/Syntax/Nodes.h
@@ -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 @@ class ThisExpression final : public Expression {
   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 {

diff  --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index f027a60030b7..2e3dbc6c6fbd 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -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 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
     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 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
                        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
index ecd4c4dac728..6a7be0f0ea79 100644
--- a/clang/lib/Tooling/Syntax/Nodes.cpp
+++ b/clang/lib/Tooling/Syntax/Nodes.cpp
@@ -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));

diff  --git a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp
index 398f12c45081..6ab01e8f65f0 100644
--- a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp
+++ b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp
@@ -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"}));
 }
 


        


More information about the cfe-commits mailing list