xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Syntax/Tree.cpp (revision fcaf7f8644a9988098ac6be2165bce3ea4786e91)
1 //===- Tree.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 //===----------------------------------------------------------------------===//
8 #include "clang/Tooling/Syntax/Tree.h"
9 #include "clang/Basic/TokenKinds.h"
10 #include "clang/Tooling/Syntax/Nodes.h"
11 #include "llvm/ADT/BitVector.h"
12 #include "llvm/Support/raw_ostream.h"
13 #include "llvm/Support/Casting.h"
14 #include <cassert>
15 
16 using namespace clang;
17 
18 namespace {
traverse(const syntax::Node * N,llvm::function_ref<void (const syntax::Node *)> Visit)19 static void traverse(const syntax::Node *N,
20                      llvm::function_ref<void(const syntax::Node *)> Visit) {
21   if (auto *T = dyn_cast<syntax::Tree>(N)) {
22     for (const syntax::Node &C : T->getChildren())
23       traverse(&C, Visit);
24   }
25   Visit(N);
26 }
traverse(syntax::Node * N,llvm::function_ref<void (syntax::Node *)> Visit)27 static void traverse(syntax::Node *N,
28                      llvm::function_ref<void(syntax::Node *)> Visit) {
29   traverse(static_cast<const syntax::Node *>(N), [&](const syntax::Node *N) {
30     Visit(const_cast<syntax::Node *>(N));
31   });
32 }
33 } // namespace
34 
Leaf(syntax::TokenManager::Key K)35 syntax::Leaf::Leaf(syntax::TokenManager::Key K) : Node(NodeKind::Leaf), K(K) {}
36 
Node(NodeKind Kind)37 syntax::Node::Node(NodeKind Kind)
38     : Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr),
39       Kind(static_cast<unsigned>(Kind)), Role(0), Original(false),
40       CanModify(false) {
41   this->setRole(NodeRole::Detached);
42 }
43 
isDetached() const44 bool syntax::Node::isDetached() const {
45   return getRole() == NodeRole::Detached;
46 }
47 
setRole(NodeRole NR)48 void syntax::Node::setRole(NodeRole NR) {
49   this->Role = static_cast<unsigned>(NR);
50 }
51 
appendChildLowLevel(Node * Child,NodeRole Role)52 void syntax::Tree::appendChildLowLevel(Node *Child, NodeRole Role) {
53   assert(Child->getRole() == NodeRole::Detached);
54   assert(Role != NodeRole::Detached);
55 
56   Child->setRole(Role);
57   appendChildLowLevel(Child);
58 }
59 
appendChildLowLevel(Node * Child)60 void syntax::Tree::appendChildLowLevel(Node *Child) {
61   assert(Child->Parent == nullptr);
62   assert(Child->NextSibling == nullptr);
63   assert(Child->PreviousSibling == nullptr);
64   assert(Child->getRole() != NodeRole::Detached);
65 
66   Child->Parent = this;
67   if (this->LastChild) {
68     Child->PreviousSibling = this->LastChild;
69     this->LastChild->NextSibling = Child;
70   } else
71     this->FirstChild = Child;
72 
73   this->LastChild = Child;
74 }
75 
prependChildLowLevel(Node * Child,NodeRole Role)76 void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
77   assert(Child->getRole() == NodeRole::Detached);
78   assert(Role != NodeRole::Detached);
79 
80   Child->setRole(Role);
81   prependChildLowLevel(Child);
82 }
83 
prependChildLowLevel(Node * Child)84 void syntax::Tree::prependChildLowLevel(Node *Child) {
85   assert(Child->Parent == nullptr);
86   assert(Child->NextSibling == nullptr);
87   assert(Child->PreviousSibling == nullptr);
88   assert(Child->getRole() != NodeRole::Detached);
89 
90   Child->Parent = this;
91   if (this->FirstChild) {
92     Child->NextSibling = this->FirstChild;
93     this->FirstChild->PreviousSibling = Child;
94   } else
95     this->LastChild = Child;
96 
97   this->FirstChild = Child;
98 }
99 
replaceChildRangeLowLevel(Node * Begin,Node * End,Node * New)100 void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End,
101                                              Node *New) {
102   assert((!Begin || Begin->Parent == this) &&
103          "`Begin` is not a child of `this`.");
104   assert((!End || End->Parent == this) && "`End` is not a child of `this`.");
105   assert(canModify() && "Cannot modify `this`.");
106 
107 #ifndef NDEBUG
108   for (auto *N = New; N; N = N->NextSibling) {
109     assert(N->Parent == nullptr);
110     assert(N->getRole() != NodeRole::Detached && "Roles must be set");
111     // FIXME: validate the role.
112   }
113 
114   auto Reachable = [](Node *From, Node *N) {
115     if (!N)
116       return true;
117     for (auto *It = From; It; It = It->NextSibling)
118       if (It == N)
119         return true;
120     return false;
121   };
122   assert(Reachable(FirstChild, Begin) && "`Begin` is not reachable.");
123   assert(Reachable(Begin, End) && "`End` is not after `Begin`.");
124 #endif
125 
126   if (!New && Begin == End)
127     return;
128 
129   // Mark modification.
130   for (auto *T = this; T && T->Original; T = T->Parent)
131     T->Original = false;
132 
133   // Save the node before the range to be removed. Later we insert the `New`
134   // range after this node.
135   auto *BeforeBegin = Begin ? Begin->PreviousSibling : LastChild;
136 
137   // Detach old nodes.
138   for (auto *N = Begin; N != End;) {
139     auto *Next = N->NextSibling;
140 
141     N->setRole(NodeRole::Detached);
142     N->Parent = nullptr;
143     N->NextSibling = nullptr;
144     N->PreviousSibling = nullptr;
145     if (N->Original)
146       traverse(N, [](Node *C) { C->Original = false; });
147 
148     N = Next;
149   }
150 
151   // Attach new range.
152   auto *&NewFirst = BeforeBegin ? BeforeBegin->NextSibling : FirstChild;
153   auto *&NewLast = End ? End->PreviousSibling : LastChild;
154 
155   if (!New) {
156     NewFirst = End;
157     NewLast = BeforeBegin;
158     return;
159   }
160 
161   New->PreviousSibling = BeforeBegin;
162   NewFirst = New;
163 
164   Node *LastInNew;
165   for (auto *N = New; N != nullptr; N = N->NextSibling) {
166     LastInNew = N;
167     N->Parent = this;
168   }
169   LastInNew->NextSibling = End;
170   NewLast = LastInNew;
171 }
172 
173 namespace {
dumpNode(raw_ostream & OS,const syntax::Node * N,const syntax::TokenManager & TM,llvm::BitVector IndentMask)174 static void dumpNode(raw_ostream &OS, const syntax::Node *N,
175                      const syntax::TokenManager &TM, llvm::BitVector IndentMask) {
176   auto DumpExtraInfo = [&OS](const syntax::Node *N) {
177     if (N->getRole() != syntax::NodeRole::Unknown)
178       OS << " " << N->getRole();
179     if (!N->isOriginal())
180       OS << " synthesized";
181     if (!N->canModify())
182       OS << " unmodifiable";
183   };
184 
185   assert(N);
186   if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
187     OS << "'";
188     OS << TM.getText(L->getTokenKey());
189     OS << "'";
190     DumpExtraInfo(N);
191     OS << "\n";
192     return;
193   }
194 
195   const auto *T = cast<syntax::Tree>(N);
196   OS << T->getKind();
197   DumpExtraInfo(N);
198   OS << "\n";
199 
200   for (const syntax::Node &It : T->getChildren()) {
201     for (unsigned Idx = 0; Idx < IndentMask.size(); ++Idx) {
202       if (IndentMask[Idx])
203         OS << "| ";
204       else
205         OS << "  ";
206     }
207     if (!It.getNextSibling()) {
208       OS << "`-";
209       IndentMask.push_back(false);
210     } else {
211       OS << "|-";
212       IndentMask.push_back(true);
213     }
214     dumpNode(OS, &It, TM, IndentMask);
215     IndentMask.pop_back();
216   }
217 }
218 } // namespace
219 
dump(const TokenManager & TM) const220 std::string syntax::Node::dump(const TokenManager &TM) const {
221   std::string Str;
222   llvm::raw_string_ostream OS(Str);
223   dumpNode(OS, this, TM, /*IndentMask=*/{});
224   return std::move(OS.str());
225 }
226 
dumpTokens(const TokenManager & TM) const227 std::string syntax::Node::dumpTokens(const TokenManager &TM) const {
228   std::string Storage;
229   llvm::raw_string_ostream OS(Storage);
230   traverse(this, [&](const syntax::Node *N) {
231     if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
232       OS << TM.getText(L->getTokenKey());
233       OS << " ";
234     }
235   });
236   return Storage;
237 }
238 
assertInvariants() const239 void syntax::Node::assertInvariants() const {
240 #ifndef NDEBUG
241   if (isDetached())
242     assert(getParent() == nullptr);
243   else
244     assert(getParent() != nullptr);
245 
246   const auto *T = dyn_cast<Tree>(this);
247   if (!T)
248     return;
249   for (const Node &C : T->getChildren()) {
250     if (T->isOriginal())
251       assert(C.isOriginal());
252     assert(!C.isDetached());
253     assert(C.getParent() == T);
254     const auto *Next = C.getNextSibling();
255     assert(!Next || &C == Next->getPreviousSibling());
256     if (!C.getNextSibling())
257       assert(&C == T->getLastChild() &&
258              "Last child is reachable by advancing from the first child.");
259   }
260 
261   const auto *L = dyn_cast<List>(T);
262   if (!L)
263     return;
264   for (const Node &C : T->getChildren()) {
265     assert(C.getRole() == NodeRole::ListElement ||
266            C.getRole() == NodeRole::ListDelimiter);
267     if (C.getRole() == NodeRole::ListDelimiter) {
268       assert(isa<Leaf>(C));
269       // FIXME: re-enable it when there is way to retrieve token kind in Leaf.
270       // assert(cast<Leaf>(C).getToken()->kind() == L->getDelimiterTokenKind());
271     }
272   }
273 
274 #endif
275 }
276 
assertInvariantsRecursive() const277 void syntax::Node::assertInvariantsRecursive() const {
278 #ifndef NDEBUG
279   traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); });
280 #endif
281 }
282 
findFirstLeaf() const283 const syntax::Leaf *syntax::Tree::findFirstLeaf() const {
284   for (const Node &C : getChildren()) {
285     if (const auto *L = dyn_cast<syntax::Leaf>(&C))
286       return L;
287     if (const auto *L = cast<syntax::Tree>(C).findFirstLeaf())
288       return L;
289   }
290   return nullptr;
291 }
292 
findLastLeaf() const293 const syntax::Leaf *syntax::Tree::findLastLeaf() const {
294   for (const auto *C = getLastChild(); C; C = C->getPreviousSibling()) {
295     if (const auto *L = dyn_cast<syntax::Leaf>(C))
296       return L;
297     if (const auto *L = cast<syntax::Tree>(C)->findLastLeaf())
298       return L;
299   }
300   return nullptr;
301 }
302 
findChild(NodeRole R) const303 const syntax::Node *syntax::Tree::findChild(NodeRole R) const {
304   for (const Node &C : getChildren()) {
305     if (C.getRole() == R)
306       return &C;
307   }
308   return nullptr;
309 }
310 
311 std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>
getElementsAsNodesAndDelimiters()312 syntax::List::getElementsAsNodesAndDelimiters() {
313   if (!getFirstChild())
314     return {};
315 
316   std::vector<syntax::List::ElementAndDelimiter<Node>> Children;
317   syntax::Node *ElementWithoutDelimiter = nullptr;
318   for (Node &C : getChildren()) {
319     switch (C.getRole()) {
320     case syntax::NodeRole::ListElement: {
321       if (ElementWithoutDelimiter) {
322         Children.push_back({ElementWithoutDelimiter, nullptr});
323       }
324       ElementWithoutDelimiter = &C;
325       break;
326     }
327     case syntax::NodeRole::ListDelimiter: {
328       Children.push_back({ElementWithoutDelimiter, cast<syntax::Leaf>(&C)});
329       ElementWithoutDelimiter = nullptr;
330       break;
331     }
332     default:
333       llvm_unreachable(
334           "A list can have only elements and delimiters as children.");
335     }
336   }
337 
338   switch (getTerminationKind()) {
339   case syntax::List::TerminationKind::Separated: {
340     Children.push_back({ElementWithoutDelimiter, nullptr});
341     break;
342   }
343   case syntax::List::TerminationKind::Terminated:
344   case syntax::List::TerminationKind::MaybeTerminated: {
345     if (ElementWithoutDelimiter) {
346       Children.push_back({ElementWithoutDelimiter, nullptr});
347     }
348     break;
349   }
350   }
351 
352   return Children;
353 }
354 
355 // Almost the same implementation of `getElementsAsNodesAndDelimiters` but
356 // ignoring delimiters
getElementsAsNodes()357 std::vector<syntax::Node *> syntax::List::getElementsAsNodes() {
358   if (!getFirstChild())
359     return {};
360 
361   std::vector<syntax::Node *> Children;
362   syntax::Node *ElementWithoutDelimiter = nullptr;
363   for (Node &C : getChildren()) {
364     switch (C.getRole()) {
365     case syntax::NodeRole::ListElement: {
366       if (ElementWithoutDelimiter) {
367         Children.push_back(ElementWithoutDelimiter);
368       }
369       ElementWithoutDelimiter = &C;
370       break;
371     }
372     case syntax::NodeRole::ListDelimiter: {
373       Children.push_back(ElementWithoutDelimiter);
374       ElementWithoutDelimiter = nullptr;
375       break;
376     }
377     default:
378       llvm_unreachable("A list has only elements or delimiters.");
379     }
380   }
381 
382   switch (getTerminationKind()) {
383   case syntax::List::TerminationKind::Separated: {
384     Children.push_back(ElementWithoutDelimiter);
385     break;
386   }
387   case syntax::List::TerminationKind::Terminated:
388   case syntax::List::TerminationKind::MaybeTerminated: {
389     if (ElementWithoutDelimiter) {
390       Children.push_back(ElementWithoutDelimiter);
391     }
392     break;
393   }
394   }
395 
396   return Children;
397 }
398 
getDelimiterTokenKind() const399 clang::tok::TokenKind syntax::List::getDelimiterTokenKind() const {
400   switch (this->getKind()) {
401   case NodeKind::NestedNameSpecifier:
402     return clang::tok::coloncolon;
403   case NodeKind::CallArguments:
404   case NodeKind::ParameterDeclarationList:
405   case NodeKind::DeclaratorList:
406     return clang::tok::comma;
407   default:
408     llvm_unreachable("This is not a subclass of List, thus "
409                      "getDelimiterTokenKind() cannot be called");
410   }
411 }
412 
getTerminationKind() const413 syntax::List::TerminationKind syntax::List::getTerminationKind() const {
414   switch (this->getKind()) {
415   case NodeKind::NestedNameSpecifier:
416     return TerminationKind::Terminated;
417   case NodeKind::CallArguments:
418   case NodeKind::ParameterDeclarationList:
419   case NodeKind::DeclaratorList:
420     return TerminationKind::Separated;
421   default:
422     llvm_unreachable("This is not a subclass of List, thus "
423                      "getTerminationKind() cannot be called");
424   }
425 }
426 
canBeEmpty() const427 bool syntax::List::canBeEmpty() const {
428   switch (this->getKind()) {
429   case NodeKind::NestedNameSpecifier:
430     return false;
431   case NodeKind::CallArguments:
432     return true;
433   case NodeKind::ParameterDeclarationList:
434     return true;
435   case NodeKind::DeclaratorList:
436     return true;
437   default:
438     llvm_unreachable("This is not a subclass of List, thus canBeEmpty() "
439                      "cannot be called");
440   }
441 }
442