eduucaldas updated this revision to Diff 286593. eduucaldas added a comment.
. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D86227/new/ https://reviews.llvm.org/D86227 Files: 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
Index: clang/unittests/Tooling/Syntax/BuildTreeTest.cpp =================================================================== --- clang/unittests/Tooling/Syntax/BuildTreeTest.cpp +++ clang/unittests/Tooling/Syntax/BuildTreeTest.cpp @@ -491,19 +491,20 @@ operator int(); }; void test(X x) { - // TODO: Expose `id-expression` from `MemberExpr` [[x.operator int()]]; } )cpp", {R"txt( UnknownExpression -|-UnknownExpression +|-MemberExpression | |-IdExpression | | `-UnqualifiedId | | `-x | |-. -| |-operator -| `-int +| `-IdExpression +| `-UnqualifiedId +| |-operator +| `-int |-( `-) )txt"})); @@ -542,19 +543,20 @@ R"cpp( struct X { }; void test(X x) { - // TODO: Expose `id-expression` from `MemberExpr` [[x.~X()]]; } )cpp", {R"txt( UnknownExpression -|-UnknownExpression +|-MemberExpression | |-IdExpression | | `-UnqualifiedId | | `-x | |-. -| |-~ -| `-X +| `-IdExpression +| `-UnqualifiedId +| |-~ +| `-X |-( `-) )txt"})); @@ -568,18 +570,23 @@ R"cpp( struct X { }; void test(X x) { - // TODO: Expose `id-expression` from `MemberExpr` + // FIXME: Make `decltype(x)` a child of `MemberExpression`. It is currently + // not because `Expr::getSourceRange()` returns the range of `x.~` for the + // `MemberExpr` instead of the expected `x.~decltype(x)`, this is a bug in + // clang. [[x.~decltype(x)()]]; } )cpp", {R"txt( UnknownExpression -|-UnknownExpression +|-MemberExpression | |-IdExpression | | `-UnqualifiedId | | `-x | |-. -| `-~ +| `-IdExpression +| `-UnqualifiedId +| `-~ |-decltype |-( |-x @@ -624,6 +631,9 @@ struct S { }; } void test() { + // FIXME: Remove the terminal `UnknownExpression` wrapping `s1` and `s2`. This + // `UnknownExpression` comes from a terminal `CXXConstructExpr` in the + // ClangAST. We need to ignore terminal implicit nodes. [[::n::S s1]]; [[n::S s2]]; } @@ -1756,6 +1766,9 @@ struct X { friend X operator+(X, const X&); }; +// FIXME: Remove additional `UnknownExpression` wrapping `x`. For that, ignore +// implicit copy constructor called on `x`. This should've been ignored already, +// as we `IgnoreImplicit` when traversing an `Stmt`. void test(X x, X y) { [[x + y]]; } @@ -1961,6 +1974,306 @@ )txt"})); } +TEST_P(SyntaxTreeTest, MemberExpression_SimpleWithDot) { + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + int a; +}; +void test(struct S s) { + [[s.a]]; +} +)cpp", + {R"txt( +MemberExpression +|-IdExpression +| `-UnqualifiedId +| `-s +|-. +`-IdExpression + `-UnqualifiedId + `-a +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_SimpleWithArrow) { + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + int a; +}; +void test(struct S* sp) { + [[sp->a]]; +} +)cpp", + {R"txt( +MemberExpression +|-IdExpression +| `-UnqualifiedId +| `-sp +|--> +`-IdExpression + `-UnqualifiedId + `-a +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_Chaining) { + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + struct S* next; +}; +void test(struct S s){ + [[s.next->next]]; +} +)cpp", + {R"txt( +MemberExpression +|-MemberExpression +| |-IdExpression +| | `-UnqualifiedId +| | `-s +| |-. +| `-IdExpression +| `-UnqualifiedId +| `-next +|--> +`-IdExpression + `-UnqualifiedId + `-next +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_OperatorFunction) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + bool operator!(); +}; +void test(S s) { + [[s.operator!()]]; +} +)cpp", + {R"txt( +UnknownExpression +|-MemberExpression +| |-IdExpression +| | `-UnqualifiedId +| | `-s +| |-. +| `-IdExpression +| `-UnqualifiedId +| |-operator +| `-! +|-( +`-) +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_Implicit) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + int a; + int geta(){ + // FIXME: Remove the terminal`UnknownExpression` wrapping `a`. This + // `UnknownExpression` comes from a terminal implicit `CXXThisExpr`. + [[a]]; + } +}; +)cpp", + {R"txt( +MemberExpression +`-IdExpression + `-UnqualifiedId + `-UnknownExpression + `-a +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_Template) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + template<typename T> + T f(); +}; +void test(S* sp){ + [[sp->f<int>()]]; +} +)cpp", + {R"txt( +UnknownExpression +|-MemberExpression +| |-IdExpression +| | `-UnqualifiedId +| | `-sp +| |--> +| `-IdExpression +| `-UnqualifiedId +| |-f +| |-< +| |-int +| `-> +|-( +`-) +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_TemplateWithTemplateKeyword) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct S { + template<typename T> + T f(); +}; +void test(S s){ + [[s.template f<int>()]]; +} +)cpp", + {R"txt( +UnknownExpression +|-MemberExpression +| |-IdExpression +| | `-UnqualifiedId +| | `-s +| |-. +| |-template +| `-IdExpression +| `-UnqualifiedId +| |-f +| |-< +| |-int +| `-> +|-( +`-) +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_WithQualifier) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +struct Base { + void f(); +}; +struct S : public Base {}; +void test(S s){ + [[s.Base::f()]]; + [[s.::S::~S()]]; +} +)cpp", + {R"txt( +UnknownExpression +|-MemberExpression +| |-IdExpression +| | `-UnqualifiedId +| | `-s +| |-. +| `-IdExpression +| |-NestedNameSpecifier +| | |-IdentifierNameSpecifier +| | | `-Base +| | `-:: +| `-UnqualifiedId +| `-f +|-( +`-) + )txt", + R"txt( +UnknownExpression +|-MemberExpression +| |-IdExpression +| | `-UnqualifiedId +| | `-s +| |-. +| `-IdExpression +| |-NestedNameSpecifier +| | |-:: +| | |-IdentifierNameSpecifier +| | | `-S +| | `-:: +| `-UnqualifiedId +| |-~ +| `-S +|-( +`-) +)txt"})); +} + +TEST_P(SyntaxTreeTest, MemberExpression_Complex) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +template<typename T> +struct U { + template<typename U> + U f(); +}; +struct S { + U<int> getU(); +}; +void test(S* sp) { + // FIXME: The first 'template' keyword is a child of `NestedNameSpecifier`, + // but it should be a child of `MemberExpression` according to the grammar. + // However one might argue that the 'template' keyword fits better inside + // `NestedNameSpecifier` because if we change `U<int>` to `UI` we would like + // equally to change the `NameSpecifier` `template U<int>` to just `UI`. + [[sp->getU().template U<int>::template f<int>()]]; +} +)cpp", + {R"txt( +UnknownExpression +|-MemberExpression +| |-UnknownExpression +| | |-MemberExpression +| | | |-IdExpression +| | | | `-UnqualifiedId +| | | | `-sp +| | | |--> +| | | `-IdExpression +| | | `-UnqualifiedId +| | | `-getU +| | |-( +| | `-) +| |-. +| `-IdExpression +| |-NestedNameSpecifier +| | |-SimpleTemplateNameSpecifier +| | | |-template +| | | |-U +| | | |-< +| | | |-int +| | | `-> +| | `-:: +| |-template +| `-UnqualifiedId +| |-f +| |-< +| |-int +| `-> +|-( +`-) +)txt"})); +} + TEST_P(SyntaxTreeTest, MultipleDeclaratorsGrouping) { EXPECT_TRUE(treeDumpEqual( R"cpp( Index: clang/lib/Tooling/Syntax/Nodes.cpp =================================================================== --- clang/lib/Tooling/Syntax/Nodes.cpp +++ clang/lib/Tooling/Syntax/Nodes.cpp @@ -126,6 +126,8 @@ return OS << "SimpleTemplateNameSpecifier"; case NodeKind::NestedNameSpecifier: return OS << "NestedNameSpecifier"; + case NodeKind::MemberExpression: + return OS << "MemberExpression"; } llvm_unreachable("unknown node kind"); } @@ -202,6 +204,12 @@ return OS << "IdExpression_qualifier"; case syntax::NodeRole::ParenExpression_subExpression: return OS << "ParenExpression_subExpression"; + case syntax::NodeRole::MemberExpression_object: + return OS << "MemberExpression_object"; + case syntax::NodeRole::MemberExpression_accessToken: + return OS << "MemberExpression_accessToken"; + case syntax::NodeRole::MemberExpression_member: + return OS << "MemberExpression_member"; } llvm_unreachable("invalid role"); } @@ -230,6 +238,26 @@ return Children; } +syntax::Expression *syntax::MemberExpression::object() { + return cast_or_null<syntax::Expression>( + findChild(syntax::NodeRole::MemberExpression_object)); +} + +syntax::Leaf *syntax::MemberExpression::templateKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::TemplateKeyword)); +} + +syntax::Leaf *syntax::MemberExpression::accessToken() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::MemberExpression_accessToken)); +} + +syntax::IdExpression *syntax::MemberExpression::member() { + return cast_or_null<syntax::IdExpression>( + findChild(syntax::NodeRole::MemberExpression_member)); +} + syntax::NestedNameSpecifier *syntax::IdExpression::qualifier() { return cast_or_null<syntax::NestedNameSpecifier>( findChild(syntax::NodeRole::IdExpression_qualifier)); Index: clang/lib/Tooling/Syntax/BuildTree.cpp =================================================================== --- clang/lib/Tooling/Syntax/BuildTree.cpp +++ clang/lib/Tooling/Syntax/BuildTree.cpp @@ -881,6 +881,42 @@ return true; } + bool WalkUpFromMemberExpr(MemberExpr *S) { + if (!S->isImplicitAccess()) { + Builder.markExprChild(S->getBase(), + syntax::NodeRole::MemberExpression_object); + Builder.markChildToken(S->getOperatorLoc(), + syntax::NodeRole::MemberExpression_accessToken); + } + + auto TemplateKeywordLoc = S->getTemplateKeywordLoc(); + if (TemplateKeywordLoc.isValid()) + Builder.markChildToken(TemplateKeywordLoc, + syntax::NodeRole::TemplateKeyword); + + if (auto QualifierLoc = S->getQualifierLoc()) + Builder.markChild(QualifierLoc, syntax::NodeRole::IdExpression_qualifier); + + auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId; + Builder.foldNode(Builder.getRange(S->getMemberLoc(), S->getEndLoc()), + unqualifiedId, nullptr); + + Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id); + + auto *idExpression = new (allocator()) syntax::IdExpression; + Builder.foldNode(Builder.getRange(S->hasQualifier() + ? S->getQualifierLoc().getBeginLoc() + : S->getMemberLoc(), + S->getEndLoc()), + idExpression, nullptr); + + Builder.markChild(idExpression, syntax::NodeRole::MemberExpression_member); + + Builder.foldNode(Builder.getExprRange(S), + new (allocator()) syntax::MemberExpression, S); + return true; + } + bool WalkUpFromDeclRefExpr(DeclRefExpr *S) { if (auto QualifierLoc = S->getQualifierLoc()) Builder.markChild(QualifierLoc, syntax::NodeRole::IdExpression_qualifier); Index: clang/include/clang/Tooling/Syntax/Nodes.h =================================================================== --- clang/include/clang/Tooling/Syntax/Nodes.h +++ clang/include/clang/Tooling/Syntax/Nodes.h @@ -55,6 +55,7 @@ CharUserDefinedLiteralExpression, StringUserDefinedLiteralExpression, IdExpression, + MemberExpression, // Statements. UnknownStatement, @@ -173,7 +174,10 @@ ParametersAndQualifiers_trailingReturn, IdExpression_id, IdExpression_qualifier, - ParenExpression_subExpression + ParenExpression_subExpression, + MemberExpression_object, + MemberExpression_member, + MemberExpression_accessToken, }; /// For debugging purposes. raw_ostream &operator<<(raw_ostream &OS, NodeRole R); @@ -322,6 +326,24 @@ Leaf *closeParen(); }; +/// Models a class member access. C++ [expr.ref] +/// member-expression: +/// expression -> template_opt id-expression +/// expression . template_opt id-expression +/// id-expression +/// e.g. `x.a`, `xp->a` or even just `a` when we have an implicit `this->`. +class MemberExpression final : public Expression { +public: + MemberExpression() : Expression(NodeKind::MemberExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::MemberExpression; + } + Expression *object(); + Leaf *accessToken(); + Leaf *templateKeyword(); + IdExpression *member(); +}; + /// Expression for literals. C++ [lex.literal] class LiteralExpression : public Expression { public:
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits