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 { 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 } 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 35 syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts, 36 TokenBuffer Tokens) 37 : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {} 38 39 const clang::syntax::TokenBuffer &syntax::Arena::tokenBuffer() const { 40 return Tokens; 41 } 42 43 std::pair<FileID, llvm::ArrayRef<syntax::Token>> 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 51 syntax::Leaf::Leaf(const syntax::Token *Tok) : Node(NodeKind::Leaf), Tok(Tok) { 52 assert(Tok != nullptr); 53 } 54 55 bool syntax::Leaf::classof(const Node *N) { 56 return N->kind() == NodeKind::Leaf; 57 } 58 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 64 bool syntax::Node::isDetached() const { return role() == NodeRole::Detached; } 65 66 bool syntax::Tree::classof(const Node *N) { return N->kind() > NodeKind::Leaf; } 67 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 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 { 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 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 186 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 193 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 206 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 225 void syntax::Node::assertInvariantsRecursive() const { 226 #ifndef NDEBUG 227 traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); }); 228 #endif 229 } 230 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 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 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