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" 2188bf9b3dSMarcel 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" 28a711a3a4SMarcel Hlopko #include "llvm/ADT/DenseMap.h" 29a711a3a4SMarcel Hlopko #include "llvm/ADT/PointerUnion.h" 309b3f38f9SIlya Biryukov #include "llvm/ADT/STLExtras.h" 317d382dcdSMarcel Hlopko #include "llvm/ADT/ScopeExit.h" 329b3f38f9SIlya Biryukov #include "llvm/ADT/SmallVector.h" 339b3f38f9SIlya Biryukov #include "llvm/Support/Allocator.h" 349b3f38f9SIlya Biryukov #include "llvm/Support/Casting.h" 3596065cf7SIlya Biryukov #include "llvm/Support/Compiler.h" 369b3f38f9SIlya Biryukov #include "llvm/Support/FormatVariadic.h" 371ad15046SIlya Biryukov #include "llvm/Support/MemoryBuffer.h" 389b3f38f9SIlya Biryukov #include "llvm/Support/raw_ostream.h" 39a711a3a4SMarcel Hlopko #include <cstddef> 409b3f38f9SIlya Biryukov #include <map> 419b3f38f9SIlya Biryukov 429b3f38f9SIlya Biryukov using namespace clang; 439b3f38f9SIlya Biryukov 4496065cf7SIlya Biryukov LLVM_ATTRIBUTE_UNUSED 4558fa50f4SIlya Biryukov static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; } 4658fa50f4SIlya Biryukov 477d382dcdSMarcel Hlopko static SourceLocation getQualifiedNameStart(DeclaratorDecl *D) { 487d382dcdSMarcel Hlopko auto DN = D->getDeclName(); 497d382dcdSMarcel Hlopko bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo(); 507d382dcdSMarcel Hlopko if (IsAnonymous) 517d382dcdSMarcel Hlopko return SourceLocation(); 527d382dcdSMarcel Hlopko return D->getQualifierLoc() ? D->getQualifierLoc().getBeginLoc() 537d382dcdSMarcel Hlopko : D->getLocation(); 547d382dcdSMarcel Hlopko } 557d382dcdSMarcel Hlopko 567d382dcdSMarcel Hlopko namespace { 577d382dcdSMarcel Hlopko /// Get start location of the Declarator from the TypeLoc. 587d382dcdSMarcel Hlopko /// E.g.: 597d382dcdSMarcel Hlopko /// loc of `(` in `int (a)` 607d382dcdSMarcel Hlopko /// loc of `*` in `int *(a)` 617d382dcdSMarcel Hlopko /// loc of the first `(` in `int (*a)(int)` 627d382dcdSMarcel Hlopko /// loc of the `*` in `int *(a)(int)` 637d382dcdSMarcel Hlopko /// loc of the first `*` in `const int *const *volatile a;` 647d382dcdSMarcel Hlopko /// 657d382dcdSMarcel Hlopko /// It is non-trivial to get the start location because TypeLocs are stored 667d382dcdSMarcel Hlopko /// inside out. In the example above `*volatile` is the TypeLoc returned 677d382dcdSMarcel Hlopko /// by `Decl.getTypeSourceInfo()`, and `*const` is what `.getPointeeLoc()` 687d382dcdSMarcel Hlopko /// returns. 697d382dcdSMarcel Hlopko struct GetStartLoc : TypeLocVisitor<GetStartLoc, SourceLocation> { 707d382dcdSMarcel Hlopko SourceLocation VisitParenTypeLoc(ParenTypeLoc T) { 717d382dcdSMarcel Hlopko auto L = Visit(T.getInnerLoc()); 727d382dcdSMarcel Hlopko if (L.isValid()) 737d382dcdSMarcel Hlopko return L; 747d382dcdSMarcel Hlopko return T.getLParenLoc(); 757d382dcdSMarcel Hlopko } 767d382dcdSMarcel Hlopko 777d382dcdSMarcel Hlopko // Types spelled in the prefix part of the declarator. 787d382dcdSMarcel Hlopko SourceLocation VisitPointerTypeLoc(PointerTypeLoc T) { 797d382dcdSMarcel Hlopko return HandlePointer(T); 807d382dcdSMarcel Hlopko } 817d382dcdSMarcel Hlopko 827d382dcdSMarcel Hlopko SourceLocation VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) { 837d382dcdSMarcel Hlopko return HandlePointer(T); 847d382dcdSMarcel Hlopko } 857d382dcdSMarcel Hlopko 867d382dcdSMarcel Hlopko SourceLocation VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) { 877d382dcdSMarcel Hlopko return HandlePointer(T); 887d382dcdSMarcel Hlopko } 897d382dcdSMarcel Hlopko 907d382dcdSMarcel Hlopko SourceLocation VisitReferenceTypeLoc(ReferenceTypeLoc T) { 917d382dcdSMarcel Hlopko return HandlePointer(T); 927d382dcdSMarcel Hlopko } 937d382dcdSMarcel Hlopko 947d382dcdSMarcel Hlopko SourceLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc T) { 957d382dcdSMarcel Hlopko return HandlePointer(T); 967d382dcdSMarcel Hlopko } 977d382dcdSMarcel Hlopko 987d382dcdSMarcel Hlopko // All other cases are not important, as they are either part of declaration 997d382dcdSMarcel Hlopko // specifiers (e.g. inheritors of TypeSpecTypeLoc) or introduce modifiers on 1007d382dcdSMarcel Hlopko // existing declarators (e.g. QualifiedTypeLoc). They cannot start the 1017d382dcdSMarcel Hlopko // declarator themselves, but their underlying type can. 1027d382dcdSMarcel Hlopko SourceLocation VisitTypeLoc(TypeLoc T) { 1037d382dcdSMarcel Hlopko auto N = T.getNextTypeLoc(); 1047d382dcdSMarcel Hlopko if (!N) 1057d382dcdSMarcel Hlopko return SourceLocation(); 1067d382dcdSMarcel Hlopko return Visit(N); 1077d382dcdSMarcel Hlopko } 1087d382dcdSMarcel Hlopko 1097d382dcdSMarcel Hlopko SourceLocation VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc T) { 1107d382dcdSMarcel Hlopko if (T.getTypePtr()->hasTrailingReturn()) 1117d382dcdSMarcel Hlopko return SourceLocation(); // avoid recursing into the suffix of declarator. 1127d382dcdSMarcel Hlopko return VisitTypeLoc(T); 1137d382dcdSMarcel Hlopko } 1147d382dcdSMarcel Hlopko 1157d382dcdSMarcel Hlopko private: 1167d382dcdSMarcel Hlopko template <class PtrLoc> SourceLocation HandlePointer(PtrLoc T) { 1177d382dcdSMarcel Hlopko auto L = Visit(T.getPointeeLoc()); 1187d382dcdSMarcel Hlopko if (L.isValid()) 1197d382dcdSMarcel Hlopko return L; 1207d382dcdSMarcel Hlopko return T.getLocalSourceRange().getBegin(); 1217d382dcdSMarcel Hlopko } 1227d382dcdSMarcel Hlopko }; 1237d382dcdSMarcel Hlopko } // namespace 1247d382dcdSMarcel Hlopko 1257d382dcdSMarcel Hlopko /// Gets the range of declarator as defined by the C++ grammar. E.g. 1267d382dcdSMarcel Hlopko /// `int a;` -> range of `a`, 1277d382dcdSMarcel Hlopko /// `int *a;` -> range of `*a`, 1287d382dcdSMarcel Hlopko /// `int a[10];` -> range of `a[10]`, 1297d382dcdSMarcel Hlopko /// `int a[1][2][3];` -> range of `a[1][2][3]`, 1307d382dcdSMarcel Hlopko /// `int *a = nullptr` -> range of `*a = nullptr`. 1317d382dcdSMarcel Hlopko /// FIMXE: \p Name must be a source range, e.g. for `operator+`. 1327d382dcdSMarcel Hlopko static SourceRange getDeclaratorRange(const SourceManager &SM, TypeLoc T, 1337d382dcdSMarcel Hlopko SourceLocation Name, 1347d382dcdSMarcel Hlopko SourceRange Initializer) { 1357d382dcdSMarcel Hlopko SourceLocation Start = GetStartLoc().Visit(T); 1367d382dcdSMarcel Hlopko SourceLocation End = T.getSourceRange().getEnd(); 1377d382dcdSMarcel Hlopko assert(End.isValid()); 1387d382dcdSMarcel Hlopko if (Name.isValid()) { 1397d382dcdSMarcel Hlopko if (Start.isInvalid()) 1407d382dcdSMarcel Hlopko Start = Name; 1417d382dcdSMarcel Hlopko if (SM.isBeforeInTranslationUnit(End, Name)) 1427d382dcdSMarcel Hlopko End = Name; 1437d382dcdSMarcel Hlopko } 1447d382dcdSMarcel Hlopko if (Initializer.isValid()) { 1457d382dcdSMarcel Hlopko assert(SM.isBeforeInTranslationUnit(End, Initializer.getEnd())); 1467d382dcdSMarcel Hlopko End = Initializer.getEnd(); 1477d382dcdSMarcel Hlopko } 1487d382dcdSMarcel Hlopko return SourceRange(Start, End); 1497d382dcdSMarcel Hlopko } 1507d382dcdSMarcel Hlopko 151a711a3a4SMarcel Hlopko namespace { 152a711a3a4SMarcel Hlopko /// All AST hierarchy roots that can be represented as pointers. 153a711a3a4SMarcel Hlopko using ASTPtr = llvm::PointerUnion<Stmt *, Decl *>; 154a711a3a4SMarcel Hlopko /// Maintains a mapping from AST to syntax tree nodes. This class will get more 155a711a3a4SMarcel Hlopko /// complicated as we support more kinds of AST nodes, e.g. TypeLocs. 156a711a3a4SMarcel Hlopko /// FIXME: expose this as public API. 157a711a3a4SMarcel Hlopko class ASTToSyntaxMapping { 158a711a3a4SMarcel Hlopko public: 159a711a3a4SMarcel Hlopko void add(ASTPtr From, syntax::Tree *To) { 160a711a3a4SMarcel Hlopko assert(To != nullptr); 161a711a3a4SMarcel Hlopko assert(!From.isNull()); 162a711a3a4SMarcel Hlopko 163a711a3a4SMarcel Hlopko bool Added = Nodes.insert({From, To}).second; 164a711a3a4SMarcel Hlopko (void)Added; 165a711a3a4SMarcel Hlopko assert(Added && "mapping added twice"); 166a711a3a4SMarcel Hlopko } 167a711a3a4SMarcel Hlopko 168a711a3a4SMarcel Hlopko syntax::Tree *find(ASTPtr P) const { return Nodes.lookup(P); } 169a711a3a4SMarcel Hlopko 170a711a3a4SMarcel Hlopko private: 171a711a3a4SMarcel Hlopko llvm::DenseMap<ASTPtr, syntax::Tree *> Nodes; 172a711a3a4SMarcel Hlopko }; 173a711a3a4SMarcel Hlopko } // namespace 174a711a3a4SMarcel Hlopko 1759b3f38f9SIlya Biryukov /// A helper class for constructing the syntax tree while traversing a clang 1769b3f38f9SIlya Biryukov /// AST. 1779b3f38f9SIlya Biryukov /// 1789b3f38f9SIlya Biryukov /// At each point of the traversal we maintain a list of pending nodes. 1799b3f38f9SIlya Biryukov /// Initially all tokens are added as pending nodes. When processing a clang AST 1809b3f38f9SIlya Biryukov /// node, the clients need to: 1819b3f38f9SIlya Biryukov /// - create a corresponding syntax node, 1829b3f38f9SIlya Biryukov /// - assign roles to all pending child nodes with 'markChild' and 1839b3f38f9SIlya Biryukov /// 'markChildToken', 1849b3f38f9SIlya Biryukov /// - replace the child nodes with the new syntax node in the pending list 1859b3f38f9SIlya Biryukov /// with 'foldNode'. 1869b3f38f9SIlya Biryukov /// 1879b3f38f9SIlya Biryukov /// Note that all children are expected to be processed when building a node. 1889b3f38f9SIlya Biryukov /// 1899b3f38f9SIlya Biryukov /// Call finalize() to finish building the tree and consume the root node. 1909b3f38f9SIlya Biryukov class syntax::TreeBuilder { 1919b3f38f9SIlya Biryukov public: 192c1bbefefSIlya Biryukov TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) { 193c1bbefefSIlya Biryukov for (const auto &T : Arena.tokenBuffer().expandedTokens()) 194c1bbefefSIlya Biryukov LocationToToken.insert({T.location().getRawEncoding(), &T}); 195c1bbefefSIlya Biryukov } 1969b3f38f9SIlya Biryukov 1979b3f38f9SIlya Biryukov llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); } 1987d382dcdSMarcel Hlopko const SourceManager &sourceManager() const { return Arena.sourceManager(); } 1999b3f38f9SIlya Biryukov 2009b3f38f9SIlya Biryukov /// Populate children for \p New node, assuming it covers tokens from \p 2019b3f38f9SIlya Biryukov /// Range. 202a711a3a4SMarcel Hlopko void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New, 203a711a3a4SMarcel Hlopko ASTPtr From) { 204a711a3a4SMarcel Hlopko assert(New); 205a711a3a4SMarcel Hlopko Pending.foldChildren(Arena, Range, New); 206a711a3a4SMarcel Hlopko if (From) 207a711a3a4SMarcel Hlopko Mapping.add(From, New); 208a711a3a4SMarcel Hlopko } 209a711a3a4SMarcel Hlopko void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New, 210a711a3a4SMarcel Hlopko TypeLoc L) { 211a711a3a4SMarcel Hlopko // FIXME: add mapping for TypeLocs 212a711a3a4SMarcel Hlopko foldNode(Range, New, nullptr); 213a711a3a4SMarcel Hlopko } 2149b3f38f9SIlya Biryukov 215e702bdb8SIlya Biryukov /// Must be called with the range of each `DeclaratorDecl`. Ensures the 216e702bdb8SIlya Biryukov /// corresponding declarator nodes are covered by `SimpleDeclaration`. 2177d382dcdSMarcel Hlopko void noticeDeclRange(llvm::ArrayRef<syntax::Token> Range); 218e702bdb8SIlya Biryukov 219e702bdb8SIlya Biryukov /// Notifies that we should not consume trailing semicolon when computing 220e702bdb8SIlya Biryukov /// token range of \p D. 2217d382dcdSMarcel Hlopko void noticeDeclWithoutSemicolon(Decl *D); 222e702bdb8SIlya Biryukov 22358fa50f4SIlya Biryukov /// Mark the \p Child node with a corresponding \p Role. All marked children 22458fa50f4SIlya Biryukov /// should be consumed by foldNode. 2257d382dcdSMarcel Hlopko /// When called on expressions (clang::Expr is derived from clang::Stmt), 22658fa50f4SIlya Biryukov /// wraps expressions into expression statement. 22758fa50f4SIlya Biryukov void markStmtChild(Stmt *Child, NodeRole Role); 22858fa50f4SIlya Biryukov /// Should be called for expressions in non-statement position to avoid 22958fa50f4SIlya Biryukov /// wrapping into expression statement. 23058fa50f4SIlya Biryukov void markExprChild(Expr *Child, NodeRole Role); 2319b3f38f9SIlya Biryukov /// Set role for a token starting at \p Loc. 232def65bb4SIlya Biryukov void markChildToken(SourceLocation Loc, NodeRole R); 2337d382dcdSMarcel Hlopko /// Set role for \p T. 2347d382dcdSMarcel Hlopko void markChildToken(const syntax::Token *T, NodeRole R); 2357d382dcdSMarcel Hlopko 236a711a3a4SMarcel Hlopko /// Set role for \p N. 237a711a3a4SMarcel Hlopko void markChild(syntax::Node *N, NodeRole R); 238a711a3a4SMarcel Hlopko /// Set role for the syntax node matching \p N. 239a711a3a4SMarcel Hlopko void markChild(ASTPtr N, NodeRole R); 2407d382dcdSMarcel Hlopko /// Set role for the delayed node that spans exactly \p Range. 2417d382dcdSMarcel Hlopko void markDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R); 24288bf9b3dSMarcel Hlopko /// Set role for the node that may or may not be delayed. Node must span 24388bf9b3dSMarcel Hlopko /// exactly \p Range. 24488bf9b3dSMarcel Hlopko void markMaybeDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R); 2459b3f38f9SIlya Biryukov 2469b3f38f9SIlya Biryukov /// Finish building the tree and consume the root node. 2479b3f38f9SIlya Biryukov syntax::TranslationUnit *finalize() && { 2489b3f38f9SIlya Biryukov auto Tokens = Arena.tokenBuffer().expandedTokens(); 249bfbf6b6cSIlya Biryukov assert(!Tokens.empty()); 250bfbf6b6cSIlya Biryukov assert(Tokens.back().kind() == tok::eof); 251bfbf6b6cSIlya Biryukov 2529b3f38f9SIlya Biryukov // Build the root of the tree, consuming all the children. 2531ad15046SIlya Biryukov Pending.foldChildren(Arena, Tokens.drop_back(), 2549b3f38f9SIlya Biryukov new (Arena.allocator()) syntax::TranslationUnit); 2559b3f38f9SIlya Biryukov 2563b929fe7SIlya Biryukov auto *TU = cast<syntax::TranslationUnit>(std::move(Pending).finalize()); 2573b929fe7SIlya Biryukov TU->assertInvariantsRecursive(); 2583b929fe7SIlya Biryukov return TU; 2599b3f38f9SIlya Biryukov } 2609b3f38f9SIlya Biryukov 26188bf9b3dSMarcel Hlopko /// Finds a token starting at \p L. The token must exist if \p L is valid. 26288bf9b3dSMarcel Hlopko const syntax::Token *findToken(SourceLocation L) const; 26388bf9b3dSMarcel Hlopko 264a711a3a4SMarcel Hlopko /// Finds the syntax tokens corresponding to the \p SourceRange. 265a711a3a4SMarcel Hlopko llvm::ArrayRef<syntax::Token> getRange(SourceRange Range) const { 266a711a3a4SMarcel Hlopko assert(Range.isValid()); 267a711a3a4SMarcel Hlopko return getRange(Range.getBegin(), Range.getEnd()); 268a711a3a4SMarcel Hlopko } 269a711a3a4SMarcel Hlopko 270a711a3a4SMarcel Hlopko /// Finds the syntax tokens corresponding to the passed source locations. 2719b3f38f9SIlya Biryukov /// \p First is the start position of the first token and \p Last is the start 2729b3f38f9SIlya Biryukov /// position of the last token. 2739b3f38f9SIlya Biryukov llvm::ArrayRef<syntax::Token> getRange(SourceLocation First, 2749b3f38f9SIlya Biryukov SourceLocation Last) const { 2759b3f38f9SIlya Biryukov assert(First.isValid()); 2769b3f38f9SIlya Biryukov assert(Last.isValid()); 2779b3f38f9SIlya Biryukov assert(First == Last || 2789b3f38f9SIlya Biryukov Arena.sourceManager().isBeforeInTranslationUnit(First, Last)); 2799b3f38f9SIlya Biryukov return llvm::makeArrayRef(findToken(First), std::next(findToken(Last))); 2809b3f38f9SIlya Biryukov } 28188bf9b3dSMarcel Hlopko 28288bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> 28388bf9b3dSMarcel Hlopko getTemplateRange(const ClassTemplateSpecializationDecl *D) const { 284a711a3a4SMarcel Hlopko auto Tokens = getRange(D->getSourceRange()); 28588bf9b3dSMarcel Hlopko return maybeAppendSemicolon(Tokens, D); 28688bf9b3dSMarcel Hlopko } 28788bf9b3dSMarcel Hlopko 28888bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> getDeclRange(const Decl *D) const { 28988bf9b3dSMarcel Hlopko llvm::ArrayRef<clang::syntax::Token> Tokens; 29088bf9b3dSMarcel Hlopko // We want to drop the template parameters for specializations. 29188bf9b3dSMarcel Hlopko if (const auto *S = llvm::dyn_cast<TagDecl>(D)) 29288bf9b3dSMarcel Hlopko Tokens = getRange(S->TypeDecl::getBeginLoc(), S->getEndLoc()); 29388bf9b3dSMarcel Hlopko else 294a711a3a4SMarcel Hlopko Tokens = getRange(D->getSourceRange()); 29588bf9b3dSMarcel Hlopko return maybeAppendSemicolon(Tokens, D); 2969b3f38f9SIlya Biryukov } 29758fa50f4SIlya Biryukov llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const { 298a711a3a4SMarcel Hlopko return getRange(E->getSourceRange()); 29958fa50f4SIlya Biryukov } 30058fa50f4SIlya Biryukov /// Find the adjusted range for the statement, consuming the trailing 30158fa50f4SIlya Biryukov /// semicolon when needed. 30258fa50f4SIlya Biryukov llvm::ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const { 303a711a3a4SMarcel Hlopko auto Tokens = getRange(S->getSourceRange()); 30458fa50f4SIlya Biryukov if (isa<CompoundStmt>(S)) 30558fa50f4SIlya Biryukov return Tokens; 30658fa50f4SIlya Biryukov 30758fa50f4SIlya Biryukov // Some statements miss a trailing semicolon, e.g. 'return', 'continue' and 30858fa50f4SIlya Biryukov // all statements that end with those. Consume this semicolon here. 309e702bdb8SIlya Biryukov if (Tokens.back().kind() == tok::semi) 310e702bdb8SIlya Biryukov return Tokens; 311e702bdb8SIlya Biryukov return withTrailingSemicolon(Tokens); 312e702bdb8SIlya Biryukov } 313e702bdb8SIlya Biryukov 314e702bdb8SIlya Biryukov private: 315e702bdb8SIlya Biryukov llvm::ArrayRef<syntax::Token> 31688bf9b3dSMarcel Hlopko maybeAppendSemicolon(llvm::ArrayRef<syntax::Token> Tokens, 31788bf9b3dSMarcel Hlopko const Decl *D) const { 31888bf9b3dSMarcel Hlopko if (llvm::isa<NamespaceDecl>(D)) 31988bf9b3dSMarcel Hlopko return Tokens; 32088bf9b3dSMarcel Hlopko if (DeclsWithoutSemicolons.count(D)) 32188bf9b3dSMarcel Hlopko return Tokens; 32288bf9b3dSMarcel Hlopko // FIXME: do not consume trailing semicolon on function definitions. 32388bf9b3dSMarcel Hlopko // Most declarations own a semicolon in syntax trees, but not in clang AST. 32488bf9b3dSMarcel Hlopko return withTrailingSemicolon(Tokens); 32588bf9b3dSMarcel Hlopko } 32688bf9b3dSMarcel Hlopko 32788bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> 328e702bdb8SIlya Biryukov withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const { 329e702bdb8SIlya Biryukov assert(!Tokens.empty()); 330e702bdb8SIlya Biryukov assert(Tokens.back().kind() != tok::eof); 3317d382dcdSMarcel Hlopko // We never consume 'eof', so looking at the next token is ok. 33258fa50f4SIlya Biryukov if (Tokens.back().kind() != tok::semi && Tokens.end()->kind() == tok::semi) 33358fa50f4SIlya Biryukov return llvm::makeArrayRef(Tokens.begin(), Tokens.end() + 1); 33458fa50f4SIlya Biryukov return Tokens; 3359b3f38f9SIlya Biryukov } 3369b3f38f9SIlya Biryukov 337a711a3a4SMarcel Hlopko void setRole(syntax::Node *N, NodeRole R) { 338a711a3a4SMarcel Hlopko assert(N->role() == NodeRole::Detached); 339a711a3a4SMarcel Hlopko N->setRole(R); 340a711a3a4SMarcel Hlopko } 341a711a3a4SMarcel Hlopko 3429b3f38f9SIlya Biryukov /// A collection of trees covering the input tokens. 3439b3f38f9SIlya Biryukov /// When created, each tree corresponds to a single token in the file. 3449b3f38f9SIlya Biryukov /// Clients call 'foldChildren' to attach one or more subtrees to a parent 3459b3f38f9SIlya Biryukov /// node and update the list of trees accordingly. 3469b3f38f9SIlya Biryukov /// 3479b3f38f9SIlya Biryukov /// Ensures that added nodes properly nest and cover the whole token stream. 3489b3f38f9SIlya Biryukov struct Forest { 3499b3f38f9SIlya Biryukov Forest(syntax::Arena &A) { 350bfbf6b6cSIlya Biryukov assert(!A.tokenBuffer().expandedTokens().empty()); 351bfbf6b6cSIlya Biryukov assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof); 3529b3f38f9SIlya Biryukov // Create all leaf nodes. 353bfbf6b6cSIlya Biryukov // Note that we do not have 'eof' in the tree. 3541ad15046SIlya Biryukov for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) { 3551ad15046SIlya Biryukov auto *L = new (A.allocator()) syntax::Leaf(&T); 3561ad15046SIlya Biryukov L->Original = true; 3571ad15046SIlya Biryukov L->CanModify = A.tokenBuffer().spelledForExpanded(T).hasValue(); 358a711a3a4SMarcel Hlopko Trees.insert(Trees.end(), {&T, L}); 3591ad15046SIlya Biryukov } 3609b3f38f9SIlya Biryukov } 3619b3f38f9SIlya Biryukov 362e702bdb8SIlya Biryukov ~Forest() { assert(DelayedFolds.empty()); } 363e702bdb8SIlya Biryukov 3647d382dcdSMarcel Hlopko void assignRoleDelayed(llvm::ArrayRef<syntax::Token> Range, 3657d382dcdSMarcel Hlopko syntax::NodeRole Role) { 3667d382dcdSMarcel Hlopko auto It = DelayedFolds.find(Range.begin()); 3677d382dcdSMarcel Hlopko assert(It != DelayedFolds.end()); 3687d382dcdSMarcel Hlopko assert(It->second.End == Range.end()); 3697d382dcdSMarcel Hlopko It->second.Role = Role; 3707d382dcdSMarcel Hlopko } 3717d382dcdSMarcel Hlopko 37288bf9b3dSMarcel Hlopko void assignRoleMaybeDelayed(llvm::ArrayRef<syntax::Token> Range, 37388bf9b3dSMarcel Hlopko syntax::NodeRole Role) { 37488bf9b3dSMarcel Hlopko auto It = DelayedFolds.find(Range.begin()); 37588bf9b3dSMarcel Hlopko if (It == DelayedFolds.end()) 37688bf9b3dSMarcel Hlopko return assignRole(Range, Role); 37788bf9b3dSMarcel Hlopko assert(It->second.End == Range.end()); 37888bf9b3dSMarcel Hlopko It->second.Role = Role; 37988bf9b3dSMarcel Hlopko } 38088bf9b3dSMarcel Hlopko 3819b3f38f9SIlya Biryukov void assignRole(llvm::ArrayRef<syntax::Token> Range, 3829b3f38f9SIlya Biryukov syntax::NodeRole Role) { 3839b3f38f9SIlya Biryukov assert(!Range.empty()); 3849b3f38f9SIlya Biryukov auto It = Trees.lower_bound(Range.begin()); 3859b3f38f9SIlya Biryukov assert(It != Trees.end() && "no node found"); 3869b3f38f9SIlya Biryukov assert(It->first == Range.begin() && "no child with the specified range"); 3879b3f38f9SIlya Biryukov assert((std::next(It) == Trees.end() || 3889b3f38f9SIlya Biryukov std::next(It)->first == Range.end()) && 3899b3f38f9SIlya Biryukov "no child with the specified range"); 390a711a3a4SMarcel Hlopko assert(It->second->role() == NodeRole::Detached && 391a711a3a4SMarcel Hlopko "re-assigning role for a child"); 392a711a3a4SMarcel Hlopko It->second->setRole(Role); 3939b3f38f9SIlya Biryukov } 3949b3f38f9SIlya Biryukov 395e702bdb8SIlya Biryukov /// Add \p Node to the forest and attach child nodes based on \p Tokens. 3961ad15046SIlya Biryukov void foldChildren(const syntax::Arena &A, 3971ad15046SIlya Biryukov llvm::ArrayRef<syntax::Token> Tokens, 3989b3f38f9SIlya Biryukov syntax::Tree *Node) { 399e702bdb8SIlya Biryukov // Execute delayed folds inside `Tokens`. 4007d382dcdSMarcel Hlopko auto BeginFolds = DelayedFolds.lower_bound(Tokens.begin()); 4017d382dcdSMarcel Hlopko auto EndFolds = BeginFolds; 4027d382dcdSMarcel Hlopko for (; EndFolds != DelayedFolds.end() && 4037d382dcdSMarcel Hlopko EndFolds->second.End <= Tokens.end(); 4047d382dcdSMarcel Hlopko ++EndFolds) 4057d382dcdSMarcel Hlopko ; 4067d382dcdSMarcel Hlopko // We go in reverse order to ensure we fold deeper nodes first. 4077d382dcdSMarcel Hlopko for (auto RevIt = EndFolds; RevIt != BeginFolds; --RevIt) { 4087d382dcdSMarcel Hlopko auto It = std::prev(RevIt); 4091ad15046SIlya Biryukov foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End), 410e702bdb8SIlya Biryukov It->second.Node); 4117d382dcdSMarcel Hlopko } 4127d382dcdSMarcel Hlopko DelayedFolds.erase(BeginFolds, EndFolds); 4139b3f38f9SIlya Biryukov 414e702bdb8SIlya Biryukov // Attach children to `Node`. 4151ad15046SIlya Biryukov foldChildrenEager(A, Tokens, Node); 416e702bdb8SIlya Biryukov } 4179b3f38f9SIlya Biryukov 418e702bdb8SIlya Biryukov /// Schedule a call to `foldChildren` that will only be executed when 419e702bdb8SIlya Biryukov /// containing node is folded. The range of delayed nodes can be extended by 420e702bdb8SIlya Biryukov /// calling `extendDelayedFold`. Only one delayed node for each starting 421e702bdb8SIlya Biryukov /// token is allowed. 422e702bdb8SIlya Biryukov void foldChildrenDelayed(llvm::ArrayRef<syntax::Token> Tokens, 423e702bdb8SIlya Biryukov syntax::Tree *Node) { 424e702bdb8SIlya Biryukov assert(!Tokens.empty()); 425e702bdb8SIlya Biryukov bool Inserted = 426e702bdb8SIlya Biryukov DelayedFolds.insert({Tokens.begin(), DelayedFold{Tokens.end(), Node}}) 427e702bdb8SIlya Biryukov .second; 428e702bdb8SIlya Biryukov (void)Inserted; 429e702bdb8SIlya Biryukov assert(Inserted && "Multiple delayed folds start at the same token"); 430e702bdb8SIlya Biryukov } 4319b3f38f9SIlya Biryukov 432e702bdb8SIlya Biryukov /// If there a delayed fold, starting at `ExtendedRange.begin()`, extends 433e702bdb8SIlya Biryukov /// its endpoint to `ExtendedRange.end()` and returns true. 434e702bdb8SIlya Biryukov /// Otherwise, returns false. 435e702bdb8SIlya Biryukov bool extendDelayedFold(llvm::ArrayRef<syntax::Token> ExtendedRange) { 436e702bdb8SIlya Biryukov assert(!ExtendedRange.empty()); 437e702bdb8SIlya Biryukov auto It = DelayedFolds.find(ExtendedRange.data()); 438e702bdb8SIlya Biryukov if (It == DelayedFolds.end()) 439e702bdb8SIlya Biryukov return false; 440e702bdb8SIlya Biryukov assert(It->second.End <= ExtendedRange.end()); 441e702bdb8SIlya Biryukov It->second.End = ExtendedRange.end(); 442e702bdb8SIlya Biryukov return true; 4439b3f38f9SIlya Biryukov } 4449b3f38f9SIlya Biryukov 4459b3f38f9SIlya Biryukov // EXPECTS: all tokens were consumed and are owned by a single root node. 4469b3f38f9SIlya Biryukov syntax::Node *finalize() && { 4479b3f38f9SIlya Biryukov assert(Trees.size() == 1); 448a711a3a4SMarcel Hlopko auto *Root = Trees.begin()->second; 4499b3f38f9SIlya Biryukov Trees = {}; 4509b3f38f9SIlya Biryukov return Root; 4519b3f38f9SIlya Biryukov } 4529b3f38f9SIlya Biryukov 4539b3f38f9SIlya Biryukov std::string str(const syntax::Arena &A) const { 4549b3f38f9SIlya Biryukov std::string R; 4559b3f38f9SIlya Biryukov for (auto It = Trees.begin(); It != Trees.end(); ++It) { 4569b3f38f9SIlya Biryukov unsigned CoveredTokens = 4579b3f38f9SIlya Biryukov It != Trees.end() 4589b3f38f9SIlya Biryukov ? (std::next(It)->first - It->first) 4599b3f38f9SIlya Biryukov : A.tokenBuffer().expandedTokens().end() - It->first; 4609b3f38f9SIlya Biryukov 461adcd0268SBenjamin Kramer R += std::string(llvm::formatv( 462a711a3a4SMarcel Hlopko "- '{0}' covers '{1}'+{2} tokens\n", It->second->kind(), 463adcd0268SBenjamin Kramer It->first->text(A.sourceManager()), CoveredTokens)); 464a711a3a4SMarcel Hlopko R += It->second->dump(A); 4659b3f38f9SIlya Biryukov } 4669b3f38f9SIlya Biryukov return R; 4679b3f38f9SIlya Biryukov } 4689b3f38f9SIlya Biryukov 4699b3f38f9SIlya Biryukov private: 470e702bdb8SIlya Biryukov /// Implementation detail of `foldChildren`, does acutal folding ignoring 471e702bdb8SIlya Biryukov /// delayed folds. 4721ad15046SIlya Biryukov void foldChildrenEager(const syntax::Arena &A, 4731ad15046SIlya Biryukov llvm::ArrayRef<syntax::Token> Tokens, 474e702bdb8SIlya Biryukov syntax::Tree *Node) { 475e702bdb8SIlya Biryukov assert(Node->firstChild() == nullptr && "node already has children"); 476e702bdb8SIlya Biryukov 477e702bdb8SIlya Biryukov auto *FirstToken = Tokens.begin(); 478e702bdb8SIlya Biryukov auto BeginChildren = Trees.lower_bound(FirstToken); 479e702bdb8SIlya Biryukov assert((BeginChildren == Trees.end() || 480e702bdb8SIlya Biryukov BeginChildren->first == FirstToken) && 481e702bdb8SIlya Biryukov "fold crosses boundaries of existing subtrees"); 482e702bdb8SIlya Biryukov auto EndChildren = Trees.lower_bound(Tokens.end()); 483e702bdb8SIlya Biryukov assert( 484e702bdb8SIlya Biryukov (EndChildren == Trees.end() || EndChildren->first == Tokens.end()) && 485e702bdb8SIlya Biryukov "fold crosses boundaries of existing subtrees"); 486e702bdb8SIlya Biryukov 4877d382dcdSMarcel Hlopko // We need to go in reverse order, because we can only prepend. 488a711a3a4SMarcel Hlopko for (auto It = EndChildren; It != BeginChildren; --It) { 489a711a3a4SMarcel Hlopko auto *C = std::prev(It)->second; 490a711a3a4SMarcel Hlopko if (C->role() == NodeRole::Detached) 491a711a3a4SMarcel Hlopko C->setRole(NodeRole::Unknown); 492a711a3a4SMarcel Hlopko Node->prependChildLowLevel(C); 493a711a3a4SMarcel Hlopko } 494e702bdb8SIlya Biryukov 4951ad15046SIlya Biryukov // Mark that this node came from the AST and is backed by the source code. 4961ad15046SIlya Biryukov Node->Original = true; 4971ad15046SIlya Biryukov Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue(); 4981ad15046SIlya Biryukov 499e702bdb8SIlya Biryukov Trees.erase(BeginChildren, EndChildren); 500a711a3a4SMarcel Hlopko Trees.insert({FirstToken, Node}); 501e702bdb8SIlya Biryukov } 5029b3f38f9SIlya Biryukov 5039b3f38f9SIlya Biryukov /// Maps from the start token to a subtree starting at that token. 504302cb3bcSIlya Biryukov /// Keys in the map are pointers into the array of expanded tokens, so 505302cb3bcSIlya Biryukov /// pointer order corresponds to the order of preprocessor tokens. 506a711a3a4SMarcel Hlopko std::map<const syntax::Token *, syntax::Node *> Trees; 507e702bdb8SIlya Biryukov 508e702bdb8SIlya Biryukov /// See documentation of `foldChildrenDelayed` for details. 509e702bdb8SIlya Biryukov struct DelayedFold { 510e702bdb8SIlya Biryukov const syntax::Token *End = nullptr; 511e702bdb8SIlya Biryukov syntax::Tree *Node = nullptr; 5127d382dcdSMarcel Hlopko NodeRole Role = NodeRole::Unknown; 513e702bdb8SIlya Biryukov }; 514e702bdb8SIlya Biryukov std::map<const syntax::Token *, DelayedFold> DelayedFolds; 5159b3f38f9SIlya Biryukov }; 5169b3f38f9SIlya Biryukov 5179b3f38f9SIlya Biryukov /// For debugging purposes. 5189b3f38f9SIlya Biryukov std::string str() { return Pending.str(Arena); } 5199b3f38f9SIlya Biryukov 5209b3f38f9SIlya Biryukov syntax::Arena &Arena; 521c1bbefefSIlya Biryukov /// To quickly find tokens by their start location. 522c1bbefefSIlya Biryukov llvm::DenseMap</*SourceLocation*/ unsigned, const syntax::Token *> 523c1bbefefSIlya Biryukov LocationToToken; 5249b3f38f9SIlya Biryukov Forest Pending; 525e702bdb8SIlya Biryukov llvm::DenseSet<Decl *> DeclsWithoutSemicolons; 526a711a3a4SMarcel Hlopko ASTToSyntaxMapping Mapping; 5279b3f38f9SIlya Biryukov }; 5289b3f38f9SIlya Biryukov 5299b3f38f9SIlya Biryukov namespace { 5309b3f38f9SIlya Biryukov class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> { 5319b3f38f9SIlya Biryukov public: 5329b3f38f9SIlya Biryukov explicit BuildTreeVisitor(ASTContext &Ctx, syntax::TreeBuilder &Builder) 5339b3f38f9SIlya Biryukov : Builder(Builder), LangOpts(Ctx.getLangOpts()) {} 5349b3f38f9SIlya Biryukov 5359b3f38f9SIlya Biryukov bool shouldTraversePostOrder() const { return true; } 5369b3f38f9SIlya Biryukov 5377d382dcdSMarcel Hlopko bool WalkUpFromDeclaratorDecl(DeclaratorDecl *DD) { 538e702bdb8SIlya Biryukov // Ensure declarators are covered by SimpleDeclaration. 53988bf9b3dSMarcel Hlopko Builder.noticeDeclRange(Builder.getDeclRange(DD)); 5407d382dcdSMarcel Hlopko 5417d382dcdSMarcel Hlopko // Build the declarator node. 5427d382dcdSMarcel Hlopko SourceRange Initializer; 5437d382dcdSMarcel Hlopko if (auto *V = llvm::dyn_cast<VarDecl>(DD)) { 5447d382dcdSMarcel Hlopko auto *I = V->getInit(); 5457d382dcdSMarcel Hlopko // Initializers in range-based-for are not part of the declarator 5467d382dcdSMarcel Hlopko if (I && !V->isCXXForRangeDecl()) 5477d382dcdSMarcel Hlopko Initializer = I->getSourceRange(); 5487d382dcdSMarcel Hlopko } 5497d382dcdSMarcel Hlopko auto Declarator = getDeclaratorRange( 5507d382dcdSMarcel Hlopko Builder.sourceManager(), DD->getTypeSourceInfo()->getTypeLoc(), 5517d382dcdSMarcel Hlopko getQualifiedNameStart(DD), Initializer); 5527d382dcdSMarcel Hlopko if (Declarator.isValid()) { 553a711a3a4SMarcel Hlopko auto *N = new (allocator()) syntax::SimpleDeclarator; 554a711a3a4SMarcel Hlopko Builder.foldNode(Builder.getRange(Declarator), N, DD); 555a711a3a4SMarcel Hlopko Builder.markChild(N, syntax::NodeRole::SimpleDeclaration_declarator); 5567d382dcdSMarcel Hlopko } 5577d382dcdSMarcel Hlopko 558e702bdb8SIlya Biryukov return true; 559e702bdb8SIlya Biryukov } 5607d382dcdSMarcel Hlopko 561e702bdb8SIlya Biryukov bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) { 5627d382dcdSMarcel Hlopko // Ensure declarators are covered by SimpleDeclaration. 56388bf9b3dSMarcel Hlopko Builder.noticeDeclRange(Builder.getDeclRange(D)); 5647d382dcdSMarcel Hlopko 5657d382dcdSMarcel Hlopko auto R = getDeclaratorRange( 5667d382dcdSMarcel Hlopko Builder.sourceManager(), D->getTypeSourceInfo()->getTypeLoc(), 5677d382dcdSMarcel Hlopko /*Name=*/D->getLocation(), /*Initializer=*/SourceRange()); 5687d382dcdSMarcel Hlopko if (R.isValid()) { 569a711a3a4SMarcel Hlopko auto *N = new (allocator()) syntax::SimpleDeclarator; 570a711a3a4SMarcel Hlopko Builder.foldNode(Builder.getRange(R), N, D); 571a711a3a4SMarcel Hlopko Builder.markChild(N, syntax::NodeRole::SimpleDeclaration_declarator); 5727d382dcdSMarcel Hlopko } 573e702bdb8SIlya Biryukov return true; 5749b3f38f9SIlya Biryukov } 5759b3f38f9SIlya Biryukov 5769b3f38f9SIlya Biryukov bool VisitDecl(Decl *D) { 5779b3f38f9SIlya Biryukov assert(!D->isImplicit()); 57888bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(D), 579a711a3a4SMarcel Hlopko new (allocator()) syntax::UnknownDeclaration(), D); 580e702bdb8SIlya Biryukov return true; 581e702bdb8SIlya Biryukov } 582e702bdb8SIlya Biryukov 58388bf9b3dSMarcel Hlopko // RAV does not call WalkUpFrom* on explicit instantiations, so we have to 58488bf9b3dSMarcel Hlopko // override Traverse. 58588bf9b3dSMarcel Hlopko // FIXME: make RAV call WalkUpFrom* instead. 58688bf9b3dSMarcel Hlopko bool 58788bf9b3dSMarcel Hlopko TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *C) { 58888bf9b3dSMarcel Hlopko if (!RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(C)) 58988bf9b3dSMarcel Hlopko return false; 59088bf9b3dSMarcel Hlopko if (C->isExplicitSpecialization()) 59188bf9b3dSMarcel Hlopko return true; // we are only interested in explicit instantiations. 592a711a3a4SMarcel Hlopko auto *Declaration = 593a711a3a4SMarcel Hlopko cast<syntax::SimpleDeclaration>(handleFreeStandingTagDecl(C)); 59488bf9b3dSMarcel Hlopko foldExplicitTemplateInstantiation( 59588bf9b3dSMarcel Hlopko Builder.getTemplateRange(C), Builder.findToken(C->getExternLoc()), 596a711a3a4SMarcel Hlopko Builder.findToken(C->getTemplateKeywordLoc()), Declaration, C); 59788bf9b3dSMarcel Hlopko return true; 59888bf9b3dSMarcel Hlopko } 59988bf9b3dSMarcel Hlopko 60088bf9b3dSMarcel Hlopko bool WalkUpFromTemplateDecl(TemplateDecl *S) { 60188bf9b3dSMarcel Hlopko foldTemplateDeclaration( 60288bf9b3dSMarcel Hlopko Builder.getDeclRange(S), 60388bf9b3dSMarcel Hlopko Builder.findToken(S->getTemplateParameters()->getTemplateLoc()), 604a711a3a4SMarcel Hlopko Builder.getDeclRange(S->getTemplatedDecl()), S); 60588bf9b3dSMarcel Hlopko return true; 60688bf9b3dSMarcel Hlopko } 60788bf9b3dSMarcel Hlopko 608e702bdb8SIlya Biryukov bool WalkUpFromTagDecl(TagDecl *C) { 60904f627f6SIlya Biryukov // FIXME: build the ClassSpecifier node. 61088bf9b3dSMarcel Hlopko if (!C->isFreeStanding()) { 61188bf9b3dSMarcel Hlopko assert(C->getNumTemplateParameterLists() == 0); 61204f627f6SIlya Biryukov return true; 61304f627f6SIlya Biryukov } 614a711a3a4SMarcel Hlopko handleFreeStandingTagDecl(C); 615a711a3a4SMarcel Hlopko return true; 616a711a3a4SMarcel Hlopko } 617a711a3a4SMarcel Hlopko 618a711a3a4SMarcel Hlopko syntax::Declaration *handleFreeStandingTagDecl(TagDecl *C) { 619a711a3a4SMarcel Hlopko assert(C->isFreeStanding()); 62088bf9b3dSMarcel Hlopko // Class is a declaration specifier and needs a spanning declaration node. 62188bf9b3dSMarcel Hlopko auto DeclarationRange = Builder.getDeclRange(C); 622a711a3a4SMarcel Hlopko syntax::Declaration *Result = new (allocator()) syntax::SimpleDeclaration; 623a711a3a4SMarcel Hlopko Builder.foldNode(DeclarationRange, Result, nullptr); 62488bf9b3dSMarcel Hlopko 62588bf9b3dSMarcel Hlopko // Build TemplateDeclaration nodes if we had template parameters. 62688bf9b3dSMarcel Hlopko auto ConsumeTemplateParameters = [&](const TemplateParameterList &L) { 62788bf9b3dSMarcel Hlopko const auto *TemplateKW = Builder.findToken(L.getTemplateLoc()); 62888bf9b3dSMarcel Hlopko auto R = llvm::makeArrayRef(TemplateKW, DeclarationRange.end()); 629a711a3a4SMarcel Hlopko Result = 630a711a3a4SMarcel Hlopko foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr); 63188bf9b3dSMarcel Hlopko DeclarationRange = R; 63288bf9b3dSMarcel Hlopko }; 63388bf9b3dSMarcel Hlopko if (auto *S = llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(C)) 63488bf9b3dSMarcel Hlopko ConsumeTemplateParameters(*S->getTemplateParameters()); 63588bf9b3dSMarcel Hlopko for (unsigned I = C->getNumTemplateParameterLists(); 0 < I; --I) 63688bf9b3dSMarcel Hlopko ConsumeTemplateParameters(*C->getTemplateParameterList(I - 1)); 637a711a3a4SMarcel Hlopko return Result; 6389b3f38f9SIlya Biryukov } 6399b3f38f9SIlya Biryukov 6409b3f38f9SIlya Biryukov bool WalkUpFromTranslationUnitDecl(TranslationUnitDecl *TU) { 6417d382dcdSMarcel Hlopko // We do not want to call VisitDecl(), the declaration for translation 6429b3f38f9SIlya Biryukov // unit is built by finalize(). 6439b3f38f9SIlya Biryukov return true; 6449b3f38f9SIlya Biryukov } 6459b3f38f9SIlya Biryukov 6469b3f38f9SIlya Biryukov bool WalkUpFromCompoundStmt(CompoundStmt *S) { 64751dad419SIlya Biryukov using NodeRole = syntax::NodeRole; 6489b3f38f9SIlya Biryukov 649def65bb4SIlya Biryukov Builder.markChildToken(S->getLBracLoc(), NodeRole::OpenParen); 65058fa50f4SIlya Biryukov for (auto *Child : S->body()) 65158fa50f4SIlya Biryukov Builder.markStmtChild(Child, NodeRole::CompoundStatement_statement); 652def65bb4SIlya Biryukov Builder.markChildToken(S->getRBracLoc(), NodeRole::CloseParen); 6539b3f38f9SIlya Biryukov 65458fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 655a711a3a4SMarcel Hlopko new (allocator()) syntax::CompoundStatement, S); 6569b3f38f9SIlya Biryukov return true; 6579b3f38f9SIlya Biryukov } 6589b3f38f9SIlya Biryukov 65958fa50f4SIlya Biryukov // Some statements are not yet handled by syntax trees. 66058fa50f4SIlya Biryukov bool WalkUpFromStmt(Stmt *S) { 66158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 662a711a3a4SMarcel Hlopko new (allocator()) syntax::UnknownStatement, S); 66358fa50f4SIlya Biryukov return true; 66458fa50f4SIlya Biryukov } 66558fa50f4SIlya Biryukov 66658fa50f4SIlya Biryukov bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) { 66758fa50f4SIlya Biryukov // We override to traverse range initializer as VarDecl. 66858fa50f4SIlya Biryukov // RAV traverses it as a statement, we produce invalid node kinds in that 66958fa50f4SIlya Biryukov // case. 67058fa50f4SIlya Biryukov // FIXME: should do this in RAV instead? 67158fa50f4SIlya Biryukov if (S->getInit() && !TraverseStmt(S->getInit())) 67258fa50f4SIlya Biryukov return false; 67358fa50f4SIlya Biryukov if (S->getLoopVariable() && !TraverseDecl(S->getLoopVariable())) 67458fa50f4SIlya Biryukov return false; 67558fa50f4SIlya Biryukov if (S->getRangeInit() && !TraverseStmt(S->getRangeInit())) 67658fa50f4SIlya Biryukov return false; 67758fa50f4SIlya Biryukov if (S->getBody() && !TraverseStmt(S->getBody())) 67858fa50f4SIlya Biryukov return false; 67958fa50f4SIlya Biryukov return true; 68058fa50f4SIlya Biryukov } 68158fa50f4SIlya Biryukov 68258fa50f4SIlya Biryukov bool TraverseStmt(Stmt *S) { 683e702bdb8SIlya Biryukov if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) { 684e702bdb8SIlya Biryukov // We want to consume the semicolon, make sure SimpleDeclaration does not. 685e702bdb8SIlya Biryukov for (auto *D : DS->decls()) 6867d382dcdSMarcel Hlopko Builder.noticeDeclWithoutSemicolon(D); 687e702bdb8SIlya Biryukov } else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) { 6887d382dcdSMarcel Hlopko // Do not recurse into subexpressions. 6897d382dcdSMarcel Hlopko // We do not have syntax trees for expressions yet, so we only want to see 69058fa50f4SIlya Biryukov // the first top-level expression. 69158fa50f4SIlya Biryukov return WalkUpFromExpr(E->IgnoreImplicit()); 69258fa50f4SIlya Biryukov } 69358fa50f4SIlya Biryukov return RecursiveASTVisitor::TraverseStmt(S); 69458fa50f4SIlya Biryukov } 69558fa50f4SIlya Biryukov 69658fa50f4SIlya Biryukov // Some expressions are not yet handled by syntax trees. 69758fa50f4SIlya Biryukov bool WalkUpFromExpr(Expr *E) { 69858fa50f4SIlya Biryukov assert(!isImplicitExpr(E) && "should be handled by TraverseStmt"); 69958fa50f4SIlya Biryukov Builder.foldNode(Builder.getExprRange(E), 700a711a3a4SMarcel Hlopko new (allocator()) syntax::UnknownExpression, E); 70158fa50f4SIlya Biryukov return true; 70258fa50f4SIlya Biryukov } 70358fa50f4SIlya Biryukov 704be14a22bSIlya Biryukov bool WalkUpFromNamespaceDecl(NamespaceDecl *S) { 70588bf9b3dSMarcel Hlopko auto Tokens = Builder.getDeclRange(S); 706be14a22bSIlya Biryukov if (Tokens.front().kind() == tok::coloncolon) { 707be14a22bSIlya Biryukov // Handle nested namespace definitions. Those start at '::' token, e.g. 708be14a22bSIlya Biryukov // namespace a^::b {} 709be14a22bSIlya Biryukov // FIXME: build corresponding nodes for the name of this namespace. 710be14a22bSIlya Biryukov return true; 711be14a22bSIlya Biryukov } 712a711a3a4SMarcel Hlopko Builder.foldNode(Tokens, new (allocator()) syntax::NamespaceDefinition, S); 713be14a22bSIlya Biryukov return true; 714be14a22bSIlya Biryukov } 715be14a22bSIlya Biryukov 7167d382dcdSMarcel Hlopko bool TraverseParenTypeLoc(ParenTypeLoc L) { 7177d382dcdSMarcel Hlopko // We reverse order of traversal to get the proper syntax structure. 7187d382dcdSMarcel Hlopko if (!WalkUpFromParenTypeLoc(L)) 7197d382dcdSMarcel Hlopko return false; 7207d382dcdSMarcel Hlopko return TraverseTypeLoc(L.getInnerLoc()); 7217d382dcdSMarcel Hlopko } 7227d382dcdSMarcel Hlopko 7237d382dcdSMarcel Hlopko bool WalkUpFromParenTypeLoc(ParenTypeLoc L) { 7247d382dcdSMarcel Hlopko Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen); 7257d382dcdSMarcel Hlopko Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen); 7267d382dcdSMarcel Hlopko Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getRParenLoc()), 727a711a3a4SMarcel Hlopko new (allocator()) syntax::ParenDeclarator, L); 7287d382dcdSMarcel Hlopko return true; 7297d382dcdSMarcel Hlopko } 7307d382dcdSMarcel Hlopko 7317d382dcdSMarcel Hlopko // Declarator chunks, they are produced by type locs and some clang::Decls. 7327d382dcdSMarcel Hlopko bool WalkUpFromArrayTypeLoc(ArrayTypeLoc L) { 7337d382dcdSMarcel Hlopko Builder.markChildToken(L.getLBracketLoc(), syntax::NodeRole::OpenParen); 7347d382dcdSMarcel Hlopko Builder.markExprChild(L.getSizeExpr(), 7357d382dcdSMarcel Hlopko syntax::NodeRole::ArraySubscript_sizeExpression); 7367d382dcdSMarcel Hlopko Builder.markChildToken(L.getRBracketLoc(), syntax::NodeRole::CloseParen); 7377d382dcdSMarcel Hlopko Builder.foldNode(Builder.getRange(L.getLBracketLoc(), L.getRBracketLoc()), 738a711a3a4SMarcel Hlopko new (allocator()) syntax::ArraySubscript, L); 7397d382dcdSMarcel Hlopko return true; 7407d382dcdSMarcel Hlopko } 7417d382dcdSMarcel Hlopko 7427d382dcdSMarcel Hlopko bool WalkUpFromFunctionTypeLoc(FunctionTypeLoc L) { 7437d382dcdSMarcel Hlopko Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen); 7447d382dcdSMarcel Hlopko for (auto *P : L.getParams()) 7457d382dcdSMarcel Hlopko Builder.markDelayedChild( 74688bf9b3dSMarcel Hlopko Builder.getDeclRange(P), 7477d382dcdSMarcel Hlopko syntax::NodeRole::ParametersAndQualifiers_parameter); 7487d382dcdSMarcel Hlopko Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen); 7497d382dcdSMarcel Hlopko Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getEndLoc()), 750a711a3a4SMarcel Hlopko new (allocator()) syntax::ParametersAndQualifiers, L); 7517d382dcdSMarcel Hlopko return true; 7527d382dcdSMarcel Hlopko } 7537d382dcdSMarcel Hlopko 7547d382dcdSMarcel Hlopko bool WalkUpFromFunctionProtoTypeLoc(FunctionProtoTypeLoc L) { 7557d382dcdSMarcel Hlopko if (!L.getTypePtr()->hasTrailingReturn()) 7567d382dcdSMarcel Hlopko return WalkUpFromFunctionTypeLoc(L); 7577d382dcdSMarcel Hlopko 7587d382dcdSMarcel Hlopko auto TrailingReturnTokens = BuildTrailingReturn(L); 7597d382dcdSMarcel Hlopko // Finish building the node for parameters. 7607d382dcdSMarcel Hlopko Builder.markChild(TrailingReturnTokens, 7617d382dcdSMarcel Hlopko syntax::NodeRole::ParametersAndQualifiers_trailingReturn); 7627d382dcdSMarcel Hlopko return WalkUpFromFunctionTypeLoc(L); 7637d382dcdSMarcel Hlopko } 7647d382dcdSMarcel Hlopko 7657d382dcdSMarcel Hlopko bool WalkUpFromMemberPointerTypeLoc(MemberPointerTypeLoc L) { 7667d382dcdSMarcel Hlopko auto SR = L.getLocalSourceRange(); 767a711a3a4SMarcel Hlopko Builder.foldNode(Builder.getRange(SR), 768a711a3a4SMarcel Hlopko new (allocator()) syntax::MemberPointer, L); 7697d382dcdSMarcel Hlopko return true; 7707d382dcdSMarcel Hlopko } 7717d382dcdSMarcel Hlopko 77258fa50f4SIlya Biryukov // The code below is very regular, it could even be generated with some 77358fa50f4SIlya Biryukov // preprocessor magic. We merely assign roles to the corresponding children 77458fa50f4SIlya Biryukov // and fold resulting nodes. 77558fa50f4SIlya Biryukov bool WalkUpFromDeclStmt(DeclStmt *S) { 77658fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 777a711a3a4SMarcel Hlopko new (allocator()) syntax::DeclarationStatement, S); 77858fa50f4SIlya Biryukov return true; 77958fa50f4SIlya Biryukov } 78058fa50f4SIlya Biryukov 78158fa50f4SIlya Biryukov bool WalkUpFromNullStmt(NullStmt *S) { 78258fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 783a711a3a4SMarcel Hlopko new (allocator()) syntax::EmptyStatement, S); 78458fa50f4SIlya Biryukov return true; 78558fa50f4SIlya Biryukov } 78658fa50f4SIlya Biryukov 78758fa50f4SIlya Biryukov bool WalkUpFromSwitchStmt(SwitchStmt *S) { 788def65bb4SIlya Biryukov Builder.markChildToken(S->getSwitchLoc(), 78958fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 79058fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 79158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 792a711a3a4SMarcel Hlopko new (allocator()) syntax::SwitchStatement, S); 79358fa50f4SIlya Biryukov return true; 79458fa50f4SIlya Biryukov } 79558fa50f4SIlya Biryukov 79658fa50f4SIlya Biryukov bool WalkUpFromCaseStmt(CaseStmt *S) { 797def65bb4SIlya Biryukov Builder.markChildToken(S->getKeywordLoc(), 79858fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 79958fa50f4SIlya Biryukov Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseStatement_value); 80058fa50f4SIlya Biryukov Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 80158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 802a711a3a4SMarcel Hlopko new (allocator()) syntax::CaseStatement, S); 80358fa50f4SIlya Biryukov return true; 80458fa50f4SIlya Biryukov } 80558fa50f4SIlya Biryukov 80658fa50f4SIlya Biryukov bool WalkUpFromDefaultStmt(DefaultStmt *S) { 807def65bb4SIlya Biryukov Builder.markChildToken(S->getKeywordLoc(), 80858fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 80958fa50f4SIlya Biryukov Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); 81058fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 811a711a3a4SMarcel Hlopko new (allocator()) syntax::DefaultStatement, S); 81258fa50f4SIlya Biryukov return true; 81358fa50f4SIlya Biryukov } 81458fa50f4SIlya Biryukov 81558fa50f4SIlya Biryukov bool WalkUpFromIfStmt(IfStmt *S) { 816def65bb4SIlya Biryukov Builder.markChildToken(S->getIfLoc(), syntax::NodeRole::IntroducerKeyword); 81758fa50f4SIlya Biryukov Builder.markStmtChild(S->getThen(), 81858fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_thenStatement); 819def65bb4SIlya Biryukov Builder.markChildToken(S->getElseLoc(), 82058fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_elseKeyword); 82158fa50f4SIlya Biryukov Builder.markStmtChild(S->getElse(), 82258fa50f4SIlya Biryukov syntax::NodeRole::IfStatement_elseStatement); 82358fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 824a711a3a4SMarcel Hlopko new (allocator()) syntax::IfStatement, S); 82558fa50f4SIlya Biryukov return true; 82658fa50f4SIlya Biryukov } 82758fa50f4SIlya Biryukov 82858fa50f4SIlya Biryukov bool WalkUpFromForStmt(ForStmt *S) { 829def65bb4SIlya Biryukov Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); 83058fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 83158fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 832a711a3a4SMarcel Hlopko new (allocator()) syntax::ForStatement, S); 83358fa50f4SIlya Biryukov return true; 83458fa50f4SIlya Biryukov } 83558fa50f4SIlya Biryukov 83658fa50f4SIlya Biryukov bool WalkUpFromWhileStmt(WhileStmt *S) { 837def65bb4SIlya Biryukov Builder.markChildToken(S->getWhileLoc(), 83858fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 83958fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 84058fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 841a711a3a4SMarcel Hlopko new (allocator()) syntax::WhileStatement, S); 84258fa50f4SIlya Biryukov return true; 84358fa50f4SIlya Biryukov } 84458fa50f4SIlya Biryukov 84558fa50f4SIlya Biryukov bool WalkUpFromContinueStmt(ContinueStmt *S) { 846def65bb4SIlya Biryukov Builder.markChildToken(S->getContinueLoc(), 84758fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 84858fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 849a711a3a4SMarcel Hlopko new (allocator()) syntax::ContinueStatement, S); 85058fa50f4SIlya Biryukov return true; 85158fa50f4SIlya Biryukov } 85258fa50f4SIlya Biryukov 85358fa50f4SIlya Biryukov bool WalkUpFromBreakStmt(BreakStmt *S) { 854def65bb4SIlya Biryukov Builder.markChildToken(S->getBreakLoc(), 85558fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 85658fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 857a711a3a4SMarcel Hlopko new (allocator()) syntax::BreakStatement, S); 85858fa50f4SIlya Biryukov return true; 85958fa50f4SIlya Biryukov } 86058fa50f4SIlya Biryukov 86158fa50f4SIlya Biryukov bool WalkUpFromReturnStmt(ReturnStmt *S) { 862def65bb4SIlya Biryukov Builder.markChildToken(S->getReturnLoc(), 86358fa50f4SIlya Biryukov syntax::NodeRole::IntroducerKeyword); 86458fa50f4SIlya Biryukov Builder.markExprChild(S->getRetValue(), 86558fa50f4SIlya Biryukov syntax::NodeRole::ReturnStatement_value); 86658fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 867a711a3a4SMarcel Hlopko new (allocator()) syntax::ReturnStatement, S); 86858fa50f4SIlya Biryukov return true; 86958fa50f4SIlya Biryukov } 87058fa50f4SIlya Biryukov 87158fa50f4SIlya Biryukov bool WalkUpFromCXXForRangeStmt(CXXForRangeStmt *S) { 872def65bb4SIlya Biryukov Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); 87358fa50f4SIlya Biryukov Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); 87458fa50f4SIlya Biryukov Builder.foldNode(Builder.getStmtRange(S), 875a711a3a4SMarcel Hlopko new (allocator()) syntax::RangeBasedForStatement, S); 87658fa50f4SIlya Biryukov return true; 87758fa50f4SIlya Biryukov } 87858fa50f4SIlya Biryukov 879be14a22bSIlya Biryukov bool WalkUpFromEmptyDecl(EmptyDecl *S) { 88088bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 881a711a3a4SMarcel Hlopko new (allocator()) syntax::EmptyDeclaration, S); 882be14a22bSIlya Biryukov return true; 883be14a22bSIlya Biryukov } 884be14a22bSIlya Biryukov 885be14a22bSIlya Biryukov bool WalkUpFromStaticAssertDecl(StaticAssertDecl *S) { 886be14a22bSIlya Biryukov Builder.markExprChild(S->getAssertExpr(), 887be14a22bSIlya Biryukov syntax::NodeRole::StaticAssertDeclaration_condition); 888be14a22bSIlya Biryukov Builder.markExprChild(S->getMessage(), 889be14a22bSIlya Biryukov syntax::NodeRole::StaticAssertDeclaration_message); 89088bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 891a711a3a4SMarcel Hlopko new (allocator()) syntax::StaticAssertDeclaration, S); 892be14a22bSIlya Biryukov return true; 893be14a22bSIlya Biryukov } 894be14a22bSIlya Biryukov 895be14a22bSIlya Biryukov bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) { 89688bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 897a711a3a4SMarcel Hlopko new (allocator()) syntax::LinkageSpecificationDeclaration, 898a711a3a4SMarcel Hlopko S); 899be14a22bSIlya Biryukov return true; 900be14a22bSIlya Biryukov } 901be14a22bSIlya Biryukov 902be14a22bSIlya Biryukov bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) { 90388bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 904a711a3a4SMarcel Hlopko new (allocator()) syntax::NamespaceAliasDefinition, S); 905be14a22bSIlya Biryukov return true; 906be14a22bSIlya Biryukov } 907be14a22bSIlya Biryukov 908be14a22bSIlya Biryukov bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) { 90988bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 910a711a3a4SMarcel Hlopko new (allocator()) syntax::UsingNamespaceDirective, S); 911be14a22bSIlya Biryukov return true; 912be14a22bSIlya Biryukov } 913be14a22bSIlya Biryukov 914be14a22bSIlya Biryukov bool WalkUpFromUsingDecl(UsingDecl *S) { 91588bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 916a711a3a4SMarcel Hlopko new (allocator()) syntax::UsingDeclaration, S); 917be14a22bSIlya Biryukov return true; 918be14a22bSIlya Biryukov } 919be14a22bSIlya Biryukov 920be14a22bSIlya Biryukov bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) { 92188bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 922a711a3a4SMarcel Hlopko new (allocator()) syntax::UsingDeclaration, S); 923be14a22bSIlya Biryukov return true; 924be14a22bSIlya Biryukov } 925be14a22bSIlya Biryukov 926be14a22bSIlya Biryukov bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) { 92788bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 928a711a3a4SMarcel Hlopko new (allocator()) syntax::UsingDeclaration, S); 929be14a22bSIlya Biryukov return true; 930be14a22bSIlya Biryukov } 931be14a22bSIlya Biryukov 932be14a22bSIlya Biryukov bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) { 93388bf9b3dSMarcel Hlopko Builder.foldNode(Builder.getDeclRange(S), 934a711a3a4SMarcel Hlopko new (allocator()) syntax::TypeAliasDeclaration, S); 935be14a22bSIlya Biryukov return true; 936be14a22bSIlya Biryukov } 937be14a22bSIlya Biryukov 9389b3f38f9SIlya Biryukov private: 9397d382dcdSMarcel Hlopko /// Returns the range of the built node. 940a711a3a4SMarcel Hlopko syntax::TrailingReturnType *BuildTrailingReturn(FunctionProtoTypeLoc L) { 9417d382dcdSMarcel Hlopko assert(L.getTypePtr()->hasTrailingReturn()); 9427d382dcdSMarcel Hlopko 9437d382dcdSMarcel Hlopko auto ReturnedType = L.getReturnLoc(); 9447d382dcdSMarcel Hlopko // Build node for the declarator, if any. 9457d382dcdSMarcel Hlopko auto ReturnDeclaratorRange = 9467d382dcdSMarcel Hlopko getDeclaratorRange(this->Builder.sourceManager(), ReturnedType, 9477d382dcdSMarcel Hlopko /*Name=*/SourceLocation(), 9487d382dcdSMarcel Hlopko /*Initializer=*/SourceLocation()); 949a711a3a4SMarcel Hlopko syntax::SimpleDeclarator *ReturnDeclarator = nullptr; 9507d382dcdSMarcel Hlopko if (ReturnDeclaratorRange.isValid()) { 951a711a3a4SMarcel Hlopko ReturnDeclarator = new (allocator()) syntax::SimpleDeclarator; 952a711a3a4SMarcel Hlopko Builder.foldNode(Builder.getRange(ReturnDeclaratorRange), 953a711a3a4SMarcel Hlopko ReturnDeclarator, nullptr); 9547d382dcdSMarcel Hlopko } 9557d382dcdSMarcel Hlopko 9567d382dcdSMarcel Hlopko // Build node for trailing return type. 957a711a3a4SMarcel Hlopko auto Return = Builder.getRange(ReturnedType.getSourceRange()); 9587d382dcdSMarcel Hlopko const auto *Arrow = Return.begin() - 1; 9597d382dcdSMarcel Hlopko assert(Arrow->kind() == tok::arrow); 9607d382dcdSMarcel Hlopko auto Tokens = llvm::makeArrayRef(Arrow, Return.end()); 9617d382dcdSMarcel Hlopko Builder.markChildToken(Arrow, syntax::NodeRole::TrailingReturnType_arrow); 962a711a3a4SMarcel Hlopko if (ReturnDeclarator) 963a711a3a4SMarcel Hlopko Builder.markChild(ReturnDeclarator, 9647d382dcdSMarcel Hlopko syntax::NodeRole::TrailingReturnType_declarator); 965a711a3a4SMarcel Hlopko auto *R = new (allocator()) syntax::TrailingReturnType; 966a711a3a4SMarcel Hlopko Builder.foldNode(Tokens, R, nullptr); 967a711a3a4SMarcel Hlopko return R; 9687d382dcdSMarcel Hlopko } 96988bf9b3dSMarcel Hlopko 970a711a3a4SMarcel Hlopko void foldExplicitTemplateInstantiation( 971a711a3a4SMarcel Hlopko ArrayRef<syntax::Token> Range, const syntax::Token *ExternKW, 97288bf9b3dSMarcel Hlopko const syntax::Token *TemplateKW, 973a711a3a4SMarcel Hlopko syntax::SimpleDeclaration *InnerDeclaration, Decl *From) { 97488bf9b3dSMarcel Hlopko assert(!ExternKW || ExternKW->kind() == tok::kw_extern); 97588bf9b3dSMarcel Hlopko assert(TemplateKW && TemplateKW->kind() == tok::kw_template); 97688bf9b3dSMarcel Hlopko Builder.markChildToken( 97788bf9b3dSMarcel Hlopko ExternKW, 97888bf9b3dSMarcel Hlopko syntax::NodeRole::ExplicitTemplateInstantiation_externKeyword); 97988bf9b3dSMarcel Hlopko Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword); 98088bf9b3dSMarcel Hlopko Builder.markChild( 98188bf9b3dSMarcel Hlopko InnerDeclaration, 98288bf9b3dSMarcel Hlopko syntax::NodeRole::ExplicitTemplateInstantiation_declaration); 983a711a3a4SMarcel Hlopko Builder.foldNode( 984a711a3a4SMarcel Hlopko Range, new (allocator()) syntax::ExplicitTemplateInstantiation, From); 98588bf9b3dSMarcel Hlopko } 98688bf9b3dSMarcel Hlopko 987a711a3a4SMarcel Hlopko syntax::TemplateDeclaration *foldTemplateDeclaration( 988a711a3a4SMarcel Hlopko ArrayRef<syntax::Token> Range, const syntax::Token *TemplateKW, 989a711a3a4SMarcel Hlopko ArrayRef<syntax::Token> TemplatedDeclaration, Decl *From) { 99088bf9b3dSMarcel Hlopko assert(TemplateKW && TemplateKW->kind() == tok::kw_template); 99188bf9b3dSMarcel Hlopko Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword); 99288bf9b3dSMarcel Hlopko Builder.markMaybeDelayedChild( 99388bf9b3dSMarcel Hlopko TemplatedDeclaration, 99488bf9b3dSMarcel Hlopko syntax::NodeRole::TemplateDeclaration_declaration); 995a711a3a4SMarcel Hlopko 996a711a3a4SMarcel Hlopko auto *N = new (allocator()) syntax::TemplateDeclaration; 997a711a3a4SMarcel Hlopko Builder.foldNode(Range, N, From); 998a711a3a4SMarcel Hlopko return N; 99988bf9b3dSMarcel Hlopko } 100088bf9b3dSMarcel Hlopko 10019b3f38f9SIlya Biryukov /// A small helper to save some typing. 10029b3f38f9SIlya Biryukov llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); } 10039b3f38f9SIlya Biryukov 10049b3f38f9SIlya Biryukov syntax::TreeBuilder &Builder; 10059b3f38f9SIlya Biryukov const LangOptions &LangOpts; 10069b3f38f9SIlya Biryukov }; 10079b3f38f9SIlya Biryukov } // namespace 10089b3f38f9SIlya Biryukov 10097d382dcdSMarcel Hlopko void syntax::TreeBuilder::noticeDeclRange(llvm::ArrayRef<syntax::Token> Range) { 1010e702bdb8SIlya Biryukov if (Pending.extendDelayedFold(Range)) 1011e702bdb8SIlya Biryukov return; 1012e702bdb8SIlya Biryukov Pending.foldChildrenDelayed(Range, 1013e702bdb8SIlya Biryukov new (allocator()) syntax::SimpleDeclaration); 1014e702bdb8SIlya Biryukov } 1015e702bdb8SIlya Biryukov 10167d382dcdSMarcel Hlopko void syntax::TreeBuilder::noticeDeclWithoutSemicolon(Decl *D) { 1017e702bdb8SIlya Biryukov DeclsWithoutSemicolons.insert(D); 1018e702bdb8SIlya Biryukov } 1019e702bdb8SIlya Biryukov 1020def65bb4SIlya Biryukov void syntax::TreeBuilder::markChildToken(SourceLocation Loc, NodeRole Role) { 10219b3f38f9SIlya Biryukov if (Loc.isInvalid()) 10229b3f38f9SIlya Biryukov return; 10239b3f38f9SIlya Biryukov Pending.assignRole(*findToken(Loc), Role); 10249b3f38f9SIlya Biryukov } 10259b3f38f9SIlya Biryukov 10267d382dcdSMarcel Hlopko void syntax::TreeBuilder::markChildToken(const syntax::Token *T, NodeRole R) { 10277d382dcdSMarcel Hlopko if (!T) 10287d382dcdSMarcel Hlopko return; 10297d382dcdSMarcel Hlopko Pending.assignRole(*T, R); 10307d382dcdSMarcel Hlopko } 10317d382dcdSMarcel Hlopko 1032a711a3a4SMarcel Hlopko void syntax::TreeBuilder::markChild(syntax::Node *N, NodeRole R) { 1033a711a3a4SMarcel Hlopko assert(N); 1034a711a3a4SMarcel Hlopko setRole(N, R); 1035a711a3a4SMarcel Hlopko } 1036a711a3a4SMarcel Hlopko 1037a711a3a4SMarcel Hlopko void syntax::TreeBuilder::markChild(ASTPtr N, NodeRole R) { 1038a711a3a4SMarcel Hlopko auto *SN = Mapping.find(N); 1039a711a3a4SMarcel Hlopko assert(SN != nullptr); 1040a711a3a4SMarcel Hlopko setRole(SN, R); 10417d382dcdSMarcel Hlopko } 10427d382dcdSMarcel Hlopko 10437d382dcdSMarcel Hlopko void syntax::TreeBuilder::markDelayedChild(llvm::ArrayRef<syntax::Token> Range, 10447d382dcdSMarcel Hlopko NodeRole R) { 10457d382dcdSMarcel Hlopko Pending.assignRoleDelayed(Range, R); 10467d382dcdSMarcel Hlopko } 10477d382dcdSMarcel Hlopko 104888bf9b3dSMarcel Hlopko void syntax::TreeBuilder::markMaybeDelayedChild( 104988bf9b3dSMarcel Hlopko llvm::ArrayRef<syntax::Token> Range, NodeRole R) { 105088bf9b3dSMarcel Hlopko Pending.assignRoleMaybeDelayed(Range, R); 105188bf9b3dSMarcel Hlopko } 105288bf9b3dSMarcel Hlopko 105358fa50f4SIlya Biryukov void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { 105458fa50f4SIlya Biryukov if (!Child) 105558fa50f4SIlya Biryukov return; 105658fa50f4SIlya Biryukov 1057a711a3a4SMarcel Hlopko syntax::Tree *ChildNode = Mapping.find(Child); 1058a711a3a4SMarcel Hlopko assert(ChildNode != nullptr); 1059a711a3a4SMarcel Hlopko 106058fa50f4SIlya Biryukov // This is an expression in a statement position, consume the trailing 106158fa50f4SIlya Biryukov // semicolon and form an 'ExpressionStatement' node. 1062*896fa30fSSimon Pilgrim if (isa<Expr>(Child)) { 1063a711a3a4SMarcel Hlopko setRole(ChildNode, NodeRole::ExpressionStatement_expression); 1064a711a3a4SMarcel Hlopko ChildNode = new (allocator()) syntax::ExpressionStatement; 1065a711a3a4SMarcel Hlopko // (!) 'getStmtRange()' ensures this covers a trailing semicolon. 1066a711a3a4SMarcel Hlopko Pending.foldChildren(Arena, getStmtRange(Child), ChildNode); 106758fa50f4SIlya Biryukov } 1068a711a3a4SMarcel Hlopko setRole(ChildNode, Role); 106958fa50f4SIlya Biryukov } 107058fa50f4SIlya Biryukov 107158fa50f4SIlya Biryukov void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) { 1072be14a22bSIlya Biryukov if (!Child) 1073be14a22bSIlya Biryukov return; 1074a711a3a4SMarcel Hlopko Child = Child->IgnoreImplicit(); 1075be14a22bSIlya Biryukov 1076a711a3a4SMarcel Hlopko syntax::Tree *ChildNode = Mapping.find(Child); 1077a711a3a4SMarcel Hlopko assert(ChildNode != nullptr); 1078a711a3a4SMarcel Hlopko setRole(ChildNode, Role); 107958fa50f4SIlya Biryukov } 108058fa50f4SIlya Biryukov 10819b3f38f9SIlya Biryukov const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const { 108288bf9b3dSMarcel Hlopko if (L.isInvalid()) 108388bf9b3dSMarcel Hlopko return nullptr; 1084c1bbefefSIlya Biryukov auto It = LocationToToken.find(L.getRawEncoding()); 1085c1bbefefSIlya Biryukov assert(It != LocationToToken.end()); 1086c1bbefefSIlya Biryukov return It->second; 10879b3f38f9SIlya Biryukov } 10889b3f38f9SIlya Biryukov 10899b3f38f9SIlya Biryukov syntax::TranslationUnit * 10909b3f38f9SIlya Biryukov syntax::buildSyntaxTree(Arena &A, const TranslationUnitDecl &TU) { 10919b3f38f9SIlya Biryukov TreeBuilder Builder(A); 10929b3f38f9SIlya Biryukov BuildTreeVisitor(TU.getASTContext(), Builder).TraverseAST(TU.getASTContext()); 10939b3f38f9SIlya Biryukov return std::move(Builder).finalize(); 10949b3f38f9SIlya Biryukov } 1095