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

- [SyntaxTree] Fix crash on name specifier.

This diff revision is based on https://reviews.llvm.org/D84348


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D84781

Files:
  clang/include/clang/Tooling/Syntax/Nodes.h
  clang/include/clang/Tooling/Syntax/Tree.h
  clang/lib/Tooling/Syntax/BuildTree.cpp
  clang/lib/Tooling/Syntax/Nodes.cpp
  clang/lib/Tooling/Syntax/Tree.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
@@ -994,18 +994,19 @@
     | | |-IdExpression
     | | | |-NestedNameSpecifier
     | | | | |-::
-    | | | | |-IdentifierNameSpecifier
+    | | | | |-NameSpecifier
     | | | | | `-n
     | | | | |-::
-    | | | | |-IdentifierNameSpecifier
+    | | | | |-NameSpecifier
     | | | | | `-S
     | | | | |-::
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-template
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
+    | | | | |-NameSpecifier
+    | | | | | `-SimpleTemplateSpecifier
+    | | | | |   |-template
+    | | | | |   |-ST
+    | | | | |   |-<
+    | | | | |   |-int
+    | | | | |   `->
     | | | | `-::
     | | | `-UnqualifiedId
     | | |   `-f
@@ -1016,17 +1017,18 @@
     | |-UnknownExpression
     | | |-IdExpression
     | | | |-NestedNameSpecifier
-    | | | | |-IdentifierNameSpecifier
+    | | | | |-NameSpecifier
     | | | | | `-n
     | | | | |-::
-    | | | | |-IdentifierNameSpecifier
+    | | | | |-NameSpecifier
     | | | | | `-S
     | | | | |-::
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
+    | | | | |-NameSpecifier
+    | | | | | `-SimpleTemplateSpecifier
+    | | | | |   |-ST
+    | | | | |   |-<
+    | | | | |   |-int
+    | | | | |   `->
     | | | | `-::
     | | | `-UnqualifiedId
     | | |   `-f
@@ -1037,13 +1039,14 @@
     | |-UnknownExpression
     | | |-IdExpression
     | | | |-NestedNameSpecifier
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
+    | | | | |-NameSpecifier
+    | | | | | `-SimpleTemplateSpecifier
+    | | | | |   |-ST
+    | | | | |   |-<
+    | | | | |   |-int
+    | | | | |   `->
     | | | | |-::
-    | | | | |-IdentifierNameSpecifier
+    | | | | |-NameSpecifier
     | | | | | `-S
     | | | | `-::
     | | | `-UnqualifiedId
@@ -1058,13 +1061,14 @@
     | |-UnknownExpression
     | | |-IdExpression
     | | | |-NestedNameSpecifier
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
+    | | | | |-NameSpecifier
+    | | | | | `-SimpleTemplateSpecifier
+    | | | | |   |-ST
+    | | | | |   |-<
+    | | | | |   |-int
+    | | | | |   `->
     | | | | |-::
-    | | | | |-IdentifierNameSpecifier
+    | | | | |-NameSpecifier
     | | | | | `-S
     | | | | `-::
     | | | |-template
@@ -1122,15 +1126,16 @@
       | |-UnknownExpression
       | | |-IdExpression
       | | | |-NestedNameSpecifier
-      | | | | |-IdentifierNameSpecifier
+      | | | | |-NameSpecifier
       | | | | | `-T
       | | | | |-::
-      | | | | |-SimpleTemplateNameSpecifier
-      | | | | | |-template
-      | | | | | |-U
-      | | | | | |-<
-      | | | | | |-int
-      | | | | | `->
+      | | | | |-NameSpecifier
+      | | | | | `-SimpleTemplateSpecifier
+      | | | | |   |-template
+      | | | | |   |-U
+      | | | | |   |-<
+      | | | | |   |-int
+      | | | | |   `->
       | | | | `-::
       | | | `-UnqualifiedId
       | | |   `-f
@@ -1141,10 +1146,10 @@
       | |-UnknownExpression
       | | |-IdExpression
       | | | |-NestedNameSpecifier
