[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas abandoned this revision. eduucaldas added inline comments. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:252 + Kind = IteratorKind::NotSentinel; + if (isElement(Begin)) +Current = getWithDelimiter(cast(Begin)); Since `NodeRole` is forward declared, we cannot access `NodeRole::ListElement` within the header, this is my work-around. Another possibility would be to not forward declare and put `NodeRole` definition here. I think this is a bad choice because most roles are linked to syntax. I declare `isElement` as a static private member function of `List` from lack of better place, I accept suggestions. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:390 + + ElementAndDelimiterIterator getBeforeBeginNode(); + ElementAndDelimiterIterator getBeginNode(); I have a hard time finding a name that is expressive enough and concise enough. The current one seems to imply that we're getting a node... Alternatives: * `getBeforeBeginWithElementAsNode` * `getBeforeBeginWithNodes` * `getBeforeBeginBase` * `getBeforeBeginNodeAndDelimiter` Comment at: clang/include/clang/Tooling/Syntax/Tree.h:241-242 /// "a; b; c" <=> [("a" , ";"), ("b" , ";" ), ("c" , null)] + template + class ElementAndDelimiterIterator + : public llvm::iterator_facade_base< eduucaldas wrote: > Since we're gonna provide strongly-typed iterators, I make the Iterator a > class template. > > I keep the base functions as they were, `getElementAndDelimiterAfter...`, but > I cast their result using `castToElementType`. > > Another option would be to make the base functions also templated and not > perform any casting. > > We'll use `castToElementType` to provide the strongly-typed iterators as well. Ignore comment above Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88106/new/ https://reviews.llvm.org/D88106 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 299348. eduucaldas added a comment. rename getBeforeBegin 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 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 @@ -11,6 +11,7 @@ #include "clang/Tooling/Syntax/BuildTree.h" #include "clang/Tooling/Syntax/Nodes.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" using namespace clang; @@ -125,7 +126,7 @@ } class ListTest : public SyntaxTreeTest { -private: +protected: std::string dumpQuotedTokensOrNull(const Node *N) { return N ? "'" + StringRef(N->dumpTokens(Arena->getSourceManager())) @@ -135,7 +136,15 @@ : "null"; } -protected: + std::string + dumpElementAndDelimiter(const List::ElementAndDelimiter ED) { +std::string Storage; +llvm::raw_string_ostream OS(Storage); +OS << "(" << dumpQuotedTokensOrNull(ED.element) << ", " + << dumpQuotedTokensOrNull(ED.delimiter) << ")"; +return OS.str(); + } + std::string dumpElementsAndDelimiters(ArrayRef> EDs) { std::string Storage; @@ -145,8 +154,7 @@ llvm::interleaveComma( EDs, OS, [, this](const List::ElementAndDelimiter ) { - OS << "(" << dumpQuotedTokensOrNull(ED.element) << ", " - << dumpQuotedTokensOrNull(ED.delimiter) << ")"; + OS << dumpElementAndDelimiter(ED); }); OS << "]"; @@ -351,4 +359,40 @@ EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']"); } +TEST_P(ListTest, List_Iterator_StableDereference) { + if (!GetParam().isCXX()) { +return; + } + buildTree("", GetParam()); + + // "a:: b:: c" + auto *List = dyn_cast(syntax::createTree( + *Arena, + { + {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement}, + }, + NodeKind::NestedNameSpecifier)); + + auto It = List->getElementAndDelimiterBegin(); + const auto = *It; + auto ItAssign = It; + + EXPECT_EQ(dumpElementAndDelimiter(First), "('a', '::')"); + ++It; + EXPECT_EQ(dumpElementAndDelimiter(First), "('a', '::')"); + + EXPECT_EQ(*ItAssign, First); + + auto It2 = std::next(List->getElementAndDelimiterBeforeBegin(), 2); + EXPECT_EQ(It, It2); + EXPECT_EQ(*It, *It2); + + ++It; + ++It; + EXPECT_EQ(It, List->getElementAndDelimiterEnd()); +} } // namespace Index: clang/lib/Tooling/Syntax/Tree.cpp === --- clang/lib/Tooling/Syntax/Tree.cpp +++ clang/lib/Tooling/Syntax/Tree.cpp @@ -311,91 +311,41 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} - } +bool syntax::List::isElement(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListElement; +} - 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}); -} -break; - } - } +bool syntax::List::isDelimiter(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListDelimiter; +} - return Children; +syntax::List::ElementAndDelimiterIterator +syntax::List::getElementAndDelimiterBeforeBegin() { + return ElementAndDelimiterIterator::makeBeforeBegin(this); } -// Almost the same implementation of `getElementsAsNodesAndDelimiters` but -// ignoring delimiters
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 299347. eduucaldas marked 2 inline comments as not done. eduucaldas added a comment. Add tests, `ElementAndDelimiter` are input 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 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 @@ -11,6 +11,7 @@ #include "clang/Tooling/Syntax/BuildTree.h" #include "clang/Tooling/Syntax/Nodes.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" using namespace clang; @@ -125,7 +126,7 @@ } class ListTest : public SyntaxTreeTest { -private: +protected: std::string dumpQuotedTokensOrNull(const Node *N) { return N ? "'" + StringRef(N->dumpTokens(Arena->getSourceManager())) @@ -135,7 +136,15 @@ : "null"; } -protected: + std::string + dumpElementAndDelimiter(const List::ElementAndDelimiter ED) { +std::string Storage; +llvm::raw_string_ostream OS(Storage); +OS << "(" << dumpQuotedTokensOrNull(ED.element) << ", " + << dumpQuotedTokensOrNull(ED.delimiter) << ")"; +return OS.str(); + } + std::string dumpElementsAndDelimiters(ArrayRef> EDs) { std::string Storage; @@ -145,8 +154,7 @@ llvm::interleaveComma( EDs, OS, [, this](const List::ElementAndDelimiter ) { - OS << "(" << dumpQuotedTokensOrNull(ED.element) << ", " - << dumpQuotedTokensOrNull(ED.delimiter) << ")"; + OS << dumpElementAndDelimiter(ED); }); OS << "]"; @@ -351,4 +359,40 @@ EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']"); } +TEST_P(ListTest, List_Iterator_StableDereference) { + if (!GetParam().isCXX()) { +return; + } + buildTree("", GetParam()); + + // "a:: b:: c" + auto *List = dyn_cast(syntax::createTree( + *Arena, + { + {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement}, + }, + NodeKind::NestedNameSpecifier)); + + auto It = List->getBeginNode(); + const auto = *It; + auto ItAssign = It; + + EXPECT_EQ(dumpElementAndDelimiter(First), "('a', '::')"); + ++It; + EXPECT_EQ(dumpElementAndDelimiter(First), "('a', '::')"); + + EXPECT_EQ(*ItAssign, First); + + auto It2 = std::next(List->getBeforeBegin(), 2); + EXPECT_EQ(It, It2); + EXPECT_EQ(*It, *It2); + + ++It; + ++It; + EXPECT_EQ(It, List->getEndNode()); +} } // namespace Index: clang/lib/Tooling/Syntax/Tree.cpp === --- clang/lib/Tooling/Syntax/Tree.cpp +++ clang/lib/Tooling/Syntax/Tree.cpp @@ -311,91 +311,40 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} - } +bool syntax::List::isElement(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListElement; +} - 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}); -} -break; - } - } +bool syntax::List::isDelimiter(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListDelimiter; +} - return Children; +syntax::List::ElementAndDelimiterIterator +syntax::List::getBeforeBegin() { + return ElementAndDelimiterIterator::makeBeforeBegin(this); } -// Almost the same implementation of `getElementsAsNodesAndDelimiters` but -// ignoring
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 298420. eduucaldas added a comment. Linting 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 @@ -311,91 +311,40 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} - } +bool syntax::List::isElement(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListElement; +} - 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}); -} -break; - } - } +bool syntax::List::isDelimiter(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListDelimiter; +} - return Children; +syntax::List::ElementAndDelimiterIterator +syntax::List::getBeforeBeginWithElementAsNode() { + return ElementAndDelimiterIterator::makeBeforeBegin(this); } -// Almost the same implementation of `getElementsAsNodesAndDelimiters` but -// ignoring delimiters -std::vector syntax::List::getElementsAsNodes() { - if (!getFirstChild()) -return {}; +syntax::List::ElementAndDelimiterIterator +syntax::List::getBeginNode() { + return std::next(ElementAndDelimiterIterator::makeBeforeBegin(this)); +} - std::vector 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."); -} - } +syntax::List::ElementAndDelimiterIterator +syntax::List::getEndNode() { + return ElementAndDelimiterIterator::makeEnd(this); +} - 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; - } - } +std::vector> +syntax::List::getElementsAsNodesAndDelimiters() { + return std::vector>( + getBeginNode(), getEndNode()); +} +std::vector syntax::List::getElementsAsNodes() { + std::vector Children; + std::transform( + getBeginNode(), getEndNode(), std::back_inserter(Children), + [](ElementAndDelimiter 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::NestedNameSpecifier::getSpecifiers() { - auto SpecifiersAsNodes = getElementsAsNodes(); std::vector Children; - for (const auto : SpecifiersAsNodes) { -Children.push_back(llvm::cast(Element)); - } + for (auto C : getNodeRange()) +Children.push_back(cast(C.element)); + return Children; } std::vector> syntax::NestedNameSpecifier::getSpecifiersAndDoubleColons() { - auto SpecifiersAsNodesAndDoubleColons = getElementsAsNodesAndDelimiters(); std::vector> Children; - for (const auto : SpecifiersAsNodesAndDoubleColons) { -Children.push_back( -{llvm::cast(SpecifierAndDoubleColon.element), - SpecifierAndDoubleColon.delimiter}); - } + for (auto C : getNodeRange()) +
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 298416. eduucaldas added a comment. - [SyntaxTree] `ElementAndDelimiterIterator` is polymorphic and supports `BeforeBegin` iterator 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 @@ -311,91 +312,40 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} - } +bool syntax::List::isElement(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListElement; +} - 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}); -} -break; - } - } +bool syntax::List::isDelimiter(syntax::Node *N) { + return N && N->getRole() == NodeRole::ListDelimiter; +} - return Children; +syntax::List::ElementAndDelimiterIterator +syntax::List::getBeforeBeginNode() { + return ElementAndDelimiterIterator::makeBeforeBegin(this); } -// Almost the same implementation of `getElementsAsNodesAndDelimiters` but -// ignoring delimiters -std::vector syntax::List::getElementsAsNodes() { - if (!getFirstChild()) -return {}; +syntax::List::ElementAndDelimiterIterator +syntax::List::getBeginNode() { + return std::next(ElementAndDelimiterIterator::makeBeforeBegin(this)); +} - std::vector 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."); -} - } +syntax::List::ElementAndDelimiterIterator +syntax::List::getEndNode() { + return ElementAndDelimiterIterator::makeEnd(this); +} - 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; - } - } +std::vector> +syntax::List::getElementsAsNodesAndDelimiters() { + return std::vector>( + getBeginNode(), getEndNode()); +} +std::vector syntax::List::getElementsAsNodes() { + std::vector Children; + std::transform( + getBeginNode(), getEndNode(), std::back_inserter(Children), + [](ElementAndDelimiter 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::NestedNameSpecifier::getSpecifiers() { - auto SpecifiersAsNodes = getElementsAsNodes(); std::vector Children; - for (const auto : SpecifiersAsNodes) { -Children.push_back(llvm::cast(Element)); - } + for (auto C : getNodeRange()) +Children.push_back(cast(C.element)); + return Children; } std::vector> syntax::NestedNameSpecifier::getSpecifiersAndDoubleColons() { - auto
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas added inline comments. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:241-242 /// "a; b; c" <=> [("a" , ";"), ("b" , ";" ), ("c" , null)] + template + class ElementAndDelimiterIterator + : public llvm::iterator_facade_base< Since we're gonna provide strongly-typed iterators, I make the Iterator a class template. I keep the base functions as they were, `getElementAndDelimiterAfter...`, but I cast their result using `castToElementType`. Another option would be to make the base functions also templated and not perform any casting. We'll use `castToElementType` to provide the strongly-typed iterators as well. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88106/new/ https://reviews.llvm.org/D88106 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas added a comment. Haven't yet implemented `BeforeBegin`, waiting for a heads up on the patch as is. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88106/new/ https://reviews.llvm.org/D88106 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas added inline comments. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:269 + return EDI == Other.EDI; +} + gribozavr2 wrote: > Please also define `operator!=`. this is defined by the `iterato_facade_base`, take a look at the comments in this class template Comment at: clang/lib/Tooling/Syntax/Tree.cpp:405 return Children; } gribozavr2 wrote: > Ditto? Here we could do `std::transform(getBegin(), getEnd(), std::back_inserter(result), [](ElementAndDelimiter ED){return ED.element;})`. Is that more idiomatic? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88106/new/ https://reviews.llvm.org/D88106 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 298156. eduucaldas marked an inline comment as done. eduucaldas added a comment. - Make `ElementAndDelimiterIterator` templated. 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 @@ -311,91 +312,112 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} +syntax::List::ElementAndDelimiter +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(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::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *List = cast(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>( + {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>( +{nullptr, cast(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::List::getElementsAsNodes() { - if (!getFirstChild()) -return {}; +llvm::Optional> +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(Next)); - std::vector 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
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
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 @@ -294,91 +295,110 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} +syntax::List::ElementAndDelimiter +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(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::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *List = cast(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>( + {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>( +{nullptr, cast(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::List::getElementsAsNodes() { - if (!getFirstChild()) -return {}; +llvm::Optional> +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(Next)); - std::vector 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
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
gribozavr2 added inline comments. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:211 + return element == Other.element && delimiter == Other.delimiter; +} }; Please also define `operator!=` even if it is not used yet. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:225 + /// elements and delimiters are represented as null pointers. Below we give + /// examples of how this iteration would look like: /// "how something looks" or "what something looks like" Comment at: clang/include/clang/Tooling/Syntax/Tree.h:238-273 + class ElementAndDelimiterIterator + : public llvm::iterator_facade_base> { + public: +ElementAndDelimiterIterator(llvm::Optional> ED) +: EDI(ED) {} eduucaldas wrote: > Should we hide some of this? Most of the member functions are a couple of > lines, so I decided not to. What is your opinion? I think it is fine as is. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:269 + return EDI == Other.EDI; +} + Please also define `operator!=`. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:283 +return ElementsAndDelimitersRange(getBegin(), getEnd()); + } + I'd imagine derived classes would have iterators that produce strongly-typed elements, right? If so, these methods getBegin()/getEnd()/getRange() should have the word "Node" in them. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:314 +private: + // Auxiliary methods for implementing `ElementAndDelimiterIterator`. + static ElementAndDelimiter getWithDelimiter(Node *Element); People can use "find usages" to find what uses these methods. Such comments often go out of date. Comment at: clang/lib/Tooling/Syntax/Tree.cpp:350 + auto *Next = Element->getNextSibling(); + // a b, x => End of list, this was the last ElementAndDelimiter. + if (!Next) I have a hard time understand what a b x and the comma stand for in these comments. Comment at: clang/lib/Tooling/Syntax/Tree.cpp:391-396 + auto Children = std::vector>(); + for (auto C : getRange()) { +Children.push_back(C); } + + return Children; Comment at: clang/lib/Tooling/Syntax/Tree.cpp:405 return Children; } Ditto? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88106/new/ https://reviews.llvm.org/D88106 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas added a reviewer: gribozavr2. eduucaldas added a comment. This is quite low priority, compared to the other branches of work, but it was almost ready work, so I decided to polish it and send it to review now. Comment at: clang/include/clang/Tooling/Syntax/Tree.h:238-273 + class ElementAndDelimiterIterator + : public llvm::iterator_facade_base> { + public: +ElementAndDelimiterIterator(llvm::Optional> ED) +: EDI(ED) {} Should we hide some of this? Most of the member functions are a couple of lines, so I decided not to. What is your opinion? Comment at: clang/include/clang/Tooling/Syntax/Tree.h:275-276 + + ElementAndDelimiterIterator getBegin(); + ElementAndDelimiterIterator getEnd(); + I chose to leave it as `getBegin` and `getEnd` instead of `getElementsAndDelimitersBegin`. I did this because the return type of those methods already tells us that we're getting an `ElementAndDelimiterIterator`. What do you think? Comment at: clang/include/clang/Tooling/Syntax/Tree.h:312-319 + +private: + // Auxiliary methods for implementing `ElementAndDelimiterIterator`. + static ElementAndDelimiter getWithDelimiter(Node *Element); + static llvm::Optional> + getElementAndDelimiterAfterDelimiter(Leaf *Delimiter); + static llvm::Optional> These are all private static methods, should we hide them from the header? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88106/new/ https://reviews.llvm.org/D88106 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 297006. eduucaldas added a comment. Replace `auto .. = std::vector();` with `std::vector ..;` 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 @@ -294,89 +295,111 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} +syntax::List::ElementAndDelimiter +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(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::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *List = cast(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>( + {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>( +{nullptr, cast(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::List::getElementsAsNodes() { - if (!getFirstChild()) -return {}; +llvm::Optional> +syntax::List::getElementAndDelimiterAfterElement(syntax::Node *Element) { + assert(Element && Element->getRole() == syntax::NodeRole::ListElement); + auto *Next = Element->getNextSibling(); + // a b, x => End of list, this was the last ElementAndDelimiter. + if (!Next) +return None; - std::vector 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."); -} + switch (Next->getRole()) { + // x b, c => next ElementAndDelimiter starts with 'b'. + case syntax::NodeRole::ListElement: +return getWithDelimiter(Next); + + // a x, c => next ElementAndDelimiter starts after ','.
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 297001. eduucaldas added a comment. Reorganize methods to minimize diffs 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 @@ -294,89 +295,111 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} +syntax::List::ElementAndDelimiter +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(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::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *List = cast(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>( + {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>( +{nullptr, cast(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::List::getElementsAsNodes() { - if (!getFirstChild()) -return {}; +llvm::Optional> +syntax::List::getElementAndDelimiterAfterElement(syntax::Node *Element) { + assert(Element && Element->getRole() == syntax::NodeRole::ListElement); + auto *Next = Element->getNextSibling(); + // a b, x => End of list, this was the last ElementAndDelimiter. + if (!Next) +return None; - std::vector 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."); -} + switch (Next->getRole()) { + // x b, c => next ElementAndDelimiter starts with 'b'. + case syntax::NodeRole::ListElement: +return getWithDelimiter(Next); + + // a x, c => next ElementAndDelimiter starts after ','. + case
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 296996. eduucaldas added a comment. Better comments 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 @@ -294,89 +295,111 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; - - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); -} +syntax::List::ElementAndDelimiter +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(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::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *List = cast(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>( + {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>( +{nullptr, cast(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::List::getElementsAsNodes() { - if (!getFirstChild()) -return {}; +llvm::Optional> +syntax::List::getElementAndDelimiterAfterElement(syntax::Node *Element) { + assert(Element && Element->getRole() == syntax::NodeRole::ListElement); + auto *Next = Element->getNextSibling(); + // a b, x => End of list, this was the last ElementAndDelimiter. + if (!Next) +return None; - std::vector 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."); -} + switch (Next->getRole()) { + // x b, c => next ElementAndDelimiter starts with 'b'. + case syntax::NodeRole::ListElement: +return getWithDelimiter(Next); + + // a x, c => next ElementAndDelimiter starts after ','. + case syntax::NodeRole::ListDelimiter:
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas updated this revision to Diff 296994. eduucaldas added a comment. - [SyntaxTree] Provide iterator for `List` that iterates through `ElementAndDelimiter`s even for not well-defined lists. 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 @@ -294,45 +295,102 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; +syntax::List::ElementAndDelimiter +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(Next)}; + default: +llvm_unreachable( +"A list can have only elements and delimiters as children."); + } +} - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); +llvm::Optional> +syntax::List::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *List = cast(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>( + {nullptr, nullptr}); +case syntax::List::TerminationKind::Terminated: +case syntax::List::TerminationKind::MaybeTerminated: + return None; } } + switch (Next->getRole()) { + case syntax::NodeRole::ListElement: +return getWithDelimiter(Next); + + // Consecutive Delimiters => missing Element + case syntax::NodeRole::ListDelimiter: +return llvm::Optional>( +{nullptr, cast(Next)}); + default: +llvm_unreachable( +"A list can have only elements and delimiters as children."); + } +} + +llvm::Optional> +syntax::List::getElementAndDelimiterAfterElement(syntax::Node *Element) { + assert(Element && Element->getRole() == syntax::NodeRole::ListElement); + auto *Next = Element->getNextSibling(); + // a b, x => End of list, this was the last ElementAndDelimiter. + if (!Next) +return None; + + switch (Next->getRole()) { + // x b, c => next ElementAndDelimiter starts with 'b'. + case syntax::NodeRole::ListElement: +return getWithDelimiter(Next); + + // a x, c => next ElementAndDelimiter starts after ','. + case syntax::NodeRole::ListDelimiter: +return getElementAndDelimiterAfterDelimiter(cast(Next)); - switch (getTerminationKind()) { - case syntax::List::TerminationKind::Separated: { -Children.push_back({ElementWithoutDelimiter, nullptr}); -break; + default: +llvm_unreachable( +"A list can have only elements and delimiters as children."); } - case syntax::List::TerminationKind::Terminated: - case syntax::List::TerminationKind::MaybeTerminated: { -if (ElementWithoutDelimiter) { - Children.push_back({ElementWithoutDelimiter, nullptr}); -} -break; +} + +syntax::List::ElementAndDelimiterIterator syntax::List::getEnd() { + return llvm::Optional>(None); +} + +syntax::List::ElementAndDelimiterIterator syntax::List::getBegin() { + auto *First = getFirstChild(); + if (!First) +return getEnd(); + switch (First->getRole()) { + case syntax::NodeRole::ListElement: +return llvm::Optional>(getWithDelimiter(First)); + case syntax::NodeRole::ListDelimiter: +return llvm::Optional>( +{nullptr, cast(First)}); + default: +llvm_unreachable( +"A list can have only elements and
[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists
eduucaldas created this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. eduucaldas requested review of this revision. Repository: rG LLVM Github Monorepo 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 @@ -294,46 +295,107 @@ } } -std::vector> -syntax::List::getElementsAsNodesAndDelimiters() { - if (!getFirstChild()) -return {}; +syntax::List::ElementAndDelimiter +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(Next)}; + default: +llvm_unreachable( +"A list can have only elements and delimiters as children."); + } +} - std::vector> 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(C)}); - ElementWithoutDelimiter = nullptr; - break; -} -default: - llvm_unreachable( - "A list can have only elements and delimiters as children."); +llvm::Optional> +syntax::List::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) { + assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter); + auto *Next = Delimiter->getNextSibling(); + if (!Next) { +switch (getTerminationKind()) { +// List is separated and ends with delimiter +// => missing last ElementAndDelimiter. +case syntax::List::TerminationKind::Separated: + return llvm::Optional>( + {nullptr, nullptr}); +case syntax::List::TerminationKind::Terminated: +case syntax::List::TerminationKind::MaybeTerminated: + return None; } } - - switch (getTerminationKind()) { - case syntax::List::TerminationKind::Separated: { -Children.push_back({ElementWithoutDelimiter, nullptr}); -break; + switch (Next->getRole()) { + case syntax::NodeRole::ListElement: +return getWithDelimiter(Next); + + // Consecutive Delimiters => missing Element + case syntax::NodeRole::ListDelimiter: +return llvm::Optional>( +{nullptr, cast(Next)}); + default: +llvm_unreachable( +"A list can have only elements and delimiters as children."); } - case syntax::List::TerminationKind::Terminated: - case syntax::List::TerminationKind::MaybeTerminated: { -if (ElementWithoutDelimiter) { - Children.push_back({ElementWithoutDelimiter, nullptr}); -} -break; +} + +llvm::Optional> +syntax::List::getElementAndDelimiterAfterElement(syntax::Node *Element) { + assert(Element && Element->getRole() == syntax::NodeRole::ListElement); + auto *Next = Element->getNextSibling(); + // a b, x => End of list, this was the last ElementAndDelimiter. + if (!Next) +return None; + + switch (Next->getRole()) { + // x b, c => next ElementAndDelimiter starts with 'b'. + case syntax::NodeRole::ListElement: +return getWithDelimiter(Next); + + // a x, c => next ElementAndDelimiter starts after ','. + case syntax::NodeRole::ListDelimiter: +return getElementAndDelimiterAfterDelimiter(cast(Next)); + + default: +llvm_unreachable( +"A list can have only elements and delimiters as children."); } +} + +llvm::Optional> +syntax::List::getNext(syntax::List::ElementAndDelimiter ) { + if (auto *Delimiter = ED.delimiter) +return getElementAndDelimiterAfterDelimiter(Delimiter); + if (auto *Element = ED.element) +return getElementAndDelimiterAfterElement(Element); + return None; +} + +llvm::Optional> +syntax::List::getFirst() { + auto *First = this->getFirstChild(); + if (!First) +return None; + switch (First->getRole()) { + case syntax::NodeRole::ListElement: +return getWithDelimiter(First); + case syntax::NodeRole::ListDelimiter: +return llvm::Optional>( +{nullptr, cast(First)}); + default: +llvm_unreachable( +"A list can have only elements and delimiters as