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