[clang] 1b2f6b4 - Add support for DeclRefExpr in SyntaxTree, by generating IdExpressions

Dmitri Gribenko via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 18 12:07:31 PDT 2020


Author: Eduardo Caldas
Date: 2020-06-18T21:05:23+02:00
New Revision: 1b2f6b4a08ba74d965dcf7c9fee97d286c0250f8

URL: https://github.com/llvm/llvm-project/commit/1b2f6b4a08ba74d965dcf7c9fee97d286c0250f8
DIFF: https://github.com/llvm/llvm-project/commit/1b2f6b4a08ba74d965dcf7c9fee97d286c0250f8.diff

LOG: Add support for DeclRefExpr in SyntaxTree, by generating IdExpressions

Reviewers: gribozavr2

Reviewed By: gribozavr2

Subscribers: hlopko, gribozavr2, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D81168

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/TreeTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h
index 7e05aa968f02..139ac9aa8eca 100644
--- a/clang/include/clang/Tooling/Syntax/Nodes.h
+++ b/clang/include/clang/Tooling/Syntax/Nodes.h
@@ -45,6 +45,7 @@ enum class NodeKind : uint16_t {
   BinaryOperatorExpression,
   CxxNullPtrExpression,
   IntegerLiteralExpression,
+  IdExpression,
 
   // Statements.
   UnknownStatement,
@@ -84,7 +85,10 @@ enum class NodeKind : uint16_t {
   ArraySubscript,
   TrailingReturnType,
   ParametersAndQualifiers,
-  MemberPointer
+  MemberPointer,
+  NestedNameSpecifier,
+  NameSpecifier,
+  UnqualifiedId
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -150,7 +154,10 @@ enum class NodeRole : uint8_t {
   ArraySubscript_sizeExpression,
   TrailingReturnType_declarator,
   ParametersAndQualifiers_parameter,
-  ParametersAndQualifiers_trailingReturn
+  ParametersAndQualifiers_trailingReturn,
+  IdExpression_id,
+  IdExpression_qualifier,
+  NestedNameSpecifier_specifier
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeRole R);
@@ -177,6 +184,56 @@ class Expression : public Tree {
   }
 };
 
+/// A sequence of these specifiers make a `nested-name-specifier`.
+/// e.g. the `std::` or `vector<int>::` in `std::vector<int>::size`.
+class NameSpecifier final : public Tree {
+public:
+  NameSpecifier() : Tree(NodeKind::NameSpecifier) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::NameSpecifier;
+  }
+};
+
+/// Models a `nested-name-specifier`. C++ [expr.prim.id.qual]
+/// e.g. the `std::vector<int>::` in `std::vector<int>::size`.
+class NestedNameSpecifier final : public Tree {
+public:
+  NestedNameSpecifier() : Tree(NodeKind::NestedNameSpecifier) {}
+  static bool classof(const Node *N) {
+    return N->kind() <= NodeKind::NestedNameSpecifier;
+  }
+  std::vector<syntax::NameSpecifier *> specifiers();
+};
+
+/// Models an `unqualified-id`. C++ [expr.prim.id.unqual]
+/// e.g. the `size` in `std::vector<int>::size`.
+class UnqualifiedId final : public Tree {
+public:
+  UnqualifiedId() : Tree(NodeKind::UnqualifiedId) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::UnqualifiedId;
+  }
+};
+
+/// Models an `id-expression`, e.g. `std::vector<int>::size`.
+/// C++ [expr.prim.id]
+/// id-expression:
+///   unqualified-id
+///   qualified-id
+/// qualified-id:
+///   nested-name-specifier template_opt unqualified-id
+class IdExpression final : public Expression {
+public:
+  IdExpression() : Expression(NodeKind::IdExpression) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::IdExpression;
+  }
+  syntax::NestedNameSpecifier *qualifier();
+  // TODO after expose `id-expression` from `DependentScopeDeclRefExpr`:
+  // Add accessor for `template_opt`.
+  syntax::UnqualifiedId *unqualifiedId();
+};
+
 /// An expression of an unknown kind, i.e. one not currently handled by the
 /// syntax tree.
 class UnknownExpression final : public Expression {

diff  --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index 9ce12ac21f8b..3ee66aabfb6d 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -608,6 +608,45 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
     return true;
   }
 
