xref: /llvm-project/clang/unittests/Tooling/Syntax/TreeTest.cpp (revision 7dfdca1961aadc75ca397818bfb9bd32f1879248)
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:
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(
30263dcf45SHaojian 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 *>>
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 *>
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 
106*7dfdca19SJulian Schmidt INSTANTIATE_TEST_SUITE_P(
107*7dfdca19SJulian Schmidt     TreeTests, TreeTest, ::testing::ValuesIn(allTestClangConfigs()),
108*7dfdca19SJulian Schmidt     [](const testing::TestParamInfo<TestClangConfig> &Info) {
109*7dfdca19SJulian Schmidt       return Info.param.toShortString();
110*7dfdca19SJulian Schmidt     });
111af582c9bSEduardo Caldas 
112af582c9bSEduardo Caldas TEST_P(TreeTest, FirstLeaf) {
113af582c9bSEduardo Caldas   buildTree("", GetParam());
114263dcf45SHaojian Wu   std::vector<const Node *> Leafs = {createLeaf(*Arena, *TM, tok::l_paren),
115263dcf45SHaojian Wu                                      createLeaf(*Arena, *TM, tok::r_paren)};
116af582c9bSEduardo Caldas   for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) {
117af582c9bSEduardo Caldas     ASSERT_TRUE(Tree->findFirstLeaf() != nullptr);
118263dcf45SHaojian Wu     EXPECT_EQ(TM->getToken(Tree->findFirstLeaf()->getTokenKey())->kind(), tok::l_paren);
119af582c9bSEduardo Caldas   }
120af582c9bSEduardo Caldas }
121af582c9bSEduardo Caldas 
122af582c9bSEduardo Caldas TEST_P(TreeTest, LastLeaf) {
123af582c9bSEduardo Caldas   buildTree("", GetParam());
124263dcf45SHaojian Wu   std::vector<const Node *> Leafs = {createLeaf(*Arena, *TM, tok::l_paren),
125263dcf45SHaojian Wu                                      createLeaf(*Arena, *TM, tok::r_paren)};
126af582c9bSEduardo Caldas   for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) {
127af582c9bSEduardo Caldas     ASSERT_TRUE(Tree->findLastLeaf() != nullptr);
128263dcf45SHaojian Wu     EXPECT_EQ(TM->getToken(Tree->findLastLeaf()->getTokenKey())->kind(), tok::r_paren);
129af582c9bSEduardo Caldas   }
130af582c9bSEduardo Caldas }
131af582c9bSEduardo Caldas 
132d4934eb5SSam McCall TEST_F(TreeTest, Iterators) {
133d4934eb5SSam McCall   buildTree("", allTestClangConfigs().front());
134263dcf45SHaojian Wu   std::vector<Node *> Children = {createLeaf(*Arena, *TM, tok::identifier, "a"),
135263dcf45SHaojian Wu                                   createLeaf(*Arena, *TM, tok::identifier, "b"),
136263dcf45SHaojian Wu                                   createLeaf(*Arena, *TM, tok::identifier, "c")};
137d4934eb5SSam McCall   auto *Tree = syntax::createTree(*Arena,
138d4934eb5SSam McCall                                   {{Children[0], NodeRole::LeftHandSide},
139d4934eb5SSam McCall                                    {Children[1], NodeRole::OperatorToken},
140d4934eb5SSam McCall                                    {Children[2], NodeRole::RightHandSide}},
141d4934eb5SSam McCall                                   NodeKind::TranslationUnit);
142d4934eb5SSam McCall   const auto *ConstTree = Tree;
143d4934eb5SSam McCall 
144d4934eb5SSam McCall   auto Range = Tree->getChildren();
145d4934eb5SSam McCall   EXPECT_THAT(Range, ElementsAre(role(NodeRole::LeftHandSide),
146d4934eb5SSam McCall                                  role(NodeRole::OperatorToken),
147d4934eb5SSam McCall                                  role(NodeRole::RightHandSide)));
148d4934eb5SSam McCall 
149d4934eb5SSam McCall   auto ConstRange = ConstTree->getChildren();
150d4934eb5SSam McCall   EXPECT_THAT(ConstRange, ElementsAre(role(NodeRole::LeftHandSide),
151d4934eb5SSam McCall                                       role(NodeRole::OperatorToken),
152d4934eb5SSam McCall                                       role(NodeRole::RightHandSide)));
153d4934eb5SSam McCall 
154d4934eb5SSam McCall   // FIXME: mutate and observe no invalidation. Mutations are private for now...
155d4934eb5SSam McCall   auto It = Range.begin();
156d4934eb5SSam McCall   auto CIt = ConstRange.begin();
157108e41d9SNathan James   static_assert(std::is_same_v<decltype(*It), syntax::Node &>, "mutable range");
158108e41d9SNathan James   static_assert(std::is_same_v<decltype(*CIt), const syntax::Node &>,
159d4934eb5SSam McCall                 "const range");
160d4934eb5SSam McCall 
161d4934eb5SSam McCall   for (unsigned I = 0; I < 3; ++I) {
162d4934eb5SSam McCall     EXPECT_EQ(It, CIt);
163d4934eb5SSam McCall     EXPECT_TRUE(It);
164d4934eb5SSam McCall     EXPECT_TRUE(CIt);
165d4934eb5SSam McCall     EXPECT_EQ(It.asPointer(), Children[I]);
166d4934eb5SSam McCall     EXPECT_EQ(CIt.asPointer(), Children[I]);
167d4934eb5SSam McCall     EXPECT_EQ(&*It, Children[I]);
168d4934eb5SSam McCall     EXPECT_EQ(&*CIt, Children[I]);
169d4934eb5SSam McCall     ++It;
170d4934eb5SSam McCall     ++CIt;
171d4934eb5SSam McCall   }
172d4934eb5SSam McCall   EXPECT_EQ(It, CIt);
173d4934eb5SSam McCall   EXPECT_EQ(It, Tree::ChildIterator());
174d4934eb5SSam McCall   EXPECT_EQ(CIt, Tree::ConstChildIterator());
175d4934eb5SSam McCall   EXPECT_FALSE(It);
176d4934eb5SSam McCall   EXPECT_FALSE(CIt);
177d4934eb5SSam McCall   EXPECT_EQ(nullptr, It.asPointer());
178d4934eb5SSam McCall   EXPECT_EQ(nullptr, CIt.asPointer());
179d4934eb5SSam McCall }
180d4934eb5SSam McCall 
181c3c08bfdSEduardo Caldas class ListTest : public SyntaxTreeTest {
182c3c08bfdSEduardo Caldas private:
183c3c08bfdSEduardo Caldas   std::string dumpQuotedTokensOrNull(const Node *N) {
184c3c08bfdSEduardo Caldas     return N ? "'" +
185263dcf45SHaojian Wu                    StringRef(N->dumpTokens(*TM))
186c3c08bfdSEduardo Caldas                        .trim()
187c3c08bfdSEduardo Caldas                        .str() +
188c3c08bfdSEduardo Caldas                    "'"
189c3c08bfdSEduardo Caldas              : "null";
190c3c08bfdSEduardo Caldas   }
191c3c08bfdSEduardo Caldas 
192c3c08bfdSEduardo Caldas protected:
193c3c08bfdSEduardo Caldas   std::string
194c3c08bfdSEduardo Caldas   dumpElementsAndDelimiters(ArrayRef<List::ElementAndDelimiter<Node>> EDs) {
195c3c08bfdSEduardo Caldas     std::string Storage;
196c3c08bfdSEduardo Caldas     llvm::raw_string_ostream OS(Storage);
197c3c08bfdSEduardo Caldas 
198c3c08bfdSEduardo Caldas     OS << "[";
199c3c08bfdSEduardo Caldas 
200c3c08bfdSEduardo Caldas     llvm::interleaveComma(
201c3c08bfdSEduardo Caldas         EDs, OS, [&OS, this](const List::ElementAndDelimiter<Node> &ED) {
202c3c08bfdSEduardo Caldas           OS << "(" << dumpQuotedTokensOrNull(ED.element) << ", "
203c3c08bfdSEduardo Caldas              << dumpQuotedTokensOrNull(ED.delimiter) << ")";
204c3c08bfdSEduardo Caldas         });
205c3c08bfdSEduardo Caldas 
206c3c08bfdSEduardo Caldas     OS << "]";
207c3c08bfdSEduardo Caldas 
20808eb614eSLogan Smith     return Storage;
209c3c08bfdSEduardo Caldas   }
210c3c08bfdSEduardo Caldas 
211c3c08bfdSEduardo Caldas   std::string dumpNodes(ArrayRef<Node *> Nodes) {
212c3c08bfdSEduardo Caldas     std::string Storage;
213c3c08bfdSEduardo Caldas     llvm::raw_string_ostream OS(Storage);
214c3c08bfdSEduardo Caldas 
215c3c08bfdSEduardo Caldas     OS << "[";
216c3c08bfdSEduardo Caldas 
217c3c08bfdSEduardo Caldas     llvm::interleaveComma(Nodes, OS, [&OS, this](const Node *N) {
218c3c08bfdSEduardo Caldas       OS << dumpQuotedTokensOrNull(N);
219c3c08bfdSEduardo Caldas     });
220c3c08bfdSEduardo Caldas 
221c3c08bfdSEduardo Caldas     OS << "]";
222c3c08bfdSEduardo Caldas 
22308eb614eSLogan Smith     return Storage;
224c3c08bfdSEduardo Caldas   }
225c3c08bfdSEduardo Caldas };
226c3c08bfdSEduardo Caldas 
227*7dfdca19SJulian Schmidt INSTANTIATE_TEST_SUITE_P(
228*7dfdca19SJulian Schmidt     TreeTests, ListTest, ::testing::ValuesIn(allTestClangConfigs()),
229*7dfdca19SJulian Schmidt     [](const testing::TestParamInfo<TestClangConfig> &Info) {
230*7dfdca19SJulian Schmidt       return Info.param.toShortString();
231*7dfdca19SJulian Schmidt     });
232c3c08bfdSEduardo Caldas 
233c3c08bfdSEduardo Caldas /// "a, b, c"  <=> [("a", ","), ("b", ","), ("c", null)]
234c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_WellFormed) {
235c3c08bfdSEduardo Caldas   buildTree("", GetParam());
236c3c08bfdSEduardo Caldas 
237c3c08bfdSEduardo Caldas   // "a, b, c"
238c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
239c3c08bfdSEduardo Caldas       *Arena,
240c3c08bfdSEduardo Caldas       {
241263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
242263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
243263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
244263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
245263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
246c3c08bfdSEduardo Caldas       },
247c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
248c3c08bfdSEduardo Caldas 
249c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
250c3c08bfdSEduardo Caldas             "[('a', ','), ('b', ','), ('c', null)]");
251c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
252c3c08bfdSEduardo Caldas }
253c3c08bfdSEduardo Caldas 
254c3c08bfdSEduardo Caldas /// "a,  , c"  <=> [("a", ","), (null, ","), ("c", null)]
255c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_MissingElement) {
256c3c08bfdSEduardo Caldas   buildTree("", GetParam());
257c3c08bfdSEduardo Caldas 
258c3c08bfdSEduardo Caldas   // "a,  , c"
259c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
260c3c08bfdSEduardo Caldas       *Arena,
261c3c08bfdSEduardo Caldas       {
262263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
263263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
264263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
265263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
266c3c08bfdSEduardo Caldas       },
267c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
268c3c08bfdSEduardo Caldas 
269c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
270c3c08bfdSEduardo Caldas             "[('a', ','), (null, ','), ('c', null)]");
271c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', null, 'c']");
272c3c08bfdSEduardo Caldas }
273c3c08bfdSEduardo Caldas 
274c3c08bfdSEduardo Caldas /// "a, b  c"  <=> [("a", ","), ("b", null), ("c", null)]
275c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_MissingDelimiter) {
276c3c08bfdSEduardo Caldas   buildTree("", GetParam());
277c3c08bfdSEduardo Caldas 
278c3c08bfdSEduardo Caldas   // "a, b  c"
279c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
280c3c08bfdSEduardo Caldas       *Arena,
281c3c08bfdSEduardo Caldas       {
282263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
283263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
284263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
285263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
286c3c08bfdSEduardo Caldas       },
287c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
288c3c08bfdSEduardo Caldas 
289c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
290c3c08bfdSEduardo Caldas             "[('a', ','), ('b', null), ('c', null)]");
291c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
292c3c08bfdSEduardo Caldas }
293c3c08bfdSEduardo Caldas 
294c3c08bfdSEduardo Caldas /// "a, b,"    <=> [("a", ","), ("b", ","), (null, null)]
295c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Separated_MissingLastElement) {
296c3c08bfdSEduardo Caldas   buildTree("", GetParam());
297c3c08bfdSEduardo Caldas 
298c3c08bfdSEduardo Caldas   // "a, b, c"
299c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
300c3c08bfdSEduardo Caldas       *Arena,
301c3c08bfdSEduardo Caldas       {
302263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
303263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
304263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
305263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::comma), NodeRole::ListDelimiter},
306c3c08bfdSEduardo Caldas       },
307c3c08bfdSEduardo Caldas       NodeKind::CallArguments));
308c3c08bfdSEduardo Caldas 
309c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
310c3c08bfdSEduardo Caldas             "[('a', ','), ('b', ','), (null, null)]");
311c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', null]");
312c3c08bfdSEduardo Caldas }
313c3c08bfdSEduardo Caldas 
314c3c08bfdSEduardo Caldas /// "a:: b:: c::" <=> [("a", "::"), ("b", "::"), ("c", "::")]
315c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_WellFormed) {
316c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
317c3c08bfdSEduardo Caldas     return;
318c3c08bfdSEduardo Caldas   }
319c3c08bfdSEduardo Caldas   buildTree("", GetParam());
320c3c08bfdSEduardo Caldas 
321c3c08bfdSEduardo Caldas   // "a:: b:: c::"
322c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
323c3c08bfdSEduardo Caldas       *Arena,
324c3c08bfdSEduardo Caldas       {
325263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
326263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
327263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
328263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
329263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
330263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
331c3c08bfdSEduardo Caldas       },
332c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
333c3c08bfdSEduardo Caldas 
334c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
335c3c08bfdSEduardo Caldas             "[('a', '::'), ('b', '::'), ('c', '::')]");
336c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
337c3c08bfdSEduardo Caldas }
338c3c08bfdSEduardo Caldas 
339c3c08bfdSEduardo Caldas /// "a::  :: c::" <=> [("a", "::"), (null, "::"), ("c", "::")]
340c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_MissingElement) {
341c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
342c3c08bfdSEduardo Caldas     return;
343c3c08bfdSEduardo Caldas   }
344c3c08bfdSEduardo Caldas   buildTree("", GetParam());
345c3c08bfdSEduardo Caldas 
346c3c08bfdSEduardo Caldas   // "a:: b:: c::"
347c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
348c3c08bfdSEduardo Caldas       *Arena,
349c3c08bfdSEduardo Caldas       {
350263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
351263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
352263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
353263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
354263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
355c3c08bfdSEduardo Caldas       },
356c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
357c3c08bfdSEduardo Caldas 
358c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
359c3c08bfdSEduardo Caldas             "[('a', '::'), (null, '::'), ('c', '::')]");
360c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', null, 'c']");
361c3c08bfdSEduardo Caldas }
362c3c08bfdSEduardo Caldas 
363c3c08bfdSEduardo Caldas /// "a:: b  c::" <=> [("a", "::"), ("b", null), ("c", "::")]
364c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_MissingDelimiter) {
365c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
366c3c08bfdSEduardo Caldas     return;
367c3c08bfdSEduardo Caldas   }
368c3c08bfdSEduardo Caldas   buildTree("", GetParam());
369c3c08bfdSEduardo Caldas 
370c3c08bfdSEduardo Caldas   // "a:: b  c::"
371c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
372c3c08bfdSEduardo Caldas       *Arena,
373c3c08bfdSEduardo Caldas       {
374263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
375263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
376263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
377263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
378263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
379c3c08bfdSEduardo Caldas       },
380c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
381c3c08bfdSEduardo Caldas 
382c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
383c3c08bfdSEduardo Caldas             "[('a', '::'), ('b', null), ('c', '::')]");
384c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
385c3c08bfdSEduardo Caldas }
386c3c08bfdSEduardo Caldas 
387c3c08bfdSEduardo Caldas /// "a:: b:: c"  <=> [("a", "::"), ("b", "::"), ("c", null)]
388c3c08bfdSEduardo Caldas TEST_P(ListTest, List_Terminated_MissingLastDelimiter) {
389c3c08bfdSEduardo Caldas   if (!GetParam().isCXX()) {
390c3c08bfdSEduardo Caldas     return;
391c3c08bfdSEduardo Caldas   }
392c3c08bfdSEduardo Caldas   buildTree("", GetParam());
393c3c08bfdSEduardo Caldas 
394c3c08bfdSEduardo Caldas   // "a:: b:: c"
395c3c08bfdSEduardo Caldas   auto *List = dyn_cast<syntax::List>(syntax::createTree(
396c3c08bfdSEduardo Caldas       *Arena,
397c3c08bfdSEduardo Caldas       {
398263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "a"), NodeRole::ListElement},
399263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
400263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "b"), NodeRole::ListElement},
401263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::coloncolon), NodeRole::ListDelimiter},
402263dcf45SHaojian Wu           {createLeaf(*Arena, *TM, tok::identifier, "c"), NodeRole::ListElement},
403c3c08bfdSEduardo Caldas       },
404c3c08bfdSEduardo Caldas       NodeKind::NestedNameSpecifier));
405c3c08bfdSEduardo Caldas 
406c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpElementsAndDelimiters(List->getElementsAsNodesAndDelimiters()),
407c3c08bfdSEduardo Caldas             "[('a', '::'), ('b', '::'), ('c', null)]");
408c3c08bfdSEduardo Caldas   EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']");
409c3c08bfdSEduardo Caldas }
410c3c08bfdSEduardo Caldas 
411af582c9bSEduardo Caldas } // namespace
412