1af582c9bSEduardo Caldas //===- TreeTest.cpp ---------------------------------------------*- C++ -*-===//
2af582c9bSEduardo Caldas //
3af582c9bSEduardo Caldas // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af582c9bSEduardo Caldas // See https://llvm.org/LICENSE.txt for license information.
5af582c9bSEduardo Caldas // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af582c9bSEduardo Caldas //
7af582c9bSEduardo Caldas //===----------------------------------------------------------------------===//
8af582c9bSEduardo Caldas 
9af582c9bSEduardo Caldas #include "clang/Tooling/Syntax/Tree.h"
10af582c9bSEduardo Caldas #include "TreeTestBase.h"
11d4934eb5SSam McCall #include "clang/Basic/SourceManager.h"
12af582c9bSEduardo Caldas #include "clang/Tooling/Syntax/BuildTree.h"
13c3c08bfdSEduardo Caldas #include "clang/Tooling/Syntax/Nodes.h"
14c3c08bfdSEduardo Caldas #include "llvm/ADT/STLExtras.h"
15af582c9bSEduardo Caldas #include "gtest/gtest.h"
16af582c9bSEduardo Caldas 
17af582c9bSEduardo Caldas using namespace clang;
18af582c9bSEduardo Caldas using namespace clang::syntax;
19af582c9bSEduardo Caldas 
20af582c9bSEduardo Caldas namespace {
21d4934eb5SSam McCall using testing::ElementsAre;
22af582c9bSEduardo Caldas 
23af582c9bSEduardo Caldas class TreeTest : public SyntaxTreeTest {
24af582c9bSEduardo Caldas private:
createTree(ArrayRef<const Node * > Children)25af582c9bSEduardo Caldas   Tree *createTree(ArrayRef<const Node *> Children) {
26af582c9bSEduardo Caldas     std::vector<std::pair<Node *, NodeRole>> ChildrenWithRoles;
27af582c9bSEduardo Caldas     ChildrenWithRoles.reserve(Children.size());
28af582c9bSEduardo Caldas     for (const auto *Child : Children) {
2966bcb143SEduardo Caldas       ChildrenWithRoles.push_back(std::make_pair(
30*263dcf45SHaojian Wu           deepCopyExpandingMacros(*Arena, *TM, Child), NodeRole::Unknown));
31af582c9bSEduardo Caldas     }
32af582c9bSEduardo Caldas     return clang::syntax::createTree(*Arena, ChildrenWithRoles,
33af582c9bSEduardo Caldas                                      NodeKind::UnknownExpression);
34af582c9bSEduardo Caldas   }
35af582c9bSEduardo Caldas 
36af582c9bSEduardo Caldas   // Generate Forests by combining `Children` into `ParentCount` Trees.
37af582c9bSEduardo Caldas   //
38af582c9bSEduardo Caldas   // We do this recursively.
39af582c9bSEduardo Caldas   std::vector<std::vector<const Tree *>>
generateAllForests(ArrayRef<const Node * > Children,unsigned ParentCount)40af582c9bSEduardo Caldas   generateAllForests(ArrayRef<const Node *> Children, unsigned ParentCount) {
41af582c9bSEduardo Caldas     assert(ParentCount > 0);
42af582c9bSEduardo Caldas     // If there is only one Parent node, then combine `Children` under
43af582c9bSEduardo Caldas     // this Parent.
44af582c9bSEduardo Caldas     if (ParentCount == 1)
45af582c9bSEduardo Caldas       return {{createTree(Children)}};
46af582c9bSEduardo Caldas 
47af582c9bSEduardo Caldas     // Otherwise, combine `ChildrenCount` children under the last parent and
48af582c9bSEduardo Caldas     // solve the smaller problem without these children and this parent. Do this
49af582c9bSEduardo Caldas     // for every `ChildrenCount` and combine the results.
50af582c9bSEduardo Caldas     std::vector<std::vector<const Tree *>> AllForests;
51af582c9bSEduardo Caldas     for (unsigned ChildrenCount = 0; ChildrenCount <= Children.size();
52af582c9bSEduardo Caldas          ++ChildrenCount) {
53af582c9bSEduardo Caldas       auto *LastParent = createTree(Children.take_back(ChildrenCount));
54af582c9bSEduardo Caldas       for (auto &Forest : generateAllForests(Children.drop_back(ChildrenCount),
55af582c9bSEduardo Caldas                                              ParentCount - 1)) {
56af582c9bSEduardo Caldas         Forest.push_back(LastParent);
57af582c9bSEduardo Caldas         AllForests.push_back(Forest);
58af582c9bSEduardo Caldas       }
59af582c9bSEduardo Caldas     }
60af582c9bSEduardo Caldas     return AllForests;
61af582c9bSEduardo Caldas   }
62af582c9bSEduardo Caldas 
63af582c9bSEduardo Caldas protected:
64af582c9bSEduardo Caldas   // Generates all trees with a `Base` of `Node`s and `NodeCountPerLayer`
65af582c9bSEduardo Caldas   // `Node`s per layer. An example of Tree with `Base` = {`(`, `)`} and
66af582c9bSEduardo Caldas   // `NodeCountPerLayer` = {2, 2}:
67af582c9bSEduardo Caldas   //  Tree
68af582c9bSEduardo Caldas   //  |-Tree
69af582c9bSEduardo Caldas   //  `-Tree
70af582c9bSEduardo Caldas   //    |-Tree
71af582c9bSEduardo Caldas   //    | `-'('
72af582c9bSEduardo Caldas   //    `-Tree
73af582c9bSEduardo Caldas   //      `-')'
74af582c9bSEduardo Caldas   std::vector<const Tree *>
generateAllTreesWithShape(ArrayRef<const Node * > Base,ArrayRef<unsigned> NodeCountPerLayer)75af582c9bSEduardo Caldas   generateAllTreesWithShape(ArrayRef<const Node *> Base,
76af582c9bSEduardo Caldas                             ArrayRef<unsigned> NodeCountPerLayer) {
77af582c9bSEduardo Caldas     // We compute the solution per layer. A layer is a collection of bases,
78af582c9bSEduardo Caldas     // where each base has the same number of nodes, given by
79af582c9bSEduardo Caldas     // `NodeCountPerLayer`.
80af582c9bSEduardo Caldas     auto GenerateNextLayer = [this](ArrayRef<std::vector<const Node *>> Layer,
81af582c9bSEduardo Caldas                                     unsigned NextLayerNodeCount) {
82af582c9bSEduardo Caldas       std::vector<std::vector<const Node *>> NextLayer;
83af582c9bSEduardo Caldas       for (const auto &Base : Layer) {
84af582c9bSEduardo Caldas         for (const auto &NextBase :
85af582c9bSEduardo Caldas              generateAllForests(Base, NextLayerNodeCount)) {
86af582c9bSEduardo Caldas           NextLayer.push_back(
87af582c9bSEduardo Caldas               std::vector<const Node *>(NextBase.begin(), NextBase.end()));
88af582c9bSEduardo Caldas         }
89af582c9bSEduardo Caldas       }
90af582c9bSEduardo Caldas       return NextLayer;
91af582c9bSEduardo Caldas     };
92af582c9bSEduardo Caldas 
93af582c9bSEduardo Caldas     std::vector<std::vector<const Node *>> Layer = {Base};
94af582c9bSEduardo Caldas     for (auto NodeCount : NodeCountPerLayer)
95af582c9bSEduardo Caldas       Layer = GenerateNextLayer(Layer, NodeCount);
96af582c9bSEduardo Caldas 
97af582c9bSEduardo Caldas     std::vector<const Tree *> AllTrees;
98af582c9bSEduardo Caldas     AllTrees.reserve(Layer.size());
99af582c9bSEduardo Caldas     for (const auto &Base : Layer)
100af582c9bSEduardo Caldas       AllTrees.push_back(createTree(Base));
101af582c9bSEduardo Caldas 
102af582c9bSEduardo Caldas     return AllTrees;
103af582c9bSEduardo Caldas   }
104af582c9bSEduardo Caldas };
105af582c9bSEduardo Caldas 
106d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(TreeTests, TreeTest,
107d4d80a29SBenjamin Kramer                         ::testing::ValuesIn(allTestClangConfigs()) );
108af582c9bSEduardo Caldas 
TEST_P(TreeTest,FirstLeaf)109af582c9bSEduardo Caldas TEST_P(TreeTest, FirstLeaf) {
110af582c9bSEduardo Caldas   buildTree("", GetParam());
111*263dcf45SHaojian Wu   std::vector<const Node *> Leafs = {createLeaf(*Arena, *TM, tok::l_paren),
112*263dcf45SHaojian Wu                                      createLeaf(*Arena, *TM, tok::r_paren)};
113af582c9bSEduardo Caldas   for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) {
114af582c9bSEduardo Caldas     ASSERT_TRUE(Tree->findFirstLeaf() != nullptr);
115*263dcf45SHaojian Wu     EXPECT_EQ(TM->getToken(Tree->findFirstLeaf()->getTokenKey())->kind(), tok::l_paren);
116af582c9bSEduardo Caldas   }
117af582c9bSEduardo Caldas }
118af582c9bSEduardo Caldas 
TEST_P(TreeTest,LastLeaf)119af582c9bSEduardo Caldas TEST_P(TreeTest, LastLeaf) {
120af582c9bSEduardo Caldas   buildTree("", GetParam());
121*263dcf45SHaojian Wu   std::vector<const Node *> Leafs = {createLeaf(*Arena, *TM, tok::l_paren),
122*263dcf45SHaojian Wu                                      createLeaf(*Arena, *TM, tok::r_paren)};
123af582c9bSEduardo Caldas   for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) {
124af582c9bSEduardo Caldas     ASSERT_TRUE(Tree->findLastLeaf() != nullptr);
125*263dcf45SHaojian Wu     EXPECT_EQ(TM->getToken(Tree->findLastLeaf()->getTokenKey())->kind(), tok::r_paren);
126af582c9bSEduardo Caldas   }
127af582c9bSEduardo Caldas }
128af582c9bSEduardo Caldas 
TEST_F(TreeTest,Iterators)129d4934eb5SSam McCall TEST_F(TreeTest, Iterators) {
130d4934eb5SSam McCall   buildTree("", allTestClangConfigs().front());
131*263dcf45SHaojian Wu   std::vector<Node *> Children = {createLeaf(*Arena, *TM, tok::identifier, "a"),
132*263dcf45SHaojian Wu                                   createLeaf(*Arena, *TM, tok::identifier, "b"),
133*263dcf45SHaojian Wu                                   createLeaf(*Arena, *TM, tok::identifier, "c")};
134d4934eb5SSam McCall   auto *Tree = syntax::createTree(*Arena,
135d4934eb5SSam McCall                                   {{Children[0], NodeRole::LeftHandSide},
136d4934eb5SSam McCall                                    {Children[1], NodeRole::OperatorToken},
137d4934eb5SSam McCall                                    {Children[2], NodeRole::RightHandSide}},
138d4934eb5SSam McCall                                   NodeKind::TranslationUnit);
139d4934eb5SSam McCall   const auto *ConstTree = Tree;
140d4934eb5SSam McCall 
141d4934eb5SSam McCall   auto Range = Tree->getChildren();
142d4934eb5SSam McCall   EXPECT_THAT(Range, ElementsAre(role(NodeRole::LeftHandSide),
143d4934eb5SSam McCall                                  role(NodeRole::OperatorToken),
144d4934eb5SSam McCall                                  role(NodeRole::RightHandSide)));
145d4934eb5SSam McCall 
146d4934eb5SSam McCall   auto ConstRange = ConstTree->getChildren();
147d4934eb5SSam McCall   EXPECT_THAT(ConstRange, ElementsAre(role(NodeRole::LeftHandSide),
148d4934eb5SSam McCall                                       role(NodeRole::OperatorToken),
149d4934eb5SSam McCall                                       role(NodeRole::RightHandSide)));
150d4934eb5SSam McCall 
151d4934eb5SSam McCall   // FIXME: mutate and observe no invalidation. Mutations are private for now...
152d4934eb5SSam McCall   auto It = Range.begin();
153d4934eb5SSam McCall   auto CIt = ConstRange.begin();
154d4934eb5SSam McCall   static_assert(std::is_same<decltype(*It), syntax::Node &>::value,
155d4934eb5SSam McCall                 "mutable range");
156d4934eb5SSam McCall   static_assert(std::is_same<decltype(*CIt), const syntax::Node &>::value,
157d4934eb5SSam McCall                 "const range");
158d4934eb5SSam McCall 
159d4934eb5SSam McCall   for (unsigned I = 0; I < 3; ++I) {
160d4934eb5SSam McCall     EXPECT_EQ(It, CIt);
161d4934eb5SSam McCall     EXPECT_TRUE(It);
162d4934eb5SSam McCall     EXPECT_TRUE(CIt);
163d4934eb5SSam McCall     EXPECT_EQ(It.asPointer(), Children[I]);
164d4934eb5SSam McCall     EXPECT_EQ(CIt.asPointer(), Children[I]);
165d4934eb5SSam McCall     EXPECT_EQ(&*It, Children[I]);
166d4934eb5SSam McCall     EXPECT_EQ(&*CIt, Children[I]);
167d4934eb5SSam McCall     ++It;
168d4934eb5SSam McCall     ++CIt;
169d4934eb5SSam McCall   }
170d4934eb5SSam McCall   EXPECT_EQ(It, CIt);
171d4934eb5SSam McCall   EXPECT_EQ(It, Tree::ChildIterator());
172d4934eb5SSam McCall   EXPECT_EQ(CIt, Tree::ConstChildIterator());
173d4934eb5SSam McCall   EXPECT_FALSE(It);
174d4934eb5SSam McCall   EXPECT_FALSE(CIt);
175d4934eb5SSam McCall   EXPECT_EQ(nullptr, It.asPointer());
176d4934eb5SSam McCall   EXPECT_EQ(nullptr, CIt.asPointer());
177d4934eb5SSam McCall }
178d4934eb5SSam McCall 
179c3c08bfdSEduardo Caldas class ListTest : public SyntaxTreeTest {
180c3c08bfdSEduardo Caldas private:
dumpQuotedTokensOrNull(const Node * N)181c3c08bfdSEduardo Caldas   std::string dumpQuotedTokensOrNull(const Node *N) {
182c3c08bfdSEduardo Caldas     return N ? "'" +
183*263dcf45SHaojian Wu                    StringRef(N->dumpTokens(*TM))
184c3c08bfdSEduardo Caldas                        .trim()
185c3c08bfdSEduardo Caldas                        .str() +
186c3c08bfdSEduardo Caldas                    "'"
187c3c08bfdSEduardo Caldas              : "null";
188c3c08bfdSEduardo Caldas   }
189c3c08bfdSEduardo Caldas 
190c3c08bfdSEduardo Caldas protected:
191c3c08bfdSEduardo Caldas   std::string
dumpElementsAndDelimiters(ArrayRef<List::ElementAndDelimiter<Node>> EDs)192c3c08bfdSEduardo Caldas   dumpElementsAndDelimiters(ArrayRef<List::ElementAndDelimiter<Node>> EDs) {
193c3c08bfdSEduardo Caldas     std::string Storage;
194c3c08bfdSEduardo Caldas     llvm::raw_string_ostream OS(Storage);
195c3c08bfdSEduardo Caldas 
196c3c08bfdSEduardo Caldas     OS << "[";
197c3c08bfdSEduardo Caldas 
198c3c08bfdSEduardo Caldas     llvm::interleaveComma(
199c3c08bfdSEduardo Caldas         EDs, OS, [&OS, this](const List::ElementAndDelimiter<Node> &ED) {
200c3c08bfdSEduardo Caldas           OS << "(" << dumpQuotedTokensOrNull(ED.element) << ", "
201c3c08bfdSEduardo Caldas              << dumpQuotedTokensOrNull(ED.delimiter) << ")";
202c3c08bfdSEduardo Caldas         });
203c3c08bfdSEduardo Caldas 
204c3c08bfdSEduardo Caldas     OS << "]";
205c3c08bfdSEduardo Caldas 
20608eb614eSLogan Smith     return Storage;
207c3c08bfdSEduardo Caldas   }
208c3c08bfdSEduardo Caldas 
dumpNodes(ArrayRef<Node * > Nodes)209c3c08bfdSEduardo Caldas   std::string dumpNodes(ArrayRef<Node *> Nodes) {
210c3c08bfdSEduardo Caldas     std::string Storage;
211c3c08bfdSEduardo Caldas     llvm::raw_string_ostream OS(Storage);
212c3c08bfdSEduardo Caldas 
213c3c08bfdSEduardo Caldas     OS << "[";
214c3c08bfdSEduardo Caldas 
215c3c08bfdSEduardo Caldas     llvm::interleaveComma(Nodes, OS, [&OS, this](const Node *N) {
216c3c08bfdSEduardo Caldas       OS << dumpQuotedTokensOrNull(N);
217c3c08bfdSEduardo Caldas     });
218c3c08bfdSEduardo Caldas 
219c3c08bfdSEduardo Caldas     OS << "]";
220c3c08bfdSEduardo Caldas 
22108eb614eSLogan Smith     return Storage;
222c3c08bfdSEduardo Caldas   }
223c3c08bfdSEduardo Caldas };
224c3c08bfdSEduardo Caldas 
225d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(TreeTests, ListTest,
226d4d80a29SBenjamin Kramer                         ::testing::ValuesIn(allTestClangConfigs()) );
227c3c08bfdSEduardo Caldas 
228c3c08bfdSEduardo Caldas /// "a, b, c"  <=> [("a", ","), ("b", ","), ("c", null)]
TEST_P(ListTest,List_Separated_WellFormed)229c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_WellFormed) {
230c3c08bfdSEduardo Caldas   buildTree("", GetParam());
231c3c08bfdSEduardo Caldas 
232c3c08bfdSEduardo Caldas   // "a, b, c"
233c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
234c3c08bfdSEduardo Caldas       *Arena,
235c3c08bfdSEduardo Caldas       {
236*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
237*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
238*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
239*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
240*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
241c3c08bfdSEduardo Caldas       },
242c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
243c3c08bfdSEduardo Caldas 
244c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
245c3c08bfdSEduardo Caldas             "[('a', ','), ('b', ','), ('c', null)]");
246c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
247c3c08bfdSEduardo Caldas }
248c3c08bfdSEduardo Caldas 
249c3c08bfdSEduardo Caldas /// "a,  , c"  <=> [("a", ","), (null, ","), ("c", null)]
TEST_P(ListTest,List_Separated_MissingElement)250c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_MissingElement) {
251c3c08bfdSEduardo Caldas   buildTree("", GetParam());
252c3c08bfdSEduardo Caldas 
253c3c08bfdSEduardo Caldas   // "a,  , c"
254c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
255c3c08bfdSEduardo Caldas       *Arena,
256c3c08bfdSEduardo Caldas       {
257*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
258*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
259*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
260*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
261c3c08bfdSEduardo Caldas       },
262c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
263c3c08bfdSEduardo Caldas 
264c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
265c3c08bfdSEduardo Caldas             "[('a', ','), (null, ','), ('c', null)]");
266c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', null, 'c']");
267c3c08bfdSEduardo Caldas }
268c3c08bfdSEduardo Caldas 
269c3c08bfdSEduardo Caldas /// "a, b  c"  <=> [("a", ","), ("b", null), ("c", null)]
TEST_P(ListTest,List_Separated_MissingDelimiter)270c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_MissingDelimiter) {
271c3c08bfdSEduardo Caldas   buildTree("", GetParam());
272c3c08bfdSEduardo Caldas 
273c3c08bfdSEduardo Caldas   // "a, b  c"
274c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
275c3c08bfdSEduardo Caldas       *Arena,
276c3c08bfdSEduardo Caldas       {
277*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
278*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
279*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
280*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
281c3c08bfdSEduardo Caldas       },
282c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
283c3c08bfdSEduardo Caldas 
284c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
285c3c08bfdSEduardo Caldas             "[('a', ','), ('b', null), ('c', null)]");
286c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
287c3c08bfdSEduardo Caldas }
288c3c08bfdSEduardo Caldas 
289c3c08bfdSEduardo Caldas /// "a, b,"    <=> [("a", ","), ("b", ","), (null, null)]
TEST_P(ListTest,List_Separated_MissingLastElement)290c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_MissingLastElement) {
291c3c08bfdSEduardo Caldas   buildTree("", GetParam());
292c3c08bfdSEduardo Caldas 
293c3c08bfdSEduardo Caldas   // "a, b, c"
294c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
295c3c08bfdSEduardo Caldas       *Arena,
296c3c08bfdSEduardo Caldas       {
297*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
298*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
299*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
300*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
301c3c08bfdSEduardo Caldas       },
302c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
303c3c08bfdSEduardo Caldas 
304c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
305c3c08bfdSEduardo Caldas             "[('a', ','), ('b', ','), (null, null)]");
306c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', null]");
307c3c08bfdSEduardo Caldas }
308c3c08bfdSEduardo Caldas 
309c3c08bfdSEduardo Caldas /// "a:: b:: c::" <=> [("a", "::"), ("b", "::"), ("c", "::")]
TEST_P(ListTest,List_Terminated_WellFormed)310c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_WellFormed) {
311c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
312c3c08bfdSEduardo Caldas     return;
313c3c08bfdSEduardo Caldas   }
314c3c08bfdSEduardo Caldas   buildTree("", GetParam());
315c3c08bfdSEduardo Caldas 
316c3c08bfdSEduardo Caldas   // "a:: b:: c::"
317c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
318c3c08bfdSEduardo Caldas       *Arena,
319c3c08bfdSEduardo Caldas       {
320*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
321*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
322*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
323*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
324*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
325*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
326c3c08bfdSEduardo Caldas       },
327c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
328c3c08bfdSEduardo Caldas 
329c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
330c3c08bfdSEduardo Caldas             "[('a', '::'), ('b', '::'), ('c', '::')]");
331c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
332c3c08bfdSEduardo Caldas }
333c3c08bfdSEduardo Caldas 
334c3c08bfdSEduardo Caldas /// "a::  :: c::" <=> [("a", "::"), (null, "::"), ("c", "::")]
TEST_P(ListTest,List_Terminated_MissingElement)335c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_MissingElement) {
336c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
337c3c08bfdSEduardo Caldas     return;
338c3c08bfdSEduardo Caldas   }
339c3c08bfdSEduardo Caldas   buildTree("", GetParam());
340c3c08bfdSEduardo Caldas 
341c3c08bfdSEduardo Caldas   // "a:: b:: c::"
342c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
343c3c08bfdSEduardo Caldas       *Arena,
344c3c08bfdSEduardo Caldas       {
345*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
346*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
347*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
348*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
349*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
350c3c08bfdSEduardo Caldas       },
351c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
352c3c08bfdSEduardo Caldas 
353c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
354c3c08bfdSEduardo Caldas             "[('a', '::'), (null, '::'), ('c', '::')]");
355c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', null, 'c']");
356c3c08bfdSEduardo Caldas }
357c3c08bfdSEduardo Caldas 
358c3c08bfdSEduardo Caldas /// "a:: b  c::" <=> [("a", "::"), ("b", null), ("c", "::")]
TEST_P(ListTest,List_Terminated_MissingDelimiter)359c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_MissingDelimiter) {
360c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
361c3c08bfdSEduardo Caldas     return;
362c3c08bfdSEduardo Caldas   }
363c3c08bfdSEduardo Caldas   buildTree("", GetParam());
364c3c08bfdSEduardo Caldas 
365c3c08bfdSEduardo Caldas   // "a:: b  c::"
366c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
367c3c08bfdSEduardo Caldas       *Arena,
368c3c08bfdSEduardo Caldas       {
369*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
370*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
371*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
372*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
373*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
374c3c08bfdSEduardo Caldas       },
375c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
376c3c08bfdSEduardo Caldas 
377c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
378c3c08bfdSEduardo Caldas             "[('a', '::'), ('b', null), ('c', '::')]");
379c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
380c3c08bfdSEduardo Caldas }
381c3c08bfdSEduardo Caldas 
382c3c08bfdSEduardo Caldas /// "a:: b:: c"  <=> [("a", "::"), ("b", "::"), ("c", null)]
TEST_P(ListTest,List_Terminated_MissingLastDelimiter)383c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_MissingLastDelimiter) {
384c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
385c3c08bfdSEduardo Caldas     return;
386c3c08bfdSEduardo Caldas   }
387c3c08bfdSEduardo Caldas   buildTree("", GetParam());
388c3c08bfdSEduardo Caldas 
389c3c08bfdSEduardo Caldas   // "a:: b:: c"
390c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
391c3c08bfdSEduardo Caldas       *Arena,
392c3c08bfdSEduardo Caldas       {
393*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
394*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
395*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
396*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
397*263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
398c3c08bfdSEduardo Caldas       },
399c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
400c3c08bfdSEduardo Caldas 
401c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
402c3c08bfdSEduardo Caldas             "[('a', '::'), ('b', '::'), ('c', null)]");
403c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
404c3c08bfdSEduardo Caldas }
405c3c08bfdSEduardo Caldas 
406af582c9bSEduardo Caldas } // namespace
407