eduucaldas updated this revision to Diff 280497.
eduucaldas added a comment.

- Improve getLocalSourceRange
- nested-name-specifier is now a ::-separated list of name-specifiers


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 TS {
+      static void f();
+    };
   };
 }
+template<typename T>
+struct TS {
+  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 TS<int>:: // type-template-instantiation-specifier
+  f();
+
+  n::                // namespace-specifier
+  S::                // type-name-specifier
+  TS<int>::          // type-template-instantiation-specifier
+  f();
+
+  TS<int>::         // type-name-specifier
+  S::               // type-name-specifier
   f<int>();
+
+  TS<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
+| | |   |-TS
+| | |   |-{
+| | |   |-SimpleDeclaration
+| | |   | |-static
+| | |   | |-void
+| | |   | |-SimpleDeclarator
+| | |   | | |-f
+| | |   | | `-ParametersAndQualifiers
+| | |   | |   |-(
+| | |   | |   `-)
+| | |   | `-;
+| | |   |-}
+| | |   `-;
 | | |-}
 | | `-;
 | `-}
+|-TemplateDeclaration
+| |-template
+| |-<
+| |-UnknownDeclaration
+| | |-typename
+| | `-T
+| |->
+| `-SimpleDeclaration
+|   |-struct
+|   |-TS
+|   |-{
+|   |-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
+    | | | | | |-TS
+    | | | | | |-<
+    | | | | | |-int
+    | | | | | `->
+    | | | | `-::
+    | | | `-UnqualifiedId
+    | | |   `-f
+    | | |-(
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-n
+    | | | | |-::
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-S
+    | | | | |-::
+    | | | | |-SimpleTemplateNameSpecifier
+    | | | | | |-TS
+    | | | | | |-<
+    | | | | | |-int
+    | | | | | `->
+    | | | | `-::
+    | | | `-UnqualifiedId
+    | | |   `-f
+    | | |-(
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | |-SimpleTemplateNameSpecifier
+    | | | | | |-TS
+    | | | | | |-<
+    | | | | | |-int
+    | | | | | `->
+    | | | | |-::
+    | | | | |-IdentifierNameSpecifier
+    | | | | | `-S
+    | | | | `-::
+    | | | `-UnqualifiedId
+    | | |   |-f
+    | | |   |-<
+    | | |   |-int
+    | | |   `->
+    | | |-(
+    | | `-)
+    | `-;
+    |-ExpressionStatement
+    | |-UnknownExpression
+    | | |-IdExpression
+    | | | |-NestedNameSpecifier
+    | | | | |-SimpleTemplateNameSpecifier
+    | | | | | |-TS
+    | | | | | |-<
+    | | | | | |-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
@@ -695,21 +695,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 +744,133 @@
     return true;
   }
 
+  bool isDecltype(const Type &T) {
+    return T.getTypeClass() == Type::TypeClass::Decltype;
+  }
+
+  bool isTemplateInstantiation(const Type &T) {
+    return T.getTypeClass() == Type::TypeClass::TemplateSpecialization ||
+           T.getTypeClass() == Type::TypeClass::DependentTemplateSpecialization;
+  }
+
+  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 (isDecltype(*NNSType))
+        return new (allocator()) syntax::DecltypeNameSpecifier;
+      if (!isTemplateInstantiation(*NNSType))
+        return new (allocator()) syntax::IdentifierNameSpecifier;
+      return new (allocator()) syntax::SimpleTemplateNameSpecifier;
+    }
+    case clang::NestedNameSpecifier::Super:
+      // FIXME: Support Microsoft's __super
+      assert(false && "We don't yet treat the __super specifier");
+    }
+  }
+
+  // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` instead
+  // Given a nested-name-specifier `std::T::template X<U>::`
+  // return the range for the last specifier i.e. `template X<U>::`
+  SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) {
+    // The method `NestedNameSpecifierLoc::getLocalSourceRange` *should* return
+    // the desired `SourceRange`, 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>::`
+    auto SR = NNSLoc.getLocalSourceRange();
+
+    if (auto TL = NNSLoc.getTypeLoc()) {
+      if (auto DependentTL =
+              TL.getAs<DependentTemplateSpecializationTypeLoc>()) {
+        // The 'template' keyword is always present in dependent template
+        // specializations
+        SR.setBegin(DependentTL.getTemplateKeywordLoc());
+      }
+    }
+    // Removes :: from the SourceRange
+    SR.setEnd(SR.getEnd().getLocWithOffset(-1));
+    SR.dump(Builder.sourceManager());
+    return SR;
+  }
+
+  syntax::NestedNameSpecifier *
+  BuildNestedNameSpecifier(const NestedNameSpecifierLoc &QualifierLoc) {
+    if (!QualifierLoc)
+      return nullptr;
+    for (auto it = QualifierLoc; it; it = it.getPrefix()) {
+      const auto *NNS = it.getNestedNameSpecifier();
+      assert(NNS);
+      auto *NS = BuildNameSpecifier(*NNS);
+      if (!syntax::GlobalNameSpecifier::classof(NS))
+        Builder.foldNode(Builder.getRange(getLocalSourceRange(it)), NS,
+                         nullptr);
+      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,
+        nullptr); // FIXME: add link to semantic NestedNameSpecifier
+    return NNS;
+  }
+
+  // FIXME: I feel like this could be upstreamed.
+  SourceRange getUnqualifiedIdSourceRange(DeclRefExpr *S) {
+    if (S->hasExplicitTemplateArgs())
+      return SourceRange(S->getNameInfo().getBeginLoc(), S->getRAngleLoc());
+    return S->getNameInfo().getSourceRange();
+  }
+
   bool WalkUpFromDeclRefExpr(DeclRefExpr *S) {
     if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
       Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
 
+    if (auto TKL = S->getTemplateKeywordLoc(); TKL.isValid())
+      Builder.markChildToken(TKL, 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(getUnqualifiedIdSourceRange(S)),
+                     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?
+  SourceRange getUnqualifiedIdSourceRange(DependentScopeDeclRefExpr *S) {
+    if (S->hasExplicitTemplateArgs())
+      return SourceRange(S->getNameInfo().getBeginLoc(), S->getRAngleLoc());
+    return S->getNameInfo().getSourceRange();
+  }
+
+  // FIXME: Same logic as DeclRefExpr. How to DRY
+  bool WalkUpFromDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
+    if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
+      Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
+
+    if (auto TKL = S->getTemplateKeywordLoc(); TKL.isValid())
+      Builder.markChildToken(TKL, syntax::NodeRole::TemplateKeyword);
+
+    auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId;
+
+    Builder.foldNode(Builder.getRange(getUnqualifiedIdSourceRange(S)),
+                     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,14 @@
   TrailingReturnType,
   ParametersAndQualifiers,
   MemberPointer,
+  UnqualifiedId,
+  // Nested Name Specifiers.
   NestedNameSpecifier,
-  NameSpecifier,
-  UnqualifiedId
+  UnknownNameSpecifier,
+  GlobalNameSpecifier,
+  DecltypeNameSpecifier,
+  IdentifierNameSpecifier,
+  SimpleTemplateNameSpecifier
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -138,6 +143,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 +173,7 @@
   IdExpression_id,
   IdExpression_qualifier,
   NestedNameSpecifier_specifier,
+  NestedNameSpecifier_delimiter,
   ParenExpression_subExpression
 };
 /// For debugging purposes.
@@ -196,11 +203,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 +266,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 +293,8 @@
     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