+  syntax::NestedNameSpecifier *
+  BuildNestedNameSpecifier(NestedNameSpecifierLoc QualifierLoc) {
+    if (!QualifierLoc)
+      return nullptr;
+    for (auto it = QualifierLoc; it; it = it.getPrefix()) {
+      auto *NS = new (allocator()) syntax::NameSpecifier;
+      Builder.foldNode(Builder.getRange(it.getLocalSourceRange()), NS, nullptr);
+      Builder.markChild(NS, syntax::NodeRole::NestedNameSpecifier_specifier);
+    }
+    auto *NNS = new (allocator()) syntax::NestedNameSpecifier;
+    Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()), NNS,
+                     nullptr);
+    return NNS;
+  }
+
+  bool WalkUpFromDeclRefExpr(DeclRefExpr *S) {
+    if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
+      Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
+
+    auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId;
+    // Get `UnqualifiedId` from `DeclRefExpr`.
+    // FIXME: Extract this logic so that it can be used by `MemberExpr`,
+    // and other semantic constructs, now it is tied to `DeclRefExpr`.
+    if (!S->hasExplicitTemplateArgs()) {
+      Builder.foldNode(Builder.getRange(S->getNameInfo().getSourceRange()),
+                       unqualifiedId, nullptr);
+    } else {
+      auto templateIdSourceRange =
+          SourceRange(S->getNameInfo().getBeginLoc(), S->getRAngleLoc());
+      Builder.foldNode(Builder.getRange(templateIdSourceRange), unqualifiedId,
+                       nullptr);
+    }
+    Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
+
+    Builder.foldNode(Builder.getExprRange(S),
+                     new (allocator()) syntax::IdExpression, 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
index 7498ddceeb14..623391a7d844 100644
--- a/clang/lib/Tooling/Syntax/Nodes.cpp
+++ b/clang/lib/Tooling/Syntax/Nodes.cpp
@@ -28,6 +28,10 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
     return OS << "PostfixUnaryOperatorExpression";
   case NodeKind::BinaryOperatorExpression:
     return OS << "BinaryOperatorExpression";
+  case NodeKind::UnqualifiedId:
+    return OS << "UnqualifiedId";
+  case NodeKind::IdExpression:
+    return OS << "IdExpression";
   case NodeKind::UnknownStatement:
     return OS << "UnknownStatement";
   case NodeKind::DeclarationStatement:
@@ -94,6 +98,10 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
     return OS << "ParametersAndQualifiers";
   case NodeKind::MemberPointer:
     return OS << "MemberPointer";
+  case NodeKind::NameSpecifier:
+    return OS << "NameSpecifier";
+  case NodeKind::NestedNameSpecifier:
+    return OS << "NestedNameSpecifier";
   }
   llvm_unreachable("unknown node kind");
 }
@@ -158,10 +166,35 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
     return OS << "ParametersAndQualifiers_parameter";
   case syntax::NodeRole::ParametersAndQualifiers_trailingReturn:
     return OS << "ParametersAndQualifiers_trailingReturn";
+  case syntax::NodeRole::IdExpression_id:
+    return OS << "IdExpression_id";
+  case syntax::NodeRole::IdExpression_qualifier:
+    return OS << "IdExpression_qualifier";
+  case syntax::NodeRole::NestedNameSpecifier_specifier:
+    return OS << "NestedNameSpecifier_specifier";
   }
   llvm_unreachable("invalid role");
 }
 
