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 @@ -173,8 +173,6 @@ ParametersAndQualifiers_trailingReturn, IdExpression_id, IdExpression_qualifier, - NestedNameSpecifier_specifier, - NestedNameSpecifier_delimiter, ParenExpression_subExpression }; /// For debugging purposes. @@ -262,14 +260,15 @@ /// Models a `nested-name-specifier`. C++ [expr.prim.id.qual] /// e.g. the `std::vector::` in `std::vector::size`. -class NestedNameSpecifier final : public Tree { +class NestedNameSpecifier final : public List { public: - NestedNameSpecifier() : Tree(NodeKind::NestedNameSpecifier) {} + NestedNameSpecifier() : List(NodeKind::NestedNameSpecifier) {} static bool classof(const Node *N) { return N->kind() <= NodeKind::NestedNameSpecifier; } std::vector specifiers(); - std::vector delimiters(); + std::vector> + specifiersAndDoubleColons(); }; /// Models an `unqualified-id`. C++ [expr.prim.id.unqual] 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 @@ -809,9 +809,8 @@ 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); + Builder.markChild(NS, syntax::NodeRole::List_element); + Builder.markChildToken(it.getEndLoc(), syntax::NodeRole::List_delimiter); } auto *NNS = new (allocator()) syntax::NestedNameSpecifier; Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()), NNS, 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 @@ -200,30 +200,32 @@ return OS << "IdExpression_id"; case syntax::NodeRole::IdExpression_qualifier: 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::NestedNameSpecifier::delimiters() { - std::vector Children; - for (auto *C = firstChild(); C; C = C->nextSibling()) { - assert(C->role() == syntax::NodeRole::NestedNameSpecifier_delimiter); - Children.push_back(llvm::cast(C)); +// We could have an interator in list to not pay memory costs of temporary +// vector +std::vector syntax::NestedNameSpecifier::specifiers() { + auto specifiersAsNodes = getElementsAsNodes(); + std::vector Children; + for (const auto &element : specifiersAsNodes) { + Children.push_back(llvm::cast(element)); } return Children; } -std::vector syntax::NestedNameSpecifier::specifiers() { - std::vector Children; - for (auto *C = firstChild(); C; C = C->nextSibling()) { - assert(C->role() == syntax::NodeRole::NestedNameSpecifier_specifier); - Children.push_back(cast(C)); +std::vector> +syntax::NestedNameSpecifier::specifiersAndDoubleColons() { + auto specifiersAsNodesAndDoubleColons = getElementsAsNodesAndDelimiters(); + std::vector> + Children; + for (const auto &specifierAndDoubleColon : specifiersAsNodesAndDoubleColons) { + Children.push_back( + {llvm::cast(specifierAndDoubleColon.element), + specifierAndDoubleColon.delimiter}); } return Children; } 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 @@ -357,21 +357,32 @@ return children; } -// The methods below can't be implemented without information about the derived -// list. These methods will be implemented by switching on the derived list's -// `NodeKind` - clang::tok::TokenKind syntax::List::getDelimiterTokenKind() { - llvm_unreachable("There are no subclasses of List, thus " - "getDelimiterTokenKind() cannot be called"); + switch (this->kind()) { + case NodeKind::NestedNameSpecifier: + return clang::tok::coloncolon; + default: + llvm_unreachable("This is not a subclass of List, thus " + "getDelimiterTokenKind() cannot be called"); + } } syntax::List::TerminationKind syntax::List::getTerminationKind() { - llvm_unreachable("There are no subclasses of List, thus getTerminationKind() " - "cannot be called"); + switch (this->kind()) { + case NodeKind::NestedNameSpecifier: + return TerminationKind::Terminated; + default: + llvm_unreachable("This is not a subclass of List, thus " + "getTerminationKind() cannot be called"); + } } bool syntax::List::canBeEmpty() { - llvm_unreachable( - "There are no subclasses of List, thus canBeEmpty() cannot be called"); + switch (this->kind()) { + case NodeKind::NestedNameSpecifier: + return false; + default: + llvm_unreachable("This is not a subclass of List, thus canBeEmpty() " + "cannot be called"); + } }