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