diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h index 8b499bc5ceb96d..0b3991768008a2 100644 --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -56,6 +56,7 @@ enum class NodeKind : uint16_t { StringUserDefinedLiteralExpression, IdExpression, MemberExpression, + ThisExpression, // Statements. UnknownStatement, @@ -313,6 +314,16 @@ class UnknownExpression final : public Expression { } }; +/// Models a this expression `this`. C++ [expr.prim.this] +class ThisExpression final : public Expression { +public: + ThisExpression() : Expression(NodeKind::ThisExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::ThisExpression; + } + Leaf *thisKeyword(); +}; + /// 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 37d29a270463a3..3ab52ce5b7b4b2 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -950,6 +950,16 @@ class BuildTreeVisitor : public RecursiveASTVisitor { return true; } + bool WalkUpFromCXXThisExpr(CXXThisExpr *S) { + if (!S->isImplicit()) { + Builder.markChildToken(S->getLocation(), + syntax::NodeRole::IntroducerKeyword); + Builder.foldNode(Builder.getExprRange(S), + new (allocator()) syntax::ThisExpression, S); + } + return true; + } + bool WalkUpFromParenExpr(ParenExpr *S) { Builder.markChildToken(S->getLParen(), syntax::NodeRole::OpenParen); Builder.markExprChild(S->getSubExpr(), diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp index e09c8f20f210c0..ecd4c4dac72888 100644 --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -20,6 +20,8 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeKind K) { return OS << "UnknownExpression"; case NodeKind::ParenExpression: return OS << "ParenExpression"; + case NodeKind::ThisExpression: + return OS << "ThisExpression"; case NodeKind::IntegerLiteralExpression: return OS << "IntegerLiteralExpression"; case NodeKind::CharacterLiteralExpression: @@ -286,6 +288,11 @@ syntax::Leaf *syntax::ParenExpression::closeParen() { return cast_or_null(findChild(syntax::NodeRole::CloseParen)); } +syntax::Leaf *syntax::ThisExpression::thisKeyword() { + return cast_or_null( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + syntax::Leaf *syntax::LiteralExpression::literalToken() { return cast_or_null(findChild(syntax::NodeRole::LiteralToken)); } diff --git a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp index a3e86dac50c5d1..d4e2684934f37d 100644 --- a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp @@ -905,6 +905,68 @@ UnknownExpression )txt"})); } +TEST_P(SyntaxTreeTest, This_Simple) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + S* test(){ + return [[this]]; + } +}; +)cpp", + {R"txt( +ThisExpression +`-this +)txt"})); +} + +TEST_P(SyntaxTreeTest, This_ExplicitMemberAccess) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + int a; + void test(){ + [[this->a]]; + } +}; +)cpp", + {R"txt( +MemberExpression +|-ThisExpression +| `-this +|--> +`-IdExpression + `-UnqualifiedId + `-a +)txt"})); +} + +TEST_P(SyntaxTreeTest, This_ImplicitMemberAccess) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + int a; + void test(){ + [[a]]; + } +}; +)cpp", + {R"txt( +IdExpression +`-UnqualifiedId + `-a +)txt"})); +} + TEST_P(SyntaxTreeTest, ParenExpr) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( @@ -2099,29 +2161,6 @@ UnknownExpression )txt"})); } -TEST_P(SyntaxTreeTest, MemberExpression_Implicit) { - if (!GetParam().isCXX()) { - return; - } - EXPECT_TRUE(treeDumpEqualOnAnnotations( - R"cpp( -struct S { - int a; - int test(){ - // FIXME: Remove the `UnknownExpression` wrapping `a`. This - // `UnknownExpression` comes from an implicit leaf `CXXThisExpr`. - [[a]]; - } -}; -)cpp", - {R"txt( -IdExpression -`-UnqualifiedId - `-UnknownExpression - `-a -)txt"})); -} - TEST_P(SyntaxTreeTest, MemberExpression_VariableTemplate) { if (!GetParam().isCXX14OrLater()) { return;