diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/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. raw_ostream &operator<<(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` in `std::vector::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` 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::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` in -/// `std::vector::size`. -class SimpleTemplateNameSpecifier final : public NameSpecifier { +/// A sequence of these specifiers make a `nested-name-specifier`. +/// e.g. the `std` or `vector` in `std::vector::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 + child(); }; /// Models a `nested-name-specifier`. C++ [expr.prim.id.qual] diff --git a/clang/include/clang/Tooling/Syntax/Tree.h b/clang/include/clang/Tooling/Syntax/Tree.h --- a/clang/include/clang/Tooling/Syntax/Tree.h +++ b/clang/include/clang/Tooling/Syntax/Tree.h @@ -148,6 +148,12 @@ const 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: diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -744,25 +744,25 @@ return true; } - syntax::NameSpecifier *BuildNameSpecifier(const NestedNameSpecifier &NNS) { + 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(NNSType)) - return new (allocator()) syntax::DecltypeNameSpecifier; + return syntax::NodeKind::DecltypeSpecifier; if (isa( 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 @@ -771,6 +771,46 @@ } } + syntax::NameSpecifier * + BuildNameSpecifier(const NestedNameSpecifierLoc &NNSLoc) { + auto NameSpecifierTokens = + Builder.getRange(getLocalSourceRange(NNSLoc)).drop_back(1); + + 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"); + } + + auto *NS = new (allocator()) syntax::NameSpecifier; + Builder.foldNode(NameSpecifierTokens, NS, nullptr); + return NS; + } + // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` for the // `DependentTemplateSpecializationType` case. /// Given a nested-name-specifier return the range for the last name specifier @@ -802,12 +842,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(NS)) - Builder.foldNode(Builder.getRange(getLocalSourceRange(it)).drop_back(), - NS, it); Builder.markChild(NS, syntax::NodeRole::NestedNameSpecifier_specifier); Builder.markChildToken(it.getEndLoc(), syntax::NodeRole::NestedNameSpecifier_delimiter); diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -12,6 +12,8 @@ raw_ostream &syntax::operator<<(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::NameSpecifier::child() { + return llvm::PointerUnion< + syntax::EmptyNode *, syntax::Leaf *, syntax::DecltypeSpecifier *, + syntax::SimpleTemplateSpecifier *>::getFromOpaqueValue(firstChild()); +} + std::vector syntax::NestedNameSpecifier::delimiters() { std::vector Children; for (auto *C = firstChild(); C; C = C->nextSibling()) { diff --git a/clang/lib/Tooling/Syntax/Tree.cpp b/clang/lib/Tooling/Syntax/Tree.cpp --- a/clang/lib/Tooling/Syntax/Tree.cpp +++ b/clang/lib/Tooling/Syntax/Tree.cpp @@ -54,6 +54,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(Kind)), Role(0), Original(false), CanModify(false) { diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -993,18 +993,19 @@ | | |-IdExpression | | | |-NestedNameSpecifier | | | | |-:: - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-n | | | | |-:: - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-S | | | | |-:: - | | | | |-SimpleTemplateNameSpecifier - | | | | | |-template - | | | | | |-ST - | | | | | |-< - | | | | | |-int - | | | | | `-> + | | | | |-NameSpecifier + | | | | | `-SimpleTemplateSpecifier + | | | | | |-template + | | | | | |-ST + | | | | | |-< + | | | | | |-int + | | | | | `-> | | | | `-:: | | | `-UnqualifiedId | | | `-f @@ -1015,17 +1016,18 @@ | |-UnknownExpression | | |-IdExpression | | | |-NestedNameSpecifier - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-n | | | | |-:: - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-S | | | | |-:: - | | | | |-SimpleTemplateNameSpecifier - | | | | | |-ST - | | | | | |-< - | | | | | |-int - | | | | | `-> + | | | | |-NameSpecifier + | | | | | `-SimpleTemplateSpecifier + | | | | | |-ST + | | | | | |-< + | | | | | |-int + | | | | | `-> | | | | `-:: | | | `-UnqualifiedId | | | `-f @@ -1036,13 +1038,14 @@ | |-UnknownExpression | | |-IdExpression | | | |-NestedNameSpecifier - | | | | |-SimpleTemplateNameSpecifier - | | | | | |-ST - | | | | | |-< - | | | | | |-int - | | | | | `-> + | | | | |-NameSpecifier + | | | | | `-SimpleTemplateSpecifier + | | | | | |-ST + | | | | | |-< + | | | | | |-int + | | | | | `-> | | | | |-:: - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-S | | | | `-:: | | | `-UnqualifiedId @@ -1057,13 +1060,14 @@ | |-UnknownExpression | | |-IdExpression | | | |-NestedNameSpecifier - | | | | |-SimpleTemplateNameSpecifier - | | | | | |-ST - | | | | | |-< - | | | | | |-int - | | | | | `-> + | | | | |-NameSpecifier + | | | | | `-SimpleTemplateSpecifier + | | | | | |-ST + | | | | | |-< + | | | | | |-int + | | | | | `-> | | | | |-:: - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-S | | | | `-:: | | | |-template @@ -1121,15 +1125,16 @@ | |-UnknownExpression | | |-IdExpression | | | |-NestedNameSpecifier - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-T | | | | |-:: - | | | | |-SimpleTemplateNameSpecifier - | | | | | |-template - | | | | | |-U - | | | | | |-< - | | | | | |-int - | | | | | `-> + | | | | |-NameSpecifier + | | | | | `-SimpleTemplateSpecifier + | | | | | |-template + | | | | | |-U + | | | | | |-< + | | | | | |-int + | | | | | `-> | | | | `-:: | | | `-UnqualifiedId | | | `-f @@ -1140,10 +1145,10 @@ | |-UnknownExpression | | |-IdExpression | | | |-NestedNameSpecifier - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-T | | | | |-:: - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-U | | | | `-:: | | | `-UnqualifiedId @@ -1155,7 +1160,7 @@ | |-UnknownExpression | | |-IdExpression | | | |-NestedNameSpecifier - | | | | |-IdentifierNameSpecifier + | | | | |-NameSpecifier | | | | | `-T | | | | `-:: | | | |-template @@ -1222,13 +1227,14 @@ | |-UnknownExpression | | |-IdExpression | | | |-NestedNameSpecifier - | | | | |-DecltypeNameSpecifier - | | | | | |-decltype - | | | | | |-( - | | | | | |-IdExpression - | | | | | | `-UnqualifiedId - | | | | | | `-s - | | | | | `-) + | | | | |-NameSpecifier + | | | | | `-DecltypeSpecifier + | | | | | |-decltype + | | | | | |-( + | | | | | |-IdExpression + | | | | | | `-UnqualifiedId + | | | | | | `-s + | | | | | `-) | | | | `-:: | | | `-UnqualifiedId | | | `-f