clang: lib/Tooling/Syntax/Tree.cpp Source File (original) (raw)
1
2
3
4
5
6
7
11#include "llvm/ADT/BitVector.h"
12#include "llvm/Support/raw_ostream.h"
13#include "llvm/Support/Casting.h"
14#include
15
16using namespace clang;
17
18namespace {
20 llvm::function_ref<void(const syntax::Node *)> Visit) {
21 if (auto *T = dyn_castsyntax::Tree(N)) {
24 }
25 Visit(N);
26}
28 llvm::function_ref<void(syntax::Node *)> Visit) {
31 });
32}
33}
34
36
38 : Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr),
39 Kind(static_cast<unsigned>(Kind)), Role(0), Original(false),
40 CanModify(false) {
42}
43
46}
47
48void syntax::Node::setRole(NodeRole NR) {
49 this->Role = static_cast<unsigned>(NR);
50}
51
52void syntax::Tree::appendChildLowLevel(Node *Child, NodeRole Role) {
55
56 Child->setRole(Role);
57 appendChildLowLevel(Child);
59
60void syntax::Tree::appendChildLowLevel(Node *Child) {
61 assert(Child->Parent == nullptr);
62 assert(Child->NextSibling == nullptr);
63 assert(Child->PreviousSibling == nullptr);
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
76void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
79
80 Child->setRole(Role);
81 prependChildLowLevel(Child);
82}
83
84void syntax::Tree::prependChildLowLevel(Node *Child) {
85 assert(Child->Parent == nullptr);
86 assert(Child->NextSibling == nullptr);
87 assert(Child->PreviousSibling == nullptr);
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
100void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End,
101 Node *New) {
102 assert(( || 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);
111
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
130 for (auto *T = this; T && T->Original; T = T->Parent)
131 T->Original = false;
132
133
134
135 auto *BeforeBegin = Begin ? Begin->PreviousSibling : LastChild;
136
137
138 for (auto *N = Begin; N != End;) {
139 auto *Next = N->NextSibling;
140
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
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
173namespace {
174static void dumpNode(raw_ostream &OS, const syntax::Node *N,
176 auto DumpExtraInfo = [&OS](const syntax::Node *N) {
178 OS << " " << N->getRole();
180 OS << " synthesized";
182 OS << " unmodifiable";
183 };
184
185 assert(N);
186 if (const auto *L = dyn_castsyntax::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 = castsyntax::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}
219
221 std::string Str;
222 llvm::raw_string_ostream OS(Str);
223 dumpNode(OS, this, TM, {});
224 return std::move(OS.str());
225}
226
228 std::string Storage;
229 llvm::raw_string_ostream OS(Storage);
231 if (const auto *L = dyn_castsyntax::Leaf(N)) {
232 OS << TM.getText(L->getTokenKey());
233 OS << " ";
234 }
235 });
236 return Storage;
237}
238
240#ifndef NDEBUG
241 if (isDetached())
242 assert(getParent() == nullptr);
243 else
244 assert(getParent() != nullptr);
245
246 const auto *T = dyn_cast(this);
247 if ()
248 return;
249 for (const Node &C : T->getChildren()) {
250 if (T->isOriginal())
251 assert(C.isOriginal());
252 assert(.isDetached());
253 assert(C.getParent() == T);
254 const auto *Next = C.getNextSibling();
255 assert(!Next || &C == Next->getPreviousSibling());
256 if (.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(T);
262 if (!L)
263 return;
264 for (const Node &C : T->getChildren()) {
268 assert(isa(C));
269
270
271 }
272 }
273
274#endif
275}
276
278#ifndef NDEBUG
280#endif
281}
282
284 for (const Node &C : getChildren()) {
285 if (const auto *L = dyn_castsyntax::Leaf(&C))
286 return L;
287 if (const auto *L = castsyntax::Tree(C).findFirstLeaf())
288 return L;
289 }
290 return nullptr;
291}
292
294 for (const auto *C = getLastChild(); C; C = C->getPreviousSibling()) {
295 if (const auto *L = dyn_castsyntax::Leaf(C))
296 return L;
297 if (const auto *L = castsyntax::Tree(C)->findLastLeaf())
298 return L;
299 }
300 return nullptr;
301}
302
304 for (const Node &C : getChildren()) {
305 if (C.getRole() == R)
306 return &C;
307 }
308 return nullptr;
309}
310
311std::vector<syntax::List::ElementAndDelimitersyntax::Node>
313 if (!getFirstChild())
314 return {};
315
316 std::vector<syntax::List::ElementAndDelimiter> Children;
317 syntax::Node *ElementWithoutDelimiter = nullptr;
318 for (Node &C : getChildren()) {
319 switch (C.getRole()) {
321 if (ElementWithoutDelimiter) {
322 Children.push_back({ElementWithoutDelimiter, nullptr});
323 }
324 ElementWithoutDelimiter = &C;
325 break;
326 }
328 Children.push_back({ElementWithoutDelimiter, castsyntax::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()) {
340 Children.push_back({ElementWithoutDelimiter, nullptr});
341 break;
342 }
345 if (ElementWithoutDelimiter) {
346 Children.push_back({ElementWithoutDelimiter, nullptr});
347 }
348 break;
349 }
350 }
351
352 return Children;
353}
354
355
356
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()) {
366 if (ElementWithoutDelimiter) {
367 Children.push_back(ElementWithoutDelimiter);
368 }
369 ElementWithoutDelimiter = &C;
370 break;
371 }
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()) {
384 Children.push_back(ElementWithoutDelimiter);
385 break;
386 }
389 if (ElementWithoutDelimiter) {
390 Children.push_back(ElementWithoutDelimiter);
391 }
392 break;
393 }
394 }
395
396 return Children;
397}
398
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
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
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}
static Decl::Kind getKind(const Decl *D)
Defines the clang::TokenKind enum and support functions.
A leaf node points to a single token.
Leaf(TokenManager::Key K)
bool canBeEmpty() const
Whether this list can be empty in syntactically and semantically correct code.
std::vector< Node * > getElementsAsNodes()
Returns the elements of the list.
std::vector< ElementAndDelimiter< Node > > getElementsAsNodesAndDelimiters()
Returns the elements and corresponding delimiters.
TerminationKind getTerminationKind() const
clang::tok::TokenKind getDelimiterTokenKind() const
Returns the appropriate delimiter for this list.
void assertInvariants() const
Asserts invariants on this node of the tree and its immediate children.
bool canModify() const
If this function return false, the tree cannot be modified because there is no reasonable way to prod...
void assertInvariantsRecursive() const
Runs checkInvariants on all nodes in the subtree. No-op if NDEBUG is set.
Node(NodeKind Kind)
Newly created nodes are detached from a tree, parent and sibling links are set when the node is added...
std::string dump(const TokenManager &SM) const
Dumps the structure of a subtree. For debugging and testing purposes.
std::string dumpTokens(const TokenManager &SM) const
Dumps the tokens forming this subtree.
bool isOriginal() const
Whether the node was created from the AST backed by the source code rather than added later through m...
bool isDetached() const
Whether the node is detached from a tree, i.e. does not have a parent.
Defines interfaces for operating "Token" in the clang syntax-tree.
uintptr_t Key
A key to identify a specific token.
virtual llvm::StringRef getText(Key K) const =0
const Leaf * findLastLeaf() const
const Leaf * findFirstLeaf() const
const Node * findChild(NodeRole R) const
Find the first node with a corresponding role.
internal::Matcher< T > traverse(TraversalKind TK, const internal::Matcher< T > &InnerMatcher)
Causes all nested matchers to be matched with the specified traversal kind.
NodeRole
A relation between a parent and child node, e.g.
@ ListElement
List API roles.
@ Detached
A node without a parent.
@ Unknown
Children of an unknown semantic nature, e.g. skipped tokens, comments.
NodeKind
A kind of a syntax node, used for implementing casts.
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
The JSON file list parser is used to communicate input to InstallAPI.
for(const auto &A :T->param_types())
const FunctionProtoType * T