eduucaldas updated this revision to Diff 280899.
eduucaldas marked 9 inline comments as done.
eduucaldas added a comment.

- Answer code review
- Simpler logic for `getUnqualifiedIdSourceRange` and inline it
- Remove ambiguously named variable NNS


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84348/new/

https://reviews.llvm.org/D84348

Files:
  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

Index: clang/unittests/Tooling/Syntax/TreeTest.cpp
===================================================================
--- clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -867,24 +867,47 @@
   }
   EXPECT_TRUE(treeDumpEqual(
       R"cpp(
-namespace a {
+namespace n {
   struct S {
     template<typename T>
-    static T f(){}
+    struct ST {
+      static void f();
+    };
   };
 }
+template<typename T>
+struct ST {
+  struct S {
+    template<typename U>
+    static U f();
+  };
+};
 void test() {
-  ::              // global-namespace-specifier
-  a::             // namespace-specifier
-  S::             // type-name-specifier
+  ::                 // global-namespace-specifier
+  n::                // namespace-specifier
+  S::                // type-name-specifier
+  template ST<int>:: // type-template-instantiation-specifier
+  f();
+
+  n::                // namespace-specifier
+  S::                // type-name-specifier
+  ST<int>::          // type-template-instantiation-specifier
+  f();
+
+  ST<int>::         // type-name-specifier
+  S::               // type-name-specifier
   f<int>();
+
+  ST<int>::         // type-name-specifier
+  S::               // type-name-specifier
+  template f<int>();
 }
 )cpp",
       R"txt(
 *: TranslationUnit
 |-NamespaceDefinition
 | |-namespace
-| |-a
+| |-n
 | |-{
 | |-SimpleDeclaration
 | | |-struct
@@ -898,19 +921,58 @@
 | | | | `-T
 | | | |->
 | | | `-SimpleDeclaration
-| | |   |-static
-| | |   |-T
-| | |   |-SimpleDeclarator
-| | |   | |-f
-| | |   | `-ParametersAndQualifiers
-| | |   |   |-(
-| | |   |   `-)
-| | |   `-CompoundStatement
-| | |     |-{
-| | |     `-}
+| | |   |-struct
+| | |   |-ST
+| | |   |-{
+| | |   |-SimpleDeclaration
+| | |   | |-static
+| | |   | |-void
+| | |   | |-SimpleDeclarator
+| | |   | | |-f
+| | |   | | `-ParametersAndQualifiers
+| | |   | |   |-(
+| | |   | |   `-)
+| | |   | `-;
+| | |   |-}
+| | |   `-;
 | | |-}
 | | `-;
 | `-}
+|-TemplateDeclaration
+| |-template
+| |-<
+| |-UnknownDeclaration
+| | |-typename
+| | `-T
+| |->
+| `-SimpleDeclaration
+|   |-struct
+|   |-ST
+|   |-{
+|   |-SimpleDeclaration
+|   | |-struct
+|   | |-S
+|   | |-{
+|   | |-TemplateDeclaration
+|   | | |-template
+|   | | |-<
+|   | | |-UnknownDeclaration
+|   | | | |-typename
+|   | | | `-U
+|   | | |->
+|   | | `-SimpleDeclaration
+|   | |   |-static
+|   | |   |-U
+|   | |   |-SimpleDeclarator
+|   | |   | |-f
+|   | |   | `-ParametersAndQualifiers
+|   | |   |   |-(
+|   | |   |   `-)
+|   | |   `-;
+|   | |-}
+|   | `-;
+|   |-}
+|   `-;
 `-SimpleDeclaration
   |-void
   |-SimpleDeclarator
@@ -924,14 +986,81 @@
     | |-UnknownExpression
     | | |-IdExpression
     | | | |-NestedNameSpecifier