+std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::specifiers() {
+  std::vector<syntax::NameSpecifier *> Children;
+  for (auto *C = firstChild(); C; C = C->nextSibling()) {
+    assert(C->role() == syntax::NodeRole::NestedNameSpecifier_specifier);
+    Children.push_back(llvm::cast<syntax::NameSpecifier>(C));
+  }
+  return Children;
+}
+
+syntax::NestedNameSpecifier *syntax::IdExpression::qualifier() {
+  return llvm::cast_or_null<syntax::NestedNameSpecifier>(
+      findChild(syntax::NodeRole::IdExpression_qualifier));
+}
+
+syntax::UnqualifiedId *syntax::IdExpression::unqualifiedId() {
+  return llvm::cast_or_null<syntax::UnqualifiedId>(
+      findChild(syntax::NodeRole::IdExpression_id));
+}
+
 syntax::Leaf *syntax::IntegerLiteralExpression::literalToken() {
   return llvm::cast_or_null<syntax::Leaf>(
       findChild(syntax::NodeRole::LiteralToken));
@@ -315,8 +348,8 @@ syntax::Leaf *syntax::CompoundStatement::lbrace() {
 std::vector<syntax::Statement *> syntax::CompoundStatement::statements() {
   std::vector<syntax::Statement *> Children;
   for (auto *C = firstChild(); C; C = C->nextSibling()) {
-    if (C->role() == syntax::NodeRole::CompoundStatement_statement)
-      Children.push_back(llvm::cast<syntax::Statement>(C));
+    assert(C->role() == syntax::NodeRole::CompoundStatement_statement);
+    Children.push_back(llvm::cast<syntax::Statement>(C));
   }
   return Children;
 }

diff  --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp
index 64acfe30a05b..5f48ef129988 100644
--- a/clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -485,8 +485,9 @@ void test() {
     | | |-SimpleDeclarator
     | | | `-x
     | | `-:
-    | |-UnknownExpression
-    | | `-a
+    | |-IdExpression
+    | | `-UnqualifiedId
+    | |   `-a
     | |-)
     | `-EmptyStatement
     |   `-;
@@ -662,8 +663,9 @@ void test() {
     |-{
     |-ExpressionStatement
     | |-UnknownExpression
-    | | |-UnknownExpression
-    | | | `-test
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-test
     | | |-(
     | | `-)
     | `-;
@@ -675,16 +677,18 @@ void test() {
     | |-)
     | |-ExpressionStatement
     | | |-UnknownExpression
-    | | | |-UnknownExpression
-    | | | | `-test
+    | | | |-IdExpression
+    | | | | `-UnqualifiedId
+    | | | |   `-test
     | | | |-(
     | | | `-)
     | | `-;
     | |-else
     | `-ExpressionStatement
     |   |-UnknownExpression
-    |   | |-UnknownExpression
-    |   | | `-test
+    |   | |-IdExpression
+    |   | | `-UnqualifiedId
+    |   | |   `-test
     |   | |-(
     |   | `-)
     |   `-;
@@ -692,6 +696,509 @@ void test() {
 )txt"));
 }
 
+TEST_P(SyntaxTreeTest, UnqualifiedId) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqual(
+      R"cpp(
+struct X {
+  // TODO: Expose `id-expression` from `Declarator`
+  friend X operator+(const X&, const X&);
+  operator int();
+};
+template<typename T>
+void f(T&);
+void test(X x) {
+  x;                      // identifier
+  operator+(x, x);        // operator-function-id
+  f<X>(x);                // template-id
+  // TODO: Expose `id-expression` from `MemberExpr`
+  x.operator int();       // conversion-funtion-id
+  x.~X();                 // ~type-name
+}
+)cpp",
+      R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-struct
+| |-X
+| |-{
+| |-UnknownDeclaration
+| | `-SimpleDeclaration
+| |   |-friend
+| |   |-X
+| |   |-SimpleDeclarator
+| |   | |-operator
+| |   | |-+
+| |   | `-ParametersAndQualifiers
+| |   |   |-(
+| |   |   |-SimpleDeclaration
+| |   |   | |-const
+| |   |   | |-X
+| |   |   | `-SimpleDeclarator
+| |   |   |   `-&
+| |   |   |-,
+| |   |   |-SimpleDeclaration
+| |   |   | |-const
+| |   |   | |-X
+| |   |   | `-SimpleDeclarator
+| |   |   |   `-&
+| |   |   `-)
+| |   `-;
+| |-SimpleDeclaration
+| | |-SimpleDeclarator
+| | | |-operator
+| | | |-int
+| | | `-ParametersAndQualifiers
+| | |   |-(
+| | |   `-)
+| | `-;
+| |-}
+| `-;
+|-TemplateDeclaration
+| |-template
+| |-<
+| |-UnknownDeclaration
+| | |-typename
+| | `-T
+| |->
+| `-SimpleDeclaration
+|   |-void
+|   |-SimpleDeclarator
+|   | |-f
+|   | `-ParametersAndQualifiers
+|   |   |-(
+|   |   |-SimpleDeclaration
+|   |   | |-T
+|   |   | `-SimpleDeclarator
+|   |   |   `-&
+|   |   `-)
+|   `-;
+`-SimpleDeclaration
+  |-void
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-SimpleDeclaration
+  |   | |-X
+  |   | `-SimpleDeclarator
+  |   |   `-x
+  |   `-)
+  `-CompoundStatement
+    |-{
+    |-ExpressionStatement
+    | |-IdExpression
+    | | `-UnqualifiedId
+    | |   `-x
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   |-operator
+    | | |   `-+
+    | | |-(
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-x
+    | | |-,
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-x
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   |-f
+    | | |   |-<
+    | | |   |-X
+    | | |   `->
+    | | |-(
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-x
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-UnknownExpression
+    | | | |-IdExpression
+    | | | | `-UnqualifiedId
+    | | | |   `-x
+    | | | |-.
+    | | | |-operator
+    | | | `-int
+    | | |-(
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-UnknownExpression
+    | | | |-IdExpression
+    | | | | `-UnqualifiedId
+    | | | |   `-x
+    | | | |-.
+    | | | |-~
+    | | | `-X
+    | | |-(
+    | | `-)
+    | `-;
+    `-}
+)txt"));
+}
+
+TEST_P(SyntaxTreeTest, UnqualifiedIdCxx11OrLater) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqual(
+      R"cpp(
+struct X { };
+unsigned operator "" _w(long long unsigned);
+void test(X x) {
+  operator "" _w(1llu);   // literal-operator-id
+  // TODO: Expose `id-expression` from `MemberExpr`
+  x.~decltype(x)();       // ~decltype-specifier
+}
+)cpp",
+      R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-struct
+| |-X
+| |-{
+| |-}
+| `-;
+|-SimpleDeclaration
+| |-unsigned
+| |-SimpleDeclarator
+| | |-operator
+| | |-""
+| | |-_w
+| | `-ParametersAndQualifiers
+| |   |-(
+| |   |-SimpleDeclaration
+| |   | |-long
+| |   | |-long
+| |   | `-unsigned
+| |   `-)
+| `-;
+`-SimpleDeclaration
+  |-void
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-SimpleDeclaration
+  |   | |-X
+  |   | `-SimpleDeclarator
+  |   |   `-x
+  |   `-)
+  `-CompoundStatement
+    |-{
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   |-operator
+    | | |   |-""
+    | | |   `-_w
+    | | |-(
+    | | |-IntegerLiteralExpression
+    | | | `-1llu
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-UnknownExpression
+    | | | |-IdExpression
+    | | | | `-UnqualifiedId
+    | | | |   `-x
+    | | | |-.
+    | | | `-~
+    | | |-decltype
+    | | |-(
+    | | |-x
+    | | |-)
+    | | |-(
+    | | `-)
+    | `-;
+    `-}
+)txt"));
+}
+
+TEST_P(SyntaxTreeTest, QualifiedId) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqual(
+      R"cpp(
+namespace a {
+  struct S {
+    template<typename T>
+    static T f(){}
+  };
+}
+void test() {
+  ::              // global-namespace-specifier
+  a::             // namespace-specifier
+  S::             // type-name-specifier
+  f<int>();
+}
+)cpp",
+      R"txt(
+*: TranslationUnit
+|-NamespaceDefinition
+| |-namespace
+| |-a
+| |-{
+| |-SimpleDeclaration
+| | |-struct
+| | |-S
+| | |-{
+| | |-TemplateDeclaration
+| | | |-template
+| | | |-<
+| | | |-UnknownDeclaration
+| | | | |-typename
+| | | | `-T
+| | | |->
+| | | `-SimpleDeclaration
+| | |   |-static
+| | |   |-T
+| | |   |-SimpleDeclarator
+| | |   | |-f
+| | |   | `-ParametersAndQualifiers
+| | |   |   |-(
+| | |   |   `-)
+| | |   `-CompoundStatement
+| | |     |-{
+| | |     `-}
+| | |-}
+| | `-;
+| `-}
+`-SimpleDeclaration
+  |-void
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
+  `-CompoundStatement
+    |-{
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | |-NameSpecifier
+    | | | | | `-::
+    | | | | |-NameSpecifier
+    | | | | | |-a
+    | | | | | `-::
+    | | | | `-NameSpecifier
+    | | | |   |-S
+    | | | |   `-::
+    | | | `-UnqualifiedId
+    | | |   |-f
+    | | |   |-<
+    | | |   |-int
+    | | |   `->
+    | | |-(
+    | | `-)
+    | `-;
+    `-}
+)txt"));
+}
+
+TEST_P(SyntaxTreeTest, QualifiedIdWithTemplateKeyword) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  if (GetParam().hasDelayedTemplateParsing()) {
+    // FIXME: Make this test work on Windows by generating the expected syntax
+    // tree when `-fdelayed-template-parsing` is active.
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqual(
+      R"cpp(
+struct X {
+  template<int> static void f();
+  template<int>
+  struct Y {
+    static void f();
+  };
+};
+template<typename T> void test() {
+  // TODO: Expose `id-expression` from `DependentScopeDeclRefExpr`
+  T::template f<0>();     // nested-name-specifier template unqualified-id
+  T::template Y<0>::f();  // nested-name-specifier template :: unqualified-id
+}
+)cpp",
+      R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-struct
+| |-X
+| |-{
+| |-TemplateDeclaration
+| | |-template
+| | |-<
+| | |-SimpleDeclaration
+| | | `-int
+| | |->
+| | `-SimpleDeclaration
+| |   |-static
+| |   |-void
+| |   |-SimpleDeclarator
+| |   | |-f
+| |   | `-ParametersAndQualifiers
+| |   |   |-(
+| |   |   `-)
+| |   `-;
+| |-TemplateDeclaration
+| | |-template
+| | |-<
+| | |-SimpleDeclaration
+| | | `-int
+| | |->
+| | `-SimpleDeclaration
+| |   |-struct
+| |   |-Y
+| |   |-{
+| |   |-SimpleDeclaration
+| |   | |-static
+| |   | |-void
+| |   | |-SimpleDeclarator
+| |   | | |-f
+| |   | | `-ParametersAndQualifiers
+| |   | |   |-(
+| |   | |   `-)
+| |   | `-;
+| |   |-}
+| |   `-;
+| |-}
+| `-;
+`-TemplateDeclaration
+  |-template
+  |-<
+  |-UnknownDeclaration
+  | |-typename
+  | `-T
+  |->
+  `-SimpleDeclaration
+    |-void
+    |-SimpleDeclarator
+    | |-test
+    | `-ParametersAndQualifiers
+    |   |-(
+    |   `-)
+    `-CompoundStatement
+      |-{
+      |-ExpressionStatement
+      | |-UnknownExpression
+      | | |-UnknownExpression
+      | | | |-T
+      | | | |-::
+      | | | |-template
+      | | | |-f
+      | | | |-<
+      | | | |-IntegerLiteralExpression
+      | | | | `-0
+      | | | `->
+      | | |-(
+      | | `-)
+      | `-;
+      |-ExpressionStatement
+      | |-UnknownExpression
+      | | |-UnknownExpression
+      | | | |-T
+      | | | |-::
+      | | | |-template
+      | | | |-Y
+      | | | |-<
+      | | | |-IntegerLiteralExpression
+      | | | | `-0
+      | | | |->
+      | | | |-::
+      | | | `-f
+      | | |-(
+      | | `-)
+      | `-;
+      `-}
+)txt"));
+}
+
+TEST_P(SyntaxTreeTest, QualifiedIdDecltype) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqual(
+      R"cpp(
+struct S {
+  static void f(){}
+};
+void test(S s) {
+  decltype(s)::   // decltype-specifier
+      f();
+}
+)cpp",
+      R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-struct
+| |-S
+| |-{
+| |-SimpleDeclaration
+| | |-static
+| | |-void
+| | |-SimpleDeclarator
+| | | |-f
+| | | `-ParametersAndQualifiers
+| | |   |-(
+| | |   `-)
+| | `-CompoundStatement
+| |   |-{
+| |   `-}
+| |-}
+| `-;
+`-SimpleDeclaration
+  |-void
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-SimpleDeclaration
+  |   | |-S
+  |   | `-SimpleDeclarator
+  |   |   `-s
+  |   `-)
+  `-CompoundStatement
+    |-{
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | `-NameSpecifier
+    | | | |   |-decltype
+    | | | |   |-(
+    | | | |   |-IdExpression
+    | | | |   | `-UnqualifiedId
+    | | | |   |   `-s
+    | | | |   |-)
+    | | | |   `-::
+    | | | `-UnqualifiedId
+    | | |   `-f
+    | | |-(
+    | | `-)
+    | `-;
+    `-}
+)txt"));
+}
+
 TEST_P(SyntaxTreeTest, CxxNullPtrLiteral) {
   if (!GetParam().isCXX11OrLater()) {
     return;
@@ -889,14 +1396,16 @@ void test(int a) {
     |-{
     |-ExpressionStatement
     | |-PostfixUnaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-a
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
     | | `-++
     | `-;
     |-ExpressionStatement
     | |-PostfixUnaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-a
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
     | | `---
     | `-;
     `-}
@@ -941,62 +1450,72 @@ void test(int a, int *ap) {
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |---
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-++
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-~
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |--
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-+
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-&
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-*
-    | | `-UnknownExpression
-    | |   `-ap
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-ap
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-!
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-__real
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-__imag
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     `-}
 )txt"));
@@ -1036,14 +1555,16 @@ void test(int a, bool b) {
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-compl
-    | | `-UnknownExpression
-    | |   `-a
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-a
     | `-;
     |-ExpressionStatement
     | |-PrefixUnaryOperatorExpression
     | | |-not
-    | | `-UnknownExpression
-    | |   `-b
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-b
     | `-;
     `-}
 )txt"));
