12 #include "llvm/Support/SaveAndRestore.h"
14 using namespace clang;
15 using namespace tooling;
21 if (!isa<ObjCImplDecl>(D))
27 R.
getEnd(), tok::raw_identifier,
SM, LangOpts,
36 class ASTSelectionFinder
42 SelectionBegin(Selection.getBegin()),
43 SelectionEnd(Selection.getBegin() == Selection.getEnd()
45 : Selection.getEnd()),
46 TargetFile(TargetFile), Context(Context) {
48 SelectionStack.push_back(
54 assert(SelectionStack.size() == 1 &&
"stack was not popped");
55 SelectedASTNode Result = std::move(SelectionStack.back());
56 SelectionStack.pop_back();
57 if (Result.Children.empty())
59 return std::move(Result);
71 if (!LookThroughOpaqueValueExprs)
77 bool TraverseDecl(
Decl *D) {
78 if (isa<TranslationUnitDecl>(D))
88 FileLoc = DeclRange.
getEnd();
90 FileLoc =
SM.getSpellingLoc(DeclRange.
getBegin());
91 if (
SM.getFileID(FileLoc) != TargetFile)
95 selectionKindFor(getLexicalDeclRange(D,
SM, Context.
getLangOpts()));
96 SelectionStack.push_back(
99 popAndAddToSelectionIfSelected(SelectionKind);
102 SM.isBeforeInTranslationUnit(SelectionEnd.isValid() ? SelectionEnd
111 bool TraverseStmt(
Stmt *S) {
114 if (
auto *Opaque = dyn_cast<OpaqueValueExpr>(S))
115 return TraverseOpaqueValueExpr(Opaque);
117 if (
auto *TE = dyn_cast<CXXThisExpr>(S)) {
118 if (TE->isImplicit())
124 SelectionStack.push_back(
127 popAndAddToSelectionIfSelected(SelectionKind);
133 SelectedASTNode
Node = std::move(SelectionStack.back());
134 SelectionStack.pop_back();
136 SelectionStack.back().Children.push_back(std::move(
Node));
142 if (
Range.isTokenRange())
146 if (!SelectionEnd.isValid()) {
148 if (
SM.isPointWithin(SelectionBegin,
Range.getBegin(),
End))
152 bool HasStart =
SM.isPointWithin(SelectionBegin,
Range.getBegin(),
End);
153 bool HasEnd =
SM.isPointWithin(SelectionEnd,
Range.getBegin(),
End);
154 if (HasStart && HasEnd)
156 if (
SM.isPointWithin(
Range.getBegin(), SelectionBegin, SelectionEnd) &&
157 SM.isPointWithin(
End, SelectionBegin, SelectionEnd))
161 if (HasStart && SelectionBegin !=
End)
163 if (HasEnd && SelectionEnd !=
Range.getBegin())
172 std::vector<SelectedASTNode> SelectionStack;
176 bool LookThroughOpaqueValueExprs =
false;
184 assert(SelectionRange.
isValid() &&
186 SelectionRange.
getEnd()) &&
187 "Expected a file range");
192 "selection range must span one file");
194 ASTSelectionFinder Visitor(SelectionRange, TargetFile, Context);
196 return Visitor.getSelectedASTNode();
204 return "contains-selection";
206 return "contains-selection-start";
208 return "contains-selection-end";
212 llvm_unreachable(
"invalid selection kind");
215 static void dump(
const SelectedASTNode &
Node, llvm::raw_ostream &OS,
220 if (
const auto *ND = dyn_cast<NamedDecl>(D))
221 OS <<
" \"" << ND->getDeclName() <<
'"';
223 OS << S->getStmtClassName();
226 for (
const auto &Child :
Node.Children)
240 for (
const auto &Child :
Node.Children) {
241 if (Child.SelectionKind ==
Kind)
250 struct SelectedNodeWithParents {
259 enum SelectionCanonicalizationAction { KeepSelection, SelectParent };
263 SelectionCanonicalizationAction
264 getSelectionCanonizalizationAction(
const Stmt *S,
const Stmt *
Parent) {
269 if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(
Parent))
278 else if (
const auto *CE = dyn_cast<CallExpr>(
Parent)) {
279 if ((isa<MemberExpr>(S) || isa<DeclRefExpr>(S)) &&
280 CE->getCallee()->IgnoreImpCasts() == S)
284 return KeepSelection;
289 void SelectedNodeWithParents::canonicalize() {
291 assert(S &&
"non statement selection!");
292 const Stmt *
Parent = Parents[Parents.size() - 1].get().Node.get<
Stmt>();
297 unsigned ParentIndex = 1;
298 for (; (ParentIndex + 1) <= Parents.size() && isa<ImplicitCastExpr>(
Parent);
300 const Stmt *NewParent =
301 Parents[Parents.size() - ParentIndex - 1].get().Node.get<
Stmt>();
307 switch (getSelectionCanonizalizationAction(S,
Parent)) {
309 Node = Parents[Parents.size() - ParentIndex];
310 for (; ParentIndex != 0; --ParentIndex)
341 const SelectedASTNode &ASTSelection,
345 if (ASTSelection.Node.get<
DeclStmt>()) {
348 for (
const auto &Child : ASTSelection.Children) {
350 MatchingNodes.push_back(SelectedNodeWithParents{
351 std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
358 MatchingNodes.push_back(SelectedNodeWithParents{
359 std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
364 ParentStack.push_back(std::cref(ASTSelection));
365 for (
const auto &Child : ASTSelection.Children)
367 ParentStack.pop_back();
371 const SelectedASTNode &ASTSelection,
389 if (ContainSelection.size() != 1)
391 SelectedNodeWithParents &Selected = ContainSelection[0];
392 if (!Selected.Node.get().Node.get<
Stmt>())
394 const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<
Stmt>();
395 if (!isa<CompoundStmt>(CodeRangeStmt)) {
396 Selected.canonicalize();
408 Selected.Parents.push_back(Selected.Node);
415 return isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D);
419 bool IsPrevCompound =
false;
423 for (
const auto &
Parent : llvm::reverse(Parents)) {
427 return IsPrevCompound;
432 if (isa<TypeDecl>(D))
441 for (
const auto &
Parent : llvm::reverse(Parents)) {