xref: /llvm-project/clang/lib/Tooling/Syntax/Tree.cpp (revision 5b8337cf402b224c5ed310dc570aa471dcdbd116)
19b3f38f9SIlya Biryukov //===- Tree.cpp -----------------------------------------------*- C++ -*-=====//
29b3f38f9SIlya Biryukov //
39b3f38f9SIlya Biryukov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49b3f38f9SIlya Biryukov // See https://llvm.org/LICENSE.txt for license information.
59b3f38f9SIlya Biryukov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69b3f38f9SIlya Biryukov //
79b3f38f9SIlya Biryukov //===----------------------------------------------------------------------===//
89b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Tree.h"
99b3f38f9SIlya Biryukov #include "clang/Basic/TokenKinds.h"
109b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Nodes.h"
11600c6714SJan Svoboda #include "llvm/ADT/BitVector.h"
12*5b8337cfSHaojian Wu #include "llvm/Support/raw_ostream.h"
139b3f38f9SIlya Biryukov #include "llvm/Support/Casting.h"
143b929fe7SIlya Biryukov #include <cassert>
159b3f38f9SIlya Biryukov 
169b3f38f9SIlya Biryukov using namespace clang;
179b3f38f9SIlya Biryukov 
18013c07f6SIlya Biryukov namespace {
traverse(const syntax::Node * N,llvm::function_ref<void (const syntax::Node *)> Visit)19013c07f6SIlya Biryukov static void traverse(const syntax::Node *N,
20013c07f6SIlya Biryukov                      llvm::function_ref<void(const syntax::Node *)> Visit) {
21013c07f6SIlya Biryukov   if (auto *T = dyn_cast<syntax::Tree>(N)) {
22d4934eb5SSam McCall     for (const syntax::Node &C : T->getChildren())
23d4934eb5SSam McCall       traverse(&C, Visit);
24013c07f6SIlya Biryukov   }
25013c07f6SIlya Biryukov   Visit(N);
26013c07f6SIlya Biryukov }
traverse(syntax::Node * N,llvm::function_ref<void (syntax::Node *)> Visit)27013c07f6SIlya Biryukov static void traverse(syntax::Node *N,
28013c07f6SIlya Biryukov                      llvm::function_ref<void(syntax::Node *)> Visit) {
29013c07f6SIlya Biryukov   traverse(static_cast<const syntax::Node *>(N), [&](const syntax::Node *N) {
30013c07f6SIlya Biryukov     Visit(const_cast<syntax::Node *>(N));
31013c07f6SIlya Biryukov   });
32a3490e3eSMichael Liao }
33013c07f6SIlya Biryukov } // namespace
34013c07f6SIlya Biryukov 
Leaf(syntax::TokenManager::Key K)35263dcf45SHaojian Wu syntax::Leaf::Leaf(syntax::TokenManager::Key K) : Node(NodeKind::Leaf), K(K) {}
369b3f38f9SIlya Biryukov 
Node(NodeKind Kind)3751dad419SIlya Biryukov syntax::Node::Node(NodeKind Kind)
3823657d9cSEduardo Caldas     : Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr),
3923657d9cSEduardo Caldas       Kind(static_cast<unsigned>(Kind)), Role(0), Original(false),
4023657d9cSEduardo Caldas       CanModify(false) {
41a711a3a4SMarcel Hlopko   this->setRole(NodeRole::Detached);
42a711a3a4SMarcel Hlopko }
431ad15046SIlya Biryukov 
isDetached() const444c14ee61SEduardo Caldas bool syntax::Node::isDetached() const {
454c14ee61SEduardo Caldas   return getRole() == NodeRole::Detached;
464c14ee61SEduardo Caldas }
4751dad419SIlya Biryukov 
setRole(NodeRole NR)48a711a3a4SMarcel Hlopko void syntax::Node::setRole(NodeRole NR) {
49a711a3a4SMarcel Hlopko   this->Role = static_cast<unsigned>(NR);
50a711a3a4SMarcel Hlopko }
51a711a3a4SMarcel Hlopko 
appendChildLowLevel(Node * Child,NodeRole Role)5223657d9cSEduardo Caldas void syntax::Tree::appendChildLowLevel(Node *Child, NodeRole Role) {
5323657d9cSEduardo Caldas   assert(Child->getRole() == NodeRole::Detached);
5423657d9cSEduardo Caldas   assert(Role != NodeRole::Detached);
5523657d9cSEduardo Caldas 
5623657d9cSEduardo Caldas   Child->setRole(Role);
5723657d9cSEduardo Caldas   appendChildLowLevel(Child);
5823657d9cSEduardo Caldas }
5923657d9cSEduardo Caldas 
appendChildLowLevel(Node * Child)6023657d9cSEduardo Caldas void syntax::Tree::appendChildLowLevel(Node *Child) {
6123657d9cSEduardo Caldas   assert(Child->Parent == nullptr);
6223657d9cSEduardo Caldas   assert(Child->NextSibling == nullptr);
6323657d9cSEduardo Caldas   assert(Child->PreviousSibling == nullptr);
6423657d9cSEduardo Caldas   assert(Child->getRole() != NodeRole::Detached);
6523657d9cSEduardo Caldas 
6623657d9cSEduardo Caldas   Child->Parent = this;
6723657d9cSEduardo Caldas   if (this->LastChild) {
6823657d9cSEduardo Caldas     Child->PreviousSibling = this->LastChild;
6923657d9cSEduardo Caldas     this->LastChild->NextSibling = Child;
7023657d9cSEduardo Caldas   } else
7123657d9cSEduardo Caldas     this->FirstChild = Child;
7223657d9cSEduardo Caldas 
7323657d9cSEduardo Caldas   this->LastChild = Child;
7423657d9cSEduardo Caldas }
7523657d9cSEduardo Caldas 
prependChildLowLevel(Node * Child,NodeRole Role)769b3f38f9SIlya Biryukov void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
774c14ee61SEduardo Caldas   assert(Child->getRole() == NodeRole::Detached);
7851dad419SIlya Biryukov   assert(Role != NodeRole::Detached);
799b3f38f9SIlya Biryukov 
80a711a3a4SMarcel Hlopko   Child->setRole(Role);
81a711a3a4SMarcel Hlopko   prependChildLowLevel(Child);
82a711a3a4SMarcel Hlopko }
83a711a3a4SMarcel Hlopko 
prependChildLowLevel(Node * Child)84a711a3a4SMarcel Hlopko void syntax::Tree::prependChildLowLevel(Node *Child) {
85a711a3a4SMarcel Hlopko   assert(Child->Parent == nullptr);
86a711a3a4SMarcel Hlopko   assert(Child->NextSibling == nullptr);
8723657d9cSEduardo Caldas   assert(Child->PreviousSibling == nullptr);
884c14ee61SEduardo Caldas   assert(Child->getRole() != NodeRole::Detached);
89a711a3a4SMarcel Hlopko 
909b3f38f9SIlya Biryukov   Child->Parent = this;
9123657d9cSEduardo Caldas   if (this->FirstChild) {
929b3f38f9SIlya Biryukov     Child->NextSibling = this->FirstChild;
9323657d9cSEduardo Caldas     this->FirstChild->PreviousSibling = Child;
9423657d9cSEduardo Caldas   } else
9523657d9cSEduardo Caldas     this->LastChild = Child;
9623657d9cSEduardo Caldas 
979b3f38f9SIlya Biryukov   this->FirstChild = Child;
989b3f38f9SIlya Biryukov }
999b3f38f9SIlya Biryukov 
replaceChildRangeLowLevel(Node * Begin,Node * End,Node * New)10023657d9cSEduardo Caldas void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End,
1011ad15046SIlya Biryukov                                              Node *New) {
10223657d9cSEduardo Caldas   assert((!Begin || Begin->Parent == this) &&
10323657d9cSEduardo Caldas          "`Begin` is not a child of `this`.");
1044178f8f2SEduardo Caldas   assert((!End || End->Parent == this) && "`End` is not a child of `this`.");
1054178f8f2SEduardo Caldas   assert(canModify() && "Cannot modify `this`.");
1061ad15046SIlya Biryukov 
1071ad15046SIlya Biryukov #ifndef NDEBUG
1084178f8f2SEduardo Caldas   for (auto *N = New; N; N = N->NextSibling) {
1091ad15046SIlya Biryukov     assert(N->Parent == nullptr);
1104c14ee61SEduardo Caldas     assert(N->getRole() != NodeRole::Detached && "Roles must be set");
111d8e5a0c4SZarko Todorovski     // FIXME: validate the role.
1121ad15046SIlya Biryukov   }
1134178f8f2SEduardo Caldas 
1144178f8f2SEduardo Caldas   auto Reachable = [](Node *From, Node *N) {
1154178f8f2SEduardo Caldas     if (!N)
1164178f8f2SEduardo Caldas       return true;
1174178f8f2SEduardo Caldas     for (auto *It = From; It; It = It->NextSibling)
1184178f8f2SEduardo Caldas       if (It == N)
1194178f8f2SEduardo Caldas         return true;
1204178f8f2SEduardo Caldas     return false;
1214178f8f2SEduardo Caldas   };
12223657d9cSEduardo Caldas   assert(Reachable(FirstChild, Begin) && "`Begin` is not reachable.");
12323657d9cSEduardo Caldas   assert(Reachable(Begin, End) && "`End` is not after `Begin`.");
1241ad15046SIlya Biryukov #endif
1254178f8f2SEduardo Caldas 
1264178f8f2SEduardo Caldas   if (!New && Begin == End)
1274178f8f2SEduardo Caldas     return;
1284178f8f2SEduardo Caldas 
1294178f8f2SEduardo Caldas   // Mark modification.
1304178f8f2SEduardo Caldas   for (auto *T = this; T && T->Original; T = T->Parent)
1314178f8f2SEduardo Caldas     T->Original = false;
1321ad15046SIlya Biryukov 
13323657d9cSEduardo Caldas   // Save the node before the range to be removed. Later we insert the `New`
13423657d9cSEduardo Caldas   // range after this node.
13523657d9cSEduardo Caldas   auto *BeforeBegin = Begin ? Begin->PreviousSibling : LastChild;
13623657d9cSEduardo Caldas 
1371ad15046SIlya Biryukov   // Detach old nodes.
1384178f8f2SEduardo Caldas   for (auto *N = Begin; N != End;) {
1391ad15046SIlya Biryukov     auto *Next = N->NextSibling;
1401ad15046SIlya Biryukov 
141a711a3a4SMarcel Hlopko     N->setRole(NodeRole::Detached);
1421ad15046SIlya Biryukov     N->Parent = nullptr;
1431ad15046SIlya Biryukov     N->NextSibling = nullptr;
14423657d9cSEduardo Caldas     N->PreviousSibling = nullptr;
145013c07f6SIlya Biryukov     if (N->Original)
1464178f8f2SEduardo Caldas       traverse(N, [](Node *C) { C->Original = false; });
1471ad15046SIlya Biryukov 
1481ad15046SIlya Biryukov     N = Next;
1491ad15046SIlya Biryukov   }
1501ad15046SIlya Biryukov 
15123657d9cSEduardo Caldas   // Attach new range.
15223657d9cSEduardo Caldas   auto *&NewFirst = BeforeBegin ? BeforeBegin->NextSibling : FirstChild;
15323657d9cSEduardo Caldas   auto *&NewLast = End ? End->PreviousSibling : LastChild;
15423657d9cSEduardo Caldas 
1554178f8f2SEduardo Caldas   if (!New) {
15623657d9cSEduardo Caldas     NewFirst = End;
15723657d9cSEduardo Caldas     NewLast = BeforeBegin;
1584178f8f2SEduardo Caldas     return;
1594178f8f2SEduardo Caldas   }
16023657d9cSEduardo Caldas 
16123657d9cSEduardo Caldas   New->PreviousSibling = BeforeBegin;
16223657d9cSEduardo Caldas   NewFirst = New;
16323657d9cSEduardo Caldas 
16423657d9cSEduardo Caldas   Node *LastInNew;
1654178f8f2SEduardo Caldas   for (auto *N = New; N != nullptr; N = N->NextSibling) {
16623657d9cSEduardo Caldas     LastInNew = N;
1673b929fe7SIlya Biryukov     N->Parent = this;
1683b929fe7SIlya Biryukov   }
16923657d9cSEduardo Caldas   LastInNew->NextSibling = End;
17023657d9cSEduardo Caldas   NewLast = LastInNew;
1711ad15046SIlya Biryukov }
1721ad15046SIlya Biryukov 
1739b3f38f9SIlya Biryukov namespace {
dumpNode(raw_ostream & OS,const syntax::Node * N,const syntax::TokenManager & TM,llvm::BitVector IndentMask)174c655d808SEduardo Caldas static void dumpNode(raw_ostream &OS, const syntax::Node *N,
175263dcf45SHaojian Wu                      const syntax::TokenManager &TM, llvm::BitVector IndentMask) {
17687f0b51dSEduardo Caldas   auto DumpExtraInfo = [&OS](const syntax::Node *N) {
1774c14ee61SEduardo Caldas     if (N->getRole() != syntax::NodeRole::Unknown)
1784c14ee61SEduardo Caldas       OS << " " << N->getRole();
1791ad15046SIlya Biryukov     if (!N->isOriginal())
180c655d808SEduardo Caldas       OS << " synthesized";
1811ad15046SIlya Biryukov     if (!N->canModify())
182c655d808SEduardo Caldas       OS << " unmodifiable";
183c655d808SEduardo Caldas   };
18458fa50f4SIlya Biryukov 
185c655d808SEduardo Caldas   assert(N);
186c655d808SEduardo Caldas   if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
187c655d808SEduardo Caldas     OS << "'";
188263dcf45SHaojian Wu     OS << TM.getText(L->getTokenKey());
189c655d808SEduardo Caldas     OS << "'";
19087f0b51dSEduardo Caldas     DumpExtraInfo(N);
1919b3f38f9SIlya Biryukov     OS << "\n";
1929b3f38f9SIlya Biryukov     return;
1939b3f38f9SIlya Biryukov   }
1949b3f38f9SIlya Biryukov 
195c655d808SEduardo Caldas   const auto *T = cast<syntax::Tree>(N);
1964c14ee61SEduardo Caldas   OS << T->getKind();
19787f0b51dSEduardo Caldas   DumpExtraInfo(N);
198c655d808SEduardo Caldas   OS << "\n";
1999b3f38f9SIlya Biryukov 
200d4934eb5SSam McCall   for (const syntax::Node &It : T->getChildren()) {
201600c6714SJan Svoboda     for (unsigned Idx = 0; Idx < IndentMask.size(); ++Idx) {
202600c6714SJan Svoboda       if (IndentMask[Idx])
2039b3f38f9SIlya Biryukov         OS << "| ";
2049b3f38f9SIlya Biryukov       else
2059b3f38f9SIlya Biryukov         OS << "  ";
2069b3f38f9SIlya Biryukov     }
207d4934eb5SSam McCall     if (!It.getNextSibling()) {
2089b3f38f9SIlya Biryukov       OS << "`-";
2099b3f38f9SIlya Biryukov       IndentMask.push_back(false);
2109b3f38f9SIlya Biryukov     } else {
2119b3f38f9SIlya Biryukov       OS << "|-";
2129b3f38f9SIlya Biryukov       IndentMask.push_back(true);
2139b3f38f9SIlya Biryukov     }
214263dcf45SHaojian Wu     dumpNode(OS, &It, TM, IndentMask);
2159b3f38f9SIlya Biryukov     IndentMask.pop_back();
2169b3f38f9SIlya Biryukov   }
2179b3f38f9SIlya Biryukov }
2189b3f38f9SIlya Biryukov } // namespace
2199b3f38f9SIlya Biryukov 
dump(const TokenManager & TM) const220263dcf45SHaojian Wu std::string syntax::Node::dump(const TokenManager &TM) const {
2219b3f38f9SIlya Biryukov   std::string Str;
2229b3f38f9SIlya Biryukov   llvm::raw_string_ostream OS(Str);
223263dcf45SHaojian Wu   dumpNode(OS, this, TM, /*IndentMask=*/{});
2249b3f38f9SIlya Biryukov   return std::move(OS.str());
2259b3f38f9SIlya Biryukov }
2269b3f38f9SIlya Biryukov 
dumpTokens(const TokenManager & TM) const227263dcf45SHaojian Wu std::string syntax::Node::dumpTokens(const TokenManager &TM) const {
2289b3f38f9SIlya Biryukov   std::string Storage;
2299b3f38f9SIlya Biryukov   llvm::raw_string_ostream OS(Storage);
2309b3f38f9SIlya Biryukov   traverse(this, [&](const syntax::Node *N) {
231c655d808SEduardo Caldas     if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
232263dcf45SHaojian Wu       OS << TM.getText(L->getTokenKey());
2331ad15046SIlya Biryukov       OS << " ";
234c655d808SEduardo Caldas     }
2359b3f38f9SIlya Biryukov   });
2365336befeSLogan Smith   return Storage;
2379b3f38f9SIlya Biryukov }
2389b3f38f9SIlya Biryukov 
assertInvariants() const2393b929fe7SIlya Biryukov void syntax::Node::assertInvariants() const {
2403b929fe7SIlya Biryukov #ifndef NDEBUG
2413b929fe7SIlya Biryukov   if (isDetached())
2424c14ee61SEduardo Caldas     assert(getParent() == nullptr);
2433b929fe7SIlya Biryukov   else
2444c14ee61SEduardo Caldas     assert(getParent() != nullptr);
2453b929fe7SIlya Biryukov 
246ceb01285SEduardo Caldas   const auto *T = dyn_cast<Tree>(this);
2473b929fe7SIlya Biryukov   if (!T)
2483b929fe7SIlya Biryukov     return;
249d4934eb5SSam McCall   for (const Node &C : T->getChildren()) {
2503b929fe7SIlya Biryukov     if (T->isOriginal())
251d4934eb5SSam McCall       assert(C.isOriginal());
252d4934eb5SSam McCall     assert(!C.isDetached());
253d4934eb5SSam McCall     assert(C.getParent() == T);
25423657d9cSEduardo Caldas     const auto *Next = C.getNextSibling();
25523657d9cSEduardo Caldas     assert(!Next || &C == Next->getPreviousSibling());
25623657d9cSEduardo Caldas     if (!C.getNextSibling())
25723657d9cSEduardo Caldas       assert(&C == T->getLastChild() &&
25823657d9cSEduardo Caldas              "Last child is reachable by advancing from the first child.");
2593b929fe7SIlya Biryukov   }
260ceb01285SEduardo Caldas 
261ceb01285SEduardo Caldas   const auto *L = dyn_cast<List>(T);
262ceb01285SEduardo Caldas   if (!L)
263ceb01285SEduardo Caldas     return;
264d4934eb5SSam McCall   for (const Node &C : T->getChildren()) {
265d4934eb5SSam McCall     assert(C.getRole() == NodeRole::ListElement ||
266d4934eb5SSam McCall            C.getRole() == NodeRole::ListDelimiter);
267d4934eb5SSam McCall     if (C.getRole() == NodeRole::ListDelimiter) {
268ceb01285SEduardo Caldas       assert(isa<Leaf>(C));
269263dcf45SHaojian Wu       // FIXME: re-enable it when there is way to retrieve token kind in Leaf.
270263dcf45SHaojian Wu       // assert(cast<Leaf>(C).getToken()->kind() == L->getDelimiterTokenKind());
271ceb01285SEduardo Caldas     }
272ceb01285SEduardo Caldas   }
273ceb01285SEduardo Caldas 
2743b929fe7SIlya Biryukov #endif
2753b929fe7SIlya Biryukov }
2763b929fe7SIlya Biryukov 
assertInvariantsRecursive() const2773b929fe7SIlya Biryukov void syntax::Node::assertInvariantsRecursive() const {
2783b929fe7SIlya Biryukov #ifndef NDEBUG
2793b929fe7SIlya Biryukov   traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); });
2803b929fe7SIlya Biryukov #endif
2813b929fe7SIlya Biryukov }
2823b929fe7SIlya Biryukov 
findFirstLeaf() const2835ad6bbacSKirill Bobyrev const syntax::Leaf *syntax::Tree::findFirstLeaf() const {
284d4934eb5SSam McCall   for (const Node &C : getChildren()) {
285d4934eb5SSam McCall     if (const auto *L = dyn_cast<syntax::Leaf>(&C))
2861ad15046SIlya Biryukov       return L;
287d4934eb5SSam McCall     if (const auto *L = cast<syntax::Tree>(C).findFirstLeaf())
288af582c9bSEduardo Caldas       return L;
2891ad15046SIlya Biryukov   }
2901ad15046SIlya Biryukov   return nullptr;
2911ad15046SIlya Biryukov }
2921ad15046SIlya Biryukov 
findLastLeaf() const2935ad6bbacSKirill Bobyrev const syntax::Leaf *syntax::Tree::findLastLeaf() const {
29423657d9cSEduardo Caldas   for (const auto *C = getLastChild(); C; C = C->getPreviousSibling()) {
29523657d9cSEduardo Caldas     if (const auto *L = dyn_cast<syntax::Leaf>(C))
29623657d9cSEduardo Caldas       return L;
29723657d9cSEduardo Caldas     if (const auto *L = cast<syntax::Tree>(C)->findLastLeaf())
29823657d9cSEduardo Caldas       return L;
2991ad15046SIlya Biryukov   }
30023657d9cSEduardo Caldas   return nullptr;
3011ad15046SIlya Biryukov }
3021ad15046SIlya Biryukov 
findChild(NodeRole R) const3035ad6bbacSKirill Bobyrev const syntax::Node *syntax::Tree::findChild(NodeRole R) const {
304d4934eb5SSam McCall   for (const Node &C : getChildren()) {
305d4934eb5SSam McCall     if (C.getRole() == R)
306d4934eb5SSam McCall       return &C;
3079b3f38f9SIlya Biryukov   }
3089b3f38f9SIlya Biryukov   return nullptr;
3099b3f38f9SIlya Biryukov }
310a90c78acSEduardo Caldas 
311a90c78acSEduardo Caldas std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>
getElementsAsNodesAndDelimiters()312a90c78acSEduardo Caldas syntax::List::getElementsAsNodesAndDelimiters() {
3134c14ee61SEduardo Caldas   if (!getFirstChild())
314a90c78acSEduardo Caldas     return {};
315a90c78acSEduardo Caldas 
31687f0b51dSEduardo Caldas   std::vector<syntax::List::ElementAndDelimiter<Node>> Children;
31787f0b51dSEduardo Caldas   syntax::Node *ElementWithoutDelimiter = nullptr;
318d4934eb5SSam McCall   for (Node &C : getChildren()) {
319d4934eb5SSam McCall     switch (C.getRole()) {
320718e550cSEduardo Caldas     case syntax::NodeRole::ListElement: {
32187f0b51dSEduardo Caldas       if (ElementWithoutDelimiter) {
32287f0b51dSEduardo Caldas         Children.push_back({ElementWithoutDelimiter, nullptr});
323a90c78acSEduardo Caldas       }
324d4934eb5SSam McCall       ElementWithoutDelimiter = &C;
325a90c78acSEduardo Caldas       break;
326a90c78acSEduardo Caldas     }
327718e550cSEduardo Caldas     case syntax::NodeRole::ListDelimiter: {
328d4934eb5SSam McCall       Children.push_back({ElementWithoutDelimiter, cast<syntax::Leaf>(&C)});
32987f0b51dSEduardo Caldas       ElementWithoutDelimiter = nullptr;
330a90c78acSEduardo Caldas       break;
331a90c78acSEduardo Caldas     }
332a90c78acSEduardo Caldas     default:
333a90c78acSEduardo Caldas       llvm_unreachable(
334a90c78acSEduardo Caldas           "A list can have only elements and delimiters as children.");
335a90c78acSEduardo Caldas     }
336a90c78acSEduardo Caldas   }
337a90c78acSEduardo Caldas 
338a90c78acSEduardo Caldas   switch (getTerminationKind()) {
339a90c78acSEduardo Caldas   case syntax::List::TerminationKind::Separated: {
34087f0b51dSEduardo Caldas     Children.push_back({ElementWithoutDelimiter, nullptr});
341a90c78acSEduardo Caldas     break;
342a90c78acSEduardo Caldas   }
343a90c78acSEduardo Caldas   case syntax::List::TerminationKind::Terminated:
344a90c78acSEduardo Caldas   case syntax::List::TerminationKind::MaybeTerminated: {
34587f0b51dSEduardo Caldas     if (ElementWithoutDelimiter) {
34687f0b51dSEduardo Caldas       Children.push_back({ElementWithoutDelimiter, nullptr});
347a90c78acSEduardo Caldas     }
348a90c78acSEduardo Caldas     break;
349a90c78acSEduardo Caldas   }
350a90c78acSEduardo Caldas   }
351a90c78acSEduardo Caldas 
35287f0b51dSEduardo Caldas   return Children;
353a90c78acSEduardo Caldas }
354a90c78acSEduardo Caldas 
355a90c78acSEduardo Caldas // Almost the same implementation of `getElementsAsNodesAndDelimiters` but
356a90c78acSEduardo Caldas // ignoring delimiters
getElementsAsNodes()357a90c78acSEduardo Caldas std::vector<syntax::Node *> syntax::List::getElementsAsNodes() {
3584c14ee61SEduardo Caldas   if (!getFirstChild())
359a90c78acSEduardo Caldas     return {};
360a90c78acSEduardo Caldas 
36187f0b51dSEduardo Caldas   std::vector<syntax::Node *> Children;
36287f0b51dSEduardo Caldas   syntax::Node *ElementWithoutDelimiter = nullptr;
363d4934eb5SSam McCall   for (Node &C : getChildren()) {
364d4934eb5SSam McCall     switch (C.getRole()) {
365718e550cSEduardo Caldas     case syntax::NodeRole::ListElement: {
36687f0b51dSEduardo Caldas       if (ElementWithoutDelimiter) {
36787f0b51dSEduardo Caldas         Children.push_back(ElementWithoutDelimiter);
368a90c78acSEduardo Caldas       }
369d4934eb5SSam McCall       ElementWithoutDelimiter = &C;
370a90c78acSEduardo Caldas       break;
371a90c78acSEduardo Caldas     }
372718e550cSEduardo Caldas     case syntax::NodeRole::ListDelimiter: {
37387f0b51dSEduardo Caldas       Children.push_back(ElementWithoutDelimiter);
37487f0b51dSEduardo Caldas       ElementWithoutDelimiter = nullptr;
375a90c78acSEduardo Caldas       break;
376a90c78acSEduardo Caldas     }
377a90c78acSEduardo Caldas     default:
378a90c78acSEduardo Caldas       llvm_unreachable("A list has only elements or delimiters.");
379a90c78acSEduardo Caldas     }
380a90c78acSEduardo Caldas   }
381a90c78acSEduardo Caldas 
382a90c78acSEduardo Caldas   switch (getTerminationKind()) {
383a90c78acSEduardo Caldas   case syntax::List::TerminationKind::Separated: {
38487f0b51dSEduardo Caldas     Children.push_back(ElementWithoutDelimiter);
385a90c78acSEduardo Caldas     break;
386a90c78acSEduardo Caldas   }
387a90c78acSEduardo Caldas   case syntax::List::TerminationKind::Terminated:
388a90c78acSEduardo Caldas   case syntax::List::TerminationKind::MaybeTerminated: {
38987f0b51dSEduardo Caldas     if (ElementWithoutDelimiter) {
39087f0b51dSEduardo Caldas       Children.push_back(ElementWithoutDelimiter);
391a90c78acSEduardo Caldas     }
392a90c78acSEduardo Caldas     break;
393a90c78acSEduardo Caldas   }
394a90c78acSEduardo Caldas   }
395a90c78acSEduardo Caldas 
39687f0b51dSEduardo Caldas   return Children;
397a90c78acSEduardo Caldas }
398a90c78acSEduardo Caldas 
getDelimiterTokenKind() const399ceb01285SEduardo Caldas clang::tok::TokenKind syntax::List::getDelimiterTokenKind() const {
4004c14ee61SEduardo Caldas   switch (this->getKind()) {
401fdbd5996SEduardo Caldas   case NodeKind::NestedNameSpecifier:
402fdbd5996SEduardo Caldas     return clang::tok::coloncolon;
403dc3d4743SEduardo Caldas   case NodeKind::CallArguments:
40412232dc1SEduardo Caldas   case NodeKind::ParameterDeclarationList:
405dd6f7ee0SSam McCall   case NodeKind::DeclaratorList:
406dc3d4743SEduardo Caldas     return clang::tok::comma;
407fdbd5996SEduardo Caldas   default:
408fdbd5996SEduardo Caldas     llvm_unreachable("This is not a subclass of List, thus "
409a90c78acSEduardo Caldas                      "getDelimiterTokenKind() cannot be called");
410a90c78acSEduardo Caldas   }
411fdbd5996SEduardo Caldas }
412a90c78acSEduardo Caldas 
getTerminationKind() const413ceb01285SEduardo Caldas syntax::List::TerminationKind syntax::List::getTerminationKind() const {
4144c14ee61SEduardo Caldas   switch (this->getKind()) {
415fdbd5996SEduardo Caldas   case NodeKind::NestedNameSpecifier:
416fdbd5996SEduardo Caldas     return TerminationKind::Terminated;
417dc3d4743SEduardo Caldas   case NodeKind::CallArguments:
41812232dc1SEduardo Caldas   case NodeKind::ParameterDeclarationList:
419dd6f7ee0SSam McCall   case NodeKind::DeclaratorList:
420dc3d4743SEduardo Caldas     return TerminationKind::Separated;
421fdbd5996SEduardo Caldas   default:
422fdbd5996SEduardo Caldas     llvm_unreachable("This is not a subclass of List, thus "
423fdbd5996SEduardo Caldas                      "getTerminationKind() cannot be called");
424fdbd5996SEduardo Caldas   }
425a90c78acSEduardo Caldas }
426a90c78acSEduardo Caldas 
canBeEmpty() const427ceb01285SEduardo Caldas bool syntax::List::canBeEmpty() const {
4284c14ee61SEduardo Caldas   switch (this->getKind()) {
429fdbd5996SEduardo Caldas   case NodeKind::NestedNameSpecifier:
430fdbd5996SEduardo Caldas     return false;
431dc3d4743SEduardo Caldas   case NodeKind::CallArguments:
432dc3d4743SEduardo Caldas     return true;
43312232dc1SEduardo Caldas   case NodeKind::ParameterDeclarationList:
434dc3d4743SEduardo Caldas     return true;
435dd6f7ee0SSam McCall   case NodeKind::DeclaratorList:
436dd6f7ee0SSam McCall     return true;
437fdbd5996SEduardo Caldas   default:
438fdbd5996SEduardo Caldas     llvm_unreachable("This is not a subclass of List, thus canBeEmpty() "
439fdbd5996SEduardo Caldas                      "cannot be called");
440fdbd5996SEduardo Caldas   }
441a90c78acSEduardo Caldas }
442