19b3f38f9SIlya Biryukov //===- BuildTree.cpp ------------------------------------------*- C++ -*-=====// 29b3f38f9SIlya Biryukov // 39b3f38f9SIlya Biryukov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49b3f38f9SIlya Biryukov // See https://llvm.org/LICENSE.txt for license information. 59b3f38f9SIlya Biryukov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69b3f38f9SIlya Biryukov // 79b3f38f9SIlya Biryukov //===----------------------------------------------------------------------===// 89b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/BuildTree.h" 9e702bdb8SIlya Biryukov #include "clang/AST/Decl.h" 10e702bdb8SIlya Biryukov #include "clang/AST/DeclBase.h" 119b3f38f9SIlya Biryukov #include "clang/AST/RecursiveASTVisitor.h" 129b3f38f9SIlya Biryukov #include "clang/AST/Stmt.h" 139b3f38f9SIlya Biryukov #include "clang/Basic/LLVM.h" 149b3f38f9SIlya Biryukov #include "clang/Basic/SourceLocation.h" 159b3f38f9SIlya Biryukov #include "clang/Basic/SourceManager.h" 169b3f38f9SIlya Biryukov #include "clang/Basic/TokenKinds.h" 179b3f38f9SIlya Biryukov #include "clang/Lex/Lexer.h" 189b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Nodes.h" 199b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Tokens.h" 209b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Tree.h" 219b3f38f9SIlya Biryukov #include "llvm/ADT/ArrayRef.h" 229b3f38f9SIlya Biryukov #include "llvm/ADT/STLExtras.h" 239b3f38f9SIlya Biryukov #include "llvm/ADT/SmallVector.h" 249b3f38f9SIlya Biryukov #include "llvm/Support/Allocator.h" 259b3f38f9SIlya Biryukov #include "llvm/Support/Casting.h" 2696065cf7SIlya Biryukov #include "llvm/Support/Compiler.h" 279b3f38f9SIlya Biryukov #include "llvm/Support/FormatVariadic.h" 281ad15046SIlya Biryukov #include "llvm/Support/MemoryBuffer.h" 299b3f38f9SIlya Biryukov #include "llvm/Support/raw_ostream.h" 309b3f38f9SIlya Biryukov #include <map> 319b3f38f9SIlya Biryukov 329b3f38f9SIlya Biryukov using namespace clang; 339b3f38f9SIlya Biryukov 3496065cf7SIlya Biryukov LLVM_ATTRIBUTE_UNUSED 3558fa50f4SIlya Biryukov static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; } 3658fa50f4SIlya Biryukov 379b3f38f9SIlya Biryukov /// A helper class for constructing the syntax tree while traversing a clang 389b3f38f9SIlya Biryukov /// AST. 399b3f38f9SIlya Biryukov /// 409b3f38f9SIlya Biryukov /// At each point of the traversal we maintain a list of pending nodes. 419b3f38f9SIlya Biryukov /// Initially all tokens are added as pending nodes. When processing a clang AST 429b3f38f9SIlya Biryukov /// node, the clients need to: 439b3f38f9SIlya Biryukov /// - create a corresponding syntax node, 449b3f38f9SIlya Biryukov /// - assign roles to all pending child nodes with 'markChild' and 459b3f38f9SIlya Biryukov /// 'markChildToken', 469b3f38f9SIlya Biryukov /// - replace the child nodes with the new syntax node in the pending list 479b3f38f9SIlya Biryukov /// with 'foldNode'. 489b3f38f9SIlya Biryukov /// 499b3f38f9SIlya Biryukov /// Note that all children are expected to be processed when building a node. 509b3f38f9SIlya Biryukov /// 519b3f38f9SIlya Biryukov /// Call finalize() to finish building the tree and consume the root node. 529b3f38f9SIlya Biryukov class syntax::TreeBuilder { 539b3f38f9SIlya Biryukov public: 54c1bbefefSIlya Biryukov TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) { 55c1bbefefSIlya Biryukov for (const auto &T : Arena.tokenBuffer().expandedTokens()) 56c1bbefefSIlya Biryukov LocationToToken.insert({T.location().getRawEncoding(), &T}); 57c1bbefefSIlya Biryukov } 589b3f38f9SIlya Biryukov 599b3f38f9SIlya Biryukov llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); } 609b3f38f9SIlya Biryukov 619b3f38f9SIlya Biryukov /// Populate children for \p New node, assuming it covers tokens from \p 629b3f38f9SIlya Biryukov /// Range. 639b3f38f9SIlya Biryukov void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New); 649b3f38f9SIlya Biryukov 65e702bdb8SIlya Biryukov /// Must be called with the range of each `DeclaratorDecl`. Ensures the 66e702bdb8SIlya Biryukov /// corresponding declarator nodes are covered by `SimpleDeclaration`. 67e702bdb8SIlya Biryukov void noticeDeclaratorRange(llvm::ArrayRef<syntax::Token> Range); 68e702bdb8SIlya Biryukov 69e702bdb8SIlya Biryukov /// Notifies that we should not consume trailing semicolon when computing 70e702bdb8SIlya Biryukov /// token range of \p D. 71e702bdb8SIlya Biryukov void noticeDeclaratorWithoutSemicolon(Decl *D); 72e702bdb8SIlya Biryukov 7358fa50f4SIlya Biryukov /// Mark the \p Child node with a corresponding \p Role. All marked children 7458fa50f4SIlya Biryukov /// should be consumed by foldNode. 7558fa50f4SIlya Biryukov /// (!) when called on expressions (clang::Expr is derived from clang::Stmt), 7658fa50f4SIlya Biryukov /// wraps expressions into expression statement. 7758fa50f4SIlya Biryukov void markStmtChild(Stmt *Child, NodeRole Role); 7858fa50f4SIlya Biryukov /// Should be called for expressions in non-statement position to avoid 7958fa50f4SIlya Biryukov /// wrapping into expression statement. 8058fa50f4SIlya Biryukov void markExprChild(Expr *Child, NodeRole Role); 8158fa50f4SIlya Biryukov 829b3f38f9SIlya Biryukov /// Set role for a token starting at \p Loc. 83def65bb4SIlya Biryukov void markChildToken(SourceLocation Loc, NodeRole R); 849b3f38f9SIlya Biryukov 859b3f38f9SIlya Biryukov /// Finish building the tree and consume the root node. 869b3f38f9SIlya Biryukov syntax::TranslationUnit *finalize() && { 879b3f38f9SIlya Biryukov auto Tokens = Arena.tokenBuffer().expandedTokens(); 88bfbf6b6cSIlya Biryukov assert(!Tokens.empty()); 89bfbf6b6cSIlya Biryukov assert(Tokens.back().kind() == tok::eof); 90bfbf6b6cSIlya Biryukov 919b3f38f9SIlya Biryukov // Build the root of the tree, consuming all the children. 921ad15046SIlya Biryukov Pending.foldChildren(Arena, Tokens.drop_back(), 939b3f38f9SIlya Biryukov new (Arena.allocator()) syntax::TranslationUnit); 949b3f38f9SIlya Biryukov 953b929fe7SIlya Biryukov auto *TU = cast<syntax::TranslationUnit>(std::move(Pending).finalize()); 963b929fe7SIlya Biryukov TU->assertInvariantsRecursive(); 973b929fe7SIlya Biryukov return TU; 989b3f38f9SIlya Biryukov } 999b3f38f9SIlya Biryukov 1009b3f38f9SIlya Biryukov /// getRange() finds the syntax tokens corresponding to the passed source 1019b3f38f9SIlya Biryukov /// locations. 1029b3f38f9SIlya Biryukov /// \p First is the start position of the first token and \p Last is the start 1039b3f38f9SIlya Biryukov /// position of the last token. 1049b3f38f9SIlya Biryukov llvm::ArrayRef<syntax::Token> getRange(SourceLocation First, 1059b3f38f9SIlya Biryukov SourceLocation Last) const { 1069b3f38f9SIlya Biryukov assert(First.isValid()); 1079b3f38f9SIlya Biryukov assert(Last.isValid()); 1089b3f38f9SIlya Biryukov assert(First == Last || 1099b3f38f9SIlya Biryukov Arena.sourceManager().isBeforeInTranslationUnit(First, Last)); 1109b3f38f9SIlya Biryukov return llvm::makeArrayRef(findToken(First), std::next(findToken(Last))); 1119b3f38f9SIlya Biryukov } 1129b3f38f9SIlya Biryukov llvm::ArrayRef<syntax::Token> getRange(const Decl *D) const { 113e702bdb8SIlya Biryukov auto Tokens = getRange(D->getBeginLoc(), D->getEndLoc()); 114e702bdb8SIlya Biryukov if (llvm::isa<NamespaceDecl>(D)) 115e702bdb8SIlya Biryukov return Tokens; 116e702bdb8SIlya Biryukov if (DeclsWithoutSemicolons.count(D)) 117e702bdb8SIlya Biryukov return Tokens; 118e702bdb8SIlya Biryukov // FIXME: do not consume trailing semicolon on function definitions. 119e702bdb8SIlya Biryukov // Most declarations own a semicolon in syntax trees, but not in clang AST. 120e702bdb8SIlya Biryukov return withTrailingSemicolon(Tokens); 1219b3f38f9SIlya Biryukov } 12258fa50f4SIlya Biryukov llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const { 12358fa50f4SIlya Biryukov return getRange(E->getBeginLoc(), E->getEndLoc()); 12458fa50f4SIlya Biryukov } 12558fa50f4SIlya Biryukov /// Find the adjusted range for the statement, consuming the trailing 12658fa50f4SIlya Biryukov /// semicolon when needed. 12758fa50f4SIlya Biryukov llvm::ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const { 12858fa50f4SIlya Biryukov auto Tokens = getRange(S->getBeginLoc(), S->getEndLoc()); 12958fa50f4SIlya Biryukov if (isa<CompoundStmt>(S)) 13058fa50f4SIlya Biryukov return Tokens; 13158fa50f4SIlya Biryukov 13258fa50f4SIlya Biryukov // Some statements miss a trailing semicolon, e.g. 'return', 'continue' and 13358fa50f4SIlya Biryukov // all statements that end with those. Consume this semicolon here. 134e702bdb8SIlya Biryukov if (Tokens.back().kind() == tok::semi) 135e702bdb8SIlya Biryukov return Tokens; 136e702bdb8SIlya Biryukov return withTrailingSemicolon(Tokens); 137e702bdb8SIlya Biryukov } 138e702bdb8SIlya Biryukov 139e702bdb8SIlya Biryukov private: 140e702bdb8SIlya Biryukov llvm::ArrayRef<syntax::Token> 141e702bdb8SIlya Biryukov withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const { 142e702bdb8SIlya Biryukov assert(!Tokens.empty()); 143e702bdb8SIlya Biryukov assert(Tokens.back().kind() != tok::eof); 144e702bdb8SIlya Biryukov // (!) we never consume 'eof', so looking at the next token is ok. 14558fa50f4SIlya Biryukov if (Tokens.back().kind() != tok::semi && Tokens.end()->kind() == tok::semi) 14658fa50f4SIlya Biryukov return llvm::makeArrayRef(Tokens.begin(), Tokens.end() + 1); 14758fa50f4SIlya Biryukov return Tokens; 1489b3f38f9SIlya Biryukov } 1499b3f38f9SIlya Biryukov 1509b3f38f9SIlya Biryukov /// Finds a token starting at \p L. The token must exist. 1519b3f38f9SIlya Biryukov const syntax::Token *findToken(SourceLocation L) const; 1529b3f38f9SIlya Biryukov 1539b3f38f9SIlya Biryukov /// A collection of trees covering the input tokens. 1549b3f38f9SIlya Biryukov /// When created, each tree corresponds to a single token in the file. 1559b3f38f9SIlya Biryukov /// Clients call 'foldChildren' to attach one or more subtrees to a parent 1569b3f38f9SIlya Biryukov /// node and update the list of trees accordingly. 1579b3f38f9SIlya Biryukov /// 1589b3f38f9SIlya Biryukov /// Ensures that added nodes properly nest and cover the whole token stream. 1599b3f38f9SIlya Biryukov struct Forest { 1609b3f38f9SIlya Biryukov Forest(syntax::Arena &A) { 161bfbf6b6cSIlya Biryukov assert(!A.tokenBuffer().expandedTokens().empty()); 162bfbf6b6cSIlya Biryukov assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof); 1639b3f38f9SIlya Biryukov // Create all leaf nodes. 164bfbf6b6cSIlya Biryukov // Note that we do not have 'eof' in the tree. 1651ad15046SIlya Biryukov for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) { 1661ad15046SIlya Biryukov auto *L = new (A.allocator()) syntax::Leaf(&T); 1671ad15046SIlya Biryukov L->Original = true; 1681ad15046SIlya Biryukov L->CanModify = A.tokenBuffer().spelledForExpanded(T).hasValue(); 1691ad15046SIlya Biryukov Trees.insert(Trees.end(), {&T, NodeAndRole{L}}); 1701ad15046SIlya Biryukov } 1719b3f38f9SIlya Biryukov } 1729b3f38f9SIlya Biryukov 173e702bdb8SIlya Biryukov ~Forest() { assert(DelayedFolds.empty()); } 174e702bdb8SIlya Biryukov 1759b3f38f9SIlya Biryukov void assignRole(llvm::ArrayRef<syntax::Token> Range, 1769b3f38f9SIlya Biryukov syntax::NodeRole Role) { 1779b3f38f9SIlya Biryukov assert(!Range.empty()); 1789b3f38f9SIlya Biryukov auto It = Trees.lower_bound(Range.begin()); 1799b3f38f9SIlya Biryukov assert(It != Trees.end() && "no node found"); 1809b3f38f9SIlya Biryukov assert(It->first == Range.begin() && "no child with the specified range"); 1819b3f38f9SIlya Biryukov assert((std::next(It) == Trees.end() || 1829b3f38f9SIlya Biryukov std::next(It)->first == Range.end()) && 1839b3f38f9SIlya Biryukov "no child with the specified range"); 1849b3f38f9SIlya Biryukov It->second.Role = Role; 1859b3f38f9SIlya Biryukov } 1869b3f38f9SIlya Biryukov 187e702bdb8SIlya Biryukov /// Add \p Node to the forest and attach child nodes based on \p Tokens. 1881ad15046SIlya Biryukov void foldChildren(const syntax::Arena &A, 1891ad15046SIlya Biryukov llvm::ArrayRef<syntax::Token> Tokens, 1909b3f38f9SIlya Biryukov syntax::Tree *Node) { 191e702bdb8SIlya Biryukov // Execute delayed folds inside `Tokens`. 192e702bdb8SIlya Biryukov auto BeginExecuted = DelayedFolds.lower_bound(Tokens.begin()); 193e702bdb8SIlya Biryukov auto It = BeginExecuted; 194e702bdb8SIlya Biryukov for (; It != DelayedFolds.end() && It->second.End <= Tokens.end(); ++It) 1951ad15046SIlya Biryukov foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End), 196e702bdb8SIlya Biryukov It->second.Node); 197e702bdb8SIlya Biryukov DelayedFolds.erase(BeginExecuted, It); 1989b3f38f9SIlya Biryukov 199e702bdb8SIlya Biryukov // Attach children to `Node`. 2001ad15046SIlya Biryukov foldChildrenEager(A, Tokens, Node); 201e702bdb8SIlya Biryukov } 2029b3f38f9SIlya Biryukov 203e702bdb8SIlya Biryukov /// Schedule a call to `foldChildren` that will only be executed when 204e702bdb8SIlya Biryukov /// containing node is folded. The range of delayed nodes can be extended by 205e702bdb8SIlya Biryukov /// calling `extendDelayedFold`. Only one delayed node for each starting 206e702bdb8SIlya Biryukov /// token is allowed. 207e702bdb8SIlya Biryukov void foldChildrenDelayed(llvm::ArrayRef<syntax::Token> Tokens, 208e702bdb8SIlya Biryukov syntax::Tree *Node) { 209e702bdb8SIlya Biryukov assert(!Tokens.empty()); 210e702bdb8SIlya Biryukov bool Inserted = 211e702bdb8SIlya Biryukov DelayedFolds.insert({Tokens.begin(), DelayedFold{Tokens.end(), Node}}) 212e702bdb8SIlya Biryukov .second; 213e702bdb8SIlya Biryukov (void)Inserted; 214e702bdb8SIlya Biryukov assert(Inserted && "Multiple delayed folds start at the same token"); 215e702bdb8SIlya Biryukov } 2169b3f38f9SIlya Biryukov 217e702bdb8SIlya Biryukov /// If there a delayed fold, starting at `ExtendedRange.begin()`, extends 218e702bdb8SIlya Biryukov /// its endpoint to `ExtendedRange.end()` and returns true. 219e702bdb8SIlya Biryukov /// Otherwise, returns false. 220e702bdb8SIlya Biryukov bool extendDelayedFold(llvm::ArrayRef<syntax::Token> ExtendedRange) { 221e702bdb8SIlya Biryukov assert(!ExtendedRange.empty()); 222e702bdb8SIlya Biryukov auto It = DelayedFolds.find(ExtendedRange.data()); 223e702bdb8SIlya Biryukov if (It == DelayedFolds.end()) 224e702bdb8SIlya Biryukov return false; 225e702bdb8SIlya Biryukov assert(It->second.End <= ExtendedRange.end()); 226e702bdb8SIlya Biryukov It->second.End = ExtendedRange.end(); 227e702bdb8SIlya Biryukov return true; 2289b3f38f9SIlya Biryukov } 2299b3f38f9SIlya Biryukov 2309b3f38f9SIlya Biryukov // EXPECTS: all tokens were consumed and are owned by a single root node. 2319b3f38f9SIlya Biryukov syntax::Node *finalize() && { 2329b3f38f9SIlya Biryukov assert(Trees.size() == 1); 2339b3f38f9SIlya Biryukov auto *Root = Trees.begin()->second.Node; 2349b3f38f9SIlya Biryukov Trees = {}; 2359b3f38f9SIlya Biryukov return Root; 2369b3f38f9SIlya Biryukov } 2379b3f38f9SIlya Biryukov 2389b3f38f9SIlya Biryukov std::string str(const syntax::Arena &A) const { 2399b3f38f9SIlya Biryukov std::string R; 2409b3f38f9SIlya Biryukov for (auto It = Trees.begin(); It != Trees.end(); ++It) { 2419b3f38f9SIlya Biryukov unsigned CoveredTokens = 2429b3f38f9SIlya Biryukov It != Trees.end() 2439b3f38f9SIlya Biryukov ? (std::next(It)->first - It->first) 2449b3f38f9SIlya Biryukov : A.tokenBuffer().expandedTokens().end() - It->first; 2459b3f38f9SIlya Biryukov 246*adcd0268SBenjamin Kramer R += std::string(llvm::formatv( 247*adcd0268SBenjamin Kramer "- '{0}' covers '{1}'+{2} tokens\n", It->second.Node->kind(), 248*adcd0268SBenjamin Kramer It->first->text(A.sourceManager()), CoveredTokens)); 2499b3f38f9SIlya Biryukov R += It->second.Node->dump(A); 2509b3f38f9SIlya Biryukov } 2519b3f38f9SIlya Biryukov return R; 2529b3f38f9SIlya Biryukov } 2539b3f38f9SIlya Biryukov 2549b3f38f9SIlya Biryukov private: 255e702bdb8SIlya Biryukov /// Implementation detail of `foldChildren`, does acutal folding ignoring 256e702bdb8SIlya Biryukov /// delayed folds. 2571ad15046SIlya Biryukov void foldChildrenEager(const syntax::Arena &A, 2581ad15046SIlya Biryukov llvm::ArrayRef<syntax::Token> Tokens, 259e702bdb8SIlya Biryukov syntax::Tree *Node) { 260e702bdb8SIlya Biryukov assert(Node->firstChild() == nullptr && "node already has children"); 261e702bdb8SIlya Biryukov 262e702bdb8SIlya Biryukov auto *FirstToken = Tokens.begin(); 263e702bdb8SIlya Biryukov auto BeginChildren = Trees.lower_bound(FirstToken); 264e702bdb8SIlya Biryukov assert((BeginChildren == Trees.end() || 265e702bdb8SIlya Biryukov BeginChildren->first == FirstToken) && 266e702bdb8SIlya Biryukov "fold crosses boundaries of existing subtrees"); 267e702bdb8SIlya Biryukov auto EndChildren = Trees.lower_bound(Tokens.end()); 268e702bdb8SIlya Biryukov assert( 269e702bdb8SIlya Biryukov (EndChildren == Trees.end() || EndChildren->first == Tokens.end()) && 270e702bdb8SIlya Biryukov "fold crosses boundaries of existing subtrees"); 271e702bdb8SIlya Biryukov 272e702bdb8SIlya Biryukov // (!) we need to go in reverse order, because we can only prepend. 273e702bdb8SIlya Biryukov for (auto It = EndChildren; It != BeginChildren; --It) 274e702bdb8SIlya Biryukov Node->prependChildLowLevel(std::prev(It)->second.Node, 275e702bdb8SIlya Biryukov std::prev(It)->second.Role); 276e702bdb8SIlya Biryukov 2771ad15046SIlya Biryukov // Mark that this node came from the AST and is backed by the source code. 2781ad15046SIlya Biryukov Node->Original = true; 2791ad15046SIlya Biryukov Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue(); 2801ad15046SIlya Biryukov 281e702bdb8SIlya Biryukov Trees.erase(BeginChildren, EndChildren); 282e702bdb8SIlya Biryukov Trees.insert({FirstToken, NodeAndRole(Node)}); 283e702bdb8SIlya Biryukov } 2849b3f38f9SIlya Biryukov /// A with a role that should be assigned to it when adding to a parent. 2859b3f38f9SIlya Biryukov struct NodeAndRole { 2869b3f38f9SIlya Biryukov explicit NodeAndRole(syntax::Node *Node) 28751dad419SIlya Biryukov : Node(Node), Role(NodeRole::Unknown) {} 2889b3f38f9SIlya Biryukov 2899b3f38f9SIlya Biryukov syntax::Node *Node; 2909b3f38f9SIlya Biryukov NodeRole Role; 2919b3f38f9SIlya Biryukov }; 2929b3f38f9SIlya Biryukov 2939b3f38f9SIlya Biryukov /// Maps from the start token to a subtree starting at that token. 294302cb3bcSIlya Biryukov /// Keys in the map are pointers into the array of expanded tokens, so 295302cb3bcSIlya Biryukov /// pointer order corresponds to the order of preprocessor tokens. 2969b3f38f9SIlya Biryukov /// FIXME: storing the end tokens is redundant. 2979b3f38f9SIlya Biryukov /// FIXME: the key of a map is redundant, it is also stored in NodeForRange. 2989b3f38f9SIlya Biryukov std::map<const syntax::Token *, NodeAndRole> Trees; 299e702bdb8SIlya Biryukov 300e702bdb8SIlya Biryukov /// See documentation of `foldChildrenDelayed` for details. 301e702bdb8SIlya Biryukov struct DelayedFold { 302e702bdb8SIlya Biryukov const syntax::Token *End = nullptr; 303e702bdb8SIlya Biryukov syntax::Tree *Node = nullptr; 304e702bdb8SIlya Biryukov }; 305e702bdb8SIlya Biryukov std::map<const syntax::Token *, DelayedFold> DelayedFolds; 3069b3f38f9SIlya Biryukov }; 3079b3f38f9SIlya Biryukov 3089b3f38f9SIlya Biryukov /// For debugging purposes. 3099b3f38f9SIlya Biryukov std::string str() { return Pending.str(Arena); } 3109b3f38f9SIlya Biryukov 3119b3f38f9SIlya Biryukov syntax::Arena &Arena; 312c1bbefefSIlya Biryukov /// To quickly find tokens by their start location. 313c1bbefefSIlya Biryukov llvm::DenseMap</*SourceLocation*/ unsigned, const syntax::Token *> 314c1bbefefSIlya Biryukov LocationToToken; 3159b3f38f9SIlya Biryukov Forest Pending; 316e702bdb8SIlya Biryukov llvm::DenseSet<Decl *> DeclsWithoutSemicolons; 3179b3f38f9SIlya Biryukov }; 3189b3f38f9SIlya Biryukov 3199b3f38f9SIlya Biryukov namespace { 3209b3f38f9SIlya Biryukov class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> { 3219b3f38f9SIlya Biryukov public: 3229b3f38f9SIlya Biryukov explicit BuildTreeVisitor(ASTContext &Ctx, syntax::TreeBuilder &Builder) 3239b3f38f9SIlya Biryukov : Builder(Builder), LangOpts(Ctx.getLangOpts()) {} 3249b3f38f9SIlya Biryukov 3259b3f38f9SIlya Biryukov bool shouldTraversePostOrder() const { return true; } 3269b3f38f9SIlya Biryukov 327e702bdb8SIlya Biryukov bool WalkUpFromDeclaratorDecl(DeclaratorDecl *D) { 328e702bdb8SIlya Biryukov // Ensure declarators are covered by SimpleDeclaration. 329e702bdb8SIlya Biryukov Builder.noticeDeclaratorRange(Builder.getRange(D)); 330e702bdb8SIlya Biryukov // FIXME: build nodes for the declarator too. 331e702bdb8SIlya Biryukov return true; 332e702bdb8SIlya Biryukov } 333e702bdb8SIlya Biryukov bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) { 334e702bdb8SIlya Biryukov // Also a declarator. 335e702bdb8SIlya Biryukov Builder.noticeDeclaratorRange(Builder.getRange(D)); 336e702bdb8SIlya Biryukov // FIXME: build nodes for the declarator too. 337e702bdb8SIlya Biryukov return true; 3389b3f38f9SIlya Biryukov } 3399b3f38f9SIlya Biryukov 3409b3f38f9SIlya Biryukov bool VisitDecl(Decl *D) { 3419b3f38f9SIlya Biryukov assert(!D->isImplicit()); 3429b3f38f9SIlya Biryukov Builder.foldNode(Builder.getRange(D), 343e702bdb8SIlya Biryukov new (allocator()) syntax::UnknownDeclaration()); 344e702bdb8SIlya Biryukov return true; 345e702bdb8SIlya Biryukov } 346e702bdb8SIlya Biryukov 347e702bdb8SIlya Biryukov bool WalkUpFromTagDecl(TagDecl *C) { 34804f627f6SIlya Biryukov // FIXME: build the ClassSpecifier node. 34904f627f6SIlya Biryukov if (C->isFreeStanding()) { 35004f627f6SIlya Biryukov // Class is a declaration specifier and needs a spanning declaration node. 35104f627f6SIlya Biryukov Builder.foldNode(Builder.getRange(C), 35204f627f6SIlya Biryukov new (allocator()) syntax::SimpleDeclaration); 35304f627f6SIlya Biryukov return true; 35404f627f6SIlya Biryukov } 3559b3f38f9SIlya Biryukov return true; 3569b3f38f9SIlya Biryukov } 3579b3f38f9SIlya Biryukov 3589b3f38f9SIlya Biryukov bool WalkUpFromTranslationUnitDecl(TranslationUnitDecl *TU) { 3599b3f38f9SIlya Biryukov // (!) we do not want to call VisitDecl(), the declaration for translation 3609b3f38f9SIlya Biryukov // unit is built by finalize(). 3619b3f38f9SIlya Biryukov return true; 3629b3f38f9SIlya Biryukov } 3639b3f38f9SIlya Biryukov 3649b3f38f9SIlya Biryukov bool WalkUpFromCompoundStmt(CompoundStmt *S) { 36551dad419SIlya Biryukov using NodeRole = syntax::NodeRole; 3669b3f38f9SIlya Biryukov 367def65bb4SIlya Biryukov Builder.markChildToken(S->getLBracLoc(), NodeRole::OpenParen); 36858fa50f4SIlya Biryukov for (auto *Child : S->body()) 36958fa50f4SIlya Biryukov Builder.markStmtChild(Child, NodeRole::CompoundStatement_statement); 370def65bb4SIlya Biryukov Builder.markChildToken(S->getRBracLoc(), NodeRole::CloseParen); 3719b3f38f9SIlya Biryukov 37258fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 3739b3f38f9SIlya Biryukov new (allocator()) syntax::CompoundStatement); 3749b3f38f9SIlya Biryukov return true; 3759b3f38f9SIlya Biryukov } 3769b3f38f9SIlya Biryukov 37758fa50f4SIlya Biryukov // Some statements are not yet handled by syntax trees. 37858fa50f4SIlya Biryukov bool WalkUpFromStmt(Stmt *S) { 37958fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 38058fa50f4SIlya Biryukov new (allocator()) syntax::UnknownStatement); 38158fa50f4SIlya Biryukov return true; 38258fa50f4SIlya Biryukov } 38358fa50f4SIlya Biryukov 38458fa50f4SIlya Biryukov bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) { 38558fa50f4SIlya Biryukov // We override to traverse range initializer as VarDecl. 38658fa50f4SIlya Biryukov // RAV traverses it as a statement, we produce invalid node kinds in that 38758fa50f4SIlya Biryukov // case. 38858fa50f4SIlya Biryukov // FIXME: should do this in RAV instead? 38958fa50f4SIlya Biryukov if (S->getInit() && !TraverseStmt(S->getInit())) 39058fa50f4SIlya Biryukov return false; 39158fa50f4SIlya Biryukov if (S->getLoopVariable() && !TraverseDecl(S->getLoopVariable())) 39258fa50f4SIlya Biryukov return false; 39358fa50f4SIlya Biryukov if (S->getRangeInit() && !TraverseStmt(S->getRangeInit())) 39458fa50f4SIlya Biryukov return false; 39558fa50f4SIlya Biryukov if (S->getBody() && !TraverseStmt(S->getBody())) 39658fa50f4SIlya Biryukov return false; 39758fa50f4SIlya Biryukov return true; 39858fa50f4SIlya Biryukov } 39958fa50f4SIlya Biryukov 40058fa50f4SIlya Biryukov bool TraverseStmt(Stmt *S) { 401e702bdb8SIlya Biryukov if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) { 402e702bdb8SIlya Biryukov // We want to consume the semicolon, make sure SimpleDeclaration does not. 403e702bdb8SIlya Biryukov for (auto *D : DS->decls()) 404e702bdb8SIlya Biryukov Builder.noticeDeclaratorWithoutSemicolon(D); 405e702bdb8SIlya Biryukov } else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) { 40658fa50f4SIlya Biryukov // (!) do not recurse into subexpressions. 40758fa50f4SIlya Biryukov // we do not have syntax trees for expressions yet, so we only want to see 40858fa50f4SIlya Biryukov // the first top-level expression. 40958fa50f4SIlya Biryukov return WalkUpFromExpr(E->IgnoreImplicit()); 41058fa50f4SIlya Biryukov } 41158fa50f4SIlya Biryukov return RecursiveASTVisitor::TraverseStmt(S); 41258fa50f4SIlya Biryukov } 41358fa50f4SIlya Biryukov 41458fa50f4SIlya Biryukov // Some expressions are not yet handled by syntax trees. 41558fa50f4SIlya Biryukov bool WalkUpFromExpr(Expr *E) { 41658fa50f4SIlya Biryukov assert(!isImplicitExpr(E) && "should be handled by TraverseStmt"); 41758fa50f4SIlya Biryukov Builder.foldNode(Builder.getExprRange(E), 41858fa50f4SIlya Biryukov new (allocator()) syntax::UnknownExpression); 41958fa50f4SIlya Biryukov return true; 42058fa50f4SIlya Biryukov } 42158fa50f4SIlya Biryukov 422be14a22bSIlya Biryukov bool WalkUpFromNamespaceDecl(NamespaceDecl *S) { 423be14a22bSIlya Biryukov auto Tokens = Builder.getRange(S); 424be14a22bSIlya Biryukov if (Tokens.front().kind() == tok::coloncolon) { 425be14a22bSIlya Biryukov // Handle nested namespace definitions. Those start at '::' token, e.g. 426be14a22bSIlya Biryukov // namespace a^::b {} 427be14a22bSIlya Biryukov // FIXME: build corresponding nodes for the name of this namespace. 428be14a22bSIlya Biryukov return true; 429be14a22bSIlya Biryukov } 430be14a22bSIlya Biryukov Builder.foldNode(Tokens, new (allocator()) syntax::NamespaceDefinition); 431be14a22bSIlya Biryukov return true; 432be14a22bSIlya Biryukov } 433be14a22bSIlya Biryukov 43458fa50f4SIlya Biryukov // The code below is very regular, it could even be generated with some 43558fa50f4SIlya Biryukov // preprocessor magic. We merely assign roles to the corresponding children 43658fa50f4SIlya Biryukov // and fold resulting nodes. 43758fa50f4SIlya Biryukov bool WalkUpFromDeclStmt(DeclStmt *S) { 43858fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 43958fa50f4SIlya Biryukov new (allocator()) syntax::DeclarationStatement); 44058fa50f4SIlya Biryukov return true; 44158fa50f4SIlya Biryukov } 44258fa50f4SIlya Biryukov 44358fa50f4SIlya Biryukov bool WalkUpFromNullStmt(NullStmt *S) { 44458fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 44558fa50f4SIlya Biryukov new (allocator()) syntax::EmptyStatement); 44658fa50f4SIlya Biryukov return true; 44758fa50f4SIlya Biryukov } 44858fa50f4SIlya Biryukov 44958fa50f4SIlya Biryukov bool WalkUpFromSwitchStmt(SwitchStmt *S) { 450def65bb4SIlya Biryukov Builder.markChildToken(S->getSwitchLoc(), 45158fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 45258fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 45358fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 45458fa50f4SIlya Biryukov new (allocator()) syntax::SwitchStatement); 45558fa50f4SIlya Biryukov return true; 45658fa50f4SIlya Biryukov } 45758fa50f4SIlya Biryukov 45858fa50f4SIlya Biryukov bool WalkUpFromCaseStmt(CaseStmt *S) { 459def65bb4SIlya Biryukov Builder.markChildToken(S->getKeywordLoc(), 46058fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 46158fa50f4SIlya Biryukov Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseStatement_value); 46258fa50f4SIlya Biryukov Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 46358fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 46458fa50f4SIlya Biryukov new (allocator()) syntax::CaseStatement); 46558fa50f4SIlya Biryukov return true; 46658fa50f4SIlya Biryukov } 46758fa50f4SIlya Biryukov 46858fa50f4SIlya Biryukov bool WalkUpFromDefaultStmt(DefaultStmt *S) { 469def65bb4SIlya Biryukov Builder.markChildToken(S->getKeywordLoc(), 47058fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 47158fa50f4SIlya Biryukov Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 47258fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 47358fa50f4SIlya Biryukov new (allocator()) syntax::DefaultStatement); 47458fa50f4SIlya Biryukov return true; 47558fa50f4SIlya Biryukov } 47658fa50f4SIlya Biryukov 47758fa50f4SIlya Biryukov bool WalkUpFromIfStmt(IfStmt *S) { 478def65bb4SIlya Biryukov Builder.markChildToken(S->getIfLoc(), syntax::NodeRole::IntroducerKeyword); 47958fa50f4SIlya Biryukov Builder.markStmtChild(S->getThen(), 48058fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_thenStatement); 481def65bb4SIlya Biryukov Builder.markChildToken(S->getElseLoc(), 48258fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_elseKeyword); 48358fa50f4SIlya Biryukov Builder.markStmtChild(S->getElse(), 48458fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_elseStatement); 48558fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 48658fa50f4SIlya Biryukov new (allocator()) syntax::IfStatement); 48758fa50f4SIlya Biryukov return true; 48858fa50f4SIlya Biryukov } 48958fa50f4SIlya Biryukov 49058fa50f4SIlya Biryukov bool WalkUpFromForStmt(ForStmt *S) { 491def65bb4SIlya Biryukov Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); 49258fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 49358fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 49458fa50f4SIlya Biryukov new (allocator()) syntax::ForStatement); 49558fa50f4SIlya Biryukov return true; 49658fa50f4SIlya Biryukov } 49758fa50f4SIlya Biryukov 49858fa50f4SIlya Biryukov bool WalkUpFromWhileStmt(WhileStmt *S) { 499def65bb4SIlya Biryukov Builder.markChildToken(S->getWhileLoc(), 50058fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 50158fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 50258fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 50358fa50f4SIlya Biryukov new (allocator()) syntax::WhileStatement); 50458fa50f4SIlya Biryukov return true; 50558fa50f4SIlya Biryukov } 50658fa50f4SIlya Biryukov 50758fa50f4SIlya Biryukov bool WalkUpFromContinueStmt(ContinueStmt *S) { 508def65bb4SIlya Biryukov Builder.markChildToken(S->getContinueLoc(), 50958fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 51058fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 51158fa50f4SIlya Biryukov new (allocator()) syntax::ContinueStatement); 51258fa50f4SIlya Biryukov return true; 51358fa50f4SIlya Biryukov } 51458fa50f4SIlya Biryukov 51558fa50f4SIlya Biryukov bool WalkUpFromBreakStmt(BreakStmt *S) { 516def65bb4SIlya Biryukov Builder.markChildToken(S->getBreakLoc(), 51758fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 51858fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 51958fa50f4SIlya Biryukov new (allocator()) syntax::BreakStatement); 52058fa50f4SIlya Biryukov return true; 52158fa50f4SIlya Biryukov } 52258fa50f4SIlya Biryukov 52358fa50f4SIlya Biryukov bool WalkUpFromReturnStmt(ReturnStmt *S) { 524def65bb4SIlya Biryukov Builder.markChildToken(S->getReturnLoc(), 52558fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 52658fa50f4SIlya Biryukov Builder.markExprChild(S->getRetValue(), 52758fa50f4SIlya Biryukov syntax::NodeRole::ReturnStatement_value); 52858fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 52958fa50f4SIlya Biryukov new (allocator()) syntax::ReturnStatement); 53058fa50f4SIlya Biryukov return true; 53158fa50f4SIlya Biryukov } 53258fa50f4SIlya Biryukov 53358fa50f4SIlya Biryukov bool WalkUpFromCXXForRangeStmt(CXXForRangeStmt *S) { 534def65bb4SIlya Biryukov Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); 53558fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 53658fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 53758fa50f4SIlya Biryukov new (allocator()) syntax::RangeBasedForStatement); 53858fa50f4SIlya Biryukov return true; 53958fa50f4SIlya Biryukov } 54058fa50f4SIlya Biryukov 541be14a22bSIlya Biryukov bool WalkUpFromEmptyDecl(EmptyDecl *S) { 542be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 543be14a22bSIlya Biryukov new (allocator()) syntax::EmptyDeclaration); 544be14a22bSIlya Biryukov return true; 545be14a22bSIlya Biryukov } 546be14a22bSIlya Biryukov 547be14a22bSIlya Biryukov bool WalkUpFromStaticAssertDecl(StaticAssertDecl *S) { 548be14a22bSIlya Biryukov Builder.markExprChild(S->getAssertExpr(), 549be14a22bSIlya Biryukov syntax::NodeRole::StaticAssertDeclaration_condition); 550be14a22bSIlya Biryukov Builder.markExprChild(S->getMessage(), 551be14a22bSIlya Biryukov syntax::NodeRole::StaticAssertDeclaration_message); 552be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 553be14a22bSIlya Biryukov new (allocator()) syntax::StaticAssertDeclaration); 554be14a22bSIlya Biryukov return true; 555be14a22bSIlya Biryukov } 556be14a22bSIlya Biryukov 557be14a22bSIlya Biryukov bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) { 558be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 559be14a22bSIlya Biryukov new (allocator()) syntax::LinkageSpecificationDeclaration); 560be14a22bSIlya Biryukov return true; 561be14a22bSIlya Biryukov } 562be14a22bSIlya Biryukov 563be14a22bSIlya Biryukov bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) { 564be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 565be14a22bSIlya Biryukov new (allocator()) syntax::NamespaceAliasDefinition); 566be14a22bSIlya Biryukov return true; 567be14a22bSIlya Biryukov } 568be14a22bSIlya Biryukov 569be14a22bSIlya Biryukov bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) { 570be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 571be14a22bSIlya Biryukov new (allocator()) syntax::UsingNamespaceDirective); 572be14a22bSIlya Biryukov return true; 573be14a22bSIlya Biryukov } 574be14a22bSIlya Biryukov 575be14a22bSIlya Biryukov bool WalkUpFromUsingDecl(UsingDecl *S) { 576be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 577be14a22bSIlya Biryukov new (allocator()) syntax::UsingDeclaration); 578be14a22bSIlya Biryukov return true; 579be14a22bSIlya Biryukov } 580be14a22bSIlya Biryukov 581be14a22bSIlya Biryukov bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) { 582be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 583be14a22bSIlya Biryukov new (allocator()) syntax::UsingDeclaration); 584be14a22bSIlya Biryukov return true; 585be14a22bSIlya Biryukov } 586be14a22bSIlya Biryukov 587be14a22bSIlya Biryukov bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) { 588be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 589be14a22bSIlya Biryukov new (allocator()) syntax::UsingDeclaration); 590be14a22bSIlya Biryukov return true; 591be14a22bSIlya Biryukov } 592be14a22bSIlya Biryukov 593be14a22bSIlya Biryukov bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) { 594be14a22bSIlya Biryukov Builder.foldNode(Builder.getRange(S), 595be14a22bSIlya Biryukov new (allocator()) syntax::TypeAliasDeclaration); 596be14a22bSIlya Biryukov return true; 597be14a22bSIlya Biryukov } 598be14a22bSIlya Biryukov 5999b3f38f9SIlya Biryukov private: 6009b3f38f9SIlya Biryukov /// A small helper to save some typing. 6019b3f38f9SIlya Biryukov llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); } 6029b3f38f9SIlya Biryukov 6039b3f38f9SIlya Biryukov syntax::TreeBuilder &Builder; 6049b3f38f9SIlya Biryukov const LangOptions &LangOpts; 6059b3f38f9SIlya Biryukov }; 6069b3f38f9SIlya Biryukov } // namespace 6079b3f38f9SIlya Biryukov 6089b3f38f9SIlya Biryukov void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range, 6099b3f38f9SIlya Biryukov syntax::Tree *New) { 6101ad15046SIlya Biryukov Pending.foldChildren(Arena, Range, New); 6119b3f38f9SIlya Biryukov } 6129b3f38f9SIlya Biryukov 613e702bdb8SIlya Biryukov void syntax::TreeBuilder::noticeDeclaratorRange( 614e702bdb8SIlya Biryukov llvm::ArrayRef<syntax::Token> Range) { 615e702bdb8SIlya Biryukov if (Pending.extendDelayedFold(Range)) 616e702bdb8SIlya Biryukov return; 617e702bdb8SIlya Biryukov Pending.foldChildrenDelayed(Range, 618e702bdb8SIlya Biryukov new (allocator()) syntax::SimpleDeclaration); 619e702bdb8SIlya Biryukov } 620e702bdb8SIlya Biryukov 621e702bdb8SIlya Biryukov void syntax::TreeBuilder::noticeDeclaratorWithoutSemicolon(Decl *D) { 622e702bdb8SIlya Biryukov DeclsWithoutSemicolons.insert(D); 623e702bdb8SIlya Biryukov } 624e702bdb8SIlya Biryukov 625def65bb4SIlya Biryukov void syntax::TreeBuilder::markChildToken(SourceLocation Loc, NodeRole Role) { 6269b3f38f9SIlya Biryukov if (Loc.isInvalid()) 6279b3f38f9SIlya Biryukov return; 6289b3f38f9SIlya Biryukov Pending.assignRole(*findToken(Loc), Role); 6299b3f38f9SIlya Biryukov } 6309b3f38f9SIlya Biryukov 63158fa50f4SIlya Biryukov void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { 63258fa50f4SIlya Biryukov if (!Child) 63358fa50f4SIlya Biryukov return; 63458fa50f4SIlya Biryukov 63558fa50f4SIlya Biryukov auto Range = getStmtRange(Child); 63658fa50f4SIlya Biryukov // This is an expression in a statement position, consume the trailing 63758fa50f4SIlya Biryukov // semicolon and form an 'ExpressionStatement' node. 63858fa50f4SIlya Biryukov if (auto *E = dyn_cast<Expr>(Child)) { 63958fa50f4SIlya Biryukov Pending.assignRole(getExprRange(E), 64058fa50f4SIlya Biryukov NodeRole::ExpressionStatement_expression); 64158fa50f4SIlya Biryukov // (!) 'getRange(Stmt)' ensures this already covers a trailing semicolon. 6421ad15046SIlya Biryukov Pending.foldChildren(Arena, Range, 6431ad15046SIlya Biryukov new (allocator()) syntax::ExpressionStatement); 64458fa50f4SIlya Biryukov } 64558fa50f4SIlya Biryukov Pending.assignRole(Range, Role); 64658fa50f4SIlya Biryukov } 64758fa50f4SIlya Biryukov 64858fa50f4SIlya Biryukov void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) { 649be14a22bSIlya Biryukov if (!Child) 650be14a22bSIlya Biryukov return; 651be14a22bSIlya Biryukov 65258fa50f4SIlya Biryukov Pending.assignRole(getExprRange(Child), Role); 65358fa50f4SIlya Biryukov } 65458fa50f4SIlya Biryukov 6559b3f38f9SIlya Biryukov const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const { 656c1bbefefSIlya Biryukov auto It = LocationToToken.find(L.getRawEncoding()); 657c1bbefefSIlya Biryukov assert(It != LocationToToken.end()); 658c1bbefefSIlya Biryukov return It->second; 6599b3f38f9SIlya Biryukov } 6609b3f38f9SIlya Biryukov 6619b3f38f9SIlya Biryukov syntax::TranslationUnit * 6629b3f38f9SIlya Biryukov syntax::buildSyntaxTree(Arena &A, const TranslationUnitDecl &TU) { 6639b3f38f9SIlya Biryukov TreeBuilder Builder(A); 6649b3f38f9SIlya Biryukov BuildTreeVisitor(TU.getASTContext(), Builder).TraverseAST(TU.getASTContext()); 6659b3f38f9SIlya Biryukov return std::move(Builder).finalize(); 6669b3f38f9SIlya Biryukov } 667