-      | | | | |-IdentifierNameSpecifier
+      | | | | |-NameSpecifier
       | | | | | `-T
       | | | | |-::
-      | | | | |-IdentifierNameSpecifier
+      | | | | |-NameSpecifier
       | | | | | `-U
       | | | | `-::
       | | | `-UnqualifiedId
@@ -1156,7 +1161,7 @@
       | |-UnknownExpression
       | | |-IdExpression
       | | | |-NestedNameSpecifier
-      | | | | |-IdentifierNameSpecifier
+      | | | | |-NameSpecifier
       | | | | | `-T
       | | | | `-::
       | | | |-template
@@ -1223,13 +1228,14 @@
     | |-UnknownExpression
     | | |-IdExpression
     | | | |-NestedNameSpecifier
-    | | | | |-DecltypeNameSpecifier
-    | | | | | |-decltype
-    | | | | | |-(
-    | | | | | |-IdExpression
-    | | | | | | `-UnqualifiedId
-    | | | | | |   `-s
-    | | | | | `-)
+    | | | | |-NameSpecifier
+    | | | | | `-DecltypeSpecifier
+    | | | | |   |-decltype
+    | | | | |   |-(
+    | | | | |   |-IdExpression
+    | | | | |   | `-UnqualifiedId
+    | | | | |   |   `-s
+    | | | | |   `-)
     | | | | `-::
     | | | `-UnqualifiedId
     | | |   `-f
Index: clang/lib/Tooling/Syntax/Tree.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Tree.cpp
+++ clang/lib/Tooling/Syntax/Tree.cpp
@@ -56,6 +56,12 @@
   return N->kind() == NodeKind::Leaf;
 }
 
+syntax::EmptyNode::EmptyNode() : Node(NodeKind::EmptyNode) {}
+
+bool syntax::EmptyNode::classof(const Node *N) {
+  return N->kind() == NodeKind::EmptyNode;
+}
+
 syntax::Node::Node(NodeKind Kind)
     : Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)),
       Role(0), Original(false), CanModify(false) {
Index: clang/lib/Tooling/Syntax/Nodes.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Nodes.cpp
+++ clang/lib/Tooling/Syntax/Nodes.cpp
@@ -12,6 +12,8 @@
 
 llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
   switch (K) {
+  case NodeKind::EmptyNode:
+    return OS << "EmptyNode";
   case NodeKind::Leaf:
     return OS << "Leaf";
   case NodeKind::TranslationUnit:
@@ -116,14 +118,12 @@
     return OS << "ParametersAndQualifiers";
   case NodeKind::MemberPointer:
     return OS << "MemberPointer";
-  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::NameSpecifier:
+    return OS << "NameSpecifier";
+  case NodeKind::DecltypeSpecifier:
+    return OS << "DecltypeSpecifier";
+  case NodeKind::SimpleTemplateSpecifier:
+    return OS << "SimpleTemplateSpecifier";
   case NodeKind::NestedNameSpecifier:
     return OS << "NestedNameSpecifier";
   }
@@ -210,6 +210,15 @@
   llvm_unreachable("invalid role");
 }
 
