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