xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/Refactoring/ASTSelection.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===--- ASTSelection.cpp - Clang refactoring library ---------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "clang/Tooling/Refactoring/ASTSelection.h"
100b57cec5SDimitry Andric #include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
110b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
120b57cec5SDimitry Andric #include "llvm/Support/SaveAndRestore.h"
13*bdd1243dSDimitry Andric #include <optional>
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric using namespace clang;
160b57cec5SDimitry Andric using namespace tooling;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace {
190b57cec5SDimitry Andric 
getLexicalDeclRange(Decl * D,const SourceManager & SM,const LangOptions & LangOpts)200b57cec5SDimitry Andric CharSourceRange getLexicalDeclRange(Decl *D, const SourceManager &SM,
210b57cec5SDimitry Andric                                     const LangOptions &LangOpts) {
220b57cec5SDimitry Andric   if (!isa<ObjCImplDecl>(D))
230b57cec5SDimitry Andric     return CharSourceRange::getTokenRange(D->getSourceRange());
240b57cec5SDimitry Andric   // Objective-C implementation declarations end at the '@' instead of the 'end'
250b57cec5SDimitry Andric   // keyword. Use the lexer to find the location right after 'end'.
260b57cec5SDimitry Andric   SourceRange R = D->getSourceRange();
270b57cec5SDimitry Andric   SourceLocation LocAfterEnd = Lexer::findLocationAfterToken(
280b57cec5SDimitry Andric       R.getEnd(), tok::raw_identifier, SM, LangOpts,
290b57cec5SDimitry Andric       /*SkipTrailingWhitespaceAndNewLine=*/false);
300b57cec5SDimitry Andric   return LocAfterEnd.isValid()
310b57cec5SDimitry Andric              ? CharSourceRange::getCharRange(R.getBegin(), LocAfterEnd)
320b57cec5SDimitry Andric              : CharSourceRange::getTokenRange(R);
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric /// Constructs the tree of selected AST nodes that either contain the location
360b57cec5SDimitry Andric /// of the cursor or overlap with the selection range.
370b57cec5SDimitry Andric class ASTSelectionFinder
380b57cec5SDimitry Andric     : public LexicallyOrderedRecursiveASTVisitor<ASTSelectionFinder> {
390b57cec5SDimitry Andric public:
ASTSelectionFinder(SourceRange Selection,FileID TargetFile,const ASTContext & Context)400b57cec5SDimitry Andric   ASTSelectionFinder(SourceRange Selection, FileID TargetFile,
410b57cec5SDimitry Andric                      const ASTContext &Context)
420b57cec5SDimitry Andric       : LexicallyOrderedRecursiveASTVisitor(Context.getSourceManager()),
430b57cec5SDimitry Andric         SelectionBegin(Selection.getBegin()),
440b57cec5SDimitry Andric         SelectionEnd(Selection.getBegin() == Selection.getEnd()
450b57cec5SDimitry Andric                          ? SourceLocation()
460b57cec5SDimitry Andric                          : Selection.getEnd()),
470b57cec5SDimitry Andric         TargetFile(TargetFile), Context(Context) {
480b57cec5SDimitry Andric     // The TU decl is the root of the selected node tree.
490b57cec5SDimitry Andric     SelectionStack.push_back(
500b57cec5SDimitry Andric         SelectedASTNode(DynTypedNode::create(*Context.getTranslationUnitDecl()),
510b57cec5SDimitry Andric                         SourceSelectionKind::None));
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric 
getSelectedASTNode()54*bdd1243dSDimitry Andric   std::optional<SelectedASTNode> getSelectedASTNode() {
550b57cec5SDimitry Andric     assert(SelectionStack.size() == 1 && "stack was not popped");
560b57cec5SDimitry Andric     SelectedASTNode Result = std::move(SelectionStack.back());
570b57cec5SDimitry Andric     SelectionStack.pop_back();
580b57cec5SDimitry Andric     if (Result.Children.empty())
59*bdd1243dSDimitry Andric       return std::nullopt;
600b57cec5SDimitry Andric     return std::move(Result);
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric 
TraversePseudoObjectExpr(PseudoObjectExpr * E)630b57cec5SDimitry Andric   bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
640b57cec5SDimitry Andric     // Avoid traversing the semantic expressions. They should be handled by
650b57cec5SDimitry Andric     // looking through the appropriate opaque expressions in order to build
660b57cec5SDimitry Andric     // a meaningful selection tree.
67*bdd1243dSDimitry Andric     llvm::SaveAndRestore LookThrough(LookThroughOpaqueValueExprs, true);
680b57cec5SDimitry Andric     return TraverseStmt(E->getSyntacticForm());
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric 
TraverseOpaqueValueExpr(OpaqueValueExpr * E)710b57cec5SDimitry Andric   bool TraverseOpaqueValueExpr(OpaqueValueExpr *E) {
720b57cec5SDimitry Andric     if (!LookThroughOpaqueValueExprs)
730b57cec5SDimitry Andric       return true;
74*bdd1243dSDimitry Andric     llvm::SaveAndRestore LookThrough(LookThroughOpaqueValueExprs, false);
750b57cec5SDimitry Andric     return TraverseStmt(E->getSourceExpr());
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric 
TraverseDecl(Decl * D)780b57cec5SDimitry Andric   bool TraverseDecl(Decl *D) {
790b57cec5SDimitry Andric     if (isa<TranslationUnitDecl>(D))
800b57cec5SDimitry Andric       return LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
810b57cec5SDimitry Andric     if (D->isImplicit())
820b57cec5SDimitry Andric       return true;
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric     // Check if this declaration is written in the file of interest.
850b57cec5SDimitry Andric     const SourceRange DeclRange = D->getSourceRange();
860b57cec5SDimitry Andric     const SourceManager &SM = Context.getSourceManager();
870b57cec5SDimitry Andric     SourceLocation FileLoc;
880b57cec5SDimitry Andric     if (DeclRange.getBegin().isMacroID() && !DeclRange.getEnd().isMacroID())
890b57cec5SDimitry Andric       FileLoc = DeclRange.getEnd();
900b57cec5SDimitry Andric     else
910b57cec5SDimitry Andric       FileLoc = SM.getSpellingLoc(DeclRange.getBegin());
920b57cec5SDimitry Andric     if (SM.getFileID(FileLoc) != TargetFile)
930b57cec5SDimitry Andric       return true;
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric     SourceSelectionKind SelectionKind =
960b57cec5SDimitry Andric         selectionKindFor(getLexicalDeclRange(D, SM, Context.getLangOpts()));
970b57cec5SDimitry Andric     SelectionStack.push_back(
980b57cec5SDimitry Andric         SelectedASTNode(DynTypedNode::create(*D), SelectionKind));
990b57cec5SDimitry Andric     LexicallyOrderedRecursiveASTVisitor::TraverseDecl(D);
1000b57cec5SDimitry Andric     popAndAddToSelectionIfSelected(SelectionKind);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric     if (DeclRange.getEnd().isValid() &&
1030b57cec5SDimitry Andric         SM.isBeforeInTranslationUnit(SelectionEnd.isValid() ? SelectionEnd
1040b57cec5SDimitry Andric                                                             : SelectionBegin,
1050b57cec5SDimitry Andric                                      DeclRange.getEnd())) {
1060b57cec5SDimitry Andric       // Stop early when we've reached a declaration after the selection.
1070b57cec5SDimitry Andric       return false;
1080b57cec5SDimitry Andric     }
1090b57cec5SDimitry Andric     return true;
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric 
TraverseStmt(Stmt * S)1120b57cec5SDimitry Andric   bool TraverseStmt(Stmt *S) {
1130b57cec5SDimitry Andric     if (!S)
1140b57cec5SDimitry Andric       return true;
1150b57cec5SDimitry Andric     if (auto *Opaque = dyn_cast<OpaqueValueExpr>(S))
1160b57cec5SDimitry Andric       return TraverseOpaqueValueExpr(Opaque);
1170b57cec5SDimitry Andric     // Avoid selecting implicit 'this' expressions.
1180b57cec5SDimitry Andric     if (auto *TE = dyn_cast<CXXThisExpr>(S)) {
1190b57cec5SDimitry Andric       if (TE->isImplicit())
1200b57cec5SDimitry Andric         return true;
1210b57cec5SDimitry Andric     }
1220b57cec5SDimitry Andric     // FIXME (Alex Lorenz): Improve handling for macro locations.
1230b57cec5SDimitry Andric     SourceSelectionKind SelectionKind =
1240b57cec5SDimitry Andric         selectionKindFor(CharSourceRange::getTokenRange(S->getSourceRange()));
1250b57cec5SDimitry Andric     SelectionStack.push_back(
1260b57cec5SDimitry Andric         SelectedASTNode(DynTypedNode::create(*S), SelectionKind));
1270b57cec5SDimitry Andric     LexicallyOrderedRecursiveASTVisitor::TraverseStmt(S);
1280b57cec5SDimitry Andric     popAndAddToSelectionIfSelected(SelectionKind);
1290b57cec5SDimitry Andric     return true;
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric private:
popAndAddToSelectionIfSelected(SourceSelectionKind SelectionKind)1330b57cec5SDimitry Andric   void popAndAddToSelectionIfSelected(SourceSelectionKind SelectionKind) {
1340b57cec5SDimitry Andric     SelectedASTNode Node = std::move(SelectionStack.back());
1350b57cec5SDimitry Andric     SelectionStack.pop_back();
1360b57cec5SDimitry Andric     if (SelectionKind != SourceSelectionKind::None || !Node.Children.empty())
1370b57cec5SDimitry Andric       SelectionStack.back().Children.push_back(std::move(Node));
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric 
selectionKindFor(CharSourceRange Range)1400b57cec5SDimitry Andric   SourceSelectionKind selectionKindFor(CharSourceRange Range) {
1410b57cec5SDimitry Andric     SourceLocation End = Range.getEnd();
1420b57cec5SDimitry Andric     const SourceManager &SM = Context.getSourceManager();
1430b57cec5SDimitry Andric     if (Range.isTokenRange())
1440b57cec5SDimitry Andric       End = Lexer::getLocForEndOfToken(End, 0, SM, Context.getLangOpts());
1450b57cec5SDimitry Andric     if (!SourceLocation::isPairOfFileLocations(Range.getBegin(), End))
1460b57cec5SDimitry Andric       return SourceSelectionKind::None;
1470b57cec5SDimitry Andric     if (!SelectionEnd.isValid()) {
1480b57cec5SDimitry Andric       // Do a quick check when the selection is of length 0.
1490b57cec5SDimitry Andric       if (SM.isPointWithin(SelectionBegin, Range.getBegin(), End))
1500b57cec5SDimitry Andric         return SourceSelectionKind::ContainsSelection;
1510b57cec5SDimitry Andric       return SourceSelectionKind::None;
1520b57cec5SDimitry Andric     }
1530b57cec5SDimitry Andric     bool HasStart = SM.isPointWithin(SelectionBegin, Range.getBegin(), End);
1540b57cec5SDimitry Andric     bool HasEnd = SM.isPointWithin(SelectionEnd, Range.getBegin(), End);
1550b57cec5SDimitry Andric     if (HasStart && HasEnd)
1560b57cec5SDimitry Andric       return SourceSelectionKind::ContainsSelection;
1570b57cec5SDimitry Andric     if (SM.isPointWithin(Range.getBegin(), SelectionBegin, SelectionEnd) &&
1580b57cec5SDimitry Andric         SM.isPointWithin(End, SelectionBegin, SelectionEnd))
1590b57cec5SDimitry Andric       return SourceSelectionKind::InsideSelection;
1600b57cec5SDimitry Andric     // Ensure there's at least some overlap with the 'start'/'end' selection
1610b57cec5SDimitry Andric     // types.
1620b57cec5SDimitry Andric     if (HasStart && SelectionBegin != End)
1630b57cec5SDimitry Andric       return SourceSelectionKind::ContainsSelectionStart;
1640b57cec5SDimitry Andric     if (HasEnd && SelectionEnd != Range.getBegin())
1650b57cec5SDimitry Andric       return SourceSelectionKind::ContainsSelectionEnd;
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric     return SourceSelectionKind::None;
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   const SourceLocation SelectionBegin, SelectionEnd;
1710b57cec5SDimitry Andric   FileID TargetFile;
1720b57cec5SDimitry Andric   const ASTContext &Context;
1730b57cec5SDimitry Andric   std::vector<SelectedASTNode> SelectionStack;
1740b57cec5SDimitry Andric   /// Controls whether we can traverse through the OpaqueValueExpr. This is
1750b57cec5SDimitry Andric   /// typically enabled during the traversal of syntactic form for
1760b57cec5SDimitry Andric   /// PseudoObjectExprs.
1770b57cec5SDimitry Andric   bool LookThroughOpaqueValueExprs = false;
1780b57cec5SDimitry Andric };
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric } // end anonymous namespace
1810b57cec5SDimitry Andric 
182*bdd1243dSDimitry Andric std::optional<SelectedASTNode>
findSelectedASTNodes(const ASTContext & Context,SourceRange SelectionRange)1830b57cec5SDimitry Andric clang::tooling::findSelectedASTNodes(const ASTContext &Context,
1840b57cec5SDimitry Andric                                      SourceRange SelectionRange) {
1850b57cec5SDimitry Andric   assert(SelectionRange.isValid() &&
1860b57cec5SDimitry Andric          SourceLocation::isPairOfFileLocations(SelectionRange.getBegin(),
1870b57cec5SDimitry Andric                                                SelectionRange.getEnd()) &&
1880b57cec5SDimitry Andric          "Expected a file range");
1890b57cec5SDimitry Andric   FileID TargetFile =
1900b57cec5SDimitry Andric       Context.getSourceManager().getFileID(SelectionRange.getBegin());
1910b57cec5SDimitry Andric   assert(Context.getSourceManager().getFileID(SelectionRange.getEnd()) ==
1920b57cec5SDimitry Andric              TargetFile &&
1930b57cec5SDimitry Andric          "selection range must span one file");
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   ASTSelectionFinder Visitor(SelectionRange, TargetFile, Context);
1960b57cec5SDimitry Andric   Visitor.TraverseDecl(Context.getTranslationUnitDecl());
1970b57cec5SDimitry Andric   return Visitor.getSelectedASTNode();
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
selectionKindToString(SourceSelectionKind Kind)2000b57cec5SDimitry Andric static const char *selectionKindToString(SourceSelectionKind Kind) {
2010b57cec5SDimitry Andric   switch (Kind) {
2020b57cec5SDimitry Andric   case SourceSelectionKind::None:
2030b57cec5SDimitry Andric     return "none";
2040b57cec5SDimitry Andric   case SourceSelectionKind::ContainsSelection:
2050b57cec5SDimitry Andric     return "contains-selection";
2060b57cec5SDimitry Andric   case SourceSelectionKind::ContainsSelectionStart:
2070b57cec5SDimitry Andric     return "contains-selection-start";
2080b57cec5SDimitry Andric   case SourceSelectionKind::ContainsSelectionEnd:
2090b57cec5SDimitry Andric     return "contains-selection-end";
2100b57cec5SDimitry Andric   case SourceSelectionKind::InsideSelection:
2110b57cec5SDimitry Andric     return "inside";
2120b57cec5SDimitry Andric   }
2130b57cec5SDimitry Andric   llvm_unreachable("invalid selection kind");
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
dump(const SelectedASTNode & Node,llvm::raw_ostream & OS,unsigned Indent=0)2160b57cec5SDimitry Andric static void dump(const SelectedASTNode &Node, llvm::raw_ostream &OS,
2170b57cec5SDimitry Andric                  unsigned Indent = 0) {
2180b57cec5SDimitry Andric   OS.indent(Indent * 2);
2190b57cec5SDimitry Andric   if (const Decl *D = Node.Node.get<Decl>()) {
2200b57cec5SDimitry Andric     OS << D->getDeclKindName() << "Decl";
2210b57cec5SDimitry Andric     if (const auto *ND = dyn_cast<NamedDecl>(D))
222e8d8bef9SDimitry Andric       OS << " \"" << ND->getDeclName() << '"';
2230b57cec5SDimitry Andric   } else if (const Stmt *S = Node.Node.get<Stmt>()) {
2240b57cec5SDimitry Andric     OS << S->getStmtClassName();
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric   OS << ' ' << selectionKindToString(Node.SelectionKind) << "\n";
2270b57cec5SDimitry Andric   for (const auto &Child : Node.Children)
2280b57cec5SDimitry Andric     dump(Child, OS, Indent + 1);
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric 
dump(llvm::raw_ostream & OS) const2310b57cec5SDimitry Andric void SelectedASTNode::dump(llvm::raw_ostream &OS) const { ::dump(*this, OS); }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric /// Returns true if the given node has any direct children with the following
2340b57cec5SDimitry Andric /// selection kind.
2350b57cec5SDimitry Andric ///
2360b57cec5SDimitry Andric /// Note: The direct children also include children of direct children with the
2370b57cec5SDimitry Andric /// "None" selection kind.
hasAnyDirectChildrenWithKind(const SelectedASTNode & Node,SourceSelectionKind Kind)2380b57cec5SDimitry Andric static bool hasAnyDirectChildrenWithKind(const SelectedASTNode &Node,
2390b57cec5SDimitry Andric                                          SourceSelectionKind Kind) {
2400b57cec5SDimitry Andric   assert(Kind != SourceSelectionKind::None && "invalid predicate!");
2410b57cec5SDimitry Andric   for (const auto &Child : Node.Children) {
2420b57cec5SDimitry Andric     if (Child.SelectionKind == Kind)
2430b57cec5SDimitry Andric       return true;
2440b57cec5SDimitry Andric     if (Child.SelectionKind == SourceSelectionKind::None)
2450b57cec5SDimitry Andric       return hasAnyDirectChildrenWithKind(Child, Kind);
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric   return false;
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric namespace {
2510b57cec5SDimitry Andric struct SelectedNodeWithParents {
2520b57cec5SDimitry Andric   SelectedASTNode::ReferenceType Node;
2530b57cec5SDimitry Andric   llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents;
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   /// Canonicalizes the given selection by selecting different related AST nodes
2560b57cec5SDimitry Andric   /// when it makes sense to do so.
2570b57cec5SDimitry Andric   void canonicalize();
2580b57cec5SDimitry Andric };
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric enum SelectionCanonicalizationAction { KeepSelection, SelectParent };
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric /// Returns the canonicalization action which should be applied to the
2630b57cec5SDimitry Andric /// selected statement.
2640b57cec5SDimitry Andric SelectionCanonicalizationAction
getSelectionCanonizalizationAction(const Stmt * S,const Stmt * Parent)2650b57cec5SDimitry Andric getSelectionCanonizalizationAction(const Stmt *S, const Stmt *Parent) {
2660b57cec5SDimitry Andric   // Select the parent expression when:
2670b57cec5SDimitry Andric   // - The string literal in ObjC string literal is selected, e.g.:
2680b57cec5SDimitry Andric   //     @"test"   becomes   @"test"
2690b57cec5SDimitry Andric   //      ~~~~~~             ~~~~~~~
2700b57cec5SDimitry Andric   if (isa<StringLiteral>(S) && isa<ObjCStringLiteral>(Parent))
2710b57cec5SDimitry Andric     return SelectParent;
2720b57cec5SDimitry Andric   // The entire call should be selected when just the member expression
2730b57cec5SDimitry Andric   // that refers to the method or the decl ref that refers to the function
2740b57cec5SDimitry Andric   // is selected.
2750b57cec5SDimitry Andric   //    f.call(args)  becomes  f.call(args)
2760b57cec5SDimitry Andric   //      ~~~~                 ~~~~~~~~~~~~
2770b57cec5SDimitry Andric   //    func(args)  becomes  func(args)
2780b57cec5SDimitry Andric   //    ~~~~                 ~~~~~~~~~~
2790b57cec5SDimitry Andric   else if (const auto *CE = dyn_cast<CallExpr>(Parent)) {
2800b57cec5SDimitry Andric     if ((isa<MemberExpr>(S) || isa<DeclRefExpr>(S)) &&
2810b57cec5SDimitry Andric         CE->getCallee()->IgnoreImpCasts() == S)
2820b57cec5SDimitry Andric       return SelectParent;
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric   // FIXME: Syntactic form -> Entire pseudo-object expr.
2850b57cec5SDimitry Andric   return KeepSelection;
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric } // end anonymous namespace
2890b57cec5SDimitry Andric 
canonicalize()2900b57cec5SDimitry Andric void SelectedNodeWithParents::canonicalize() {
2910b57cec5SDimitry Andric   const Stmt *S = Node.get().Node.get<Stmt>();
2920b57cec5SDimitry Andric   assert(S && "non statement selection!");
2930b57cec5SDimitry Andric   const Stmt *Parent = Parents[Parents.size() - 1].get().Node.get<Stmt>();
2940b57cec5SDimitry Andric   if (!Parent)
2950b57cec5SDimitry Andric     return;
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   // Look through the implicit casts in the parents.
2980b57cec5SDimitry Andric   unsigned ParentIndex = 1;
2990b57cec5SDimitry Andric   for (; (ParentIndex + 1) <= Parents.size() && isa<ImplicitCastExpr>(Parent);
3000b57cec5SDimitry Andric        ++ParentIndex) {
3010b57cec5SDimitry Andric     const Stmt *NewParent =
3020b57cec5SDimitry Andric         Parents[Parents.size() - ParentIndex - 1].get().Node.get<Stmt>();
3030b57cec5SDimitry Andric     if (!NewParent)
3040b57cec5SDimitry Andric       break;
3050b57cec5SDimitry Andric     Parent = NewParent;
3060b57cec5SDimitry Andric   }
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   switch (getSelectionCanonizalizationAction(S, Parent)) {
3090b57cec5SDimitry Andric   case SelectParent:
3100b57cec5SDimitry Andric     Node = Parents[Parents.size() - ParentIndex];
3110b57cec5SDimitry Andric     for (; ParentIndex != 0; --ParentIndex)
3120b57cec5SDimitry Andric       Parents.pop_back();
3130b57cec5SDimitry Andric     break;
3140b57cec5SDimitry Andric   case KeepSelection:
3150b57cec5SDimitry Andric     break;
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric /// Finds the set of bottom-most selected AST nodes that are in the selection
3200b57cec5SDimitry Andric /// tree with the specified selection kind.
3210b57cec5SDimitry Andric ///
3220b57cec5SDimitry Andric /// For example, given the following selection tree:
3230b57cec5SDimitry Andric ///
3240b57cec5SDimitry Andric /// FunctionDecl "f" contains-selection
3250b57cec5SDimitry Andric ///   CompoundStmt contains-selection [#1]
3260b57cec5SDimitry Andric ///     CallExpr inside
3270b57cec5SDimitry Andric ///     ImplicitCastExpr inside
3280b57cec5SDimitry Andric ///       DeclRefExpr inside
3290b57cec5SDimitry Andric ///     IntegerLiteral inside
3300b57cec5SDimitry Andric ///     IntegerLiteral inside
3310b57cec5SDimitry Andric /// FunctionDecl "f2" contains-selection
3320b57cec5SDimitry Andric ///   CompoundStmt contains-selection [#2]
3330b57cec5SDimitry Andric ///     CallExpr inside
3340b57cec5SDimitry Andric ///     ImplicitCastExpr inside
3350b57cec5SDimitry Andric ///       DeclRefExpr inside
3360b57cec5SDimitry Andric ///     IntegerLiteral inside
3370b57cec5SDimitry Andric ///     IntegerLiteral inside
3380b57cec5SDimitry Andric ///
3390b57cec5SDimitry Andric /// This function will find references to nodes #1 and #2 when searching for the
3400b57cec5SDimitry Andric /// \c ContainsSelection kind.
findDeepestWithKind(const SelectedASTNode & ASTSelection,llvm::SmallVectorImpl<SelectedNodeWithParents> & MatchingNodes,SourceSelectionKind Kind,llvm::SmallVectorImpl<SelectedASTNode::ReferenceType> & ParentStack)3410b57cec5SDimitry Andric static void findDeepestWithKind(
3420b57cec5SDimitry Andric     const SelectedASTNode &ASTSelection,
3430b57cec5SDimitry Andric     llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes,
3440b57cec5SDimitry Andric     SourceSelectionKind Kind,
3450b57cec5SDimitry Andric     llvm::SmallVectorImpl<SelectedASTNode::ReferenceType> &ParentStack) {
3460b57cec5SDimitry Andric   if (ASTSelection.Node.get<DeclStmt>()) {
3470b57cec5SDimitry Andric     // Select the entire decl stmt when any of its child declarations is the
3480b57cec5SDimitry Andric     // bottom-most.
3490b57cec5SDimitry Andric     for (const auto &Child : ASTSelection.Children) {
3500b57cec5SDimitry Andric       if (!hasAnyDirectChildrenWithKind(Child, Kind)) {
3510b57cec5SDimitry Andric         MatchingNodes.push_back(SelectedNodeWithParents{
3520b57cec5SDimitry Andric             std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
3530b57cec5SDimitry Andric         return;
3540b57cec5SDimitry Andric       }
3550b57cec5SDimitry Andric     }
3560b57cec5SDimitry Andric   } else {
3570b57cec5SDimitry Andric     if (!hasAnyDirectChildrenWithKind(ASTSelection, Kind)) {
3580b57cec5SDimitry Andric       // This node is the bottom-most.
3590b57cec5SDimitry Andric       MatchingNodes.push_back(SelectedNodeWithParents{
3600b57cec5SDimitry Andric           std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
3610b57cec5SDimitry Andric       return;
3620b57cec5SDimitry Andric     }
3630b57cec5SDimitry Andric   }
3640b57cec5SDimitry Andric   // Search in the children.
3650b57cec5SDimitry Andric   ParentStack.push_back(std::cref(ASTSelection));
3660b57cec5SDimitry Andric   for (const auto &Child : ASTSelection.Children)
3670b57cec5SDimitry Andric     findDeepestWithKind(Child, MatchingNodes, Kind, ParentStack);
3680b57cec5SDimitry Andric   ParentStack.pop_back();
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
findDeepestWithKind(const SelectedASTNode & ASTSelection,llvm::SmallVectorImpl<SelectedNodeWithParents> & MatchingNodes,SourceSelectionKind Kind)3710b57cec5SDimitry Andric static void findDeepestWithKind(
3720b57cec5SDimitry Andric     const SelectedASTNode &ASTSelection,
3730b57cec5SDimitry Andric     llvm::SmallVectorImpl<SelectedNodeWithParents> &MatchingNodes,
3740b57cec5SDimitry Andric     SourceSelectionKind Kind) {
3750b57cec5SDimitry Andric   llvm::SmallVector<SelectedASTNode::ReferenceType, 16> ParentStack;
3760b57cec5SDimitry Andric   findDeepestWithKind(ASTSelection, MatchingNodes, Kind, ParentStack);
3770b57cec5SDimitry Andric }
3780b57cec5SDimitry Andric 
379*bdd1243dSDimitry Andric std::optional<CodeRangeASTSelection>
create(SourceRange SelectionRange,const SelectedASTNode & ASTSelection)3800b57cec5SDimitry Andric CodeRangeASTSelection::create(SourceRange SelectionRange,
3810b57cec5SDimitry Andric                               const SelectedASTNode &ASTSelection) {
3820b57cec5SDimitry Andric   // Code range is selected when the selection range is not empty.
3830b57cec5SDimitry Andric   if (SelectionRange.getBegin() == SelectionRange.getEnd())
384*bdd1243dSDimitry Andric     return std::nullopt;
3850b57cec5SDimitry Andric   llvm::SmallVector<SelectedNodeWithParents, 4> ContainSelection;
3860b57cec5SDimitry Andric   findDeepestWithKind(ASTSelection, ContainSelection,
3870b57cec5SDimitry Andric                       SourceSelectionKind::ContainsSelection);
3880b57cec5SDimitry Andric   // We are looking for a selection in one body of code, so let's focus on
3890b57cec5SDimitry Andric   // one matching result.
3900b57cec5SDimitry Andric   if (ContainSelection.size() != 1)
391*bdd1243dSDimitry Andric     return std::nullopt;
3920b57cec5SDimitry Andric   SelectedNodeWithParents &Selected = ContainSelection[0];
3930b57cec5SDimitry Andric   if (!Selected.Node.get().Node.get<Stmt>())
394*bdd1243dSDimitry Andric     return std::nullopt;
3950b57cec5SDimitry Andric   const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<Stmt>();
3960b57cec5SDimitry Andric   if (!isa<CompoundStmt>(CodeRangeStmt)) {
3970b57cec5SDimitry Andric     Selected.canonicalize();
3980b57cec5SDimitry Andric     return CodeRangeASTSelection(Selected.Node, Selected.Parents,
3990b57cec5SDimitry Andric                                  /*AreChildrenSelected=*/false);
4000b57cec5SDimitry Andric   }
4010b57cec5SDimitry Andric   // FIXME (Alex L): First selected SwitchCase means that first case statement.
4020b57cec5SDimitry Andric   // is selected actually
4030b57cec5SDimitry Andric   // (See https://github.com/apple/swift-clang & CompoundStmtRange).
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric   // FIXME (Alex L): Tweak selection rules for compound statements, see:
4060b57cec5SDimitry Andric   // https://github.com/apple/swift-clang/blob/swift-4.1-branch/lib/Tooling/
4070b57cec5SDimitry Andric   // Refactor/ASTSlice.cpp#L513
4080b57cec5SDimitry Andric   // The user selected multiple statements in a compound statement.
4090b57cec5SDimitry Andric   Selected.Parents.push_back(Selected.Node);
4100b57cec5SDimitry Andric   return CodeRangeASTSelection(Selected.Node, Selected.Parents,
4110b57cec5SDimitry Andric                                /*AreChildrenSelected=*/true);
4120b57cec5SDimitry Andric }
4130b57cec5SDimitry Andric 
isFunctionLikeDeclaration(const Decl * D)4140b57cec5SDimitry Andric static bool isFunctionLikeDeclaration(const Decl *D) {
4150b57cec5SDimitry Andric   // FIXME (Alex L): Test for BlockDecl.
4160b57cec5SDimitry Andric   return isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D);
4170b57cec5SDimitry Andric }
4180b57cec5SDimitry Andric 
isInFunctionLikeBodyOfCode() const4190b57cec5SDimitry Andric bool CodeRangeASTSelection::isInFunctionLikeBodyOfCode() const {
4200b57cec5SDimitry Andric   bool IsPrevCompound = false;
4210b57cec5SDimitry Andric   // Scan through the parents (bottom-to-top) and check if the selection is
4220b57cec5SDimitry Andric   // contained in a compound statement that's a body of a function/method
4230b57cec5SDimitry Andric   // declaration.
4240b57cec5SDimitry Andric   for (const auto &Parent : llvm::reverse(Parents)) {
4250b57cec5SDimitry Andric     const DynTypedNode &Node = Parent.get().Node;
4260b57cec5SDimitry Andric     if (const auto *D = Node.get<Decl>()) {
4270b57cec5SDimitry Andric       if (isFunctionLikeDeclaration(D))
4280b57cec5SDimitry Andric         return IsPrevCompound;
4290b57cec5SDimitry Andric       // Stop the search at any type declaration to avoid returning true for
4300b57cec5SDimitry Andric       // expressions in type declarations in functions, like:
4310b57cec5SDimitry Andric       // function foo() { struct X {
4320b57cec5SDimitry Andric       //   int m = /*selection:*/ 1 + 2 /*selection end*/; }; };
4330b57cec5SDimitry Andric       if (isa<TypeDecl>(D))
4340b57cec5SDimitry Andric         return false;
4350b57cec5SDimitry Andric     }
4360b57cec5SDimitry Andric     IsPrevCompound = Node.get<CompoundStmt>() != nullptr;
4370b57cec5SDimitry Andric   }
4380b57cec5SDimitry Andric   return false;
4390b57cec5SDimitry Andric }
4400b57cec5SDimitry Andric 
getFunctionLikeNearestParent() const4410b57cec5SDimitry Andric const Decl *CodeRangeASTSelection::getFunctionLikeNearestParent() const {
4420b57cec5SDimitry Andric   for (const auto &Parent : llvm::reverse(Parents)) {
4430b57cec5SDimitry Andric     const DynTypedNode &Node = Parent.get().Node;
4440b57cec5SDimitry Andric     if (const auto *D = Node.get<Decl>()) {
4450b57cec5SDimitry Andric       if (isFunctionLikeDeclaration(D))
4460b57cec5SDimitry Andric         return D;
4470b57cec5SDimitry Andric     }
4480b57cec5SDimitry Andric   }
4490b57cec5SDimitry Andric   return nullptr;
4500b57cec5SDimitry Andric }
451