@@ -1095,16 +1616,18 @@ void test(int a) {
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-a
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
     | | |-=
     | | `-IntegerLiteralExpression
     | |   `-1
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-a
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
     | | |-<<=
     | | `-IntegerLiteralExpression
     | |   `-1
@@ -1127,8 +1650,9 @@ void test(int a) {
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-a
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
     | | |-^=
     | | `-IntegerLiteralExpression
     | |   `-3
@@ -1191,8 +1715,9 @@ void test(int a) {
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-a
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
     | | |-xor_eq
     | | `-IntegerLiteralExpression
     | |   `-3
@@ -1257,23 +1782,27 @@ void test(int a, int b) {
     |-ExpressionStatement
     | |-BinaryOperatorExpression
     | | |-BinaryOperatorExpression
-    | | | |-UnknownExpression
-    | | | | `-a
+    | | | |-IdExpression
+    | | | | `-UnqualifiedId
+    | | | |   `-a
     | | | |-+
-    | | | `-UnknownExpression
-    | | |   `-b
+    | | | `-IdExpression
+    | | |   `-UnqualifiedId
+    | | |     `-b
     | | |-+
     | | `-IntegerLiteralExpression
     | |   `-42
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-a
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
     | | |-=
     | | `-BinaryOperatorExpression
-    | |   |-UnknownExpression
-    | |   | `-b
+    | |   |-IdExpression
+    | |   | `-UnqualifiedId
+    | |   |   `-b
     | |   |-=
     | |   `-IntegerLiteralExpression
     | |     `-42
@@ -1281,12 +1810,14 @@ void test(int a, int b) {
     |-ExpressionStatement
     | |-BinaryOperatorExpression
     | | |-BinaryOperatorExpression
-    | | | |-UnknownExpression
-    | | | | `-a
+    | | | |-IdExpression
+    | | | | `-UnqualifiedId
+    | | | |   `-a
     | | | |-+
     | | | `-BinaryOperatorExpression
-    | | |   |-UnknownExpression
-    | | |   | `-b
+    | | |   |-IdExpression
+    | | |   | `-UnqualifiedId
+    | | |   |   `-b
     | | |   |-*
     | | |   `-IntegerLiteralExpression
     | | |     `-4
@@ -1297,15 +1828,17 @@ void test(int a, int b) {
     |-ExpressionStatement
     | |-BinaryOperatorExpression
     | | |-BinaryOperatorExpression
-    | | | |-UnknownExpression
-    | | | | `-a
+    | | | |-IdExpression
+    | | | | `-UnqualifiedId
+    | | | |   `-a
     | | | |-%
     | | | `-IntegerLiteralExpression
     | | |   `-2
     | | |-+
     | | `-BinaryOperatorExpression
-    | |   |-UnknownExpression
-    | |   | `-b
+    | |   |-IdExpression
+    | |   | `-UnqualifiedId
+    | |   |   `-b
     | |   |-*
     | |   `-IntegerLiteralExpression
     | |     `-42
@@ -1415,31 +1948,40 @@ void test(X x, X y) {
     |-{
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-x
-    | | |-UnknownExpression
-    | | | `-=
-    | | `-UnknownExpression
-    | |   `-y
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-x
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-=
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-y
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
     | | |-UnknownExpression
-    | | | `-UnknownExpression
-    | | |   `-x
-    | | |-UnknownExpression
-    | | | `-+
-    | | `-UnknownExpression
-    | |   `-y
+    | | | `-IdExpression
+    | | |   `-UnqualifiedId
+    | | |     `-x
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-+
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-y
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-x
-    | | |-UnknownExpression
-    | | | `-<
-    | | `-UnknownExpression
-    | |   `-y
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-x
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-<
+    | | `-IdExpression
+    | |   `-UnqualifiedId
+    | |     `-y
     | `-;
     `-}
 )txt"));


        


More information about the cfe-commits mailing list