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/D87839

Files:
  clang/include/clang/Tooling/Syntax/Tree.h
  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
@@ -13,6 +13,7 @@
 #include "clang/Tooling/Syntax/Tree.h"
 #include "TreeTestBase.h"
 #include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/Nodes.h"
 #include "gtest/gtest.h"
 
 using namespace clang;
@@ -38,6 +39,7 @@
     return ::testing::AssertionSuccess();
   }
 
+private:
   Tree *createTree(ArrayRef<const Node *> Children) {
     auto ChildrenWithRoles = std::vector<std::pair<Node *, NodeRole>>();
     ChildrenWithRoles.reserve(Children.size());
@@ -76,6 +78,7 @@
     return AllForests;
   }
 
+public:
   // Generates all trees with a `Base` layer of `Node`s and `NodeCountPerLayer`
   // `Node`s per layer. An example of Tree with `Base` = {`(`, `)`} and
   // `NodeCountPerLayer` = {2, 2}:
@@ -138,4 +141,178 @@
   }
 }
 
+std::string dump(Arena &A, const List::ElementAndDelimiter<Node> &ED) {
+  auto Format = [](StringRef s) { return "'" + s.trim().str() + "'"; };
+
+  std::string Delimiter =
+      ED.delimiter ? Format(ED.delimiter->dumpTokens(A.getSourceManager()))
+                   : "nul";
+
+  std::string Element =
+      ED.element ? Format(ED.element->dumpTokens(A.getSourceManager())) : "nul";
+
+  return "(" + Element + ", " + Delimiter + ")";
+}
+
+std::string dump(Arena &A, ArrayRef<List::ElementAndDelimiter<Node>> EDs) {
+  if (EDs.empty())
+    return "[]";
+
+  std::string Storage;
+  llvm::raw_string_ostream OS(Storage);
+
+  OS << "[" << dump(A, EDs.front());
+  for (auto ED = std::next(EDs.begin()), End = EDs.end(); ED != End; ++ED)
+    OS << ", " << dump(A, *ED);
+  OS << "]";
+  return OS.str();
+}
+
+
+/// "a, b, c"  <=> [("a", ","), ("b", ","), ("c", nul)]
+TEST_P(TreeTest, List_Separated_WellFormed) {
+  buildTree("", GetParam());
+
+  // "a, b, c"
+  auto *List = dyn_cast<syntax::List>(syntax::createTree(*Arena, {
+      {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement},
+  }, NodeKind::CallArguments));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), ('b', ','), ('c', nul)]");
+}
+
+/// "a,  , c"  <=> [("a", ","), (nul, ","), ("c", nul)]
+TEST_P(TreeTest, List_Separated_MissingElement) {
+  buildTree("", GetParam());
+
+  // "a,  , c"
+  auto *List = dyn_cast<syntax::List>(syntax::createTree(*Arena, {
+      {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement},
+  }, NodeKind::CallArguments));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), (nul, ','), ('c', nul)]");
+}
+
+/// "a, b  c"  <=> [("a", ","), ("b", nul), ("c", nul)]
+TEST_P(TreeTest, List_Separated_MissingDelimiter) {
+  buildTree("", GetParam());
+
+  // "a, b  c"
+  auto *List = dyn_cast<syntax::List>(syntax::createTree(*Arena, {
+      {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement},
+  }, NodeKind::CallArguments));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), ('b', nul), ('c', nul)]");
+}
+
+/// "a, b,"    <=> [("a", ","), ("b", ","), (nul, nul)]
+TEST_P(TreeTest, List_Separated_MissingLastElement) {
+  buildTree("", GetParam());
+
+  // "a, b, c"
+  auto *List = dyn_cast<syntax::List>(syntax::createTree(*Arena, {
+      {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter},
+  }, NodeKind::CallArguments));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), ('b', ','), (nul, nul)]");
+}
+
+/// "a:: b:: c::" <=> [("a", "::"), ("b", "::"), ("c", "::")]
+TEST_P(TreeTest, List_Terminated_WellFormed) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  buildTree("", GetParam());
+
+  // "a:: b:: c::"
+  auto *List = dyn_cast<syntax::List>(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},
+      {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter},
+  }, NodeKind::NestedNameSpecifier));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), ('b', '::'), ('c', '::')]");
+}
+
+/// "a::  :: c::" <=> [("a", "::"), (nul, "::"), ("c", "::")]
+TEST_P(TreeTest, List_Terminated_MissingElement) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  buildTree("", GetParam());
+
+  // "a:: b:: c::"
+  auto *List = dyn_cast<syntax::List>(syntax::createTree(*Arena, {
+      {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter},
+      {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter},
+  }, NodeKind::NestedNameSpecifier));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), (nul, '::'), ('c', '::')]");
+}
+
+/// "a:: b  c::" <=> [("a", "::"), ("b", nul), ("c", "::")]
+TEST_P(TreeTest, List_Terminated_MissingDelimiter) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  buildTree("", GetParam());
+
+  // "a:: b  c::"
+  auto *List = dyn_cast<syntax::List>(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::identifier, "c"), NodeRole::ListElement},
+      {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter},
+  }, NodeKind::NestedNameSpecifier));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), ('b', nul), ('c', '::')]");
+}
+
+/// "a:: b:: c"  <=> [("a", "::"), ("b", "::"), ("c", nul)]
+TEST_P(TreeTest, List_Terminated_MissingLastDelimiter) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  buildTree("", GetParam());
+
+  // "a:: b:: c"
+  auto *List = dyn_cast<syntax::List>(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));
+
+  EXPECT_EQ(dump(*Arena, List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), ('b', '::'), ('c', nul)]");
+}
+
 } // namespace
Index: clang/include/clang/Tooling/Syntax/Tree.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Tree.h
+++ clang/include/clang/Tooling/Syntax/Tree.h
@@ -218,12 +218,16 @@
   /// and delimiters are represented as null pointers.
   ///
   /// For example, in a separated list:
-  /// "a, b, c" <=> [("a", ","), ("b", ","), ("c", null)]
-  /// "a, , c" <=> [("a", ","), (null, ","), ("c", ",)]
-  /// "a, b," <=> [("a", ","), ("b", ","), (null, null)]
+  /// "a, b, c"  <=> [("a", ","), ("b", ","), ("c", nul)]
+  /// "a,  , c"  <=> [("a", ","), (nul, ","), ("c", nul)]
+  /// "a, b  c"  <=> [("a", ","), ("b", nul), ("c", nul)]
+  /// "a, b,"    <=> [("a", ","), ("b", ","), (nul, nul)]
   ///
   /// In a terminated or maybe-terminated list:
-  /// "a, b," <=> [("a", ","), ("b", ",")]
+  /// "a; b; c;" <=> [("a", ";"), ("b", ";"), ("c", ";")]
+  /// "a;  ; c;" <=> [("a", ";"), (nul, ";"), ("c", ";")]
+  /// "a; b  c;" <=> [("a", ";"), ("b", nul), ("c", ";")]
+  /// "a; b; c"  <=> [("a", ";"), ("b", ";"), ("c", nul)]
   std::vector<ElementAndDelimiter<Node>> getElementsAsNodesAndDelimiters();
 
   /// Returns the elements of the list. Missing elements are represented
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to