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" 97d382dcdSMarcel Hlopko #include "clang/AST/ASTFwd.h" 10e702bdb8SIlya Biryukov #include "clang/AST/Decl.h" 11e702bdb8SIlya Biryukov #include "clang/AST/DeclBase.h" 127d382dcdSMarcel Hlopko #include "clang/AST/DeclCXX.h" 137d382dcdSMarcel Hlopko #include "clang/AST/DeclarationName.h" 149b3f38f9SIlya Biryukov #include "clang/AST/RecursiveASTVisitor.h" 159b3f38f9SIlya Biryukov #include "clang/AST/Stmt.h" 167d382dcdSMarcel Hlopko #include "clang/AST/TypeLoc.h" 177d382dcdSMarcel Hlopko #include "clang/AST/TypeLocVisitor.h" 189b3f38f9SIlya Biryukov #include "clang/Basic/LLVM.h" 199b3f38f9SIlya Biryukov #include "clang/Basic/SourceLocation.h" 209b3f38f9SIlya Biryukov #include "clang/Basic/SourceManager.h" 21*88bf9b3dSMarcel Hlopko #include "clang/Basic/Specifiers.h" 229b3f38f9SIlya Biryukov #include "clang/Basic/TokenKinds.h" 239b3f38f9SIlya Biryukov #include "clang/Lex/Lexer.h" 249b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Nodes.h" 259b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Tokens.h" 269b3f38f9SIlya Biryukov #include "clang/Tooling/Syntax/Tree.h" 279b3f38f9SIlya Biryukov #include "llvm/ADT/ArrayRef.h" 289b3f38f9SIlya Biryukov #include "llvm/ADT/STLExtras.h" 297d382dcdSMarcel Hlopko #include "llvm/ADT/ScopeExit.h" 309b3f38f9SIlya Biryukov #include "llvm/ADT/SmallVector.h" 319b3f38f9SIlya Biryukov #include "llvm/Support/Allocator.h" 329b3f38f9SIlya Biryukov #include "llvm/Support/Casting.h" 3396065cf7SIlya Biryukov #include "llvm/Support/Compiler.h" 349b3f38f9SIlya Biryukov #include "llvm/Support/FormatVariadic.h" 351ad15046SIlya Biryukov #include "llvm/Support/MemoryBuffer.h" 369b3f38f9SIlya Biryukov #include "llvm/Support/raw_ostream.h" 379b3f38f9SIlya Biryukov #include <map> 389b3f38f9SIlya Biryukov 399b3f38f9SIlya Biryukov using namespace clang; 409b3f38f9SIlya Biryukov 4196065cf7SIlya Biryukov LLVM_ATTRIBUTE_UNUSED 4258fa50f4SIlya Biryukov static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; } 4358fa50f4SIlya Biryukov 447d382dcdSMarcel Hlopko static SourceLocation getQualifiedNameStart(DeclaratorDecl *D) { 457d382dcdSMarcel Hlopko auto DN = D->getDeclName(); 467d382dcdSMarcel Hlopko bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo(); 477d382dcdSMarcel Hlopko if (IsAnonymous) 487d382dcdSMarcel Hlopko return SourceLocation(); 497d382dcdSMarcel Hlopko return D->getQualifierLoc() ? D->getQualifierLoc().getBeginLoc() 507d382dcdSMarcel Hlopko : D->getLocation(); 517d382dcdSMarcel Hlopko } 527d382dcdSMarcel Hlopko 537d382dcdSMarcel Hlopko namespace { 547d382dcdSMarcel Hlopko /// Get start location of the Declarator from the TypeLoc. 557d382dcdSMarcel Hlopko /// E.g.: 567d382dcdSMarcel Hlopko /// loc of `(` in `int (a)` 577d382dcdSMarcel Hlopko /// loc of `*` in `int *(a)` 587d382dcdSMarcel Hlopko /// loc of the first `(` in `int (*a)(int)` 597d382dcdSMarcel Hlopko /// loc of the `*` in `int *(a)(int)` 607d382dcdSMarcel Hlopko /// loc of the first `*` in `const int *const *volatile a;` 617d382dcdSMarcel Hlopko /// 627d382dcdSMarcel Hlopko /// It is non-trivial to get the start location because TypeLocs are stored 637d382dcdSMarcel Hlopko /// inside out. In the example above `*volatile` is the TypeLoc returned 647d382dcdSMarcel Hlopko /// by `Decl.getTypeSourceInfo()`, and `*const` is what `.getPointeeLoc()` 657d382dcdSMarcel Hlopko /// returns. 667d382dcdSMarcel Hlopko struct GetStartLoc : TypeLocVisitor<GetStartLoc, SourceLocation> { 677d382dcdSMarcel Hlopko SourceLocation VisitParenTypeLoc(ParenTypeLoc T) { 687d382dcdSMarcel Hlopko auto L = Visit(T.getInnerLoc()); 697d382dcdSMarcel Hlopko if (L.isValid()) 707d382dcdSMarcel Hlopko return L; 717d382dcdSMarcel Hlopko return T.getLParenLoc(); 727d382dcdSMarcel Hlopko } 737d382dcdSMarcel Hlopko 747d382dcdSMarcel Hlopko // Types spelled in the prefix part of the declarator. 757d382dcdSMarcel Hlopko SourceLocation VisitPointerTypeLoc(PointerTypeLoc T) { 767d382dcdSMarcel Hlopko return HandlePointer(T); 777d382dcdSMarcel Hlopko } 787d382dcdSMarcel Hlopko 797d382dcdSMarcel Hlopko SourceLocation VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) { 807d382dcdSMarcel Hlopko return HandlePointer(T); 817d382dcdSMarcel Hlopko } 827d382dcdSMarcel Hlopko 837d382dcdSMarcel Hlopko SourceLocation VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) { 847d382dcdSMarcel Hlopko return HandlePointer(T); 857d382dcdSMarcel Hlopko } 867d382dcdSMarcel Hlopko 877d382dcdSMarcel Hlopko SourceLocation VisitReferenceTypeLoc(ReferenceTypeLoc T) { 887d382dcdSMarcel Hlopko return HandlePointer(T); 897d382dcdSMarcel Hlopko } 907d382dcdSMarcel Hlopko 917d382dcdSMarcel Hlopko SourceLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc T) { 927d382dcdSMarcel Hlopko return HandlePointer(T); 937d382dcdSMarcel Hlopko } 947d382dcdSMarcel Hlopko 957d382dcdSMarcel Hlopko // All other cases are not important, as they are either part of declaration 967d382dcdSMarcel Hlopko // specifiers (e.g. inheritors of TypeSpecTypeLoc) or introduce modifiers on 977d382dcdSMarcel Hlopko // existing declarators (e.g. QualifiedTypeLoc). They cannot start the 987d382dcdSMarcel Hlopko // declarator themselves, but their underlying type can. 997d382dcdSMarcel Hlopko SourceLocation VisitTypeLoc(TypeLoc T) { 1007d382dcdSMarcel Hlopko auto N = T.getNextTypeLoc(); 1017d382dcdSMarcel Hlopko if (!N) 1027d382dcdSMarcel Hlopko return SourceLocation(); 1037d382dcdSMarcel Hlopko return Visit(N); 1047d382dcdSMarcel Hlopko } 1057d382dcdSMarcel Hlopko 1067d382dcdSMarcel Hlopko SourceLocation VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc T) { 1077d382dcdSMarcel Hlopko if (T.getTypePtr()->hasTrailingReturn()) 1087d382dcdSMarcel Hlopko return SourceLocation(); // avoid recursing into the suffix of declarator. 1097d382dcdSMarcel Hlopko return VisitTypeLoc(T); 1107d382dcdSMarcel Hlopko } 1117d382dcdSMarcel Hlopko 1127d382dcdSMarcel Hlopko private: 1137d382dcdSMarcel Hlopko template <class PtrLoc> SourceLocation HandlePointer(PtrLoc T) { 1147d382dcdSMarcel Hlopko auto L = Visit(T.getPointeeLoc()); 1157d382dcdSMarcel Hlopko if (L.isValid()) 1167d382dcdSMarcel Hlopko return L; 1177d382dcdSMarcel Hlopko return T.getLocalSourceRange().getBegin(); 1187d382dcdSMarcel Hlopko } 1197d382dcdSMarcel Hlopko }; 1207d382dcdSMarcel Hlopko } // namespace 1217d382dcdSMarcel Hlopko 1227d382dcdSMarcel Hlopko /// Gets the range of declarator as defined by the C++ grammar. E.g. 1237d382dcdSMarcel Hlopko /// `int a;` -> range of `a`, 1247d382dcdSMarcel Hlopko /// `int *a;` -> range of `*a`, 1257d382dcdSMarcel Hlopko /// `int a[10];` -> range of `a[10]`, 1267d382dcdSMarcel Hlopko /// `int a[1][2][3];` -> range of `a[1][2][3]`, 1277d382dcdSMarcel Hlopko /// `int *a = nullptr` -> range of `*a = nullptr`. 1287d382dcdSMarcel Hlopko /// FIMXE: \p Name must be a source range, e.g. for `operator+`. 1297d382dcdSMarcel Hlopko static SourceRange getDeclaratorRange(const SourceManager &SM, TypeLoc T, 1307d382dcdSMarcel Hlopko SourceLocation Name, 1317d382dcdSMarcel Hlopko SourceRange Initializer) { 1327d382dcdSMarcel Hlopko SourceLocation Start = GetStartLoc().Visit(T); 1337d382dcdSMarcel Hlopko SourceLocation End = T.getSourceRange().getEnd(); 1347d382dcdSMarcel Hlopko assert(End.isValid()); 1357d382dcdSMarcel Hlopko if (Name.isValid()) { 1367d382dcdSMarcel Hlopko if (Start.isInvalid()) 1377d382dcdSMarcel Hlopko Start = Name; 1387d382dcdSMarcel Hlopko if (SM.isBeforeInTranslationUnit(End, Name)) 1397d382dcdSMarcel Hlopko End = Name; 1407d382dcdSMarcel Hlopko } 1417d382dcdSMarcel Hlopko if (Initializer.isValid()) { 1427d382dcdSMarcel Hlopko assert(SM.isBeforeInTranslationUnit(End, Initializer.getEnd())); 1437d382dcdSMarcel Hlopko End = Initializer.getEnd(); 1447d382dcdSMarcel Hlopko } 1457d382dcdSMarcel Hlopko return SourceRange(Start, End); 1467d382dcdSMarcel Hlopko } 1477d382dcdSMarcel Hlopko 1489b3f38f9SIlya Biryukov /// A helper class for constructing the syntax tree while traversing a clang 1499b3f38f9SIlya Biryukov /// AST. 1509b3f38f9SIlya Biryukov /// 1519b3f38f9SIlya Biryukov /// At each point of the traversal we maintain a list of pending nodes. 1529b3f38f9SIlya Biryukov /// Initially all tokens are added as pending nodes. When processing a clang AST 1539b3f38f9SIlya Biryukov /// node, the clients need to: 1549b3f38f9SIlya Biryukov /// - create a corresponding syntax node, 1559b3f38f9SIlya Biryukov /// - assign roles to all pending child nodes with 'markChild' and 1569b3f38f9SIlya Biryukov /// 'markChildToken', 1579b3f38f9SIlya Biryukov /// - replace the child nodes with the new syntax node in the pending list 1589b3f38f9SIlya Biryukov /// with 'foldNode'. 1599b3f38f9SIlya Biryukov /// 1609b3f38f9SIlya Biryukov /// Note that all children are expected to be processed when building a node. 1619b3f38f9SIlya Biryukov /// 1629b3f38f9SIlya Biryukov /// Call finalize() to finish building the tree and consume the root node. 1639b3f38f9SIlya Biryukov class syntax::TreeBuilder { 1649b3f38f9SIlya Biryukov public: 165c1bbefefSIlya Biryukov TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) { 166c1bbefefSIlya Biryukov for (const auto &T : Arena.tokenBuffer().expandedTokens()) 167c1bbefefSIlya Biryukov LocationToToken.insert({T.location().getRawEncoding(), &T}); 168c1bbefefSIlya Biryukov } 1699b3f38f9SIlya Biryukov 1709b3f38f9SIlya Biryukov llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); } 1717d382dcdSMarcel Hlopko const SourceManager &sourceManager() const { return Arena.sourceManager(); } 1729b3f38f9SIlya Biryukov 1739b3f38f9SIlya Biryukov /// Populate children for \p New node, assuming it covers tokens from \p 1749b3f38f9SIlya Biryukov /// Range. 1759b3f38f9SIlya Biryukov void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New); 1769b3f38f9SIlya Biryukov 177e702bdb8SIlya Biryukov /// Must be called with the range of each `DeclaratorDecl`. Ensures the 178e702bdb8SIlya Biryukov /// corresponding declarator nodes are covered by `SimpleDeclaration`. 1797d382dcdSMarcel Hlopko void noticeDeclRange(llvm::ArrayRef<syntax::Token> Range); 180e702bdb8SIlya Biryukov 181e702bdb8SIlya Biryukov /// Notifies that we should not consume trailing semicolon when computing 182e702bdb8SIlya Biryukov /// token range of \p D. 1837d382dcdSMarcel Hlopko void noticeDeclWithoutSemicolon(Decl *D); 184e702bdb8SIlya Biryukov 18558fa50f4SIlya Biryukov /// Mark the \p Child node with a corresponding \p Role. All marked children 18658fa50f4SIlya Biryukov /// should be consumed by foldNode. 1877d382dcdSMarcel Hlopko /// When called on expressions (clang::Expr is derived from clang::Stmt), 18858fa50f4SIlya Biryukov /// wraps expressions into expression statement. 18958fa50f4SIlya Biryukov void markStmtChild(Stmt *Child, NodeRole Role); 19058fa50f4SIlya Biryukov /// Should be called for expressions in non-statement position to avoid 19158fa50f4SIlya Biryukov /// wrapping into expression statement. 19258fa50f4SIlya Biryukov void markExprChild(Expr *Child, NodeRole Role); 1939b3f38f9SIlya Biryukov /// Set role for a token starting at \p Loc. 194def65bb4SIlya Biryukov void markChildToken(SourceLocation Loc, NodeRole R); 1957d382dcdSMarcel Hlopko /// Set role for \p T. 1967d382dcdSMarcel Hlopko void markChildToken(const syntax::Token *T, NodeRole R); 1977d382dcdSMarcel Hlopko 1987d382dcdSMarcel Hlopko /// Set role for the node that spans exactly \p Range. 1997d382dcdSMarcel Hlopko void markChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R); 2007d382dcdSMarcel Hlopko /// Set role for the delayed node that spans exactly \p Range. 2017d382dcdSMarcel Hlopko void markDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R); 202*88bf9b3dSMarcel Hlopko /// Set role for the node that may or may not be delayed. Node must span 203*88bf9b3dSMarcel Hlopko /// exactly \p Range. 204*88bf9b3dSMarcel Hlopko void markMaybeDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R); 2059b3f38f9SIlya Biryukov 2069b3f38f9SIlya Biryukov /// Finish building the tree and consume the root node. 2079b3f38f9SIlya Biryukov syntax::TranslationUnit *finalize() && { 2089b3f38f9SIlya Biryukov auto Tokens = Arena.tokenBuffer().expandedTokens(); 209bfbf6b6cSIlya Biryukov assert(!Tokens.empty()); 210bfbf6b6cSIlya Biryukov assert(Tokens.back().kind() == tok::eof); 211bfbf6b6cSIlya Biryukov 2129b3f38f9SIlya Biryukov // Build the root of the tree, consuming all the children. 2131ad15046SIlya Biryukov Pending.foldChildren(Arena, Tokens.drop_back(), 2149b3f38f9SIlya Biryukov new (Arena.allocator()) syntax::TranslationUnit); 2159b3f38f9SIlya Biryukov 2163b929fe7SIlya Biryukov auto *TU = cast<syntax::TranslationUnit>(std::move(Pending).finalize()); 2173b929fe7SIlya Biryukov TU->assertInvariantsRecursive(); 2183b929fe7SIlya Biryukov return TU; 2199b3f38f9SIlya Biryukov } 2209b3f38f9SIlya Biryukov 221*88bf9b3dSMarcel Hlopko /// Finds a token starting at \p L. The token must exist if \p L is valid. 222*88bf9b3dSMarcel Hlopko const syntax::Token *findToken(SourceLocation L) const; 223*88bf9b3dSMarcel Hlopko 2249b3f38f9SIlya Biryukov /// getRange() finds the syntax tokens corresponding to the passed source 2259b3f38f9SIlya Biryukov /// locations. 2269b3f38f9SIlya Biryukov /// \p First is the start position of the first token and \p Last is the start 2279b3f38f9SIlya Biryukov /// position of the last token. 2289b3f38f9SIlya Biryukov llvm::ArrayRef<syntax::Token> getRange(SourceLocation First, 2299b3f38f9SIlya Biryukov SourceLocation Last) const { 2309b3f38f9SIlya Biryukov assert(First.isValid()); 2319b3f38f9SIlya Biryukov assert(Last.isValid()); 2329b3f38f9SIlya Biryukov assert(First == Last || 2339b3f38f9SIlya Biryukov Arena.sourceManager().isBeforeInTranslationUnit(First, Last)); 2349b3f38f9SIlya Biryukov return llvm::makeArrayRef(findToken(First), std::next(findToken(Last))); 2359b3f38f9SIlya Biryukov } 236*88bf9b3dSMarcel Hlopko 237*88bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> 238*88bf9b3dSMarcel Hlopko getTemplateRange(const ClassTemplateSpecializationDecl *D) const { 239*88bf9b3dSMarcel Hlopko auto R = D->getSourceRange(); 240*88bf9b3dSMarcel Hlopko auto Tokens = getRange(R.getBegin(), R.getEnd()); 241*88bf9b3dSMarcel Hlopko return maybeAppendSemicolon(Tokens, D); 242*88bf9b3dSMarcel Hlopko } 243*88bf9b3dSMarcel Hlopko 244*88bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> getDeclRange(const Decl *D) const { 245*88bf9b3dSMarcel Hlopko llvm::ArrayRef<clang::syntax::Token> Tokens; 246*88bf9b3dSMarcel Hlopko // We want to drop the template parameters for specializations. 247*88bf9b3dSMarcel Hlopko if (const auto *S = llvm::dyn_cast<TagDecl>(D)) 248*88bf9b3dSMarcel Hlopko Tokens = getRange(S->TypeDecl::getBeginLoc(), S->getEndLoc()); 249*88bf9b3dSMarcel Hlopko else 250*88bf9b3dSMarcel Hlopko Tokens = getRange(D->getBeginLoc(), D->getEndLoc()); 251*88bf9b3dSMarcel Hlopko return maybeAppendSemicolon(Tokens, D); 2529b3f38f9SIlya Biryukov } 25358fa50f4SIlya Biryukov llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const { 25458fa50f4SIlya Biryukov return getRange(E->getBeginLoc(), E->getEndLoc()); 25558fa50f4SIlya Biryukov } 25658fa50f4SIlya Biryukov /// Find the adjusted range for the statement, consuming the trailing 25758fa50f4SIlya Biryukov /// semicolon when needed. 25858fa50f4SIlya Biryukov llvm::ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const { 25958fa50f4SIlya Biryukov auto Tokens = getRange(S->getBeginLoc(), S->getEndLoc()); 26058fa50f4SIlya Biryukov if (isa<CompoundStmt>(S)) 26158fa50f4SIlya Biryukov return Tokens; 26258fa50f4SIlya Biryukov 26358fa50f4SIlya Biryukov // Some statements miss a trailing semicolon, e.g. 'return', 'continue' and 26458fa50f4SIlya Biryukov // all statements that end with those. Consume this semicolon here. 265e702bdb8SIlya Biryukov if (Tokens.back().kind() == tok::semi) 266e702bdb8SIlya Biryukov return Tokens; 267e702bdb8SIlya Biryukov return withTrailingSemicolon(Tokens); 268e702bdb8SIlya Biryukov } 269e702bdb8SIlya Biryukov 270e702bdb8SIlya Biryukov private: 271e702bdb8SIlya Biryukov llvm::ArrayRef<syntax::Token> 272*88bf9b3dSMarcel Hlopko maybeAppendSemicolon(llvm::ArrayRef<syntax::Token> Tokens, 273*88bf9b3dSMarcel Hlopko const Decl *D) const { 274*88bf9b3dSMarcel Hlopko if (llvm::isa<NamespaceDecl>(D)) 275*88bf9b3dSMarcel Hlopko return Tokens; 276*88bf9b3dSMarcel Hlopko if (DeclsWithoutSemicolons.count(D)) 277*88bf9b3dSMarcel Hlopko return Tokens; 278*88bf9b3dSMarcel Hlopko // FIXME: do not consume trailing semicolon on function definitions. 279*88bf9b3dSMarcel Hlopko // Most declarations own a semicolon in syntax trees, but not in clang AST. 280*88bf9b3dSMarcel Hlopko return withTrailingSemicolon(Tokens); 281*88bf9b3dSMarcel Hlopko } 282*88bf9b3dSMarcel Hlopko 283*88bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> 284e702bdb8SIlya Biryukov withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const { 285e702bdb8SIlya Biryukov assert(!Tokens.empty()); 286e702bdb8SIlya Biryukov assert(Tokens.back().kind() != tok::eof); 2877d382dcdSMarcel Hlopko // We never consume 'eof', so looking at the next token is ok. 28858fa50f4SIlya Biryukov if (Tokens.back().kind() != tok::semi && Tokens.end()->kind() == tok::semi) 28958fa50f4SIlya Biryukov return llvm::makeArrayRef(Tokens.begin(), Tokens.end() + 1); 29058fa50f4SIlya Biryukov return Tokens; 2919b3f38f9SIlya Biryukov } 2929b3f38f9SIlya Biryukov 2939b3f38f9SIlya Biryukov /// A collection of trees covering the input tokens. 2949b3f38f9SIlya Biryukov /// When created, each tree corresponds to a single token in the file. 2959b3f38f9SIlya Biryukov /// Clients call 'foldChildren' to attach one or more subtrees to a parent 2969b3f38f9SIlya Biryukov /// node and update the list of trees accordingly. 2979b3f38f9SIlya Biryukov /// 2989b3f38f9SIlya Biryukov /// Ensures that added nodes properly nest and cover the whole token stream. 2999b3f38f9SIlya Biryukov struct Forest { 3009b3f38f9SIlya Biryukov Forest(syntax::Arena &A) { 301bfbf6b6cSIlya Biryukov assert(!A.tokenBuffer().expandedTokens().empty()); 302bfbf6b6cSIlya Biryukov assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof); 3039b3f38f9SIlya Biryukov // Create all leaf nodes. 304bfbf6b6cSIlya Biryukov // Note that we do not have 'eof' in the tree. 3051ad15046SIlya Biryukov for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) { 3061ad15046SIlya Biryukov auto *L = new (A.allocator()) syntax::Leaf(&T); 3071ad15046SIlya Biryukov L->Original = true; 3081ad15046SIlya Biryukov L->CanModify = A.tokenBuffer().spelledForExpanded(T).hasValue(); 3091ad15046SIlya Biryukov Trees.insert(Trees.end(), {&T, NodeAndRole{L}}); 3101ad15046SIlya Biryukov } 3119b3f38f9SIlya Biryukov } 3129b3f38f9SIlya Biryukov 313e702bdb8SIlya Biryukov ~Forest() { assert(DelayedFolds.empty()); } 314e702bdb8SIlya Biryukov 3157d382dcdSMarcel Hlopko void assignRoleDelayed(llvm::ArrayRef<syntax::Token> Range, 3167d382dcdSMarcel Hlopko syntax::NodeRole Role) { 3177d382dcdSMarcel Hlopko auto It = DelayedFolds.find(Range.begin()); 3187d382dcdSMarcel Hlopko assert(It != DelayedFolds.end()); 3197d382dcdSMarcel Hlopko assert(It->second.End == Range.end()); 3207d382dcdSMarcel Hlopko It->second.Role = Role; 3217d382dcdSMarcel Hlopko } 3227d382dcdSMarcel Hlopko 323*88bf9b3dSMarcel Hlopko void assignRoleMaybeDelayed(llvm::ArrayRef<syntax::Token> Range, 324*88bf9b3dSMarcel Hlopko syntax::NodeRole Role) { 325*88bf9b3dSMarcel Hlopko auto It = DelayedFolds.find(Range.begin()); 326*88bf9b3dSMarcel Hlopko if (It == DelayedFolds.end()) 327*88bf9b3dSMarcel Hlopko return assignRole(Range, Role); 328*88bf9b3dSMarcel Hlopko assert(It->second.End == Range.end()); 329*88bf9b3dSMarcel Hlopko It->second.Role = Role; 330*88bf9b3dSMarcel Hlopko } 331*88bf9b3dSMarcel Hlopko 3329b3f38f9SIlya Biryukov void assignRole(llvm::ArrayRef<syntax::Token> Range, 3339b3f38f9SIlya Biryukov syntax::NodeRole Role) { 3349b3f38f9SIlya Biryukov assert(!Range.empty()); 3359b3f38f9SIlya Biryukov auto It = Trees.lower_bound(Range.begin()); 3369b3f38f9SIlya Biryukov assert(It != Trees.end() && "no node found"); 3379b3f38f9SIlya Biryukov assert(It->first == Range.begin() && "no child with the specified range"); 3389b3f38f9SIlya Biryukov assert((std::next(It) == Trees.end() || 3399b3f38f9SIlya Biryukov std::next(It)->first == Range.end()) && 3409b3f38f9SIlya Biryukov "no child with the specified range"); 3419b3f38f9SIlya Biryukov It->second.Role = Role; 3429b3f38f9SIlya Biryukov } 3439b3f38f9SIlya Biryukov 344e702bdb8SIlya Biryukov /// Add \p Node to the forest and attach child nodes based on \p Tokens. 3451ad15046SIlya Biryukov void foldChildren(const syntax::Arena &A, 3461ad15046SIlya Biryukov llvm::ArrayRef<syntax::Token> Tokens, 3479b3f38f9SIlya Biryukov syntax::Tree *Node) { 348e702bdb8SIlya Biryukov // Execute delayed folds inside `Tokens`. 3497d382dcdSMarcel Hlopko auto BeginFolds = DelayedFolds.lower_bound(Tokens.begin()); 3507d382dcdSMarcel Hlopko auto EndFolds = BeginFolds; 3517d382dcdSMarcel Hlopko for (; EndFolds != DelayedFolds.end() && 3527d382dcdSMarcel Hlopko EndFolds->second.End <= Tokens.end(); 3537d382dcdSMarcel Hlopko ++EndFolds) 3547d382dcdSMarcel Hlopko ; 3557d382dcdSMarcel Hlopko // We go in reverse order to ensure we fold deeper nodes first. 3567d382dcdSMarcel Hlopko for (auto RevIt = EndFolds; RevIt != BeginFolds; --RevIt) { 3577d382dcdSMarcel Hlopko auto It = std::prev(RevIt); 3581ad15046SIlya Biryukov foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End), 359e702bdb8SIlya Biryukov It->second.Node); 3607d382dcdSMarcel Hlopko } 3617d382dcdSMarcel Hlopko DelayedFolds.erase(BeginFolds, EndFolds); 3629b3f38f9SIlya Biryukov 363e702bdb8SIlya Biryukov // Attach children to `Node`. 3641ad15046SIlya Biryukov foldChildrenEager(A, Tokens, Node); 365e702bdb8SIlya Biryukov } 3669b3f38f9SIlya Biryukov 367e702bdb8SIlya Biryukov /// Schedule a call to `foldChildren` that will only be executed when 368e702bdb8SIlya Biryukov /// containing node is folded. The range of delayed nodes can be extended by 369e702bdb8SIlya Biryukov /// calling `extendDelayedFold`. Only one delayed node for each starting 370e702bdb8SIlya Biryukov /// token is allowed. 371e702bdb8SIlya Biryukov void foldChildrenDelayed(llvm::ArrayRef<syntax::Token> Tokens, 372e702bdb8SIlya Biryukov syntax::Tree *Node) { 373e702bdb8SIlya Biryukov assert(!Tokens.empty()); 374e702bdb8SIlya Biryukov bool Inserted = 375e702bdb8SIlya Biryukov DelayedFolds.insert({Tokens.begin(), DelayedFold{Tokens.end(), Node}}) 376e702bdb8SIlya Biryukov .second; 377e702bdb8SIlya Biryukov (void)Inserted; 378e702bdb8SIlya Biryukov assert(Inserted && "Multiple delayed folds start at the same token"); 379e702bdb8SIlya Biryukov } 3809b3f38f9SIlya Biryukov 381e702bdb8SIlya Biryukov /// If there a delayed fold, starting at `ExtendedRange.begin()`, extends 382e702bdb8SIlya Biryukov /// its endpoint to `ExtendedRange.end()` and returns true. 383e702bdb8SIlya Biryukov /// Otherwise, returns false. 384e702bdb8SIlya Biryukov bool extendDelayedFold(llvm::ArrayRef<syntax::Token> ExtendedRange) { 385e702bdb8SIlya Biryukov assert(!ExtendedRange.empty()); 386e702bdb8SIlya Biryukov auto It = DelayedFolds.find(ExtendedRange.data()); 387e702bdb8SIlya Biryukov if (It == DelayedFolds.end()) 388e702bdb8SIlya Biryukov return false; 389e702bdb8SIlya Biryukov assert(It->second.End <= ExtendedRange.end()); 390e702bdb8SIlya Biryukov It->second.End = ExtendedRange.end(); 391e702bdb8SIlya Biryukov return true; 3929b3f38f9SIlya Biryukov } 3939b3f38f9SIlya Biryukov 3949b3f38f9SIlya Biryukov // EXPECTS: all tokens were consumed and are owned by a single root node. 3959b3f38f9SIlya Biryukov syntax::Node *finalize() && { 3969b3f38f9SIlya Biryukov assert(Trees.size() == 1); 3979b3f38f9SIlya Biryukov auto *Root = Trees.begin()->second.Node; 3989b3f38f9SIlya Biryukov Trees = {}; 3999b3f38f9SIlya Biryukov return Root; 4009b3f38f9SIlya Biryukov } 4019b3f38f9SIlya Biryukov 4029b3f38f9SIlya Biryukov std::string str(const syntax::Arena &A) const { 4039b3f38f9SIlya Biryukov std::string R; 4049b3f38f9SIlya Biryukov for (auto It = Trees.begin(); It != Trees.end(); ++It) { 4059b3f38f9SIlya Biryukov unsigned CoveredTokens = 4069b3f38f9SIlya Biryukov It != Trees.end() 4079b3f38f9SIlya Biryukov ? (std::next(It)->first - It->first) 4089b3f38f9SIlya Biryukov : A.tokenBuffer().expandedTokens().end() - It->first; 4099b3f38f9SIlya Biryukov 410adcd0268SBenjamin Kramer R += std::string(llvm::formatv( 411adcd0268SBenjamin Kramer "- '{0}' covers '{1}'+{2} tokens\n", It->second.Node->kind(), 412adcd0268SBenjamin Kramer It->first->text(A.sourceManager()), CoveredTokens)); 4139b3f38f9SIlya Biryukov R += It->second.Node->dump(A); 4149b3f38f9SIlya Biryukov } 4159b3f38f9SIlya Biryukov return R; 4169b3f38f9SIlya Biryukov } 4179b3f38f9SIlya Biryukov 4189b3f38f9SIlya Biryukov private: 419e702bdb8SIlya Biryukov /// Implementation detail of `foldChildren`, does acutal folding ignoring 420e702bdb8SIlya Biryukov /// delayed folds. 4211ad15046SIlya Biryukov void foldChildrenEager(const syntax::Arena &A, 4221ad15046SIlya Biryukov llvm::ArrayRef<syntax::Token> Tokens, 423e702bdb8SIlya Biryukov syntax::Tree *Node) { 424e702bdb8SIlya Biryukov assert(Node->firstChild() == nullptr && "node already has children"); 425e702bdb8SIlya Biryukov 426e702bdb8SIlya Biryukov auto *FirstToken = Tokens.begin(); 427e702bdb8SIlya Biryukov auto BeginChildren = Trees.lower_bound(FirstToken); 428e702bdb8SIlya Biryukov assert((BeginChildren == Trees.end() || 429e702bdb8SIlya Biryukov BeginChildren->first == FirstToken) && 430e702bdb8SIlya Biryukov "fold crosses boundaries of existing subtrees"); 431e702bdb8SIlya Biryukov auto EndChildren = Trees.lower_bound(Tokens.end()); 432e702bdb8SIlya Biryukov assert( 433e702bdb8SIlya Biryukov (EndChildren == Trees.end() || EndChildren->first == Tokens.end()) && 434e702bdb8SIlya Biryukov "fold crosses boundaries of existing subtrees"); 435e702bdb8SIlya Biryukov 4367d382dcdSMarcel Hlopko // We need to go in reverse order, because we can only prepend. 437e702bdb8SIlya Biryukov for (auto It = EndChildren; It != BeginChildren; --It) 438e702bdb8SIlya Biryukov Node->prependChildLowLevel(std::prev(It)->second.Node, 439e702bdb8SIlya Biryukov std::prev(It)->second.Role); 440e702bdb8SIlya Biryukov 4411ad15046SIlya Biryukov // Mark that this node came from the AST and is backed by the source code. 4421ad15046SIlya Biryukov Node->Original = true; 4431ad15046SIlya Biryukov Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue(); 4441ad15046SIlya Biryukov 445e702bdb8SIlya Biryukov Trees.erase(BeginChildren, EndChildren); 446e702bdb8SIlya Biryukov Trees.insert({FirstToken, NodeAndRole(Node)}); 447e702bdb8SIlya Biryukov } 4489b3f38f9SIlya Biryukov /// A with a role that should be assigned to it when adding to a parent. 4499b3f38f9SIlya Biryukov struct NodeAndRole { 4509b3f38f9SIlya Biryukov explicit NodeAndRole(syntax::Node *Node) 45151dad419SIlya Biryukov : Node(Node), Role(NodeRole::Unknown) {} 4529b3f38f9SIlya Biryukov 4539b3f38f9SIlya Biryukov syntax::Node *Node; 4549b3f38f9SIlya Biryukov NodeRole Role; 4559b3f38f9SIlya Biryukov }; 4569b3f38f9SIlya Biryukov 4579b3f38f9SIlya Biryukov /// Maps from the start token to a subtree starting at that token. 458302cb3bcSIlya Biryukov /// Keys in the map are pointers into the array of expanded tokens, so 459302cb3bcSIlya Biryukov /// pointer order corresponds to the order of preprocessor tokens. 4609b3f38f9SIlya Biryukov /// FIXME: storing the end tokens is redundant. 4619b3f38f9SIlya Biryukov /// FIXME: the key of a map is redundant, it is also stored in NodeForRange. 4629b3f38f9SIlya Biryukov std::map<const syntax::Token *, NodeAndRole> Trees; 463e702bdb8SIlya Biryukov 464e702bdb8SIlya Biryukov /// See documentation of `foldChildrenDelayed` for details. 465e702bdb8SIlya Biryukov struct DelayedFold { 466e702bdb8SIlya Biryukov const syntax::Token *End = nullptr; 467e702bdb8SIlya Biryukov syntax::Tree *Node = nullptr; 4687d382dcdSMarcel Hlopko NodeRole Role = NodeRole::Unknown; 469e702bdb8SIlya Biryukov }; 470e702bdb8SIlya Biryukov std::map<const syntax::Token *, DelayedFold> DelayedFolds; 4719b3f38f9SIlya Biryukov }; 4729b3f38f9SIlya Biryukov 4739b3f38f9SIlya Biryukov /// For debugging purposes. 4749b3f38f9SIlya Biryukov std::string str() { return Pending.str(Arena); } 4759b3f38f9SIlya Biryukov 4769b3f38f9SIlya Biryukov syntax::Arena &Arena; 477c1bbefefSIlya Biryukov /// To quickly find tokens by their start location. 478c1bbefefSIlya Biryukov llvm::DenseMap</*SourceLocation*/ unsigned, const syntax::Token *> 479c1bbefefSIlya Biryukov LocationToToken; 4809b3f38f9SIlya Biryukov Forest Pending; 481e702bdb8SIlya Biryukov llvm::DenseSet<Decl *> DeclsWithoutSemicolons; 4829b3f38f9SIlya Biryukov }; 4839b3f38f9SIlya Biryukov 4849b3f38f9SIlya Biryukov namespace { 4859b3f38f9SIlya Biryukov class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> { 4869b3f38f9SIlya Biryukov public: 4879b3f38f9SIlya Biryukov explicit BuildTreeVisitor(ASTContext &Ctx, syntax::TreeBuilder &Builder) 4889b3f38f9SIlya Biryukov : Builder(Builder), LangOpts(Ctx.getLangOpts()) {} 4899b3f38f9SIlya Biryukov 4909b3f38f9SIlya Biryukov bool shouldTraversePostOrder() const { return true; } 4919b3f38f9SIlya Biryukov 4927d382dcdSMarcel Hlopko bool WalkUpFromDeclaratorDecl(DeclaratorDecl *DD) { 493e702bdb8SIlya Biryukov // Ensure declarators are covered by SimpleDeclaration. 494*88bf9b3dSMarcel Hlopko Builder.noticeDeclRange(Builder.getDeclRange(DD)); 4957d382dcdSMarcel Hlopko 4967d382dcdSMarcel Hlopko // Build the declarator node. 4977d382dcdSMarcel Hlopko SourceRange Initializer; 4987d382dcdSMarcel Hlopko if (auto *V = llvm::dyn_cast<VarDecl>(DD)) { 4997d382dcdSMarcel Hlopko auto *I = V->getInit(); 5007d382dcdSMarcel Hlopko // Initializers in range-based-for are not part of the declarator 5017d382dcdSMarcel Hlopko if (I && !V->isCXXForRangeDecl()) 5027d382dcdSMarcel Hlopko Initializer = I->getSourceRange(); 5037d382dcdSMarcel Hlopko } 5047d382dcdSMarcel Hlopko auto Declarator = getDeclaratorRange( 5057d382dcdSMarcel Hlopko Builder.sourceManager(), DD->getTypeSourceInfo()->getTypeLoc(), 5067d382dcdSMarcel Hlopko getQualifiedNameStart(DD), Initializer); 5077d382dcdSMarcel Hlopko if (Declarator.isValid()) { 5087d382dcdSMarcel Hlopko auto Tokens = 5097d382dcdSMarcel Hlopko Builder.getRange(Declarator.getBegin(), Declarator.getEnd()); 5107d382dcdSMarcel Hlopko Builder.foldNode(Tokens, new (allocator()) syntax::SimpleDeclarator); 5117d382dcdSMarcel Hlopko Builder.markChild(Tokens, syntax::NodeRole::SimpleDeclaration_declarator); 5127d382dcdSMarcel Hlopko } 5137d382dcdSMarcel Hlopko 514e702bdb8SIlya Biryukov return true; 515e702bdb8SIlya Biryukov } 5167d382dcdSMarcel Hlopko 517e702bdb8SIlya Biryukov bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) { 5187d382dcdSMarcel Hlopko // Ensure declarators are covered by SimpleDeclaration. 519*88bf9b3dSMarcel Hlopko Builder.noticeDeclRange(Builder.getDeclRange(D)); 5207d382dcdSMarcel Hlopko 5217d382dcdSMarcel Hlopko auto R = getDeclaratorRange( 5227d382dcdSMarcel Hlopko Builder.sourceManager(), D->getTypeSourceInfo()->getTypeLoc(), 5237d382dcdSMarcel Hlopko /*Name=*/D->getLocation(), /*Initializer=*/SourceRange()); 5247d382dcdSMarcel Hlopko if (R.isValid()) { 5257d382dcdSMarcel Hlopko auto Tokens = Builder.getRange(R.getBegin(), R.getEnd()); 5267d382dcdSMarcel Hlopko Builder.foldNode(Tokens, new (allocator()) syntax::SimpleDeclarator); 5277d382dcdSMarcel Hlopko Builder.markChild(Tokens, syntax::NodeRole::SimpleDeclaration_declarator); 5287d382dcdSMarcel Hlopko } 529e702bdb8SIlya Biryukov return true; 5309b3f38f9SIlya Biryukov } 5319b3f38f9SIlya Biryukov 5329b3f38f9SIlya Biryukov bool VisitDecl(Decl *D) { 5339b3f38f9SIlya Biryukov assert(!D->isImplicit()); 534*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(D), 535e702bdb8SIlya Biryukov new (allocator()) syntax::UnknownDeclaration()); 536e702bdb8SIlya Biryukov return true; 537e702bdb8SIlya Biryukov } 538e702bdb8SIlya Biryukov 539*88bf9b3dSMarcel Hlopko // RAV does not call WalkUpFrom* on explicit instantiations, so we have to 540*88bf9b3dSMarcel Hlopko // override Traverse. 541*88bf9b3dSMarcel Hlopko // FIXME: make RAV call WalkUpFrom* instead. 542*88bf9b3dSMarcel Hlopko bool 543*88bf9b3dSMarcel Hlopko TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *C) { 544*88bf9b3dSMarcel Hlopko if (!RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(C)) 545*88bf9b3dSMarcel Hlopko return false; 546*88bf9b3dSMarcel Hlopko if (C->isExplicitSpecialization()) 547*88bf9b3dSMarcel Hlopko return true; // we are only interested in explicit instantiations. 548*88bf9b3dSMarcel Hlopko if (!WalkUpFromClassTemplateSpecializationDecl(C)) 549*88bf9b3dSMarcel Hlopko return false; 550*88bf9b3dSMarcel Hlopko foldExplicitTemplateInstantiation( 551*88bf9b3dSMarcel Hlopko Builder.getTemplateRange(C), Builder.findToken(C->getExternLoc()), 552*88bf9b3dSMarcel Hlopko Builder.findToken(C->getTemplateKeywordLoc()), Builder.getDeclRange(C)); 553*88bf9b3dSMarcel Hlopko return true; 554*88bf9b3dSMarcel Hlopko } 555*88bf9b3dSMarcel Hlopko 556*88bf9b3dSMarcel Hlopko bool WalkUpFromTemplateDecl(TemplateDecl *S) { 557*88bf9b3dSMarcel Hlopko foldTemplateDeclaration( 558*88bf9b3dSMarcel Hlopko Builder.getDeclRange(S), 559*88bf9b3dSMarcel Hlopko Builder.findToken(S->getTemplateParameters()->getTemplateLoc()), 560*88bf9b3dSMarcel Hlopko Builder.getDeclRange(S->getTemplatedDecl())); 561*88bf9b3dSMarcel Hlopko return true; 562*88bf9b3dSMarcel Hlopko } 563*88bf9b3dSMarcel Hlopko 564e702bdb8SIlya Biryukov bool WalkUpFromTagDecl(TagDecl *C) { 56504f627f6SIlya Biryukov // FIXME: build the ClassSpecifier node. 566*88bf9b3dSMarcel Hlopko if (!C->isFreeStanding()) { 567*88bf9b3dSMarcel Hlopko assert(C->getNumTemplateParameterLists() == 0); 56804f627f6SIlya Biryukov return true; 56904f627f6SIlya Biryukov } 570*88bf9b3dSMarcel Hlopko // Class is a declaration specifier and needs a spanning declaration node. 571*88bf9b3dSMarcel Hlopko auto DeclarationRange = Builder.getDeclRange(C); 572*88bf9b3dSMarcel Hlopko Builder.foldNode(DeclarationRange, 573*88bf9b3dSMarcel Hlopko new (allocator()) syntax::SimpleDeclaration); 574*88bf9b3dSMarcel Hlopko 575*88bf9b3dSMarcel Hlopko // Build TemplateDeclaration nodes if we had template parameters. 576*88bf9b3dSMarcel Hlopko auto ConsumeTemplateParameters = [&](const TemplateParameterList &L) { 577*88bf9b3dSMarcel Hlopko const auto *TemplateKW = Builder.findToken(L.getTemplateLoc()); 578*88bf9b3dSMarcel Hlopko auto R = llvm::makeArrayRef(TemplateKW, DeclarationRange.end()); 579*88bf9b3dSMarcel Hlopko foldTemplateDeclaration(R, TemplateKW, DeclarationRange); 580*88bf9b3dSMarcel Hlopko 581*88bf9b3dSMarcel Hlopko DeclarationRange = R; 582*88bf9b3dSMarcel Hlopko }; 583*88bf9b3dSMarcel Hlopko if (auto *S = llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(C)) 584*88bf9b3dSMarcel Hlopko ConsumeTemplateParameters(*S->getTemplateParameters()); 585*88bf9b3dSMarcel Hlopko for (unsigned I = C->getNumTemplateParameterLists(); 0 < I; --I) 586*88bf9b3dSMarcel Hlopko ConsumeTemplateParameters(*C->getTemplateParameterList(I - 1)); 5879b3f38f9SIlya Biryukov return true; 5889b3f38f9SIlya Biryukov } 5899b3f38f9SIlya Biryukov 5909b3f38f9SIlya Biryukov bool WalkUpFromTranslationUnitDecl(TranslationUnitDecl *TU) { 5917d382dcdSMarcel Hlopko // We do not want to call VisitDecl(), the declaration for translation 5929b3f38f9SIlya Biryukov // unit is built by finalize(). 5939b3f38f9SIlya Biryukov return true; 5949b3f38f9SIlya Biryukov } 5959b3f38f9SIlya Biryukov 5969b3f38f9SIlya Biryukov bool WalkUpFromCompoundStmt(CompoundStmt *S) { 59751dad419SIlya Biryukov using NodeRole = syntax::NodeRole; 5989b3f38f9SIlya Biryukov 599def65bb4SIlya Biryukov Builder.markChildToken(S->getLBracLoc(), NodeRole::OpenParen); 60058fa50f4SIlya Biryukov for (auto *Child : S->body()) 60158fa50f4SIlya Biryukov Builder.markStmtChild(Child, NodeRole::CompoundStatement_statement); 602def65bb4SIlya Biryukov Builder.markChildToken(S->getRBracLoc(), NodeRole::CloseParen); 6039b3f38f9SIlya Biryukov 60458fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 6059b3f38f9SIlya Biryukov new (allocator()) syntax::CompoundStatement); 6069b3f38f9SIlya Biryukov return true; 6079b3f38f9SIlya Biryukov } 6089b3f38f9SIlya Biryukov 60958fa50f4SIlya Biryukov // Some statements are not yet handled by syntax trees. 61058fa50f4SIlya Biryukov bool WalkUpFromStmt(Stmt *S) { 61158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 61258fa50f4SIlya Biryukov new (allocator()) syntax::UnknownStatement); 61358fa50f4SIlya Biryukov return true; 61458fa50f4SIlya Biryukov } 61558fa50f4SIlya Biryukov 61658fa50f4SIlya Biryukov bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) { 61758fa50f4SIlya Biryukov // We override to traverse range initializer as VarDecl. 61858fa50f4SIlya Biryukov // RAV traverses it as a statement, we produce invalid node kinds in that 61958fa50f4SIlya Biryukov // case. 62058fa50f4SIlya Biryukov // FIXME: should do this in RAV instead? 62158fa50f4SIlya Biryukov if (S->getInit() && !TraverseStmt(S->getInit())) 62258fa50f4SIlya Biryukov return false; 62358fa50f4SIlya Biryukov if (S->getLoopVariable() && !TraverseDecl(S->getLoopVariable())) 62458fa50f4SIlya Biryukov return false; 62558fa50f4SIlya Biryukov if (S->getRangeInit() && !TraverseStmt(S->getRangeInit())) 62658fa50f4SIlya Biryukov return false; 62758fa50f4SIlya Biryukov if (S->getBody() && !TraverseStmt(S->getBody())) 62858fa50f4SIlya Biryukov return false; 62958fa50f4SIlya Biryukov return true; 63058fa50f4SIlya Biryukov } 63158fa50f4SIlya Biryukov 63258fa50f4SIlya Biryukov bool TraverseStmt(Stmt *S) { 633e702bdb8SIlya Biryukov if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) { 634e702bdb8SIlya Biryukov // We want to consume the semicolon, make sure SimpleDeclaration does not. 635e702bdb8SIlya Biryukov for (auto *D : DS->decls()) 6367d382dcdSMarcel Hlopko Builder.noticeDeclWithoutSemicolon(D); 637e702bdb8SIlya Biryukov } else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) { 6387d382dcdSMarcel Hlopko // Do not recurse into subexpressions. 6397d382dcdSMarcel Hlopko // We do not have syntax trees for expressions yet, so we only want to see 64058fa50f4SIlya Biryukov // the first top-level expression. 64158fa50f4SIlya Biryukov return WalkUpFromExpr(E->IgnoreImplicit()); 64258fa50f4SIlya Biryukov } 64358fa50f4SIlya Biryukov return RecursiveASTVisitor::TraverseStmt(S); 64458fa50f4SIlya Biryukov } 64558fa50f4SIlya Biryukov 64658fa50f4SIlya Biryukov // Some expressions are not yet handled by syntax trees. 64758fa50f4SIlya Biryukov bool WalkUpFromExpr(Expr *E) { 64858fa50f4SIlya Biryukov assert(!isImplicitExpr(E) && "should be handled by TraverseStmt"); 64958fa50f4SIlya Biryukov Builder.foldNode(Builder.getExprRange(E), 65058fa50f4SIlya Biryukov new (allocator()) syntax::UnknownExpression); 65158fa50f4SIlya Biryukov return true; 65258fa50f4SIlya Biryukov } 65358fa50f4SIlya Biryukov 654be14a22bSIlya Biryukov bool WalkUpFromNamespaceDecl(NamespaceDecl *S) { 655*88bf9b3dSMarcel Hlopko auto Tokens = Builder.getDeclRange(S); 656be14a22bSIlya Biryukov if (Tokens.front().kind() == tok::coloncolon) { 657be14a22bSIlya Biryukov // Handle nested namespace definitions. Those start at '::' token, e.g. 658be14a22bSIlya Biryukov // namespace a^::b {} 659be14a22bSIlya Biryukov // FIXME: build corresponding nodes for the name of this namespace. 660be14a22bSIlya Biryukov return true; 661be14a22bSIlya Biryukov } 662be14a22bSIlya Biryukov Builder.foldNode(Tokens, new (allocator()) syntax::NamespaceDefinition); 663be14a22bSIlya Biryukov return true; 664be14a22bSIlya Biryukov } 665be14a22bSIlya Biryukov 6667d382dcdSMarcel Hlopko bool TraverseParenTypeLoc(ParenTypeLoc L) { 6677d382dcdSMarcel Hlopko // We reverse order of traversal to get the proper syntax structure. 6687d382dcdSMarcel Hlopko if (!WalkUpFromParenTypeLoc(L)) 6697d382dcdSMarcel Hlopko return false; 6707d382dcdSMarcel Hlopko return TraverseTypeLoc(L.getInnerLoc()); 6717d382dcdSMarcel Hlopko } 6727d382dcdSMarcel Hlopko 6737d382dcdSMarcel Hlopko bool WalkUpFromParenTypeLoc(ParenTypeLoc L) { 6747d382dcdSMarcel Hlopko Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen); 6757d382dcdSMarcel Hlopko Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen); 6767d382dcdSMarcel Hlopko Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getRParenLoc()), 6777d382dcdSMarcel Hlopko new (allocator()) syntax::ParenDeclarator); 6787d382dcdSMarcel Hlopko return true; 6797d382dcdSMarcel Hlopko } 6807d382dcdSMarcel Hlopko 6817d382dcdSMarcel Hlopko // Declarator chunks, they are produced by type locs and some clang::Decls. 6827d382dcdSMarcel Hlopko bool WalkUpFromArrayTypeLoc(ArrayTypeLoc L) { 6837d382dcdSMarcel Hlopko Builder.markChildToken(L.getLBracketLoc(), syntax::NodeRole::OpenParen); 6847d382dcdSMarcel Hlopko Builder.markExprChild(L.getSizeExpr(), 6857d382dcdSMarcel Hlopko syntax::NodeRole::ArraySubscript_sizeExpression); 6867d382dcdSMarcel Hlopko Builder.markChildToken(L.getRBracketLoc(), syntax::NodeRole::CloseParen); 6877d382dcdSMarcel Hlopko Builder.foldNode(Builder.getRange(L.getLBracketLoc(), L.getRBracketLoc()), 6887d382dcdSMarcel Hlopko new (allocator()) syntax::ArraySubscript); 6897d382dcdSMarcel Hlopko return true; 6907d382dcdSMarcel Hlopko } 6917d382dcdSMarcel Hlopko 6927d382dcdSMarcel Hlopko bool WalkUpFromFunctionTypeLoc(FunctionTypeLoc L) { 6937d382dcdSMarcel Hlopko Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen); 6947d382dcdSMarcel Hlopko for (auto *P : L.getParams()) 6957d382dcdSMarcel Hlopko Builder.markDelayedChild( 696*88bf9b3dSMarcel Hlopko Builder.getDeclRange(P), 6977d382dcdSMarcel Hlopko syntax::NodeRole::ParametersAndQualifiers_parameter); 6987d382dcdSMarcel Hlopko Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen); 6997d382dcdSMarcel Hlopko Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getEndLoc()), 7007d382dcdSMarcel Hlopko new (allocator()) syntax::ParametersAndQualifiers); 7017d382dcdSMarcel Hlopko return true; 7027d382dcdSMarcel Hlopko } 7037d382dcdSMarcel Hlopko 7047d382dcdSMarcel Hlopko bool WalkUpFromFunctionProtoTypeLoc(FunctionProtoTypeLoc L) { 7057d382dcdSMarcel Hlopko if (!L.getTypePtr()->hasTrailingReturn()) 7067d382dcdSMarcel Hlopko return WalkUpFromFunctionTypeLoc(L); 7077d382dcdSMarcel Hlopko 7087d382dcdSMarcel Hlopko auto TrailingReturnTokens = BuildTrailingReturn(L); 7097d382dcdSMarcel Hlopko // Finish building the node for parameters. 7107d382dcdSMarcel Hlopko Builder.markChild(TrailingReturnTokens, 7117d382dcdSMarcel Hlopko syntax::NodeRole::ParametersAndQualifiers_trailingReturn); 7127d382dcdSMarcel Hlopko return WalkUpFromFunctionTypeLoc(L); 7137d382dcdSMarcel Hlopko } 7147d382dcdSMarcel Hlopko 7157d382dcdSMarcel Hlopko bool WalkUpFromMemberPointerTypeLoc(MemberPointerTypeLoc L) { 7167d382dcdSMarcel Hlopko auto SR = L.getLocalSourceRange(); 7177d382dcdSMarcel Hlopko Builder.foldNode(Builder.getRange(SR.getBegin(), SR.getEnd()), 7187d382dcdSMarcel Hlopko new (allocator()) syntax::MemberPointer); 7197d382dcdSMarcel Hlopko return true; 7207d382dcdSMarcel Hlopko } 7217d382dcdSMarcel Hlopko 72258fa50f4SIlya Biryukov // The code below is very regular, it could even be generated with some 72358fa50f4SIlya Biryukov // preprocessor magic. We merely assign roles to the corresponding children 72458fa50f4SIlya Biryukov // and fold resulting nodes. 72558fa50f4SIlya Biryukov bool WalkUpFromDeclStmt(DeclStmt *S) { 72658fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 72758fa50f4SIlya Biryukov new (allocator()) syntax::DeclarationStatement); 72858fa50f4SIlya Biryukov return true; 72958fa50f4SIlya Biryukov } 73058fa50f4SIlya Biryukov 73158fa50f4SIlya Biryukov bool WalkUpFromNullStmt(NullStmt *S) { 73258fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 73358fa50f4SIlya Biryukov new (allocator()) syntax::EmptyStatement); 73458fa50f4SIlya Biryukov return true; 73558fa50f4SIlya Biryukov } 73658fa50f4SIlya Biryukov 73758fa50f4SIlya Biryukov bool WalkUpFromSwitchStmt(SwitchStmt *S) { 738def65bb4SIlya Biryukov Builder.markChildToken(S->getSwitchLoc(), 73958fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 74058fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 74158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 74258fa50f4SIlya Biryukov new (allocator()) syntax::SwitchStatement); 74358fa50f4SIlya Biryukov return true; 74458fa50f4SIlya Biryukov } 74558fa50f4SIlya Biryukov 74658fa50f4SIlya Biryukov bool WalkUpFromCaseStmt(CaseStmt *S) { 747def65bb4SIlya Biryukov Builder.markChildToken(S->getKeywordLoc(), 74858fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 74958fa50f4SIlya Biryukov Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseStatement_value); 75058fa50f4SIlya Biryukov Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 75158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 75258fa50f4SIlya Biryukov new (allocator()) syntax::CaseStatement); 75358fa50f4SIlya Biryukov return true; 75458fa50f4SIlya Biryukov } 75558fa50f4SIlya Biryukov 75658fa50f4SIlya Biryukov bool WalkUpFromDefaultStmt(DefaultStmt *S) { 757def65bb4SIlya Biryukov Builder.markChildToken(S->getKeywordLoc(), 75858fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 75958fa50f4SIlya Biryukov Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 76058fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 76158fa50f4SIlya Biryukov new (allocator()) syntax::DefaultStatement); 76258fa50f4SIlya Biryukov return true; 76358fa50f4SIlya Biryukov } 76458fa50f4SIlya Biryukov 76558fa50f4SIlya Biryukov bool WalkUpFromIfStmt(IfStmt *S) { 766def65bb4SIlya Biryukov Builder.markChildToken(S->getIfLoc(), syntax::NodeRole::IntroducerKeyword); 76758fa50f4SIlya Biryukov Builder.markStmtChild(S->getThen(), 76858fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_thenStatement); 769def65bb4SIlya Biryukov Builder.markChildToken(S->getElseLoc(), 77058fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_elseKeyword); 77158fa50f4SIlya Biryukov Builder.markStmtChild(S->getElse(), 77258fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_elseStatement); 77358fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 77458fa50f4SIlya Biryukov new (allocator()) syntax::IfStatement); 77558fa50f4SIlya Biryukov return true; 77658fa50f4SIlya Biryukov } 77758fa50f4SIlya Biryukov 77858fa50f4SIlya Biryukov bool WalkUpFromForStmt(ForStmt *S) { 779def65bb4SIlya Biryukov Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); 78058fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 78158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 78258fa50f4SIlya Biryukov new (allocator()) syntax::ForStatement); 78358fa50f4SIlya Biryukov return true; 78458fa50f4SIlya Biryukov } 78558fa50f4SIlya Biryukov 78658fa50f4SIlya Biryukov bool WalkUpFromWhileStmt(WhileStmt *S) { 787def65bb4SIlya Biryukov Builder.markChildToken(S->getWhileLoc(), 78858fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 78958fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 79058fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 79158fa50f4SIlya Biryukov new (allocator()) syntax::WhileStatement); 79258fa50f4SIlya Biryukov return true; 79358fa50f4SIlya Biryukov } 79458fa50f4SIlya Biryukov 79558fa50f4SIlya Biryukov bool WalkUpFromContinueStmt(ContinueStmt *S) { 796def65bb4SIlya Biryukov Builder.markChildToken(S->getContinueLoc(), 79758fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 79858fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 79958fa50f4SIlya Biryukov new (allocator()) syntax::ContinueStatement); 80058fa50f4SIlya Biryukov return true; 80158fa50f4SIlya Biryukov } 80258fa50f4SIlya Biryukov 80358fa50f4SIlya Biryukov bool WalkUpFromBreakStmt(BreakStmt *S) { 804def65bb4SIlya Biryukov Builder.markChildToken(S->getBreakLoc(), 80558fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 80658fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 80758fa50f4SIlya Biryukov new (allocator()) syntax::BreakStatement); 80858fa50f4SIlya Biryukov return true; 80958fa50f4SIlya Biryukov } 81058fa50f4SIlya Biryukov 81158fa50f4SIlya Biryukov bool WalkUpFromReturnStmt(ReturnStmt *S) { 812def65bb4SIlya Biryukov Builder.markChildToken(S->getReturnLoc(), 81358fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 81458fa50f4SIlya Biryukov Builder.markExprChild(S->getRetValue(), 81558fa50f4SIlya Biryukov syntax::NodeRole::ReturnStatement_value); 81658fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 81758fa50f4SIlya Biryukov new (allocator()) syntax::ReturnStatement); 81858fa50f4SIlya Biryukov return true; 81958fa50f4SIlya Biryukov } 82058fa50f4SIlya Biryukov 82158fa50f4SIlya Biryukov bool WalkUpFromCXXForRangeStmt(CXXForRangeStmt *S) { 822def65bb4SIlya Biryukov Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); 82358fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 82458fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 82558fa50f4SIlya Biryukov new (allocator()) syntax::RangeBasedForStatement); 82658fa50f4SIlya Biryukov return true; 82758fa50f4SIlya Biryukov } 82858fa50f4SIlya Biryukov 829be14a22bSIlya Biryukov bool WalkUpFromEmptyDecl(EmptyDecl *S) { 830*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 831be14a22bSIlya Biryukov new (allocator()) syntax::EmptyDeclaration); 832be14a22bSIlya Biryukov return true; 833be14a22bSIlya Biryukov } 834be14a22bSIlya Biryukov 835be14a22bSIlya Biryukov bool WalkUpFromStaticAssertDecl(StaticAssertDecl *S) { 836be14a22bSIlya Biryukov Builder.markExprChild(S->getAssertExpr(), 837be14a22bSIlya Biryukov syntax::NodeRole::StaticAssertDeclaration_condition); 838be14a22bSIlya Biryukov Builder.markExprChild(S->getMessage(), 839be14a22bSIlya Biryukov syntax::NodeRole::StaticAssertDeclaration_message); 840*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 841be14a22bSIlya Biryukov new (allocator()) syntax::StaticAssertDeclaration); 842be14a22bSIlya Biryukov return true; 843be14a22bSIlya Biryukov } 844be14a22bSIlya Biryukov 845be14a22bSIlya Biryukov bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) { 846*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 847be14a22bSIlya Biryukov new (allocator()) syntax::LinkageSpecificationDeclaration); 848be14a22bSIlya Biryukov return true; 849be14a22bSIlya Biryukov } 850be14a22bSIlya Biryukov 851be14a22bSIlya Biryukov bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) { 852*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 853be14a22bSIlya Biryukov new (allocator()) syntax::NamespaceAliasDefinition); 854be14a22bSIlya Biryukov return true; 855be14a22bSIlya Biryukov } 856be14a22bSIlya Biryukov 857be14a22bSIlya Biryukov bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) { 858*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 859be14a22bSIlya Biryukov new (allocator()) syntax::UsingNamespaceDirective); 860be14a22bSIlya Biryukov return true; 861be14a22bSIlya Biryukov } 862be14a22bSIlya Biryukov 863be14a22bSIlya Biryukov bool WalkUpFromUsingDecl(UsingDecl *S) { 864*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 865be14a22bSIlya Biryukov new (allocator()) syntax::UsingDeclaration); 866be14a22bSIlya Biryukov return true; 867be14a22bSIlya Biryukov } 868be14a22bSIlya Biryukov 869be14a22bSIlya Biryukov bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) { 870*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 871be14a22bSIlya Biryukov new (allocator()) syntax::UsingDeclaration); 872be14a22bSIlya Biryukov return true; 873be14a22bSIlya Biryukov } 874be14a22bSIlya Biryukov 875be14a22bSIlya Biryukov bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) { 876*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 877be14a22bSIlya Biryukov new (allocator()) syntax::UsingDeclaration); 878be14a22bSIlya Biryukov return true; 879be14a22bSIlya Biryukov } 880be14a22bSIlya Biryukov 881be14a22bSIlya Biryukov bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) { 882*88bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 883be14a22bSIlya Biryukov new (allocator()) syntax::TypeAliasDeclaration); 884be14a22bSIlya Biryukov return true; 885be14a22bSIlya Biryukov } 886be14a22bSIlya Biryukov 8879b3f38f9SIlya Biryukov private: 8887d382dcdSMarcel Hlopko /// Returns the range of the built node. 8897d382dcdSMarcel Hlopko llvm::ArrayRef<syntax::Token> BuildTrailingReturn(FunctionProtoTypeLoc L) { 8907d382dcdSMarcel Hlopko assert(L.getTypePtr()->hasTrailingReturn()); 8917d382dcdSMarcel Hlopko 8927d382dcdSMarcel Hlopko auto ReturnedType = L.getReturnLoc(); 8937d382dcdSMarcel Hlopko // Build node for the declarator, if any. 8947d382dcdSMarcel Hlopko auto ReturnDeclaratorRange = 8957d382dcdSMarcel Hlopko getDeclaratorRange(this->Builder.sourceManager(), ReturnedType, 8967d382dcdSMarcel Hlopko /*Name=*/SourceLocation(), 8977d382dcdSMarcel Hlopko /*Initializer=*/SourceLocation()); 8987d382dcdSMarcel Hlopko llvm::ArrayRef<syntax::Token> ReturnDeclaratorTokens; 8997d382dcdSMarcel Hlopko if (ReturnDeclaratorRange.isValid()) { 9007d382dcdSMarcel Hlopko ReturnDeclaratorTokens = Builder.getRange( 9017d382dcdSMarcel Hlopko ReturnDeclaratorRange.getBegin(), ReturnDeclaratorRange.getEnd()); 9027d382dcdSMarcel Hlopko Builder.foldNode(ReturnDeclaratorTokens, 9037d382dcdSMarcel Hlopko new (allocator()) syntax::SimpleDeclarator); 9047d382dcdSMarcel Hlopko } 9057d382dcdSMarcel Hlopko 9067d382dcdSMarcel Hlopko // Build node for trailing return type. 9077d382dcdSMarcel Hlopko auto Return = 9087d382dcdSMarcel Hlopko Builder.getRange(ReturnedType.getBeginLoc(), ReturnedType.getEndLoc()); 9097d382dcdSMarcel Hlopko const auto *Arrow = Return.begin() - 1; 9107d382dcdSMarcel Hlopko assert(Arrow->kind() == tok::arrow); 9117d382dcdSMarcel Hlopko auto Tokens = llvm::makeArrayRef(Arrow, Return.end()); 9127d382dcdSMarcel Hlopko Builder.markChildToken(Arrow, syntax::NodeRole::TrailingReturnType_arrow); 9137d382dcdSMarcel Hlopko if (!ReturnDeclaratorTokens.empty()) 9147d382dcdSMarcel Hlopko Builder.markChild(ReturnDeclaratorTokens, 9157d382dcdSMarcel Hlopko syntax::NodeRole::TrailingReturnType_declarator); 9167d382dcdSMarcel Hlopko Builder.foldNode(Tokens, new (allocator()) syntax::TrailingReturnType); 9177d382dcdSMarcel Hlopko return Tokens; 9187d382dcdSMarcel Hlopko } 919*88bf9b3dSMarcel Hlopko 920*88bf9b3dSMarcel Hlopko void 921*88bf9b3dSMarcel Hlopko foldExplicitTemplateInstantiation(ArrayRef<syntax::Token> Range, 922*88bf9b3dSMarcel Hlopko const syntax::Token *ExternKW, 923*88bf9b3dSMarcel Hlopko const syntax::Token *TemplateKW, 924*88bf9b3dSMarcel Hlopko ArrayRef<syntax::Token> InnerDeclaration) { 925*88bf9b3dSMarcel Hlopko assert(!ExternKW || ExternKW->kind() == tok::kw_extern); 926*88bf9b3dSMarcel Hlopko assert(TemplateKW && TemplateKW->kind() == tok::kw_template); 927*88bf9b3dSMarcel Hlopko Builder.markChildToken( 928*88bf9b3dSMarcel Hlopko ExternKW, 929*88bf9b3dSMarcel Hlopko syntax::NodeRole::ExplicitTemplateInstantiation_externKeyword); 930*88bf9b3dSMarcel Hlopko Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword); 931*88bf9b3dSMarcel Hlopko Builder.markChild( 932*88bf9b3dSMarcel Hlopko InnerDeclaration, 933*88bf9b3dSMarcel Hlopko syntax::NodeRole::ExplicitTemplateInstantiation_declaration); 934*88bf9b3dSMarcel Hlopko Builder.foldNode(Range, 935*88bf9b3dSMarcel Hlopko new (allocator()) syntax::ExplicitTemplateInstantiation); 936*88bf9b3dSMarcel Hlopko } 937*88bf9b3dSMarcel Hlopko 938*88bf9b3dSMarcel Hlopko void foldTemplateDeclaration(ArrayRef<syntax::Token> Range, 939*88bf9b3dSMarcel Hlopko const syntax::Token *TemplateKW, 940*88bf9b3dSMarcel Hlopko ArrayRef<syntax::Token> TemplatedDeclaration) { 941*88bf9b3dSMarcel Hlopko assert(TemplateKW && TemplateKW->kind() == tok::kw_template); 942*88bf9b3dSMarcel Hlopko Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword); 943*88bf9b3dSMarcel Hlopko Builder.markMaybeDelayedChild( 944*88bf9b3dSMarcel Hlopko TemplatedDeclaration, 945*88bf9b3dSMarcel Hlopko syntax::NodeRole::TemplateDeclaration_declaration); 946*88bf9b3dSMarcel Hlopko Builder.foldNode(Range, new (allocator()) syntax::TemplateDeclaration); 947*88bf9b3dSMarcel Hlopko } 948*88bf9b3dSMarcel Hlopko 9499b3f38f9SIlya Biryukov /// A small helper to save some typing. 9509b3f38f9SIlya Biryukov llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); } 9519b3f38f9SIlya Biryukov 9529b3f38f9SIlya Biryukov syntax::TreeBuilder &Builder; 9539b3f38f9SIlya Biryukov const LangOptions &LangOpts; 9549b3f38f9SIlya Biryukov }; 9559b3f38f9SIlya Biryukov } // namespace 9569b3f38f9SIlya Biryukov 9579b3f38f9SIlya Biryukov void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range, 9589b3f38f9SIlya Biryukov syntax::Tree *New) { 9591ad15046SIlya Biryukov Pending.foldChildren(Arena, Range, New); 9609b3f38f9SIlya Biryukov } 9619b3f38f9SIlya Biryukov 9627d382dcdSMarcel Hlopko void syntax::TreeBuilder::noticeDeclRange(llvm::ArrayRef<syntax::Token> Range) { 963e702bdb8SIlya Biryukov if (Pending.extendDelayedFold(Range)) 964e702bdb8SIlya Biryukov return; 965e702bdb8SIlya Biryukov Pending.foldChildrenDelayed(Range, 966e702bdb8SIlya Biryukov new (allocator()) syntax::SimpleDeclaration); 967e702bdb8SIlya Biryukov } 968e702bdb8SIlya Biryukov 9697d382dcdSMarcel Hlopko void syntax::TreeBuilder::noticeDeclWithoutSemicolon(Decl *D) { 970e702bdb8SIlya Biryukov DeclsWithoutSemicolons.insert(D); 971e702bdb8SIlya Biryukov } 972e702bdb8SIlya Biryukov 973def65bb4SIlya Biryukov void syntax::TreeBuilder::markChildToken(SourceLocation Loc, NodeRole Role) { 9749b3f38f9SIlya Biryukov if (Loc.isInvalid()) 9759b3f38f9SIlya Biryukov return; 9769b3f38f9SIlya Biryukov Pending.assignRole(*findToken(Loc), Role); 9779b3f38f9SIlya Biryukov } 9789b3f38f9SIlya Biryukov 9797d382dcdSMarcel Hlopko void syntax::TreeBuilder::markChildToken(const syntax::Token *T, NodeRole R) { 9807d382dcdSMarcel Hlopko if (!T) 9817d382dcdSMarcel Hlopko return; 9827d382dcdSMarcel Hlopko Pending.assignRole(*T, R); 9837d382dcdSMarcel Hlopko } 9847d382dcdSMarcel Hlopko 9857d382dcdSMarcel Hlopko void syntax::TreeBuilder::markChild(llvm::ArrayRef<syntax::Token> Range, 9867d382dcdSMarcel Hlopko NodeRole R) { 9877d382dcdSMarcel Hlopko Pending.assignRole(Range, R); 9887d382dcdSMarcel Hlopko } 9897d382dcdSMarcel Hlopko 9907d382dcdSMarcel Hlopko void syntax::TreeBuilder::markDelayedChild(llvm::ArrayRef<syntax::Token> Range, 9917d382dcdSMarcel Hlopko NodeRole R) { 9927d382dcdSMarcel Hlopko Pending.assignRoleDelayed(Range, R); 9937d382dcdSMarcel Hlopko } 9947d382dcdSMarcel Hlopko 995*88bf9b3dSMarcel Hlopko void syntax::TreeBuilder::markMaybeDelayedChild( 996*88bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> Range, NodeRole R) { 997*88bf9b3dSMarcel Hlopko Pending.assignRoleMaybeDelayed(Range, R); 998*88bf9b3dSMarcel Hlopko } 999*88bf9b3dSMarcel Hlopko 100058fa50f4SIlya Biryukov void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { 100158fa50f4SIlya Biryukov if (!Child) 100258fa50f4SIlya Biryukov return; 100358fa50f4SIlya Biryukov 100458fa50f4SIlya Biryukov auto Range = getStmtRange(Child); 100558fa50f4SIlya Biryukov // This is an expression in a statement position, consume the trailing 100658fa50f4SIlya Biryukov // semicolon and form an 'ExpressionStatement' node. 100758fa50f4SIlya Biryukov if (auto *E = dyn_cast<Expr>(Child)) { 100858fa50f4SIlya Biryukov Pending.assignRole(getExprRange(E), 100958fa50f4SIlya Biryukov NodeRole::ExpressionStatement_expression); 10107d382dcdSMarcel Hlopko // 'getRange(Stmt)' ensures this already covers a trailing semicolon. 10111ad15046SIlya Biryukov Pending.foldChildren(Arena, Range, 10121ad15046SIlya Biryukov new (allocator()) syntax::ExpressionStatement); 101358fa50f4SIlya Biryukov } 101458fa50f4SIlya Biryukov Pending.assignRole(Range, Role); 101558fa50f4SIlya Biryukov } 101658fa50f4SIlya Biryukov 101758fa50f4SIlya Biryukov void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) { 1018be14a22bSIlya Biryukov if (!Child) 1019be14a22bSIlya Biryukov return; 1020be14a22bSIlya Biryukov 102158fa50f4SIlya Biryukov Pending.assignRole(getExprRange(Child), Role); 102258fa50f4SIlya Biryukov } 102358fa50f4SIlya Biryukov 10249b3f38f9SIlya Biryukov const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const { 1025*88bf9b3dSMarcel Hlopko if (L.isInvalid()) 1026*88bf9b3dSMarcel Hlopko return nullptr; 1027c1bbefefSIlya Biryukov auto It = LocationToToken.find(L.getRawEncoding()); 1028c1bbefefSIlya Biryukov assert(It != LocationToToken.end()); 1029c1bbefefSIlya Biryukov return It->second; 10309b3f38f9SIlya Biryukov } 10319b3f38f9SIlya Biryukov 10329b3f38f9SIlya Biryukov syntax::TranslationUnit * 10339b3f38f9SIlya Biryukov syntax::buildSyntaxTree(Arena &A, const TranslationUnitDecl &TU) { 10349b3f38f9SIlya Biryukov TreeBuilder Builder(A); 10359b3f38f9SIlya Biryukov BuildTreeVisitor(TU.getASTContext(), Builder).TraverseAST(TU.getASTContext()); 10369b3f38f9SIlya Biryukov return std::move(Builder).finalize(); 10379b3f38f9SIlya Biryukov } 1038