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 @@ -43,6 +43,7 @@ PrefixUnaryOperatorExpression, PostfixUnaryOperatorExpression, BinaryOperatorExpression, + ParenExpression, IntegerLiteralExpression, CharacterLiteralExpression, FloatingLiteralExpression, @@ -161,7 +162,8 @@ ParametersAndQualifiers_trailingReturn, IdExpression_id, IdExpression_qualifier, - NestedNameSpecifier_specifier + NestedNameSpecifier_specifier, + ParenExpression_subExpression }; /// For debugging purposes. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeRole R); @@ -248,6 +250,19 @@ } }; +/// Models a parenthesized expression `(E)`. C++ [expr.prim.paren] +/// e.g. `(3 + 2)` in `a = 1 + (3 + 2);` +class ParenExpression final : public Expression { +public: + ParenExpression() : Expression(NodeKind::ParenExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::ParenExpression; + } + syntax::Leaf *openParen(); + syntax::Expression *subExpression(); + syntax::Leaf *closeParen(); +}; + /// Expression for integer literals. C++ [lex.icon] class IntegerLiteralExpression final : public Expression { public: 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 @@ -647,6 +647,16 @@ return true; } + bool WalkUpFromParenExpr(ParenExpr *S) { + Builder.markChildToken(S->getLParen(), syntax::NodeRole::OpenParen); + Builder.markExprChild(S->getSubExpr(), + syntax::NodeRole::ParenExpression_subExpression); + Builder.markChildToken(S->getRParen(), syntax::NodeRole::CloseParen); + Builder.foldNode(Builder.getExprRange(S), + new (allocator()) syntax::ParenExpression, S); + return true; + } + bool WalkUpFromIntegerLiteral(IntegerLiteral *S) { Builder.markChildToken(S->getLocation(), syntax::NodeRole::LiteralToken); Builder.foldNode(Builder.getExprRange(S), 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 @@ -18,6 +18,8 @@ return OS << "TranslationUnit"; case NodeKind::UnknownExpression: return OS << "UnknownExpression"; + case NodeKind::ParenExpression: + return OS << "ParenExpression"; case NodeKind::IntegerLiteralExpression: return OS << "IntegerLiteralExpression"; case NodeKind::CharacterLiteralExpression: @@ -180,6 +182,8 @@ return OS << "IdExpression_qualifier"; case syntax::NodeRole::NestedNameSpecifier_specifier: return OS << "NestedNameSpecifier_specifier"; + case syntax::NodeRole::ParenExpression_subExpression: + return OS << "ParenExpression_subExpression"; } llvm_unreachable("invalid role"); } @@ -203,6 +207,21 @@ findChild(syntax::NodeRole::IdExpression_id)); } +syntax::Leaf *syntax::ParenExpression::openParen() { + return llvm::cast_or_null( + findChild(syntax::NodeRole::OpenParen)); +} + +syntax::Expression *syntax::ParenExpression::subExpression() { + return llvm::cast_or_null( + findChild(syntax::NodeRole::ParenExpression_subExpression)); +} + +syntax::Leaf *syntax::ParenExpression::closeParen() { + return llvm::cast_or_null( + findChild(syntax::NodeRole::CloseParen)); +} + syntax::Leaf *syntax::IntegerLiteralExpression::literalToken() { return llvm::cast_or_null( findChild(syntax::NodeRole::LiteralToken)); diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -1129,6 +1129,61 @@ )txt")); } +TEST_P(SyntaxTreeTest, ParenExpr) { + EXPECT_TRUE(treeDumpEqual( + R"cpp( +void test() { + (1); + ((1)); + (1 + (2)); +} +)cpp", + R"txt( +*: TranslationUnit +`-SimpleDeclaration + |-void + |-SimpleDeclarator + | |-test + | `-ParametersAndQualifiers + | |-( + | `-) + `-CompoundStatement + |-{ + |-ExpressionStatement + | |-ParenExpression + | | |-( + | | |-IntegerLiteralExpression + | | | `-1 + | | `-) + | `-; + |-ExpressionStatement + | |-ParenExpression + | | |-( + | | |-ParenExpression + | | | |-( + | | | |-IntegerLiteralExpression + | | | | `-1 + | | | `-) + | | `-) + | `-; + |-ExpressionStatement + | |-ParenExpression + | | |-( + | | |-BinaryOperatorExpression + | | | |-IntegerLiteralExpression + | | | | `-1 + | | | |-+ + | | | `-ParenExpression + | | | |-( + | | | |-IntegerLiteralExpression + | | | | `-2 + | | | `-) + | | `-) + | `-; + `-} +)txt")); +} + TEST_P(SyntaxTreeTest, IntegerLiteral) { EXPECT_TRUE(treeDumpEqual( R"cpp( @@ -2040,7 +2095,7 @@ |-{ |-ExpressionStatement | |-BinaryOperatorExpression - | | |-UnknownExpression + | | |-ParenExpression | | | |-( | | | |-BinaryOperatorExpression | | | | |-IntegerLiteralExpression @@ -2050,7 +2105,7 @@ | | | | `-2 | | | `-) | | |-* - | | `-UnknownExpression + | | `-ParenExpression | | |-( | | |-BinaryOperatorExpression | | | |-IntegerLiteralExpression