-    | | | | |-NameSpecifier
-    | | | | | `-::
-    | | | | |-NameSpecifier
-    | | | | | |-a
-    | | | | | `-::
-    | | | | `-NameSpecifier
-    | | | |   |-S
-    | | | |   `-::
+    | | | | |-::
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-n
+    | | | | |-::
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-S
+    | | | | |-::
+    | | | | |-SimpleTemplateNameSpecifier
+    | | | | | |-template
+    | | | | | |-ST
+    | | | | | |-<
+    | | | | | |-int
+    | | | | | `->
+    | | | | `-::
+    | | | `-UnqualifiedId
+    | | |   `-f
+    | | |-(
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-n
+    | | | | |-::
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-S
+    | | | | |-::
+    | | | | |-SimpleTemplateNameSpecifier
+    | | | | | |-ST
+    | | | | | |-<
+    | | | | | |-int
+    | | | | | `->
+    | | | | `-::
+    | | | `-UnqualifiedId
+    | | |   `-f
+    | | |-(
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | |-SimpleTemplateNameSpecifier
+    | | | | | |-ST
+    | | | | | |-<
+    | | | | | |-int
+    | | | | | `->
+    | | | | |-::
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-S
+    | | | | `-::
+    | | | `-UnqualifiedId
+    | | |   |-f
+    | | |   |-<
+    | | |   |-int
+    | | |   `->
+    | | |-(
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | |-SimpleTemplateNameSpecifier
+    | | | | | |-ST
+    | | | | | |-<
+    | | | | | |-int
+    | | | | | `->
+    | | | | |-::
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-S
+    | | | | `-::
+    | | | |-template
     | | | `-UnqualifiedId
     | | |   |-f
     | | |   |-<
@@ -944,7 +1073,7 @@
 )txt"));
 }
 
-TEST_P(SyntaxTreeTest, QualifiedIdWithTemplateKeyword) {
+TEST_P(SyntaxTreeTest, QualifiedIdWithDependentType) {
   if (!GetParam().isCXX()) {
     return;
   }
@@ -955,63 +1084,17 @@
   }
   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
+template <typename T>
+void test() {
+  T::template U<int>::f();
+
+  T::U::f();
+
+  T::template f<0>();
 }
 )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
   |-<
@@ -1030,31 +1113,52 @@
       |-{
       |-ExpressionStatement
       | |-UnknownExpression
-      | | |-UnknownExpression
-      | | | |-T
-      | | | |-::
-      | | | |-template
-      | | | |-f
-      | | | |-<
-      | | | |-IntegerLiteralExpression
-      | | | | `-0
-      | | | `->
+      | | |-IdExpression
+      | | | |-NestedNameSpecifier
+      | | | | |-IdentifierNameSpecifier
+      | | | | | `-T
+      | | | | |-::
+      | | | | |-SimpleTemplateNameSpecifier
+      | | | | | |-template
+      | | | | | |-U
+      | | | | | |-<
+      | | | | | |-int
+      | | | | | `->
+      | | | | `-::
+      | | | `-UnqualifiedId
+      | | |   `-f
+      | | |-(
+      | | `-)
+      | `-;
+      |-ExpressionStatement
+      | |-UnknownExpression
+      | | |-IdExpression
+      | | | |-NestedNameSpecifier
+      | | | | |-IdentifierNameSpecifier
+      | | | | | `-T
+      | | | | |-::
+      | | | | |-IdentifierNameSpecifier
+      | | | | | `-U
+      | | | | `-::
+      | | | `-UnqualifiedId
+      | | |   `-f
       | | |-(
       | | `-)
       | `-;
       |-ExpressionStatement
       | |-UnknownExpression
-      | | |-UnknownExpression
-      | | | |-T
-      | | | |-::
+      | | |-IdExpression
+      | | | |-NestedNameSpecifier
+      | | | | |-IdentifierNameSpecifier
+      | | | | | `-T
+      | | | | `-::
       | | | |-template
-      | | | |-Y
-      | | | |-<
-      | | | |-IntegerLiteralExpression
-      | | | | `-0
-      | | | |->
-      | | | |-::
-      | | | `-f
+      | | | `-UnqualifiedId
+      | | |   |-f
+      | | |   |-<
+      | | |   |-IntegerLiteralExpression
+      | | |   | `-0
+      | | |   `->
       | | |-(
       | | `-)
       | `-;
@@ -1112,14 +1216,14 @@
     | |-UnknownExpression
     | | |-IdExpression
     | | | |-NestedNameSpecifier
-    | | | | `-NameSpecifier
-    | | | |   |-decltype
-    | | | |   |-(
-    | | | |   |-IdExpression
-    | | | |   | `-UnqualifiedId
-    | | | |   |   `-s
-    | | | |   |-)
-    | | | |   `-::
+    | | | | |-DecltypeNameSpecifier
+    | | | | | |-decltype
+    | | | | | |-(
+    | | | | | |-IdExpression
+    | | | | | | `-UnqualifiedId
+    | | | | | |   `-s
+    | | | | | `-)
+    | | | | `-::
     | | | `-UnqualifiedId
     | | |   `-f
     | | |-(
Index: clang/lib/Tooling/Syntax/Nodes.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Nodes.cpp
+++ clang/lib/Tooling/Syntax/Nodes.cpp
@@ -116,8 +116,14 @@
     return OS << "ParametersAndQualifiers";
   case NodeKind::MemberPointer:
     return OS << "MemberPointer";
-  case NodeKind::NameSpecifier:
-    return OS << "NameSpecifier";
+  case NodeKind::GlobalNameSpecifier:
+    return OS << "GlobalNameSpecifier";
+  case NodeKind::DecltypeNameSpecifier:
+    return OS << "DecltypeNameSpecifier";
+  case NodeKind::IdentifierNameSpecifier:
+    return OS << "IdentifierNameSpecifier";
+  case NodeKind::SimpleTemplateNameSpecifier:
+    return OS << "SimpleTemplateNameSpecifier";
   case NodeKind::NestedNameSpecifier:
     return OS << "NestedNameSpecifier";
   }
@@ -142,6 +148,8 @@
     return OS << "ArrowToken";
   case syntax::NodeRole::ExternKeyword:
     return OS << "ExternKeyword";
+  case syntax::NodeRole::TemplateKeyword:
+    return OS << "TemplateKeyword";
   case syntax::NodeRole::BodyStatement:
     return OS << "BodyStatement";
   case syntax::NodeRole::CaseStatement_value:
@@ -190,12 +198,23 @@
     return OS << "IdExpression_qualifier";
   case syntax::NodeRole::NestedNameSpecifier_specifier:
     return OS << "NestedNameSpecifier_specifier";
+  case syntax::NodeRole::NestedNameSpecifier_delimiter:
+    return OS << "NestedNameSpecifier_delimiter";
   case syntax::NodeRole::ParenExpression_subExpression:
     return OS << "ParenExpression_subExpression";
   }
   llvm_unreachable("invalid role");
 }
 
+std::vector<syntax::Leaf *> syntax::NestedNameSpecifier::delimiters() {
+  std::vector<syntax::Leaf *> Children;
+  for (auto *C = firstChild(); C; C = C->nextSibling()) {
+    assert(C->role() == syntax::NodeRole::NestedNameSpecifier_delimiter);
+    Children.push_back(llvm::cast<syntax::Leaf>(C));
+  }
+  return Children;
+}
+
 std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::specifiers() {
   std::vector<syntax::NameSpecifier *> Children;
   for (auto *C = firstChild(); C; C = C->nextSibling()) {
@@ -210,6 +229,11 @@
       findChild(syntax::NodeRole::IdExpression_qualifier));
 }
 
+syntax::Leaf *syntax::IdExpression::templateKeyword() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::TemplateKeyword));
+}
+
 syntax::UnqualifiedId *syntax::IdExpression::unqualifiedId() {
   return llvm::cast_or_null<syntax::UnqualifiedId>(
       findChild(syntax::NodeRole::IdExpression_id));
Index: clang/lib/Tooling/Syntax/BuildTree.cpp
===================================================================
--- clang/lib/Tooling/Syntax/BuildTree.cpp
+++ clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -288,6 +288,11 @@
     foldNode(Range, New, nullptr);
   }
 
