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/ArrayRef.h"
12 #include "llvm/ADT/STLExtras.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 (auto *C = T->firstChild(); C; C = C->nextSibling())
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
Arena(SourceManager & SourceMgr,const LangOptions & LangOpts,TokenBuffer Tokens)35 syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
36 TokenBuffer Tokens)
37 : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {}
38
tokenBuffer() const39 const clang::syntax::TokenBuffer &syntax::Arena::tokenBuffer() const {
40 return Tokens;
41 }
42
43 std::pair<FileID, llvm::ArrayRef<syntax::Token>>
lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Input)44 syntax::Arena::lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Input) {
45 auto FID = SourceMgr.createFileID(std::move(Input));
46 auto It = ExtraTokens.try_emplace(FID, tokenize(FID, SourceMgr, LangOpts));
47 assert(It.second && "duplicate FileID");
48 return {FID, It.first->second};
49 }
50
Leaf(const syntax::Token * Tok)51 syntax::Leaf::Leaf(const syntax::Token *Tok) : Node(NodeKind::Leaf), Tok(Tok) {
52 assert(Tok != nullptr);
53 }
54
classof(const Node * N)55 bool syntax::Leaf::classof(const Node *N) {
56 return N->kind() == NodeKind::Leaf;
57 }
58
Node(NodeKind Kind)59 syntax::Node::Node(NodeKind Kind)
60 : Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)),
61 Role(static_cast<unsigned>(NodeRole::Detached)), Original(false),
62 CanModify(false) {}
63
isDetached() const64 bool syntax::Node::isDetached() const { return role() == NodeRole::Detached; }
65
classof(const Node * N)66 bool syntax::Tree::classof(const Node *N) { return N->kind() > NodeKind::Leaf; }
67
prependChildLowLevel(Node * Child,NodeRole Role)68 void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
69 assert(Child->Parent == nullptr);
70 assert(Child->NextSibling == nullptr);
71 assert(Child->role() == NodeRole::Detached);
72 assert(Role != NodeRole::Detached);
73
74 Child->Parent = this;
75 Child->NextSibling = this->FirstChild;
76 Child->Role = static_cast<unsigned>(Role);
77 this->FirstChild = Child;
78 }
79
replaceChildRangeLowLevel(Node * BeforeBegin,Node * End,Node * New)80 void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End,
81 Node *New) {
82 assert(!BeforeBegin || BeforeBegin->Parent == this);
83
84 #ifndef NDEBUG
85 for (auto *N = New; N; N = N->nextSibling()) {
86 assert(N->Parent == nullptr);
87 assert(N->role() != NodeRole::Detached && "Roles must be set");
88 // FIXME: sanity-check the role.
89 }
90 #endif
91
92 // Detach old nodes.
93 for (auto *N = !BeforeBegin ? FirstChild : BeforeBegin->nextSibling();
94 N != End;) {
95 auto *Next = N->NextSibling;
96
97 N->Role = static_cast<unsigned>(NodeRole::Detached);
98 N->Parent = nullptr;
99 N->NextSibling = nullptr;
100 if (N->Original)
101 traverse(N, [&](Node *C) { C->Original = false; });
102
103 N = Next;
104 }
105
106 // Attach new nodes.
107 if (BeforeBegin)
108 BeforeBegin->NextSibling = New ? New : End;
109 else
110 FirstChild = New ? New : End;
111
112 if (New) {
113 auto *Last = New;
114 for (auto *N = New; N != nullptr; N = N->nextSibling()) {
115 Last = N;
116 N->Parent = this;
117 }
118 Last->NextSibling = End;
119 }
120
121 // Mark the node as modified.
122 for (auto *T = this; T && T->Original; T = T->Parent)
123 T->Original = false;
124 }
125
126 namespace {
dumpTokens(llvm::raw_ostream & OS,ArrayRef<syntax::Token> Tokens,const SourceManager & SM)127 static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens,
128 const SourceManager &SM) {
129 assert(!Tokens.empty());
130 bool First = true;
131 for (const auto &T : Tokens) {
132 if (!First)
133 OS << " ";
134 else
135 First = false;
136 // Handle 'eof' separately, calling text() on it produces an empty string.
137 if (T.kind() == tok::eof) {
138 OS << "<eof>";
139 continue;
140 }
141 OS << T.text(SM);
142 }
143 }
144
dumpTree(llvm::raw_ostream & OS,const syntax::Node * N,const syntax::Arena & A,std::vector<bool> IndentMask)145 static void dumpTree(llvm::raw_ostream &OS, const syntax::Node *N,
146 const syntax::Arena &A, std::vector<bool> IndentMask) {
147 std::string Marks;
148 if (!N->isOriginal())
149 Marks += "M";
150 if (N->role() == syntax::NodeRole::Detached)
151 Marks += "*"; // FIXME: find a nice way to print other roles.
152 if (!N->canModify())
153 Marks += "I";
154 if (!Marks.empty())
155 OS << Marks << ": ";
156
157 if (auto *L = llvm::dyn_cast<syntax::Leaf>(N)) {
158 dumpTokens(OS, *L->token(), A.sourceManager());
159 OS << "\n";
160 return;
161 }
162
163 auto *T = llvm::cast<syntax::Tree>(N);
164 OS << T->kind() << "\n";
165
166 for (auto It = T->firstChild(); It != nullptr; It = It->nextSibling()) {
167 for (bool Filled : IndentMask) {
168 if (Filled)
169 OS << "| ";
170 else
171 OS << " ";
172 }
173 if (!It->nextSibling()) {
174 OS << "`-";
175 IndentMask.push_back(false);
176 } else {
177 OS << "|-";
178 IndentMask.push_back(true);
179 }
180 dumpTree(OS, It, A, IndentMask);
181 IndentMask.pop_back();
182 }
183 }
184 } // namespace
185
dump(const Arena & A) const186 std::string syntax::Node::dump(const Arena &A) const {
187 std::string Str;
188 llvm::raw_string_ostream OS(Str);
189 dumpTree(OS, this, A, /*IndentMask=*/{});
190 return std::move(OS.str());
191 }
192
dumpTokens(const Arena & A) const193 std::string syntax::Node::dumpTokens(const Arena &A) const {
194 std::string Storage;
195 llvm::raw_string_ostream OS(Storage);
196 traverse(this, [&](const syntax::Node *N) {
197 auto *L = llvm::dyn_cast<syntax::Leaf>(N);
198 if (!L)
199 return;
200 ::dumpTokens(OS, *L->token(), A.sourceManager());
201 OS << " ";
202 });
203 return OS.str();
204 }
205
assertInvariants() const206 void syntax::Node::assertInvariants() const {
207 #ifndef NDEBUG
208 if (isDetached())
209 assert(parent() == nullptr);
210 else
211 assert(parent() != nullptr);
212
213 auto *T = dyn_cast<Tree>(this);
214 if (!T)
215 return;
216 for (auto *C = T->firstChild(); C; C = C->nextSibling()) {
217 if (T->isOriginal())
218 assert(C->isOriginal());
219 assert(!C->isDetached());
220 assert(C->parent() == T);
221 }
222 #endif
223 }
224
assertInvariantsRecursive() const225 void syntax::Node::assertInvariantsRecursive() const {
226 #ifndef NDEBUG
227 traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); });
228 #endif
229 }
230
firstLeaf()231 syntax::Leaf *syntax::Tree::firstLeaf() {
232 auto *T = this;
233 while (auto *C = T->firstChild()) {
234 if (auto *L = dyn_cast<syntax::Leaf>(C))
235 return L;
236 T = cast<syntax::Tree>(C);
237 }
238 return nullptr;
239 }
240
lastLeaf()241 syntax::Leaf *syntax::Tree::lastLeaf() {
242 auto *T = this;
243 while (auto *C = T->firstChild()) {
244 // Find the last child.
245 while (auto *Next = C->nextSibling())
246 C = Next;
247
248 if (auto *L = dyn_cast<syntax::Leaf>(C))
249 return L;
250 T = cast<syntax::Tree>(C);
251 }
252 return nullptr;
253 }
254
findChild(NodeRole R)255 syntax::Node *syntax::Tree::findChild(NodeRole R) {
256 for (auto *C = FirstChild; C; C = C->nextSibling()) {
257 if (C->role() == R)
258 return C;
259 }
260 return nullptr;
261 }
262