[PATCH] D88106: [SyntaxTree] Provide iterator-like functions for Lists

2020-10-26 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-20 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-20 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-15 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-15 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-14 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-14 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-14 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-14 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-12 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-12 Thread Dmitri Gribenko via Phabricator via cfe-commits
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

2020-10-08 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-08 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-08 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-08 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-10-08 Thread Eduardo Caldas via Phabricator via cfe-commits
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

2020-09-22 Thread Eduardo Caldas via Phabricator via cfe-commits
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