+llvm::PointerUnion<syntax::EmptyNode *, syntax::Leaf *,
+                   syntax::DecltypeSpecifier *,
+                   syntax::SimpleTemplateSpecifier *>
+syntax::NameSpecifier::child() {
+  return llvm::PointerUnion<
+      syntax::EmptyNode *, syntax::Leaf *, syntax::DecltypeSpecifier *,
+      syntax::SimpleTemplateSpecifier *>::getFromOpaqueValue(firstChild());
+}
+
 std::vector<syntax::Leaf *> syntax::NestedNameSpecifier::delimiters() {
   std::vector<syntax::Leaf *> Children;
   for (auto *C = firstChild(); C; C = C->nextSibling()) {
Index: clang/lib/Tooling/Syntax/BuildTree.cpp
===================================================================
--- clang/lib/Tooling/Syntax/BuildTree.cpp
+++ clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -749,25 +749,51 @@
     return true;
   }
 
-  syntax::NameSpecifier *BuildNameSpecifier(const NestedNameSpecifier &NNS) {
+  // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` for the
+  // `DependentTemplateSpecializationType` case.
+  /// Given a nested-name-specifier return the range for the last name specifier
+  ///
+  /// e.g. `std::T::template X<U>::` => `template X<U>::`
+  SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) {
+    auto SR = NNSLoc.getLocalSourceRange();
+
+    // 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>::`
+    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::NodeKind getNameSpecifierChildKind(const NestedNameSpecifier &NNS) {
     switch (NNS.getKind()) {
     case clang::NestedNameSpecifier::Global:
-      return new (allocator()) syntax::GlobalNameSpecifier;
+      return syntax::NodeKind::EmptyNode;
     case clang::NestedNameSpecifier::Namespace:
     case clang::NestedNameSpecifier::NamespaceAlias:
     case clang::NestedNameSpecifier::Identifier:
-      return new (allocator()) syntax::IdentifierNameSpecifier;
+      return syntax::NodeKind::Leaf;
     case clang::NestedNameSpecifier::TypeSpecWithTemplate:
-      return new (allocator()) syntax::SimpleTemplateNameSpecifier;
+      return syntax::NodeKind::SimpleTemplateSpecifier;
     case clang::NestedNameSpecifier::TypeSpec: {
       const auto *NNSType = NNS.getAsType();
       assert(NNSType);
       if (isa<DecltypeType>(NNSType))
-        return new (allocator()) syntax::DecltypeNameSpecifier;
+        return syntax::NodeKind::DecltypeSpecifier;
       if (isa<TemplateSpecializationType, DependentTemplateSpecializationType>(
               NNSType))
-        return new (allocator()) syntax::SimpleTemplateNameSpecifier;
-      return new (allocator()) syntax::IdentifierNameSpecifier;
+        return syntax::NodeKind::SimpleTemplateSpecifier;
+      return syntax::NodeKind::Leaf;
     }
     case clang::NestedNameSpecifier::Super:
       // FIXME: Support Microsoft's __super
@@ -776,34 +802,44 @@
     }
   }
 
-  // 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));
+  syntax::NameSpecifier *
+  BuildNameSpecifier(const NestedNameSpecifierLoc &NNSLoc) {
+    auto NameSpecifierTokens =
+        Builder.getRange(getLocalSourceRange(NNSLoc)).drop_back(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());
-      }
+    auto *NNS = NNSLoc.getNestedNameSpecifier();
+    assert(NNS);
+    switch (getNameSpecifierChildKind(*NNS)) {
+    case syntax::NodeKind::EmptyNode: {
+      Builder.markChild(new (allocator()) syntax::EmptyNode,
+                        syntax::NodeRole::Unknown);
+      return new (allocator()) syntax::NameSpecifier;
+    }
+    case syntax::NodeKind::Leaf: {
+      assert(NameSpecifierTokens.size() == 1);
+      Builder.markChildToken(NameSpecifierTokens.begin(),
+                             syntax::NodeRole::Unknown);
+      break;
+    }
+    case syntax::NodeKind::SimpleTemplateSpecifier: {
+      auto *child = new (allocator()) syntax::SimpleTemplateSpecifier;
+      Builder.foldNode(NameSpecifierTokens, child, nullptr);
+      Builder.markChild(child, syntax::NodeRole::Unknown);
+      break;
+    }
+    case syntax::NodeKind::DecltypeSpecifier: {
+      auto *child = new (allocator()) syntax::DecltypeSpecifier;
+      Builder.foldNode(NameSpecifierTokens, child, nullptr);
+      Builder.markChild(child, syntax::NodeRole::Unknown);
+      break;
+    }
+    default:
+      llvm_unreachable("getChildKind() does not return this value");
     }
 
-    return SR;
+    auto *NS = new (allocator()) syntax::NameSpecifier;
+    Builder.foldNode(NameSpecifierTokens, NS, nullptr);
+    return NS;
   }
 
   syntax::NestedNameSpecifier *
@@ -811,11 +847,8 @@
     if (!QualifierLoc)
       return nullptr;
     for (auto it = QualifierLoc; it; it = it.getPrefix()) {
-      assert(it.hasQualifier());
-      auto *NS = BuildNameSpecifier(*it.getNestedNameSpecifier());
+      auto *NS = BuildNameSpecifier(it);
       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);
Index: clang/include/clang/Tooling/Syntax/Tree.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Tree.h
+++ clang/include/clang/Tooling/Syntax/Tree.h
@@ -148,6 +148,12 @@
   const syntax::Token *Tok;
 };
 
