[clang] c3c08bf - [SyntaxTree] Test the List API

Eduardo Caldas via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 22 10:07:51 PDT 2020


Author: Eduardo Caldas
Date: 2020-09-22T17:07:41Z
New Revision: c3c08bfdfd6244e0429753ee56df39c90187d772

URL: https://github.com/llvm/llvm-project/commit/c3c08bfdfd6244e0429753ee56df39c90187d772
DIFF: https://github.com/llvm/llvm-project/commit/c3c08bfdfd6244e0429753ee56df39c90187d772.diff

LOG: [SyntaxTree] Test the List API

Differential Revision: https://reviews.llvm.org/D87839

Added: 
    

Modified: 
    clang/include/clang/Tooling/Syntax/Tree.h
    clang/unittests/Tooling/Syntax/TreeTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/Syntax/Tree.h b/clang/include/clang/Tooling/Syntax/Tree.h
index a544fc1827b7..5840a86199eb 100644
--- a/clang/include/clang/Tooling/Syntax/Tree.h
+++ b/clang/include/clang/Tooling/Syntax/Tree.h
@@ -218,12 +218,16 @@ class List : public Tree {
   /// 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" , null)]
+  /// "a,  , c"  <=> [("a" , ","), (null, "," ), ("c" , null)]
+  /// "a, b  c"  <=> [("a" , ","), ("b" , null), ("c" , null)]
+  /// "a, b,"    <=> [("a" , ","), ("b" , "," ), (null, null)]
   ///
   /// In a terminated or maybe-terminated list:
-  /// "a, b," <=> [("a", ","), ("b", ",")]
+  /// "a; b; c;" <=> [("a" , ";"), ("b" , ";" ), ("c" , ";" )]
+  /// "a;  ; c;" <=> [("a" , ";"), (null, ";" ), ("c" , ";" )]
+  /// "a; b  c;" <=> [("a" , ";"), ("b" , null), ("c" , ";" )]
+  /// "a; b; c"  <=> [("a" , ";"), ("b" , ";" ), ("c" , null)]
   std::vector<ElementAndDelimiter<Node>> getElementsAsNodesAndDelimiters();
 
   /// Returns the elements of the list. Missing elements are represented

diff  --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp
index 6e777b353b04..fba3164e5966 100644
--- a/clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -9,6 +9,8 @@
 #include "clang/Tooling/Syntax/Tree.h"
 #include "TreeTestBase.h"
 #include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/Nodes.h"
+#include "llvm/ADT/STLExtras.h"
 #include "gtest/gtest.h"
 
 using namespace clang;
@@ -122,4 +124,231 @@ TEST_P(TreeTest, LastLeaf) {
   }
 }
 
+class ListTest : public SyntaxTreeTest {
+private:
+  std::string dumpQuotedTokensOrNull(const Node *N) {
+    return N ? "'" +
+                   StringRef(N->dumpTokens(Arena->getSourceManager()))
+                       .trim()
+                       .str() +
+                   "'"
+             : "null";
+  }
+
+protected:
+  std::string
+  dumpElementsAndDelimiters(ArrayRef<List::ElementAndDelimiter<Node>> EDs) {
+    std::string Storage;
+    llvm::raw_string_ostream OS(Storage);
+
+    OS << "[";
+
+    llvm::interleaveComma(
+        EDs, OS, [&OS, this](const List::ElementAndDelimiter<Node> &ED) {
+          OS << "(" << dumpQuotedTokensOrNull(ED.element) << ", "
+             << dumpQuotedTokensOrNull(ED.delimiter) << ")";
+        });
+
+    OS << "]";
+
+    return OS.str();
+  }
+
+  std::string dumpNodes(ArrayRef<Node *> Nodes) {
+    std::string Storage;
+    llvm::raw_string_ostream OS(Storage);
+
+    OS << "[";
+
+    llvm::interleaveComma(Nodes, OS, [&OS, this](const Node *N) {
+      OS << dumpQuotedTokensOrNull(N);
+    });
+
+    OS << "]";
+
+    return OS.str();
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(TreeTests, ListTest,
+                        ::testing::ValuesIn(allTestClangConfigs()), );
+
+/// "a, b, c"  <=> [("a", ","), ("b", ","), ("c", null)]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), ('b', ','), ('c', null)]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
+}
+
+/// "a,  , c"  <=> [("a", ","), (null, ","), ("c", null)]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), (null, ','), ('c', null)]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', null, 'c']");
+}
+
+/// "a, b  c"  <=> [("a", ","), ("b", null), ("c", null)]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), ('b', null), ('c', null)]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
+}
+
+/// "a, b,"    <=> [("a", ","), ("b", ","), (null, null)]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', ','), ('b', ','), (null, null)]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', null]");
+}
+
+/// "a:: b:: c::" <=> [("a", "::"), ("b", "::"), ("c", "::")]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), ('b', '::'), ('c', '::')]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
+}
+
+/// "a::  :: c::" <=> [("a", "::"), (null, "::"), ("c", "::")]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), (null, '::'), ('c', '::')]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', null, 'c']");
+}
+
+/// "a:: b  c::" <=> [("a", "::"), ("b", null), ("c", "::")]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), ('b', null), ('c', '::')]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
+}
+
+/// "a:: b:: c"  <=> [("a", "::"), ("b", "::"), ("c", null)]
+TEST_P(ListTest, 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(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
+            "[('a', '::'), ('b', '::'), ('c', null)]");
+  EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
+}
+
 } // namespace


        


More information about the cfe-commits mailing list