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

Reply via email to