+  void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New,
+                NestedNameSpecifierLoc L) {
+    // FIXME: add mapping for NestedNameSpecifierLoc
+    foldNode(Range, New, nullptr);
+  }
   /// Notifies that we should not consume trailing semicolon when computing
   /// token range of \p D.
   void noticeDeclWithoutSemicolon(Decl *D);
@@ -695,21 +700,6 @@
     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 TraverseUserDefinedLiteral(UserDefinedLiteral *S) {
     // The semantic AST node `UserDefinedLiteral` (UDL) may have one child node
     // referencing the location of the UDL suffix (`_w` in `1.2_w`). The
@@ -759,23 +749,121 @@
     return true;
   }
 
+  syntax::NameSpecifier *BuildNameSpecifier(const NestedNameSpecifier &NNS) {
+    switch (NNS.getKind()) {
+    case clang::NestedNameSpecifier::Global:
+      return new (allocator()) syntax::GlobalNameSpecifier;
+    case clang::NestedNameSpecifier::Namespace:
+    case clang::NestedNameSpecifier::NamespaceAlias:
+    case clang::NestedNameSpecifier::Identifier:
+      return new (allocator()) syntax::IdentifierNameSpecifier;
+    case clang::NestedNameSpecifier::TypeSpecWithTemplate:
+      return new (allocator()) syntax::SimpleTemplateNameSpecifier;
+    case clang::NestedNameSpecifier::TypeSpec: {
+      const auto *NNSType = NNS.getAsType();
+      assert(NNSType);
+      if (isa<DecltypeType>(NNSType))
+        return new (allocator()) syntax::DecltypeNameSpecifier;
+      if (isa<TemplateSpecializationType, DependentTemplateSpecializationType>(
+              NNSType))
+        return new (allocator()) syntax::SimpleTemplateNameSpecifier;
+      return new (allocator()) syntax::IdentifierNameSpecifier;
+    }
+    case clang::NestedNameSpecifier::Super:
+      // FIXME: Support Microsoft's __super
+      llvm::report_fatal_error("We don't yet support the __super specifier",
+                               true);
+    }
+  }
+
+  // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` for the
+  // `DependentTemplateSpecializationType` case.
+  /// Given a nested-name-specifier return the range for the last name specifier
+  /// without '::`.
+  ///
+  /// e.g. `std::T::template X<U>::` => `template X<U>`
+  SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) {
+    auto SR = NNSLoc.getLocalSourceRange();
+
+    // Remove "::" from the `SourceRange`
+    SR.setEnd(SR.getEnd().getLocWithOffset(-1));
+
+    // The method `NestedNameSpecifierLoc::getLocalSourceRange` *should* return
+    // the desired `SourceRange` with a trailing '::', but there is a corner
+    // case. For a `DependentTemplateSpecializationType` this method returns its
+    // qualifiers as well, in other words in the example above this method
+    // returns `T::template X<U>::` instead of only `template X<U>::`
+    if (auto TL = NNSLoc.getTypeLoc()) {
+      if (auto DependentTL =
+              TL.getAs<DependentTemplateSpecializationTypeLoc>()) {
+        // The 'template' keyword is always present in dependent template
+        // specializations. Except in the case of incorrect code
+        // TODO: Treat the case of incorrect code.
+        SR.setBegin(DependentTL.getTemplateKeywordLoc());
+      }
+    }
+
+    return SR;
+  }
+
+  syntax::NestedNameSpecifier *
+  BuildNestedNameSpecifier(const NestedNameSpecifierLoc &QualifierLoc) {
+    if (!QualifierLoc)
+      return nullptr;
+    for (auto it = QualifierLoc; it; it = it.getPrefix()) {
+      assert(it.hasQualifier());
+      auto *NS = BuildNameSpecifier(*it.getNestedNameSpecifier());
+      assert(NS);
+      if (!isa<syntax::GlobalNameSpecifier>(NS))
+        Builder.foldNode(Builder.getRange(getLocalSourceRange(it)), NS, it);
+      Builder.markChild(NS, syntax::NodeRole::NestedNameSpecifier_specifier);
+      Builder.markChildToken(it.getEndLoc(),
+                             syntax::NodeRole::NestedNameSpecifier_delimiter);
+    }
+    auto *NNS = new (allocator()) syntax::NestedNameSpecifier;
+    Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()), NNS,
+                     QualifierLoc);
+    return NNS;
+  }
+
   bool WalkUpFromDeclRefExpr(DeclRefExpr *S) {
-    if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
-      Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
+    auto *Qualifier = BuildNestedNameSpecifier(S->getQualifierLoc());
+    if (Qualifier)
+      Builder.markChild(Qualifier, syntax::NodeRole::IdExpression_qualifier);
+
+    auto TemplateKeywordLoc = S->getTemplateKeywordLoc();
+    if (TemplateKeywordLoc.isValid())
+      Builder.markChildToken(TemplateKeywordLoc,
+                             syntax::NodeRole::TemplateKeyword);
 
     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.foldNode(Builder.getRange(S->getLocation(), S->getEndLoc()),
+                     unqualifiedId, nullptr);
+
+    Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
+
+    Builder.foldNode(Builder.getExprRange(S),
+                     new (allocator()) syntax::IdExpression, S);
+    return true;
+  }
+
+  // FIXME: Same logic as DeclRefExpr. How to DRY
+  bool WalkUpFromDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
+    auto *Qualifier = BuildNestedNameSpecifier(S->getQualifierLoc());
+    if (Qualifier)
+      Builder.markChild(Qualifier, syntax::NodeRole::IdExpression_qualifier);
+
+    auto TemplateKeywordLoc = S->getTemplateKeywordLoc();
+    if (TemplateKeywordLoc.isValid())
+      Builder.markChildToken(TemplateKeywordLoc,
+                             syntax::NodeRole::TemplateKeyword);
+
+    auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId;
+
+    Builder.foldNode(Builder.getRange(S->getLocation(), S->getEndLoc()),
+                     unqualifiedId, nullptr);
+
     Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
 
     Builder.foldNode(Builder.getExprRange(S),
Index: clang/include/clang/Tooling/Syntax/Nodes.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Nodes.h
+++ clang/include/clang/Tooling/Syntax/Nodes.h
@@ -95,9 +95,13 @@
   TrailingReturnType,
   ParametersAndQualifiers,
   MemberPointer,
+  UnqualifiedId,
+  // Nested Name Specifiers.
   NestedNameSpecifier,
-  NameSpecifier,
-  UnqualifiedId
+  GlobalNameSpecifier,
+  DecltypeNameSpecifier,
+  IdentifierNameSpecifier,
+  SimpleTemplateNameSpecifier
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -138,6 +142,7 @@
   /// Tokens or Keywords
   ArrowToken,
   ExternKeyword,
+  TemplateKeyword,
   /// An inner statement for those that have only a single child of kind
   /// statement, e.g. loop body for while, for, etc; inner statement for case,
   /// default, etc.
@@ -167,6 +172,7 @@
   IdExpression_id,
   IdExpression_qualifier,
   NestedNameSpecifier_specifier,
+  NestedNameSpecifier_delimiter,
   ParenExpression_subExpression
 };
 /// For debugging purposes.
