11 #include "clang/AST/ASTTypeTraits.h" 12 #include "clang/AST/PrettyPrinter.h" 13 #include "clang/AST/RecursiveASTVisitor.h" 14 #include "clang/AST/TypeLoc.h" 15 #include "llvm/ADT/STLExtras.h" 21 using Node = SelectionTree::Node;
22 using ast_type_traits::DynTypedNode;
30 bool add(
unsigned Begin,
unsigned End) {
31 assert(std::is_sorted(Ranges.begin(), Ranges.end()));
34 if (covered(Begin, End))
36 auto Pair = std::make_pair(Begin, End);
37 Ranges.insert(llvm::upper_bound(Ranges, Pair), Pair);
42 bool covered(
unsigned Begin,
unsigned End) {
44 for (
const auto &R : Ranges) {
47 if (Begin < R.second) {
56 std::vector<std::pair<unsigned, unsigned>> Ranges;
67 class SelectionVisitor :
public RecursiveASTVisitor<SelectionVisitor> {
71 static std::deque<Node> collect(ASTContext &
AST,
unsigned Begin,
72 unsigned End, FileID
File) {
73 SelectionVisitor V(AST, Begin, End, File);
75 assert(V.Stack.size() == 1 &&
"Unpaired push/pop?");
76 assert(V.Stack.top() == &V.Nodes.front());
77 if (V.Nodes.size() == 1)
79 return std::move(V.Nodes);
93 bool TraverseDecl(Decl *
X) {
94 if (X && isa<TranslationUnitDecl>(X))
95 return Base::TraverseDecl(X);
97 if (X && X->isImplicit())
99 return traverseNode(X, [&] {
return Base::TraverseDecl(X); });
101 bool TraverseTypeLoc(TypeLoc X) {
102 return traverseNode(&X, [&] {
return Base::TraverseTypeLoc(X); });
104 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc X) {
106 &X, [&] {
return Base::TraverseNestedNameSpecifierLoc(X); });
108 bool TraverseConstructorInitializer(CXXCtorInitializer *X) {
110 X, [&] {
return Base::TraverseConstructorInitializer(X); });
113 bool dataTraverseStmtPre(Stmt *X) {
114 if (!X || canSafelySkipNode(X->getSourceRange()))
116 push(DynTypedNode::create(*X));
119 bool dataTraverseStmtPost(Stmt *X) {
124 bool TraverseNestedNameSpecifier(NestedNameSpecifier *) {
return true; }
125 bool TraverseType(QualType) {
return true; }
128 using Base = RecursiveASTVisitor<SelectionVisitor>;
130 SelectionVisitor(ASTContext &AST,
unsigned SelBegin,
unsigned SelEnd,
132 : SM(AST.getSourceManager()), LangOpts(AST.getLangOpts()),
133 SelBegin(SelBegin), SelEnd(SelEnd), SelFile(SelFile),
134 SelBeginTokenStart(SM.getFileOffset(Lexer::GetBeginningOfToken(
135 SM.getComposedLoc(SelFile, SelBegin), SM, LangOpts))) {
137 Nodes.emplace_back();
138 Nodes.back().ASTNode = DynTypedNode::create(*AST.getTranslationUnitDecl());
139 Nodes.back().Parent =
nullptr;
141 Stack.push(&Nodes.back());
146 template <
typename T,
typename Func>
147 bool traverseNode(T *Node,
const Func &Body) {
148 if (Node ==
nullptr || canSafelySkipNode(Node->getSourceRange()))
150 push(DynTypedNode::create(*Node));
183 bool canSafelySkipNode(SourceRange S) {
184 auto B = SM.getDecomposedLoc(S.getBegin());
185 auto E = SM.getDecomposedLoc(S.getEnd());
186 if (B.first != SelFile || E.first != SelFile)
188 return B.second >= SelEnd || E.second < SelBeginTokenStart;
193 void push(DynTypedNode Node) {
194 bool SelectedEarly = claimRange(earlySourceRange(Node));
195 Nodes.emplace_back();
196 Nodes.back().ASTNode = std::move(Node);
197 Nodes.back().Parent = Stack.top();
199 Nodes.back().Selected =
201 Stack.push(&Nodes.back());
207 Node &N = *Stack.top();
208 if (
auto Sel = claimRange(N.ASTNode.getSourceRange()))
210 if (N.Selected || !N.Children.empty()) {
212 N.Parent->Children.push_back(&N);
215 assert(&N == &Nodes.back());
224 SourceRange earlySourceRange(
const DynTypedNode &N) {
225 if (
const Decl *
D = N.get<Decl>()) {
227 if (
auto *FD = llvm::dyn_cast<FunctionDecl>(
D))
228 return FD->getNameInfo().getSourceRange();
230 else if (
auto *VD = llvm::dyn_cast<VarDecl>(
D))
231 return VD->getLocation();
233 return SourceRange();
248 auto B = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getBegin()));
249 auto E = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getEnd()));
251 if (B.first != SelFile || E.first != SelFile)
256 if (B.second >= SelEnd || E.second < SelBeginTokenStart)
261 E.second += Lexer::MeasureTokenLength(S.getEnd(), SM, LangOpts);
262 auto PreciseBounds = std::make_pair(B.second, E.second);
264 B.second = std::max(B.second, SelBegin);
265 E.second = std::min(E.second, SelEnd);
266 if (B.second >= E.second)
270 if (!Claimed.add(B.second, E.second))
274 return (PreciseBounds.first >= SelBegin && PreciseBounds.second <= SelEnd)
280 const LangOptions &LangOpts;
281 std::stack<Node *> Stack;
283 std::deque<Node> Nodes;
293 unsigned SelBeginTokenStart;
298 void SelectionTree::print(llvm::raw_ostream &OS,
const SelectionTree::Node &N,
305 if (
const TypeLoc *TL = N.ASTNode.get<TypeLoc>()) {
308 if (TL->getTypeLocClass() == TypeLoc::Qualified)
309 OS <<
"QualifiedTypeLoc";
311 OS << TL->getType()->getTypeClassName() <<
"TypeLoc";
313 OS << N.ASTNode.getNodeKind().asStringRef();
316 N.ASTNode.print(OS, PrintPolicy);
318 for (
const Node *Child : N.Children)
319 print(OS, *Child, Indent + 2);
325 StringRef Buf = AST.getSourceManager().getBufferData(FID);
331 if (Offset == Buf.size())
332 return {Offset - 1, Offset};
336 if (isWhitespace(Buf[Offset]) && !isWhitespace(Buf[Offset - 1]))
337 return {Offset - 1, Offset};
338 return {
Offset, Offset + 1};
342 : PrintPolicy(AST.getLangOpts()) {
345 FileID FID = AST.getSourceManager().getMainFileID();
347 std::tie(Begin, End) =
pointBounds(Begin, FID, AST);
348 PrintPolicy.TerseOutput =
true;
349 PrintPolicy.IncludeNewlines =
false;
351 Nodes = SelectionVisitor::collect(AST, Begin, End, FID);
352 Root = Nodes.empty() ? nullptr : &Nodes.front();
361 const Node *Ancestor = Root;
363 Ancestor = Ancestor->
Children.front();
368 for (
const Node* CurrentNode =
this; CurrentNode !=
nullptr;
369 CurrentNode = CurrentNode->Parent) {
370 if (
const Decl* Current = CurrentNode->ASTNode.get<Decl>()) {
371 if (CurrentNode !=
this)
372 if (
auto *DC = dyn_cast<DeclContext>(Current))
374 return *Current->getDeclContext();
377 llvm_unreachable(
"A tree must always be rooted at TranslationUnitDecl.");
llvm::SmallVector< const Node *, 8 > Children
static std::pair< unsigned, unsigned > pointBounds(unsigned Offset, FileID FID, ASTContext &AST)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static URISchemeRegistry::Add< TestScheme > X(TestScheme::Scheme, "Test schema")
SelectionTree(ASTContext &AST, unsigned Offset)
const Node * commonAncestor() const
std::unique_ptr< GlobalCompilationDatabase > Base
const DeclContext & getDeclContext() const