13#include "clang/AST/ASTConcept.h"
14#include "clang/AST/ASTTypeTraits.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclCXX.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/PrettyPrinter.h"
20#include "clang/AST/RecursiveASTVisitor.h"
21#include "clang/AST/TypeLoc.h"
22#include "clang/Basic/OperatorKinds.h"
23#include "clang/Basic/SourceLocation.h"
24#include "clang/Basic/SourceManager.h"
25#include "clang/Basic/TokenKinds.h"
26#include "clang/Lex/Lexer.h"
27#include "clang/Tooling/Syntax/Tokens.h"
28#include "llvm/ADT/BitVector.h"
29#include "llvm/ADT/STLExtras.h"
30#include "llvm/ADT/StringExtras.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/raw_ostream.h"
41using Node = SelectionTree::Node;
44void recordMetrics(
const SelectionTree &S,
const LangOptions &
Lang) {
47 const char *LanguageLabel =
Lang.CPlusPlus ?
"C++" :
Lang.ObjC ?
"ObjC" :
"C";
48 static constexpr trace::Metric SelectionUsedRecovery(
50 static constexpr trace::Metric RecoveryType(
52 const auto *Common = S.commonAncestor();
53 for (
const auto *N = Common; N; N = N->Parent) {
54 if (
const auto *RE = N->ASTNode.get<RecoveryExpr>()) {
55 SelectionUsedRecovery.record(1, LanguageLabel);
56 RecoveryType.record(RE->isTypeDependent() ? 0 : 1, LanguageLabel);
61 SelectionUsedRecovery.record(0, LanguageLabel);
65SourceRange getSourceRange(
const DynTypedNode &N) {
77 if (
const auto *ME = N.get<MemberExpr>()) {
78 if (!ME->getMemberDecl()->getDeclName())
80 ? getSourceRange(DynTypedNode::create(*ME->getBase()))
83 return N.getSourceRange();
104template <
typename T>
class IntervalSet {
106 IntervalSet(llvm::ArrayRef<T> Range) { UnclaimedRanges.insert(Range); }
111 llvm::SmallVector<llvm::ArrayRef<T>> erase(llvm::ArrayRef<T> Claim) {
112 llvm::SmallVector<llvm::ArrayRef<T>>
Out;
121 auto Overlap = std::make_pair(
122 UnclaimedRanges.lower_bound({Claim.begin(), Claim.begin()}),
123 UnclaimedRanges.lower_bound({Claim.end(), Claim.end()}));
125 if (Overlap.first != UnclaimedRanges.begin()) {
128 if (Overlap.first->end() <= Claim.begin())
131 if (Overlap.first == Overlap.second)
135 auto OutFirst =
Out.insert(
Out.end(), Overlap.first, Overlap.second);
139 llvm::ArrayRef<T> RemainingHead, RemainingTail;
140 if (Claim.begin() > OutFirst->begin()) {
141 RemainingHead = {OutFirst->begin(), Claim.begin()};
142 *OutFirst = {Claim.begin(), OutFirst->end()};
144 if (Claim.end() <
Out.back().end()) {
145 RemainingTail = {Claim.end(),
Out.back().end()};
146 Out.back() = {
Out.back().begin(), Claim.end()};
150 UnclaimedRanges.erase(Overlap.first, Overlap.second);
152 if (!RemainingHead.empty())
153 UnclaimedRanges.insert(RemainingHead);
154 if (!RemainingTail.empty())
155 UnclaimedRanges.insert(RemainingTail);
161 using TokenRange = llvm::ArrayRef<T>;
163 bool operator()(llvm::ArrayRef<T> L, llvm::ArrayRef<T> R)
const {
164 return L.begin() < R.begin();
169 std::set<llvm::ArrayRef<T>, RangeLess> UnclaimedRanges;
185 if (Result == NoTokens)
187 else if (Result != New)
194bool shouldIgnore(
const syntax::Token &Tok) {
195 switch (Tok.kind()) {
202 case tok::kw_volatile:
203 case tok::kw_restrict:
212bool isFirstExpansion(FileID Target, SourceLocation SpellingLoc,
213 const SourceManager &SM) {
214 SourceLocation Prev = SpellingLoc;
218 SourceLocation Next = SM.getMacroArgExpandedLocation(Prev);
221 if (SM.getFileID(Next) == Target)
226 if (SM.getFileID(Next) == SM.getFileID(Prev))
247class SelectionTester {
250 SelectionTester(
const syntax::TokenBuffer &Buf, FileID SelFile,
251 unsigned SelBegin,
unsigned SelEnd,
const SourceManager &SM)
252 : SelFile(SelFile), SelFileBounds(SM.getLocForStartOfFile(SelFile),
253 SM.getLocForEndOfFile(SelFile)),
256 auto AllSpelledTokens = Buf.spelledTokens(SelFile);
257 const syntax::Token *SelFirst =
258 llvm::partition_point(AllSpelledTokens, [&](
const syntax::Token &Tok) {
259 return SM.getFileOffset(Tok.endLocation()) <= SelBegin;
261 const syntax::Token *SelLimit = std::partition_point(
262 SelFirst, AllSpelledTokens.end(), [&](
const syntax::Token &Tok) {
263 return SM.getFileOffset(Tok.location()) < SelEnd;
265 auto Sel = llvm::ArrayRef(SelFirst, SelLimit);
267 llvm::BitVector PPIgnored(Sel.size(),
false);
268 for (
const syntax::TokenBuffer::Expansion &
X :
269 Buf.expansionsOverlapping(Sel)) {
270 if (
X.Expanded.empty()) {
271 for (
const syntax::Token &Tok :
X.Spelled) {
272 if (&Tok >= SelFirst && &Tok < SelLimit)
273 PPIgnored[&Tok - SelFirst] =
true;
278 for (
unsigned I = 0; I < Sel.size(); ++I) {
279 if (shouldIgnore(Sel[I]) || PPIgnored[I])
281 SelectedSpelled.emplace_back();
282 Tok &S = SelectedSpelled.back();
283 S.Offset = SM.getFileOffset(Sel[I].location());
284 if (S.Offset >= SelBegin && S.Offset + Sel[I].length() <= SelEnd)
289 MaybeSelectedExpanded = computeMaybeSelectedExpandedTokens(Buf);
295 test(llvm::ArrayRef<syntax::Token> ExpandedTokens)
const {
296 if (ExpandedTokens.empty())
298 if (SelectedSpelled.empty())
306 if (MaybeSelectedExpanded.empty() ||
307 &ExpandedTokens.front() > &MaybeSelectedExpanded.back() ||
308 &ExpandedTokens.back() < &MaybeSelectedExpanded.front()) {
317 if (ExpandedTokens.back().kind() == tok::eof)
318 ExpandedTokens = ExpandedTokens.drop_back();
321 while (!ExpandedTokens.empty()) {
323 SourceLocation Start = ExpandedTokens.front().location();
324 FileID FID = SM.getFileID(Start);
326 SourceLocation Limit = SM.getComposedLoc(FID, SM.getFileIDSize(FID));
327 auto Batch = ExpandedTokens.take_while([&](
const syntax::Token &T) {
328 return T.location() >= Start &&
T.location() < Limit;
330 assert(!Batch.empty());
331 ExpandedTokens = ExpandedTokens.drop_front(Batch.size());
333 update(Result, testChunk(FID, Batch));
341 bool mayHit(SourceRange R)
const {
342 if (SelectedSpelled.empty() || MaybeSelectedExpanded.empty())
348 if (
auto B = offsetInSelFile(getExpansionStart(R.getBegin())))
349 if (*B > SelectedSpelled.back().Offset)
352 SourceLocation EndLoc = R.getEnd();
353 while (EndLoc.isMacroID())
354 EndLoc = SM.getImmediateExpansionRange(EndLoc).getEnd();
357 if (
auto E = offsetInSelFile(EndLoc))
358 if (*
E < SelectedSpelled.front().Offset)
367 llvm::ArrayRef<syntax::Token>
368 computeMaybeSelectedExpandedTokens(
const syntax::TokenBuffer &Toks) {
369 if (SelectedSpelled.empty())
372 auto LastAffectedToken = [&](SourceLocation
Loc) {
375 Loc =
Loc.isMacroID() ? SM.getImmediateExpansionRange(
Loc).getEnd()
376 : SM.getIncludeLoc(SM.getFileID(
Loc));
381 auto FirstAffectedToken = [&](SourceLocation
Loc) {
384 Loc =
Loc.isMacroID() ? SM.getImmediateExpansionRange(
Loc).getBegin()
385 : SM.getIncludeLoc(SM.getFileID(
Loc));
391 const syntax::Token *Start = llvm::partition_point(
392 Toks.expandedTokens(),
393 [&, First = SelectedSpelled.front().Offset](
const syntax::Token &Tok) {
394 if (Tok.kind() == tok::eof)
397 if (auto Offset = LastAffectedToken(Tok.location()))
398 return *Offset < First;
404 bool EndInvalid =
false;
405 const syntax::Token *End = std::partition_point(
406 Start, Toks.expandedTokens().end(),
407 [&, Last = SelectedSpelled.back().Offset](
const syntax::Token &Tok) {
408 if (Tok.kind() == tok::eof)
411 if (auto Offset = FirstAffectedToken(Tok.location()))
412 return *Offset <= Last;
415 assert(false &&
"Expanded token could not be resolved to main file!");
420 End = Toks.expandedTokens().end();
422 return llvm::ArrayRef(Start, End);
427 testChunk(FileID FID, llvm::ArrayRef<syntax::Token> Batch)
const {
428 assert(!Batch.empty());
429 SourceLocation StartLoc = Batch.front().location();
438 if (FID == SelFile) {
439 return testTokenRange(*offsetInSelFile(Batch.front().location()),
440 *offsetInSelFile(Batch.back().location()));
445 if (StartLoc.isFileID()) {
446 for (SourceLocation
Loc = Batch.front().location();
Loc.isValid();
447 Loc = SM.getIncludeLoc(SM.getFileID(
Loc))) {
450 return testToken(*
Offset);
455 assert(StartLoc.isMacroID());
457 SourceLocation ArgStart = SM.getTopMacroCallerLoc(StartLoc);
458 if (
auto ArgOffset = offsetInSelFile(ArgStart)) {
459 if (isFirstExpansion(FID, ArgStart, SM)) {
460 SourceLocation ArgEnd =
461 SM.getTopMacroCallerLoc(Batch.back().location());
462 return testTokenRange(*ArgOffset, *offsetInSelFile(ArgEnd));
470 if (
auto ExpansionOffset = offsetInSelFile(getExpansionStart(StartLoc)))
472 return testToken(*ExpansionOffset);
478 assert(Begin <= End);
480 if (End < SelectedSpelled.front().Offset ||
481 Begin > SelectedSpelled.back().Offset)
485 auto B = llvm::partition_point(
486 SelectedSpelled, [&](
const Tok &T) {
return T.Offset < Begin; });
487 auto E = std::partition_point(B, SelectedSpelled.end(), [&](
const Tok &T) {
488 return T.Offset <= End;
492 bool ExtendsOutsideSelection = Begin < SelectedSpelled.front().Offset ||
493 End > SelectedSpelled.back().Offset;
496 for (
auto It = B; It !=
E; ++It)
497 update(Result, It->Selected);
504 if (
Offset < SelectedSpelled.front().Offset ||
505 Offset > SelectedSpelled.back().Offset)
508 auto It = llvm::partition_point(
509 SelectedSpelled, [&](
const Tok &T) {
return T.Offset <
Offset; });
510 if (It != SelectedSpelled.end() && It->Offset ==
Offset)
516 std::optional<unsigned> offsetInSelFile(SourceLocation
Loc)
const {
520 if (
Loc < SelFileBounds.getBegin() ||
Loc >= SelFileBounds.getEnd())
523 return Loc.getRawEncoding() - SelFileBounds.getBegin().getRawEncoding();
526 SourceLocation getExpansionStart(SourceLocation
Loc)
const {
527 while (
Loc.isMacroID())
528 Loc = SM.getImmediateExpansionRange(
Loc).getBegin();
536 std::vector<Tok> SelectedSpelled;
537 llvm::ArrayRef<syntax::Token> MaybeSelectedExpanded;
539 SourceRange SelFileBounds;
540 const SourceManager &SM;
544void printNodeKind(llvm::raw_ostream &
OS,
const DynTypedNode &N) {
545 if (
const TypeLoc *TL = N.get<TypeLoc>()) {
548 if (TL->getTypeLocClass() == TypeLoc::Qualified)
549 OS <<
"QualifiedTypeLoc";
551 OS << TL->getType()->getTypeClassName() <<
"TypeLoc";
553 OS << N.getNodeKind().asStringRef();
558std::string printNodeToString(
const DynTypedNode &N,
const PrintingPolicy &PP) {
560 llvm::raw_string_ostream
OS(S);
561 printNodeKind(
OS, N);
562 return std::move(
OS.str());
566bool isImplicit(
const Stmt *S) {
570 if (
auto *ICE = llvm::dyn_cast<ImplicitCastExpr>(S))
571 S = ICE->getSubExprAsWritten();
574 if (
auto *CTI = llvm::dyn_cast<CXXThisExpr>(S))
575 if (CTI->isImplicit())
578 if (
auto *ME = llvm::dyn_cast<MemberExpr>(S)) {
579 if (
auto *FD = llvm::dyn_cast<FieldDecl>(ME->getMemberDecl()))
580 if (FD->isAnonymousStructOrUnion())
584 return isImplicit(ME->getBase());
587 if (
auto *DRE = llvm::dyn_cast<DeclRefExpr>(S)) {
588 if (
auto *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl())) {
589 switch (FD->getOverloadedOperator()) {
613 static std::deque<Node> collect(ASTContext &
AST,
614 const syntax::TokenBuffer &Tokens,
615 const PrintingPolicy &PP,
unsigned Begin,
616 unsigned End, FileID
File) {
617 SelectionVisitor V(
AST, Tokens, PP, Begin, End,
File);
619 assert(V.Stack.size() == 1 &&
"Unpaired push/pop?");
620 assert(V.Stack.top() == &V.Nodes.front());
621 return std::move(V.Nodes);
634 bool TraverseDecl(
Decl *
X) {
635 if (llvm::isa_and_nonnull<TranslationUnitDecl>(
X))
636 return Base::TraverseDecl(
X);
638 if (
X &&
X->isImplicit()) {
642 return Base::TraverseDecl(
X);
644 return traverseNode(
X, [&] {
return Base::TraverseDecl(
X); });
646 bool TraverseTypeLoc(TypeLoc
X) {
647 return traverseNode(&
X, [&] {
return Base::TraverseTypeLoc(
X); });
649 bool TraverseTemplateArgumentLoc(
const TemplateArgumentLoc &
X) {
650 return traverseNode(&
X,
651 [&] {
return Base::TraverseTemplateArgumentLoc(
X); });
653 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc
X) {
655 &
X, [&] {
return Base::TraverseNestedNameSpecifierLoc(
X); });
657 bool TraverseConstructorInitializer(CXXCtorInitializer *
X) {
659 X, [&] {
return Base::TraverseConstructorInitializer(
X); });
661 bool TraverseCXXBaseSpecifier(
const CXXBaseSpecifier &
X) {
662 return traverseNode(&
X, [&] {
return Base::TraverseCXXBaseSpecifier(
X); });
664 bool TraverseAttr(Attr *
X) {
665 return traverseNode(
X, [&] {
return Base::TraverseAttr(
X); });
667 bool TraverseConceptReference(ConceptReference *
X) {
668 return traverseNode(
X, [&] {
return Base::TraverseConceptReference(
X); });
671 bool dataTraverseStmtPre(Stmt *
X) {
672 if (!
X || isImplicit(
X))
674 auto N = DynTypedNode::create(*
X);
675 if (canSafelySkipNode(N))
678 if (shouldSkipChildren(
X)) {
684 bool dataTraverseStmtPost(Stmt *
X) {
693 bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QX) {
694 return traverseNode<TypeLoc>(
695 &QX, [&] {
return TraverseTypeLoc(QX.getUnqualifiedLoc()); });
697 bool TraverseObjCProtocolLoc(ObjCProtocolLoc PL) {
698 return traverseNode(&PL, [&] {
return Base::TraverseObjCProtocolLoc(PL); });
701 bool TraverseNestedNameSpecifier(NestedNameSpecifier *) {
return true; }
702 bool TraverseType(QualType) {
return true; }
707 bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) {
708 return traverseNode(S, [&] {
709 return TraverseStmt(S->getInit()) && TraverseDecl(S->getLoopVariable()) &&
710 TraverseStmt(S->getRangeInit()) && TraverseStmt(S->getBody());
714 bool TraverseOpaqueValueExpr(OpaqueValueExpr *
E) {
715 return traverseNode(
E, [&] {
return TraverseStmt(
E->getSourceExpr()); });
718 bool TraversePseudoObjectExpr(PseudoObjectExpr *
E) {
719 return traverseNode(
E, [&] {
return TraverseStmt(
E->getSyntacticForm()); });
721 bool TraverseTypeConstraint(
const TypeConstraint *
C) {
722 if (
auto *
E =
C->getImmediatelyDeclaredConstraint()) {
726 return TraverseStmt(
E);
728 return Base::TraverseTypeConstraint(
C);
732 using RecursiveASTVisitor::getStmtChildren;
735 Stmt::child_range getStmtChildren(PredefinedExpr *) {
736 return {StmtIterator{}, StmtIterator{}};
742 SelectionVisitor(ASTContext &
AST,
const syntax::TokenBuffer &Tokens,
743 const PrintingPolicy &PP,
unsigned SelBegin,
unsigned SelEnd,
745 : SM(
AST.getSourceManager()), LangOpts(
AST.getLangOpts()),
749 TokenBuf(Tokens), SelChecker(Tokens, SelFile, SelBegin, SelEnd, SM),
750 UnclaimedExpandedTokens(Tokens.expandedTokens()) {
752 Nodes.emplace_back();
753 Nodes.back().ASTNode = DynTypedNode::create(*
AST.getTranslationUnitDecl());
754 Nodes.back().Parent =
nullptr;
756 Stack.push(&Nodes.back());
761 template <
typename T,
typename Func>
762 bool traverseNode(T *Node,
const Func &Body) {
765 auto N = DynTypedNode::create(*Node);
766 if (canSafelySkipNode(N))
768 push(DynTypedNode::create(*Node));
800 bool canSafelySkipNode(
const DynTypedNode &N) {
801 SourceRange S = getSourceRange(N);
802 if (
auto *TL = N.get<TypeLoc>()) {
809 if (
auto AT = TL->getAs<AttributedTypeLoc>())
810 S = AT.getModifiedLoc().getSourceRange();
815 [](
const Attr *A) {
return !
A->isImplicit(); }))
817 if (!SelChecker.mayHit(S)) {
818 dlog(
"{2}skip: {0} {1}", printNodeToString(N, PrintPolicy),
819 S.printToString(SM), indent());
827 bool shouldSkipChildren(
const Stmt *
X)
const {
831 return llvm::isa<UserDefinedLiteral>(
X);
836 void push(DynTypedNode Node) {
837 SourceRange Early = earlySourceRange(Node);
838 dlog(
"{2}push: {0} {1}", printNodeToString(Node, PrintPolicy),
839 Node.getSourceRange().printToString(SM), indent());
840 Nodes.emplace_back();
841 Nodes.back().ASTNode = std::move(Node);
842 Nodes.back().Parent = Stack.top();
843 Nodes.back().Selected = NoTokens;
844 Stack.push(&Nodes.back());
845 claimRange(Early, Nodes.back().Selected);
851 Node &N = *Stack.top();
852 dlog(
"{1}pop: {0}", printNodeToString(N.ASTNode, PrintPolicy), indent(-1));
853 claimTokensFor(N.ASTNode, N.Selected);
854 if (N.Selected == NoTokens)
856 if (N.Selected || !N.Children.empty()) {
858 N.Parent->Children.push_back(&N);
861 assert(&N == &Nodes.back());
870 SourceRange earlySourceRange(
const DynTypedNode &N) {
871 if (
const Decl *VD = N.get<VarDecl>()) {
880 return VD->getLocation();
887 if (
const auto *CDD = N.get<CXXDestructorDecl>())
888 return CDD->getNameInfo().getNamedTypeInfo()->getTypeLoc().getBeginLoc();
889 if (
const auto *ME = N.get<MemberExpr>()) {
890 auto NameInfo = ME->getMemberNameInfo();
891 if (NameInfo.getName().getNameKind() ==
892 DeclarationName::CXXDestructorName)
893 return NameInfo.getNamedTypeInfo()->getTypeLoc().getBeginLoc();
896 return SourceRange();
906 if (
const auto *CCE = N.get<CXXConstructExpr>()) {
907 claimRange(CCE->getParenOrBraceRange(), Result);
912 if (N.get<ExprWithCleanups>())
940 if (
const auto *TL = N.get<TypeLoc>()) {
941 if (
auto PTL = TL->getAs<ParenTypeLoc>()) {
942 claimRange(PTL.getLParenLoc(), Result);
943 claimRange(PTL.getRParenLoc(), Result);
946 if (
auto ATL = TL->getAs<ArrayTypeLoc>()) {
947 claimRange(ATL.getBracketsRange(), Result);
950 if (
auto PTL = TL->getAs<PointerTypeLoc>()) {
951 claimRange(PTL.getStarLoc(), Result);
954 if (
auto FTL = TL->getAs<FunctionTypeLoc>()) {
955 claimRange(SourceRange(FTL.getLParenLoc(), FTL.getEndLoc()), Result);
959 claimRange(getSourceRange(N), Result);
967 for (
const auto &ClaimedRange :
968 UnclaimedExpandedTokens.erase(TokenBuf.expandedTokens(S)))
969 update(Result, SelChecker.test(ClaimedRange));
971 if (Result && Result != NoTokens)
972 dlog(
"{1}hit selection: {0}", S.printToString(SM), indent());
975 std::string indent(
int Offset = 0) {
977 int Amount = int(Stack.size()) +
Offset;
979 return std::string(Amount,
' ');
983 const LangOptions &LangOpts;
985 const PrintingPolicy &PrintPolicy;
987 const syntax::TokenBuffer &TokenBuf;
988 std::stack<Node *> Stack;
989 SelectionTester SelChecker;
990 IntervalSet<syntax::Token> UnclaimedExpandedTokens;
991 std::deque<Node> Nodes;
997 const PrintingPolicy &PP) {
998 llvm::SmallString<256> Result;
1000 llvm::raw_svector_ostream
OS(Result);
1003 auto Pos = Result.find(
'\n');
1004 if (
Pos != llvm::StringRef::npos) {
1005 bool MoreText = !llvm::all_of(Result.str().drop_front(
Pos), llvm::isSpace);
1008 Result.append(
" …");
1013void SelectionTree::print(llvm::raw_ostream &
OS,
const SelectionTree::Node &N,
1020 printNodeKind(
OS, N.ASTNode);
1022 for (
const Node *Child : N.Children)
1023 print(
OS, *Child, Indent + 2);
1028 llvm::raw_string_ostream
OS(S);
1030 return std::move(
OS.str());
1037static llvm::SmallVector<std::pair<unsigned, unsigned>, 2>
1039 const auto &SM = Tokens.sourceManager();
1040 SourceLocation
Loc = SM.getComposedLoc(SM.getMainFileID(),
Offset);
1041 llvm::SmallVector<std::pair<unsigned, unsigned>, 2> Result;
1043 for (
const syntax::Token &Tok :
1044 llvm::reverse(spelledTokensTouching(
Loc, Tokens))) {
1045 if (shouldIgnore(Tok))
1047 unsigned Offset = Tokens.sourceManager().getFileOffset(Tok.location());
1056 const syntax::TokenBuffer &Tokens,
1057 unsigned Begin,
unsigned End,
1068 const syntax::TokenBuffer &Tokens,
1069 unsigned int Begin,
unsigned int End) {
1070 std::optional<SelectionTree> Result;
1072 Result = std::move(T);
1075 return std::move(*Result);
1079 unsigned Begin,
unsigned End)
1080 : PrintPolicy(
AST.getLangOpts()) {
1083 const SourceManager &SM =
AST.getSourceManager();
1084 FileID FID = SM.getMainFileID();
1085 PrintPolicy.TerseOutput =
true;
1086 PrintPolicy.IncludeNewlines =
false;
1088 dlog(
"Computing selection for {0}",
1089 SourceRange(SM.getComposedLoc(FID, Begin), SM.getComposedLoc(FID, End))
1090 .printToString(SM));
1091 Nodes = SelectionVisitor::collect(
AST, Tokens, PrintPolicy, Begin, End, FID);
1092 Root = Nodes.empty() ? nullptr : &Nodes.front();
1093 recordMetrics(*
this,
AST.getLangOpts());
1094 dlog(
"Built selection tree\n{0}", *
this);
1098 const Node *Ancestor = Root;
1100 Ancestor = Ancestor->
Children.front();
1104 return Ancestor != Root ? Ancestor :
nullptr;
1108 for (
const Node *CurrentNode =
this; CurrentNode !=
nullptr;
1109 CurrentNode = CurrentNode->
Parent) {
1110 if (
const Decl *Current = CurrentNode->ASTNode.get<
Decl>()) {
1111 if (CurrentNode !=
this)
1112 if (
auto *DC = dyn_cast<DeclContext>(Current))
1114 return *Current->getLexicalDeclContext();
1116 if (
const auto *LE = CurrentNode->ASTNode.get<LambdaExpr>())
1117 if (CurrentNode !=
this)
1118 return *LE->getCallOperator();
1120 llvm_unreachable(
"A tree must always be rooted at TranslationUnitDecl.");
1126 return Children.front()->ignoreImplicit();
const FunctionDecl * Decl
CompiledFragmentImpl & Out
::clang::DynTypedNode Node
SelectionTree::Selection Selected
llvm::raw_string_ostream OS
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
SelectionTree(const SelectionTree &)=delete
static SelectionTree createRight(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End)
const Node * commonAncestor() const
bool enabled()
Returns true if there is an active tracer.
llvm::SmallString< 256 > abbreviatedString(DynTypedNode N, const PrintingPolicy &PP)
std::vector< const Attr * > getAttributes(const DynTypedNode &N)
Return attributes attached directly to a node.
static llvm::SmallVector< std::pair< unsigned, unsigned >, 2 > pointBounds(unsigned Offset, const syntax::TokenBuffer &Tokens)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Simplified description of a clang AST node.
const Node & ignoreImplicit() const
llvm::SmallVector< const Node * > Children
const DeclContext & getDeclContext() const
const Node & outerImplicit() const
@ Distribution
A distribution of values with a meaningful mean and count.