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