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