@@ -196,11 +202,57 @@
 
 /// 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 {
+class NameSpecifier : public Tree {
 public:
-  NameSpecifier() : Tree(NodeKind::NameSpecifier) {}
+  NameSpecifier(NodeKind K) : Tree(K) {}
   static bool classof(const Node *N) {
-    return N->kind() == NodeKind::NameSpecifier;
+    return N->kind() == NodeKind::GlobalNameSpecifier ||
+           N->kind() == NodeKind::DecltypeNameSpecifier ||
+           N->kind() == NodeKind::IdentifierNameSpecifier ||
+           N->kind() == NodeKind::SimpleTemplateNameSpecifier;
+  }
+};
+
+/// The global namespace name specifier, e.g. the first `::` in
+/// `::std::vector<int>`
+class GlobalNameSpecifier final : public NameSpecifier {
+public:
+  GlobalNameSpecifier() : NameSpecifier(NodeKind::GlobalNameSpecifier) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::GlobalNameSpecifier;
+  }
+};
+
+/// A name specifier holding a decltype, of the form: `decltype ( expression )
+/// ::` e.g. the `decltype(s)::` in `decltype(s)::size`.
+class DecltypeNameSpecifier final : public NameSpecifier {
+public:
+  DecltypeNameSpecifier() : NameSpecifier(NodeKind::DecltypeNameSpecifier) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::DecltypeNameSpecifier;
+  }
+};
+
+/// A identifier name specifier, of the form `identifier ::`
+/// e.g. the `std::` in `std::vector<int>::size`.
+class IdentifierNameSpecifier final : public NameSpecifier {
+public:
+  IdentifierNameSpecifier()
+      : NameSpecifier(NodeKind::IdentifierNameSpecifier) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::IdentifierNameSpecifier;
+  }
+};
+
+/// A name specifier with a simple-template-id, of the form `template_opt
+/// identifier < template-args > ::` e.g. the `vector<int>::` in
+/// `std::vector<int>::size`.
+class SimpleTemplateNameSpecifier final : public NameSpecifier {
+public:
+  SimpleTemplateNameSpecifier()
+      : NameSpecifier(NodeKind::SimpleTemplateNameSpecifier) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::SimpleTemplateNameSpecifier;
   }
 };
 
@@ -213,6 +265,7 @@
     return N->kind() <= NodeKind::NestedNameSpecifier;
   }
   std::vector<syntax::NameSpecifier *> specifiers();
+  std::vector<syntax::Leaf *> delimiters();
 };
 
 /// Models an `unqualified-id`. C++ [expr.prim.id.unqual]
@@ -239,8 +292,7 @@
     return N->kind() == NodeKind::IdExpression;
   }
   syntax::NestedNameSpecifier *qualifier();
-  // TODO after expose `id-expression` from `DependentScopeDeclRefExpr`:
-  // Add accessor for `template_opt`.
+  syntax::Leaf *templateKeyword();
   syntax::UnqualifiedId *unqualifiedId();
 };
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to