19 #include "llvm/ADT/ArrayRef.h" 20 #include "llvm/ADT/STLExtras.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/Support/Allocator.h" 23 #include "llvm/Support/Casting.h" 24 #include "llvm/Support/FormatVariadic.h" 25 #include "llvm/Support/raw_ostream.h" 28 using namespace clang;
47 TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {}
49 llvm::BumpPtrAllocator &
allocator() {
return Arena.allocator(); }
60 auto Tokens = Arena.tokenBuffer().expandedTokens();
62 Pending.foldChildren(Tokens,
65 return cast<syntax::TranslationUnit>(std::move(Pending).finalize());
76 assert(First == Last ||
77 Arena.sourceManager().isBeforeInTranslationUnit(First, Last));
78 return llvm::makeArrayRef(findToken(First), std::next(findToken(Last)));
98 Forest(syntax::Arena &A) {
102 for (
auto &T : A.tokenBuffer().expandedTokens())
103 Trees.insert(Trees.end(),
104 {&T, NodeAndRole{
new (A.allocator())
syntax::Leaf(&T)}});
109 assert(!Range.empty());
110 auto It = Trees.lower_bound(Range.begin());
111 assert(It != Trees.end() &&
"no node found");
112 assert(It->first == Range.begin() &&
"no child with the specified range");
113 assert((std::next(It) == Trees.end() ||
114 std::next(It)->first == Range.end()) &&
115 "no child with the specified range");
116 It->second.Role = Role;
123 assert(!NodeTokens.empty());
124 assert(Node->firstChild() ==
nullptr &&
"node already has children");
126 auto *FirstToken = NodeTokens.begin();
127 auto BeginChildren = Trees.lower_bound(FirstToken);
128 assert(BeginChildren != Trees.end() &&
129 BeginChildren->first == FirstToken &&
130 "fold crosses boundaries of existing subtrees");
131 auto EndChildren = Trees.lower_bound(NodeTokens.end());
132 assert((EndChildren == Trees.end() ||
133 EndChildren->first == NodeTokens.end()) &&
134 "fold crosses boundaries of existing subtrees");
137 for (
auto It = EndChildren; It != BeginChildren; --It)
138 Node->prependChildLowLevel(std::prev(It)->second.Node,
139 std::prev(It)->second.Role);
141 Trees.erase(BeginChildren, EndChildren);
142 Trees.insert({FirstToken, NodeAndRole(Node)});
147 assert(Trees.size() == 1);
148 auto *Root = Trees.begin()->second.Node;
153 std::string str(
const syntax::Arena &A)
const {
155 for (
auto It = Trees.begin(); It != Trees.end(); ++It) {
156 unsigned CoveredTokens =
158 ? (std::next(It)->first - It->first)
159 : A.tokenBuffer().expandedTokens().end() - It->first;
161 R += llvm::formatv(
"- '{0}' covers '{1}'+{2} tokens\n",
162 It->second.Node->kind(),
163 It->first->text(A.sourceManager()), CoveredTokens);
164 R += It->second.Node->dump(A);
182 std::map<const syntax::Token *, NodeAndRole> Trees;
186 std::string str() {
return Pending.str(Arena); }
188 syntax::Arena &Arena;
198 bool shouldTraversePostOrder()
const {
return true; }
200 bool TraverseDecl(
Decl *D) {
201 if (!D || isa<TranslationUnitDecl>(D))
208 bool VisitDecl(
Decl *D) {
210 "expected a top-level decl");
238 llvm::BumpPtrAllocator &allocator() {
return Builder.
allocator(); }
247 Pending.foldChildren(Range, New);
254 Pending.assignRole(*findToken(Loc), Role);
257 const syntax::Token *syntax::TreeBuilder::findToken(
SourceLocation L)
const {
258 auto Tokens = Arena.tokenBuffer().expandedTokens();
259 auto &
SM = Arena.sourceManager();
260 auto It = llvm::partition_point(Tokens, [&](
const syntax::Token &T) {
263 assert(It != Tokens.end());
264 assert(It->location() == L);
270 TreeBuilder Builder(A);
272 return std::move(Builder).finalize();
SourceLocation getRBracLoc() const
Stmt - This represents one statement.
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getBeginLoc() const LLVM_READONLY
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
syntax::TranslationUnit * buildSyntaxTree(Arena &A, const clang::TranslationUnitDecl &TU)
Build a syntax tree for the main file.
SourceLocation getEndLoc() const LLVM_READONLY
void finalize(TemplateInstantiationCallbackPtrs &Callbacks, const Sema &TheSema)
void markChildToken(SourceLocation Loc, tok::TokenKind Kind, NodeRole R)
Set role for a token starting at Loc.
void foldNode(llvm::ArrayRef< syntax::Token > Range, syntax::Tree *New)
Populate children for New node, assuming it covers tokens from Range.
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
llvm::BumpPtrAllocator & allocator()
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceLocation getBeginLoc() const LLVM_READONLY
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
SourceLocation getLBracLoc() const
ASTContext & getASTContext() const
llvm::ArrayRef< syntax::Token > getRange(const Stmt *S) const
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
CompoundStmt - This represents a group of statements like { stmt stmt }.
A memory arena for syntax trees.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
DeclContext * getDeclContext()
SourceLocation getEndLoc() const LLVM_READONLY
Encodes a location in the source.
A helper class for constructing the syntax tree while traversing a clang AST.
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
syntax::TranslationUnit * finalize() &&
Finish building the tree and consume the root node.
ast_type_traits::DynTypedNode Node
NodeRole
A relation between a parent and child node. Used for implementing accessors.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
Defines the clang::TokenKind enum and support functions.
Defines the clang::SourceLocation class and associated facilities.
llvm::ArrayRef< syntax::Token > getRange(const Decl *D) const
The top declaration context.
TreeBuilder(syntax::Arena &Arena)
const LangOptions & getLangOpts() const
llvm::ArrayRef< syntax::Token > getRange(SourceLocation First, SourceLocation Last) const
getRange() finds the syntax tokens corresponding to the passed source locations.