1 //===- BuildTree.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/BuildTree.h" 9 #include "clang/AST/RecursiveASTVisitor.h" 10 #include "clang/AST/Stmt.h" 11 #include "clang/Basic/LLVM.h" 12 #include "clang/Basic/SourceLocation.h" 13 #include "clang/Basic/SourceManager.h" 14 #include "clang/Basic/TokenKinds.h" 15 #include "clang/Lex/Lexer.h" 16 #include "clang/Tooling/Syntax/Nodes.h" 17 #include "clang/Tooling/Syntax/Tokens.h" 18 #include "clang/Tooling/Syntax/Tree.h" 19 #include "llvm/ADT/ArrayRef.h" 20 #include "llvm/ADT/STLExtras.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/Support/Allocator.h" 23 #include "llvm/Support/Casting.h" 24 #include "llvm/Support/FormatVariadic.h" 25 #include "llvm/Support/raw_ostream.h" 26 #include <map> 27 28 using namespace clang; 29 30 static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; } 31 32 /// A helper class for constructing the syntax tree while traversing a clang 33 /// AST. 34 /// 35 /// At each point of the traversal we maintain a list of pending nodes. 36 /// Initially all tokens are added as pending nodes. When processing a clang AST 37 /// node, the clients need to: 38 /// - create a corresponding syntax node, 39 /// - assign roles to all pending child nodes with 'markChild' and 40 /// 'markChildToken', 41 /// - replace the child nodes with the new syntax node in the pending list 42 /// with 'foldNode'. 43 /// 44 /// Note that all children are expected to be processed when building a node. 45 /// 46 /// Call finalize() to finish building the tree and consume the root node. 47 class syntax::TreeBuilder { 48 public: 49 TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {} 50 51 llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); } 52 53 /// Populate children for \p New node, assuming it covers tokens from \p 54 /// Range. 55 void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New); 56 57 /// Mark the \p Child node with a corresponding \p Role. All marked children 58 /// should be consumed by foldNode. 59 /// (!) when called on expressions (clang::Expr is derived from clang::Stmt), 60 /// wraps expressions into expression statement. 61 void markStmtChild(Stmt *Child, NodeRole Role); 62 /// Should be called for expressions in non-statement position to avoid 63 /// wrapping into expression statement. 64 void markExprChild(Expr *Child, NodeRole Role); 65 66 /// Set role for a token starting at \p Loc. 67 void markChildToken(SourceLocation Loc, tok::TokenKind Kind, NodeRole R); 68 69 /// Finish building the tree and consume the root node. 70 syntax::TranslationUnit *finalize() && { 71 auto Tokens = Arena.tokenBuffer().expandedTokens(); 72 assert(!Tokens.empty()); 73 assert(Tokens.back().kind() == tok::eof); 74 75 // Build the root of the tree, consuming all the children. 76 Pending.foldChildren(Tokens.drop_back(), 77 new (Arena.allocator()) syntax::TranslationUnit); 78 79 return cast<syntax::TranslationUnit>(std::move(Pending).finalize()); 80 } 81 82 /// getRange() finds the syntax tokens corresponding to the passed source 83 /// locations. 84 /// \p First is the start position of the first token and \p Last is the start 85 /// position of the last token. 86 llvm::ArrayRef<syntax::Token> getRange(SourceLocation First, 87 SourceLocation Last) const { 88 assert(First.isValid()); 89 assert(Last.isValid()); 90 assert(First == Last || 91 Arena.sourceManager().isBeforeInTranslationUnit(First, Last)); 92 return llvm::makeArrayRef(findToken(First), std::next(findToken(Last))); 93 } 94 llvm::ArrayRef<syntax::Token> getRange(const Decl *D) const { 95 return getRange(D->getBeginLoc(), D->getEndLoc()); 96 } 97 llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const { 98 return getRange(E->getBeginLoc(), E->getEndLoc()); 99 } 100 /// Find the adjusted range for the statement, consuming the trailing 101 /// semicolon when needed. 102 llvm::ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const { 103 auto Tokens = getRange(S->getBeginLoc(), S->getEndLoc()); 104 if (isa<CompoundStmt>(S)) 105 return Tokens; 106 107 // Some statements miss a trailing semicolon, e.g. 'return', 'continue' and 108 // all statements that end with those. Consume this semicolon here. 109 // 110 // (!) statements never consume 'eof', so looking at the next token is ok. 111 if (Tokens.back().kind() != tok::semi && Tokens.end()->kind() == tok::semi) 112 return llvm::makeArrayRef(Tokens.begin(), Tokens.end() + 1); 113 return Tokens; 114 } 115 116 private: 117 /// Finds a token starting at \p L. The token must exist. 118 const syntax::Token *findToken(SourceLocation L) const; 119 120 /// A collection of trees covering the input tokens. 121 /// When created, each tree corresponds to a single token in the file. 122 /// Clients call 'foldChildren' to attach one or more subtrees to a parent 123 /// node and update the list of trees accordingly. 124 /// 125 /// Ensures that added nodes properly nest and cover the whole token stream. 126 struct Forest { 127 Forest(syntax::Arena &A) { 128 assert(!A.tokenBuffer().expandedTokens().empty()); 129 assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof); 130 // Create all leaf nodes. 131 // Note that we do not have 'eof' in the tree. 132 for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) 133 Trees.insert(Trees.end(), 134 {&T, NodeAndRole{new (A.allocator()) syntax::Leaf(&T)}}); 135 } 136 137 void assignRole(llvm::ArrayRef<syntax::Token> Range, 138 syntax::NodeRole Role) { 139 assert(!Range.empty()); 140 auto It = Trees.lower_bound(Range.begin()); 141 assert(It != Trees.end() && "no node found"); 142 assert(It->first == Range.begin() && "no child with the specified range"); 143 assert((std::next(It) == Trees.end() || 144 std::next(It)->first == Range.end()) && 145 "no child with the specified range"); 146 It->second.Role = Role; 147 } 148 149 /// Add \p Node to the forest and fill its children nodes based on the \p 150 /// NodeRange. 151 void foldChildren(llvm::ArrayRef<syntax::Token> NodeTokens, 152 syntax::Tree *Node) { 153 assert(!NodeTokens.empty()); 154 assert(Node->firstChild() == nullptr && "node already has children"); 155 156 auto *FirstToken = NodeTokens.begin(); 157 auto BeginChildren = Trees.lower_bound(FirstToken); 158 assert(BeginChildren != Trees.end() && 159 BeginChildren->first == FirstToken && 160 "fold crosses boundaries of existing subtrees"); 161 auto EndChildren = Trees.lower_bound(NodeTokens.end()); 162 assert((EndChildren == Trees.end() || 163 EndChildren->first == NodeTokens.end()) && 164 "fold crosses boundaries of existing subtrees"); 165 166 // (!) we need to go in reverse order, because we can only prepend. 167 for (auto It = EndChildren; It != BeginChildren; --It) 168 Node->prependChildLowLevel(std::prev(It)->second.Node, 169 std::prev(It)->second.Role); 170 171 Trees.erase(BeginChildren, EndChildren); 172 Trees.insert({FirstToken, NodeAndRole(Node)}); 173 } 174 175 // EXPECTS: all tokens were consumed and are owned by a single root node. 176 syntax::Node *finalize() && { 177 assert(Trees.size() == 1); 178 auto *Root = Trees.begin()->second.Node; 179 Trees = {}; 180 return Root; 181 } 182 183 std::string str(const syntax::Arena &A) const { 184 std::string R; 185 for (auto It = Trees.begin(); It != Trees.end(); ++It) { 186 unsigned CoveredTokens = 187 It != Trees.end() 188 ? (std::next(It)->first - It->first) 189 : A.tokenBuffer().expandedTokens().end() - It->first; 190 191 R += llvm::formatv("- '{0}' covers '{1}'+{2} tokens\n", 192 It->second.Node->kind(), 193 It->first->text(A.sourceManager()), CoveredTokens); 194 R += It->second.Node->dump(A); 195 } 196 return R; 197 } 198 199 private: 200 /// A with a role that should be assigned to it when adding to a parent. 201 struct NodeAndRole { 202 explicit NodeAndRole(syntax::Node *Node) 203 : Node(Node), Role(NodeRole::Unknown) {} 204 205 syntax::Node *Node; 206 NodeRole Role; 207 }; 208 209 /// Maps from the start token to a subtree starting at that token. 210 /// FIXME: storing the end tokens is redundant. 211 /// FIXME: the key of a map is redundant, it is also stored in NodeForRange. 212 std::map<const syntax::Token *, NodeAndRole> Trees; 213 }; 214 215 /// For debugging purposes. 216 std::string str() { return Pending.str(Arena); } 217 218 syntax::Arena &Arena; 219 Forest Pending; 220 }; 221 222 namespace { 223 class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> { 224 public: 225 explicit BuildTreeVisitor(ASTContext &Ctx, syntax::TreeBuilder &Builder) 226 : Builder(Builder), LangOpts(Ctx.getLangOpts()) {} 227 228 bool shouldTraversePostOrder() const { return true; } 229 230 bool TraverseDecl(Decl *D) { 231 if (!D || isa<TranslationUnitDecl>(D)) 232 return RecursiveASTVisitor::TraverseDecl(D); 233 if (!llvm::isa<TranslationUnitDecl>(D->getDeclContext())) 234 return true; // Only build top-level decls for now, do not recurse. 235 return RecursiveASTVisitor::TraverseDecl(D); 236 } 237 238 bool VisitDecl(Decl *D) { 239 assert(llvm::isa<TranslationUnitDecl>(D->getDeclContext()) && 240 "expected a top-level decl"); 241 assert(!D->isImplicit()); 242 Builder.foldNode(Builder.getRange(D), 243 new (allocator()) syntax::TopLevelDeclaration()); 244 return true; 245 } 246 247 bool WalkUpFromTranslationUnitDecl(TranslationUnitDecl *TU) { 248 // (!) we do not want to call VisitDecl(), the declaration for translation 249 // unit is built by finalize(). 250 return true; 251 } 252 253 bool WalkUpFromCompoundStmt(CompoundStmt *S) { 254 using NodeRole = syntax::NodeRole; 255 256 Builder.markChildToken(S->getLBracLoc(), tok::l_brace, NodeRole::OpenParen); 257 for (auto *Child : S->body()) 258 Builder.markStmtChild(Child, NodeRole::CompoundStatement_statement); 259 Builder.markChildToken(S->getRBracLoc(), tok::r_brace, 260 NodeRole::CloseParen); 261 262 Builder.foldNode(Builder.getStmtRange(S), 263 new (allocator()) syntax::CompoundStatement); 264 return true; 265 } 266 267 // Some statements are not yet handled by syntax trees. 268 bool WalkUpFromStmt(Stmt *S) { 269 Builder.foldNode(Builder.getStmtRange(S), 270 new (allocator()) syntax::UnknownStatement); 271 return true; 272 } 273 274 bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) { 275 // We override to traverse range initializer as VarDecl. 276 // RAV traverses it as a statement, we produce invalid node kinds in that 277 // case. 278 // FIXME: should do this in RAV instead? 279 if (S->getInit() && !TraverseStmt(S->getInit())) 280 return false; 281 if (S->getLoopVariable() && !TraverseDecl(S->getLoopVariable())) 282 return false; 283 if (S->getRangeInit() && !TraverseStmt(S->getRangeInit())) 284 return false; 285 if (S->getBody() && !TraverseStmt(S->getBody())) 286 return false; 287 return true; 288 } 289 290 bool TraverseStmt(Stmt *S) { 291 if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) { 292 // (!) do not recurse into subexpressions. 293 // we do not have syntax trees for expressions yet, so we only want to see 294 // the first top-level expression. 295 return WalkUpFromExpr(E->IgnoreImplicit()); 296 } 297 return RecursiveASTVisitor::TraverseStmt(S); 298 } 299 300 // Some expressions are not yet handled by syntax trees. 301 bool WalkUpFromExpr(Expr *E) { 302 assert(!isImplicitExpr(E) && "should be handled by TraverseStmt"); 303 Builder.foldNode(Builder.getExprRange(E), 304 new (allocator()) syntax::UnknownExpression); 305 return true; 306 } 307 308 // The code below is very regular, it could even be generated with some 309 // preprocessor magic. We merely assign roles to the corresponding children 310 // and fold resulting nodes. 311 bool WalkUpFromDeclStmt(DeclStmt *S) { 312 Builder.foldNode(Builder.getStmtRange(S), 313 new (allocator()) syntax::DeclarationStatement); 314 return true; 315 } 316 317 bool WalkUpFromNullStmt(NullStmt *S) { 318 Builder.foldNode(Builder.getStmtRange(S), 319 new (allocator()) syntax::EmptyStatement); 320 return true; 321 } 322 323 bool WalkUpFromSwitchStmt(SwitchStmt *S) { 324 Builder.markChildToken(S->getSwitchLoc(), tok::kw_switch, 325 syntax::NodeRole::IntroducerKeyword); 326 Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 327 Builder.foldNode(Builder.getStmtRange(S), 328 new (allocator()) syntax::SwitchStatement); 329 return true; 330 } 331 332 bool WalkUpFromCaseStmt(CaseStmt *S) { 333 Builder.markChildToken(S->getKeywordLoc(), tok::kw_case, 334 syntax::NodeRole::IntroducerKeyword); 335 Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseStatement_value); 336 Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 337 Builder.foldNode(Builder.getStmtRange(S), 338 new (allocator()) syntax::CaseStatement); 339 return true; 340 } 341 342 bool WalkUpFromDefaultStmt(DefaultStmt *S) { 343 Builder.markChildToken(S->getKeywordLoc(), tok::kw_default, 344 syntax::NodeRole::IntroducerKeyword); 345 Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 346 Builder.foldNode(Builder.getStmtRange(S), 347 new (allocator()) syntax::DefaultStatement); 348 return true; 349 } 350 351 bool WalkUpFromIfStmt(IfStmt *S) { 352 Builder.markChildToken(S->getIfLoc(), tok::kw_if, 353 syntax::NodeRole::IntroducerKeyword); 354 Builder.markStmtChild(S->getThen(), 355 syntax::NodeRole::IfStatement_thenStatement); 356 Builder.markChildToken(S->getElseLoc(), tok::kw_else, 357 syntax::NodeRole::IfStatement_elseKeyword); 358 Builder.markStmtChild(S->getElse(), 359 syntax::NodeRole::IfStatement_elseStatement); 360 Builder.foldNode(Builder.getStmtRange(S), 361 new (allocator()) syntax::IfStatement); 362 return true; 363 } 364 365 bool WalkUpFromForStmt(ForStmt *S) { 366 Builder.markChildToken(S->getForLoc(), tok::kw_for, 367 syntax::NodeRole::IntroducerKeyword); 368 Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 369 Builder.foldNode(Builder.getStmtRange(S), 370 new (allocator()) syntax::ForStatement); 371 return true; 372 } 373 374 bool WalkUpFromWhileStmt(WhileStmt *S) { 375 Builder.markChildToken(S->getWhileLoc(), tok::kw_while, 376 syntax::NodeRole::IntroducerKeyword); 377 Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 378 Builder.foldNode(Builder.getStmtRange(S), 379 new (allocator()) syntax::WhileStatement); 380 return true; 381 } 382 383 bool WalkUpFromContinueStmt(ContinueStmt *S) { 384 Builder.markChildToken(S->getContinueLoc(), tok::kw_continue, 385 syntax::NodeRole::IntroducerKeyword); 386 Builder.foldNode(Builder.getStmtRange(S), 387 new (allocator()) syntax::ContinueStatement); 388 return true; 389 } 390 391 bool WalkUpFromBreakStmt(BreakStmt *S) { 392 Builder.markChildToken(S->getBreakLoc(), tok::kw_break, 393 syntax::NodeRole::IntroducerKeyword); 394 Builder.foldNode(Builder.getStmtRange(S), 395 new (allocator()) syntax::BreakStatement); 396 return true; 397 } 398 399 bool WalkUpFromReturnStmt(ReturnStmt *S) { 400 Builder.markChildToken(S->getReturnLoc(), tok::kw_return, 401 syntax::NodeRole::IntroducerKeyword); 402 Builder.markExprChild(S->getRetValue(), 403 syntax::NodeRole::ReturnStatement_value); 404 Builder.foldNode(Builder.getStmtRange(S), 405 new (allocator()) syntax::ReturnStatement); 406 return true; 407 } 408 409 bool WalkUpFromCXXForRangeStmt(CXXForRangeStmt *S) { 410 Builder.markChildToken(S->getForLoc(), tok::kw_for, 411 syntax::NodeRole::IntroducerKeyword); 412 Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 413 Builder.foldNode(Builder.getStmtRange(S), 414 new (allocator()) syntax::RangeBasedForStatement); 415 return true; 416 } 417 418 private: 419 /// A small helper to save some typing. 420 llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); } 421 422 syntax::TreeBuilder &Builder; 423 const LangOptions &LangOpts; 424 }; 425 } // namespace 426 427 void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range, 428 syntax::Tree *New) { 429 Pending.foldChildren(Range, New); 430 } 431 432 void syntax::TreeBuilder::markChildToken(SourceLocation Loc, 433 tok::TokenKind Kind, NodeRole Role) { 434 if (Loc.isInvalid()) 435 return; 436 Pending.assignRole(*findToken(Loc), Role); 437 } 438 439 void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { 440 if (!Child) 441 return; 442 443 auto Range = getStmtRange(Child); 444 // This is an expression in a statement position, consume the trailing 445 // semicolon and form an 'ExpressionStatement' node. 446 if (auto *E = dyn_cast<Expr>(Child)) { 447 Pending.assignRole(getExprRange(E), 448 NodeRole::ExpressionStatement_expression); 449 // (!) 'getRange(Stmt)' ensures this already covers a trailing semicolon. 450 Pending.foldChildren(Range, new (allocator()) syntax::ExpressionStatement); 451 } 452 Pending.assignRole(Range, Role); 453 } 454 455 void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) { 456 Pending.assignRole(getExprRange(Child), Role); 457 } 458 459 const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const { 460 auto Tokens = Arena.tokenBuffer().expandedTokens(); 461 auto &SM = Arena.sourceManager(); 462 auto It = llvm::partition_point(Tokens, [&](const syntax::Token &T) { 463 return SM.isBeforeInTranslationUnit(T.location(), L); 464 }); 465 assert(It != Tokens.end()); 466 assert(It->location() == L); 467 return &*It; 468 } 469 470 syntax::TranslationUnit * 471 syntax::buildSyntaxTree(Arena &A, const TranslationUnitDecl &TU) { 472 TreeBuilder Builder(A); 473 BuildTreeVisitor(TU.getASTContext(), Builder).TraverseAST(TU.getASTContext()); 474 return std::move(Builder).finalize(); 475 } 476