+class EmptyNode final : public Node {
+public:
+  EmptyNode();
+  static bool classof(const Node *N);
+};
+
 /// A node that has children and represents a syntactic language construct.
 class Tree : public Node {
 public:
Index: clang/include/clang/Tooling/Syntax/Nodes.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Nodes.h
+++ clang/include/clang/Tooling/Syntax/Nodes.h
@@ -36,6 +36,7 @@
 /// of syntax::Node.
 enum class NodeKind : uint16_t {
   Leaf,
+  EmptyNode,
   TranslationUnit,
 
   // Expressions.
@@ -96,12 +97,12 @@
   ParametersAndQualifiers,
   MemberPointer,
   UnqualifiedId,
+
   // Nested Name Specifiers.
   NestedNameSpecifier,
-  GlobalNameSpecifier,
-  DecltypeNameSpecifier,
-  IdentifierNameSpecifier,
-  SimpleTemplateNameSpecifier
+  NameSpecifier,
+  DecltypeSpecifier,
+  SimpleTemplateSpecifier
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -202,62 +203,34 @@
   }
 };
 
-/// A sequence of these specifiers make a `nested-name-specifier`.
-/// e.g. the `std` or `vector<int>` in `std::vector<int>::size`.
-class NameSpecifier : public Tree {
-public:
-  NameSpecifier(NodeKind K) : Tree(K) {}
-  static bool classof(const Node *N) {
-    return N->kind() == NodeKind::GlobalNameSpecifier ||
-           N->kind() == NodeKind::DecltypeNameSpecifier ||
-           N->kind() == NodeKind::IdentifierNameSpecifier ||
-           N->kind() == NodeKind::SimpleTemplateNameSpecifier;
-  }
-};
-
-/// The global namespace name specifier, this specifier doesn't correspond to a
-/// token instead an absence of tokens before a `::` characterizes it, in
-/// `::std::vector<int>` it would be characterized by the absence of a token
-/// before the first `::`
-class GlobalNameSpecifier final : public NameSpecifier {
+class DecltypeSpecifier final : public Tree {
 public:
-  GlobalNameSpecifier() : NameSpecifier(NodeKind::GlobalNameSpecifier) {}
+  DecltypeSpecifier() : Tree(NodeKind::DecltypeSpecifier) {}
   static bool classof(const Node *N) {
-    return N->kind() == NodeKind::GlobalNameSpecifier;
+    return N->kind() == NodeKind::DecltypeSpecifier;
   }
 };
 
-/// 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 {
+class SimpleTemplateSpecifier : public Tree {
 public:
-  DecltypeNameSpecifier() : NameSpecifier(NodeKind::DecltypeNameSpecifier) {}
+  SimpleTemplateSpecifier() : Tree(NodeKind::SimpleTemplateSpecifier) {}
   static bool classof(const Node *N) {
-    return N->kind() == NodeKind::DecltypeNameSpecifier;
+    return N->kind() == NodeKind::SimpleTemplateSpecifier;
   }
 };
 
-/// 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 {
+/// 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:
-  SimpleTemplateNameSpecifier()
-      : NameSpecifier(NodeKind::SimpleTemplateNameSpecifier) {}
+  NameSpecifier() : Tree(NodeKind::NameSpecifier) {}
   static bool classof(const Node *N) {
-    return N->kind() == NodeKind::SimpleTemplateNameSpecifier;
+    return N->kind() == NodeKind::NameSpecifier;
   }
+  llvm::PointerUnion<syntax::EmptyNode *, syntax::Leaf *,
+                     syntax::DecltypeSpecifier *,
+                     syntax::SimpleTemplateSpecifier *>
+  child();
 };
 
 /// Models a `nested-name-specifier`. C++ [expr.prim.id.qual]
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to