eduucaldas updated this revision to Diff 297574. eduucaldas marked 8 inline comments as done. eduucaldas added a comment.
Answer comments, TODO: think about templated iterators Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88106/new/ https://reviews.llvm.org/D88106 Files: clang/include/clang/Tooling/Syntax/Tree.h clang/lib/Tooling/Syntax/Nodes.cpp clang/lib/Tooling/Syntax/Tree.cpp
Index: clang/lib/Tooling/Syntax/Tree.cpp =================================================================== --- clang/lib/Tooling/Syntax/Tree.cpp +++ clang/lib/Tooling/Syntax/Tree.cpp @@ -9,6 +9,7 @@ #include "clang/Basic/TokenKinds.h" #include "clang/Tooling/Syntax/Nodes.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" #include <cassert> @@ -294,91 +295,110 @@ } } -std::vector<syntax::List::ElementAndDelimiter<syntax::Node>> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) - return {}; - - std::vector<syntax::List::ElementAndDelimiter<Node>> Children; - syntax::Node *ElementWithoutDelimiter = nullptr; - for (auto *C = getFirstChild(); C; C = C->getNextSibling()) { - switch (C->getRole()) { - case syntax::NodeRole::ListElement: { - if (ElementWithoutDelimiter) { - Children.push_back({ElementWithoutDelimiter, nullptr}); - } - ElementWithoutDelimiter = C; - break; - } - case syntax::NodeRole::ListDelimiter: { - Children.push_back({ElementWithoutDelimiter, cast<syntax::Leaf>(C)}); - ElementWithoutDelimiter = nullptr; - break; - } - default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); - } +syntax::List::ElementAndDelimiter<syntax::Node> +syntax::List::getWithDelimiter(syntax::Node *Element) { + assert(Element && Element->getRole() == syntax::NodeRole::ListElement); + auto *Next = Element->getNextSibling(); + if (!Next) + return {Element, nullptr}; + switch (Next->getRole()) { + case syntax::NodeRole::ListElement: + return {Element, nullptr}; + case syntax::NodeRole::ListDelimiter: + return {Element, cast<syntax::Leaf>(Next)}; + default: + llvm_unreachable( + "A list can have only elements and delimiters as children."); } +} - switch (getTerminationKind()) { - case syntax::List::TerminationKind::Separated: { - Children.push_back({ElementWithoutDelimiter, nullptr}); - break; - } - case syntax::List::TerminationKind::Terminated: - case syntax::List::TerminationKind::MaybeTerminated: { - if (ElementWithoutDelimiter) { - Children.push_back({ElementWithoutDelimiter, nullptr}); +llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>> +syntax::List::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *List = cast<syntax::List>(Delimiter->getParent()); + auto *Next = Delimiter->getNextSibling(); + if (!Next) { + switch (List->getTerminationKind()) { + // List is separated and ends with delimiter + // => missing last ElementAndDelimiter. + case syntax::List::TerminationKind::Separated: + return llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>>( + {nullptr, nullptr}); + case syntax::List::TerminationKind::Terminated: + case syntax::List::TerminationKind::MaybeTerminated: + return None; } - break; } + switch (Next->getRole()) { + case syntax::NodeRole::ListElement: + return getWithDelimiter(Next); + + // Consecutive Delimiters => missing Element + case syntax::NodeRole::ListDelimiter: + return llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>>( + {nullptr, cast<Leaf>(Next)}); + default: + llvm_unreachable( + "A list can have only elements and delimiters as children."); } - - return Children; } -// Almost the same implementation of `getElementsAsNodesAndDelimiters` but -// ignoring delimiters -std::vector<syntax::Node *> syntax::List::getElementsAsNodes() { - if (!getFirstChild()) - return {}; +llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>> +syntax::List::getElementAndDelimiterAfterElement(syntax::Node *Element) { + assert(Element && Element->getRole() == syntax::NodeRole::ListElement); + auto *Next = Element->getNextSibling(); + if (!Next) + // This was the last element of the list. + return None; + + switch (Next->getRole()) { + case syntax::NodeRole::ListElement: + // We have something of the form "a b ..." => 'b' starts the next + // `ElementAndDelimiter`. + return getWithDelimiter(Next); + + case syntax::NodeRole::ListDelimiter: + // We have something of the form "a , ..." => whatever comes after the comma + // starts the next `ElementAndDelimiter`. + return getElementAndDelimiterAfterDelimiter(cast<Leaf>(Next)); - std::vector<syntax::Node *> Children; - syntax::Node *ElementWithoutDelimiter = nullptr; - for (auto *C = getFirstChild(); C; C = C->getNextSibling()) { - switch (C->getRole()) { - case syntax::NodeRole::ListElement: { - if (ElementWithoutDelimiter) { - Children.push_back(ElementWithoutDelimiter); - } - ElementWithoutDelimiter = C; - break; - } - case syntax::NodeRole::ListDelimiter: { - Children.push_back(ElementWithoutDelimiter); - ElementWithoutDelimiter = nullptr; - break; - } - default: - llvm_unreachable("A list has only elements or delimiters."); - } + default: + llvm_unreachable( + "A list can have only elements and delimiters as children."); } +} - switch (getTerminationKind()) { - case syntax::List::TerminationKind::Separated: { - Children.push_back(ElementWithoutDelimiter); - break; - } - case syntax::List::TerminationKind::Terminated: - case syntax::List::TerminationKind::MaybeTerminated: { - if (ElementWithoutDelimiter) { - Children.push_back(ElementWithoutDelimiter); - } - break; - } +syntax::List::ElementAndDelimiterIterator syntax::List::getEnd() { + return llvm::Optional<ElementAndDelimiter<Node>>(None); +} + +syntax::List::ElementAndDelimiterIterator syntax::List::getBegin() { + auto *First = getFirstChild(); + if (!First) + return getEnd(); + switch (First->getRole()) { + case syntax::NodeRole::ListElement: + return llvm::Optional<ElementAndDelimiter<Node>>(getWithDelimiter(First)); + case syntax::NodeRole::ListDelimiter: + return llvm::Optional<ElementAndDelimiter<Node>>( + {nullptr, cast<Leaf>(First)}); + default: + llvm_unreachable( + "A list can have only elements and delimiters as children."); } +} + +std::vector<syntax::List::ElementAndDelimiter<syntax::Node>> +syntax::List::getElementsAsNodesAndDelimiters() { + return std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>( + getBegin(), getEnd()); +} +std::vector<syntax::Node *> syntax::List::getElementsAsNodes() { + std::vector<syntax::Node *> Children; + std::transform( + getBegin(), getEnd(), std::back_inserter(Children), + [](ElementAndDelimiter<syntax::Node> ED) { return ED.element; }); return Children; } Index: clang/lib/Tooling/Syntax/Nodes.cpp =================================================================== --- clang/lib/Tooling/Syntax/Nodes.cpp +++ clang/lib/Tooling/Syntax/Nodes.cpp @@ -230,91 +230,77 @@ // vector std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::getSpecifiers() { - auto SpecifiersAsNodes = getElementsAsNodes(); std::vector<syntax::NameSpecifier *> Children; - for (const auto &Element : SpecifiersAsNodes) { - Children.push_back(llvm::cast<syntax::NameSpecifier>(Element)); - } + for (auto C : getRange()) + Children.push_back(cast<syntax::NameSpecifier>(C.element)); + return Children; } std::vector<syntax::List::ElementAndDelimiter<syntax::NameSpecifier>> syntax::NestedNameSpecifier::getSpecifiersAndDoubleColons() { - auto SpecifiersAsNodesAndDoubleColons = getElementsAsNodesAndDelimiters(); std::vector<syntax::List::ElementAndDelimiter<syntax::NameSpecifier>> Children; - for (const auto &SpecifierAndDoubleColon : SpecifiersAsNodesAndDoubleColons) { - Children.push_back( - {llvm::cast<syntax::NameSpecifier>(SpecifierAndDoubleColon.element), - SpecifierAndDoubleColon.delimiter}); - } + for (auto C : getRange()) + Children.push_back({cast<syntax::NameSpecifier>(C.element), C.delimiter}); + return Children; } std::vector<syntax::Expression *> syntax::CallArguments::getArguments() { - auto ArgumentsAsNodes = getElementsAsNodes(); std::vector<syntax::Expression *> Children; - for (const auto &ArgumentAsNode : ArgumentsAsNodes) { - Children.push_back(llvm::cast<syntax::Expression>(ArgumentAsNode)); - } + for (auto C : getRange()) + Children.push_back(cast<syntax::Expression>(C.element)); + return Children; } std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>> syntax::CallArguments::getArgumentsAndCommas() { - auto ArgumentsAsNodesAndCommas = getElementsAsNodesAndDelimiters(); std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>> Children; - for (const auto &ArgumentAsNodeAndComma : ArgumentsAsNodesAndCommas) { - Children.push_back( - {llvm::cast<syntax::Expression>(ArgumentAsNodeAndComma.element), - ArgumentAsNodeAndComma.delimiter}); - } + for (auto C : getRange()) + Children.push_back({cast<syntax::Expression>(C.element), C.delimiter}); + return Children; } std::vector<syntax::SimpleDeclaration *> syntax::ParameterDeclarationList::getParameterDeclarations() { - auto ParametersAsNodes = getElementsAsNodes(); std::vector<syntax::SimpleDeclaration *> Children; - for (const auto &ParameterAsNode : ParametersAsNodes) { - Children.push_back(llvm::cast<syntax::SimpleDeclaration>(ParameterAsNode)); - } + for (auto C : getRange()) + Children.push_back(cast<syntax::SimpleDeclaration>(C.element)); + return Children; } std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclaration>> syntax::ParameterDeclarationList::getParametersAndCommas() { - auto ParametersAsNodesAndCommas = getElementsAsNodesAndDelimiters(); std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclaration>> Children; - for (const auto &ParameterAsNodeAndComma : ParametersAsNodesAndCommas) { + for (auto C : getRange()) Children.push_back( - {llvm::cast<syntax::SimpleDeclaration>(ParameterAsNodeAndComma.element), - ParameterAsNodeAndComma.delimiter}); - } + {cast<syntax::SimpleDeclaration>(C.element), C.delimiter}); + return Children; } std::vector<syntax::SimpleDeclarator *> syntax::DeclaratorList::getDeclarators() { - auto DeclaratorsAsNodes = getElementsAsNodes(); std::vector<syntax::SimpleDeclarator *> Children; - for (const auto &DeclaratorAsNode : DeclaratorsAsNodes) { - Children.push_back(llvm::cast<syntax::SimpleDeclarator>(DeclaratorAsNode)); - } + for (auto C : getRange()) + Children.push_back(cast<syntax::SimpleDeclarator>(C.element)); + return Children; } std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclarator>> syntax::DeclaratorList::getDeclaratorsAndCommas() { - auto DeclaratorsAsNodesAndCommas = getElementsAsNodesAndDelimiters(); std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclarator>> Children; - for (const auto &DeclaratorAsNodeAndComma : DeclaratorsAsNodesAndCommas) { + for (auto C : getRange()) Children.push_back( - {llvm::cast<syntax::SimpleDeclarator>(DeclaratorAsNodeAndComma.element), - DeclaratorAsNodeAndComma.delimiter}); - } + {cast<syntax::SimpleDeclarator>(C.element), C.delimiter}); + return Children; } Index: clang/include/clang/Tooling/Syntax/Tree.h =================================================================== --- clang/include/clang/Tooling/Syntax/Tree.h +++ clang/include/clang/Tooling/Syntax/Tree.h @@ -28,6 +28,8 @@ #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" #include <cstdint> @@ -204,6 +206,12 @@ template <typename Element> struct ElementAndDelimiter { Element *element; Leaf *delimiter; + bool operator==(const ElementAndDelimiter &Other) const { + return element == Other.element && delimiter == Other.delimiter; + } + bool operator!=(const ElementAndDelimiter &Other) const { + return !(*this == Other); + } }; enum class TerminationKind { @@ -214,10 +222,12 @@ using Tree::Tree; static bool classof(const Node *N); - /// Returns the elements and corresponding delimiters. Missing elements - /// and delimiters are represented as null pointers. + + /// Iterator through elements and their corresponding delimiters. Missing + /// elements and delimiters are represented as null pointers. Below we give + /// examples of what this iteration would looks like. /// - /// For example, in a separated list: + /// In a separated list: /// "a, b, c" <=> [("a" , ","), ("b" , "," ), ("c" , null)] /// "a, , c" <=> [("a" , ","), (null, "," ), ("c" , null)] /// "a, b c" <=> [("a" , ","), ("b" , null), ("c" , null)] @@ -228,6 +238,57 @@ /// "a; ; c;" <=> [("a" , ";"), (null, ";" ), ("c" , ";" )] /// "a; b c;" <=> [("a" , ";"), ("b" , null), ("c" , ";" )] /// "a; b; c" <=> [("a" , ";"), ("b" , ";" ), ("c" , null)] + class ElementAndDelimiterIterator + : public llvm::iterator_facade_base<ElementAndDelimiterIterator, + std::forward_iterator_tag, + ElementAndDelimiter<Node>> { + public: + ElementAndDelimiterIterator(llvm::Optional<ElementAndDelimiter<Node>> ED) + : EDI(ED) {} + + ElementAndDelimiterIterator &operator++() { + assert(EDI.hasValue() && "Incrementing sentinel iterator."); + if (auto *Delimiter = EDI.getValue().delimiter) + EDI = getElementAndDelimiterAfterDelimiter(Delimiter); + else if (auto *Element = EDI.getValue().element) + EDI = getElementAndDelimiterAfterElement(Element); + else + EDI = None; + return *this; + } + + ElementAndDelimiter<Node> &operator*() { + assert(EDI.hasValue() && "Dereferencing sentinel iterator."); + return EDI.getValue(); + } + + const ElementAndDelimiter<Node> &operator*() const { + assert(EDI.hasValue() && "Dereferencing sentinel iterator."); + return EDI.getValue(); + } + + bool operator==(const ElementAndDelimiterIterator &Other) const { + return EDI == Other.EDI; + } + + private: + llvm::Optional<ElementAndDelimiter<Node>> EDI; + }; + + ElementAndDelimiterIterator getBegin(); + ElementAndDelimiterIterator getEnd(); + + using ElementsAndDelimitersRange = + llvm::iterator_range<ElementAndDelimiterIterator>; + + ElementsAndDelimitersRange getRange() { + return ElementsAndDelimitersRange(getBegin(), getEnd()); + } + + // Returns the elements of the list, and their corresponding delimiters. + // Missing elements are represented as null pointers. Iterating through + // `getElementsAsNodesAndDelimiters()` is equivalent to iterating through + // `getRange()` std::vector<ElementAndDelimiter<Node>> getElementsAsNodesAndDelimiters(); /// Returns the elements of the list. Missing elements are represented @@ -251,6 +312,13 @@ /// This list may be empty when the source code has errors even if /// canBeEmpty() returns false. bool canBeEmpty() const; + +private: + static ElementAndDelimiter<Node> getWithDelimiter(Node *Element); + static llvm::Optional<ElementAndDelimiter<Node>> + getElementAndDelimiterAfterDelimiter(Leaf *Delimiter); + static llvm::Optional<ElementAndDelimiter<Node>> + getElementAndDelimiterAfterElement(Node *Element); }; } // namespace syntax
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits