1 //===--- ExtractFunction.cpp -------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Extracts statements to a new function and replaces the statements with a
10 // call to the new function.
11 // Before:
12 //   void f(int a) {
13 //     [[if(a < 5)
14 //       a = 5;]]
15 //   }
16 // After:
17 //   void extracted(int &a) {
18 //     if(a < 5)
19 //       a = 5;
20 //   }
21 //   void f(int a) {
22 //     extracted(a);
23 //   }
24 //
25 // - Only extract statements
26 // - Extracts from non-templated free functions only.
27 // - Parameters are const only if the declaration was const
28 //   - Always passed by l-value reference
29 // - Void return type
30 // - Cannot extract declarations that will be needed in the original function
31 //   after extraction.
32 // - Checks for broken control flow (break/continue without loop/switch)
33 //
34 // 1. ExtractFunction is the tweak subclass
35 //    - Prepare does basic analysis of the selection and is therefore fast.
36 //      Successful prepare doesn't always mean we can apply the tweak.
37 //    - Apply does a more detailed analysis and can be slower. In case of
38 //      failure, we let the user know that we are unable to perform extraction.
39 // 2. ExtractionZone store information about the range being extracted and the
40 //    enclosing function.
41 // 3. NewFunction stores properties of the extracted function and provides
42 //    methods for rendering it.
43 // 4. CapturedZoneInfo uses a RecursiveASTVisitor to capture information about
44 //    the extraction like declarations, existing return statements, etc.
45 // 5. getExtractedFunction is responsible for analyzing the CapturedZoneInfo and
46 //    creating a NewFunction.
47 //===----------------------------------------------------------------------===//
48 
49 #include "AST.h"
50 #include "FindTarget.h"
51 #include "ParsedAST.h"
52 #include "Selection.h"
53 #include "SourceCode.h"
54 #include "refactor/Tweak.h"
55 #include "support/Logger.h"
56 #include "clang/AST/ASTContext.h"
57 #include "clang/AST/Decl.h"
58 #include "clang/AST/DeclBase.h"
59 #include "clang/AST/DeclTemplate.h"
60 #include "clang/AST/RecursiveASTVisitor.h"
61 #include "clang/AST/Stmt.h"
62 #include "clang/Basic/LangOptions.h"
63 #include "clang/Basic/SourceLocation.h"
64 #include "clang/Basic/SourceManager.h"
65 #include "clang/Lex/Lexer.h"
66 #include "clang/Tooling/Core/Replacement.h"
67 #include "clang/Tooling/Refactoring/Extract/SourceExtraction.h"
68 #include "llvm/ADT/None.h"
69 #include "llvm/ADT/Optional.h"
70 #include "llvm/ADT/STLExtras.h"
71 #include "llvm/ADT/SmallSet.h"
72 #include "llvm/ADT/SmallVector.h"
73 #include "llvm/ADT/StringRef.h"
74 #include "llvm/ADT/iterator_range.h"
75 #include "llvm/Support/Casting.h"
76 #include "llvm/Support/Error.h"
77 
78 namespace clang {
79 namespace clangd {
80 namespace {
81 
82 using Node = SelectionTree::Node;
83 
84 // ExtractionZone is the part of code that is being extracted.
85 // EnclosingFunction is the function/method inside which the zone lies.
86 // We split the file into 4 parts relative to extraction zone.
87 enum class ZoneRelative {
88   Before,     // Before Zone and inside EnclosingFunction.
89   Inside,     // Inside Zone.
90   After,      // After Zone and inside EnclosingFunction.
91   OutsideFunc // Outside EnclosingFunction.
92 };
93 
94 // A RootStmt is a statement that's fully selected including all it's children
95 // and it's parent is unselected.
96 // Check if a node is a root statement.
97 bool isRootStmt(const Node *N) {
98   if (!N->ASTNode.get<Stmt>())
99     return false;
100   // Root statement cannot be partially selected.
101   if (N->Selected == SelectionTree::Partial)
102     return false;
103   // Only DeclStmt can be an unselected RootStmt since VarDecls claim the entire
104   // selection range in selectionTree.
105   if (N->Selected == SelectionTree::Unselected && !N->ASTNode.get<DeclStmt>())
106     return false;
107   return true;
108 }
109 
110 // Returns the (unselected) parent of all RootStmts given the commonAncestor.
111 // Returns null if:
112 // 1. any node is partially selected
113 // 2. If all completely selected nodes don't have the same common parent
114 // 3. Any child of Parent isn't a RootStmt.
115 // Returns null if any child is not a RootStmt.
116 // We only support extraction of RootStmts since it allows us to extract without
117 // having to change the selection range. Also, this means that any scope that
118 // begins in selection range, ends in selection range and any scope that begins
119 // outside the selection range, ends outside as well.
120 const Node *getParentOfRootStmts(const Node *CommonAnc) {
121   if (!CommonAnc)
122     return nullptr;
123   const Node *Parent = nullptr;
124   switch (CommonAnc->Selected) {
125   case SelectionTree::Selection::Unselected:
126     // Typically a block, with the { and } unselected, could also be ForStmt etc
127     // Ensure all Children are RootStmts.
128     Parent = CommonAnc;
129     break;
130   case SelectionTree::Selection::Partial:
131     // Only a fully-selected single statement can be selected.
132     return nullptr;
133   case SelectionTree::Selection::Complete:
134     // If the Common Ancestor is completely selected, then it's a root statement
135     // and its parent will be unselected.
136     Parent = CommonAnc->Parent;
137     // If parent is a DeclStmt, even though it's unselected, we consider it a
138     // root statement and return its parent. This is done because the VarDecls
139     // claim the entire selection range of the Declaration and DeclStmt is
140     // always unselected.
141     if (Parent->ASTNode.get<DeclStmt>())
142       Parent = Parent->Parent;
143     break;
144   }
145   // Ensure all Children are RootStmts.
146   return llvm::all_of(Parent->Children, isRootStmt) ? Parent : nullptr;
147 }
148 
149 // The ExtractionZone class forms a view of the code wrt Zone.
150 struct ExtractionZone {
151   // Parent of RootStatements being extracted.
152   const Node *Parent = nullptr;
153   // The half-open file range of the code being extracted.
154   SourceRange ZoneRange;
155   // The function inside which our zone resides.
156   const FunctionDecl *EnclosingFunction = nullptr;
157   // The half-open file range of the enclosing function.
158   SourceRange EnclosingFuncRange;
159   // Set of statements that form the ExtractionZone.
160   llvm::DenseSet<const Stmt *> RootStmts;
161 
162   SourceLocation getInsertionPoint() const {
163     return EnclosingFuncRange.getBegin();
164   }
165   bool isRootStmt(const Stmt *S) const;
166   // The last root statement is important to decide where we need to insert a
167   // semicolon after the extraction.
168   const Node *getLastRootStmt() const { return Parent->Children.back(); }
169 
170   // Checks if declarations inside extraction zone are accessed afterwards.
171   //
172   // This performs a partial AST traversal proportional to the size of the
173   // enclosing function, so it is possibly expensive.
174   bool requiresHoisting(const SourceManager &SM,
175                         const HeuristicResolver *Resolver) const {
176     // First find all the declarations that happened inside extraction zone.
177     llvm::SmallSet<const Decl *, 1> DeclsInExtZone;
178     for (auto *RootStmt : RootStmts) {
179       findExplicitReferences(
180           RootStmt,
181           [&DeclsInExtZone](const ReferenceLoc &Loc) {
182             if (!Loc.IsDecl)
183               return;
184             DeclsInExtZone.insert(Loc.Targets.front());
185           },
186           Resolver);
187     }
188     // Early exit without performing expensive traversal below.
189     if (DeclsInExtZone.empty())
190       return false;
191     // Then make sure they are not used outside the zone.
192     for (const auto *S : EnclosingFunction->getBody()->children()) {
193       if (SM.isBeforeInTranslationUnit(S->getSourceRange().getEnd(),
194                                        ZoneRange.getEnd()))
195         continue;
196       bool HasPostUse = false;
197       findExplicitReferences(
198           S,
199           [&](const ReferenceLoc &Loc) {
200             if (HasPostUse ||
201                 SM.isBeforeInTranslationUnit(Loc.NameLoc, ZoneRange.getEnd()))
202               return;
203             HasPostUse = llvm::any_of(Loc.Targets,
204                                       [&DeclsInExtZone](const Decl *Target) {
205                                         return DeclsInExtZone.contains(Target);
206                                       });
207           },
208           Resolver);
209       if (HasPostUse)
210         return true;
211     }
212     return false;
213   }
214 };
215 
216 // Whether the code in the extraction zone is guaranteed to return, assuming
217 // no broken control flow (unbound break/continue).
218 // This is a very naive check (does it end with a return stmt).
219 // Doing some rudimentary control flow analysis would cover more cases.
220 bool alwaysReturns(const ExtractionZone &EZ) {
221   const Stmt *Last = EZ.getLastRootStmt()->ASTNode.get<Stmt>();
222   // Unwrap enclosing (unconditional) compound statement.
223   while (const auto *CS = llvm::dyn_cast<CompoundStmt>(Last)) {
224     if (CS->body_empty())
225       return false;
226     Last = CS->body_back();
227   }
228   return llvm::isa<ReturnStmt>(Last);
229 }
230 
231 bool ExtractionZone::isRootStmt(const Stmt *S) const {
232   return RootStmts.contains(S);
233 }
234 
235 // Finds the function in which the zone lies.
236 const FunctionDecl *findEnclosingFunction(const Node *CommonAnc) {
237   // Walk up the SelectionTree until we find a function Decl
238   for (const Node *CurNode = CommonAnc; CurNode; CurNode = CurNode->Parent) {
239     // Don't extract from lambdas
240     if (CurNode->ASTNode.get<LambdaExpr>())
241       return nullptr;
242     if (const FunctionDecl *Func = CurNode->ASTNode.get<FunctionDecl>()) {
243       // FIXME: Support extraction from methods.
244       if (isa<CXXMethodDecl>(Func))
245         return nullptr;
246       // FIXME: Support extraction from templated functions.
247       if (Func->isTemplated())
248         return nullptr;
249       return Func;
250     }
251   }
252   return nullptr;
253 }
254 
255 // Zone Range is the union of SourceRanges of all child Nodes in Parent since
256 // all child Nodes are RootStmts
257 llvm::Optional<SourceRange> findZoneRange(const Node *Parent,
258                                           const SourceManager &SM,
259                                           const LangOptions &LangOpts) {
260   SourceRange SR;
261   if (auto BeginFileRange = toHalfOpenFileRange(
262           SM, LangOpts, Parent->Children.front()->ASTNode.getSourceRange()))
263     SR.setBegin(BeginFileRange->getBegin());
264   else
265     return llvm::None;
266   if (auto EndFileRange = toHalfOpenFileRange(
267           SM, LangOpts, Parent->Children.back()->ASTNode.getSourceRange()))
268     SR.setEnd(EndFileRange->getEnd());
269   else
270     return llvm::None;
271   return SR;
272 }
273 
274 // Compute the range spanned by the enclosing function.
275 // FIXME: check if EnclosingFunction has any attributes as the AST doesn't
276 // always store the source range of the attributes and thus we end up extracting
277 // between the attributes and the EnclosingFunction.
278 llvm::Optional<SourceRange>
279 computeEnclosingFuncRange(const FunctionDecl *EnclosingFunction,
280                           const SourceManager &SM,
281                           const LangOptions &LangOpts) {
282   return toHalfOpenFileRange(SM, LangOpts, EnclosingFunction->getSourceRange());
283 }
284 
285 // returns true if Child can be a single RootStmt being extracted from
286 // EnclosingFunc.
287 bool validSingleChild(const Node *Child, const FunctionDecl *EnclosingFunc) {
288   // Don't extract expressions.
289   // FIXME: We should extract expressions that are "statements" i.e. not
290   // subexpressions
291   if (Child->ASTNode.get<Expr>())
292     return false;
293   // Extracting the body of EnclosingFunc would remove it's definition.
294   assert(EnclosingFunc->hasBody() &&
295          "We should always be extracting from a function body.");
296   if (Child->ASTNode.get<Stmt>() == EnclosingFunc->getBody())
297     return false;
298   return true;
299 }
300 
301 // FIXME: Check we're not extracting from the initializer/condition of a control
302 // flow structure.
303 llvm::Optional<ExtractionZone> findExtractionZone(const Node *CommonAnc,
304                                                   const SourceManager &SM,
305                                                   const LangOptions &LangOpts) {
306   ExtractionZone ExtZone;
307   ExtZone.Parent = getParentOfRootStmts(CommonAnc);
308   if (!ExtZone.Parent || ExtZone.Parent->Children.empty())
309     return llvm::None;
310   ExtZone.EnclosingFunction = findEnclosingFunction(ExtZone.Parent);
311   if (!ExtZone.EnclosingFunction)
312     return llvm::None;
313   // When there is a single RootStmt, we must check if it's valid for
314   // extraction.
315   if (ExtZone.Parent->Children.size() == 1 &&
316       !validSingleChild(ExtZone.getLastRootStmt(), ExtZone.EnclosingFunction))
317     return llvm::None;
318   if (auto FuncRange =
319           computeEnclosingFuncRange(ExtZone.EnclosingFunction, SM, LangOpts))
320     ExtZone.EnclosingFuncRange = *FuncRange;
321   if (auto ZoneRange = findZoneRange(ExtZone.Parent, SM, LangOpts))
322     ExtZone.ZoneRange = *ZoneRange;
323   if (ExtZone.EnclosingFuncRange.isInvalid() || ExtZone.ZoneRange.isInvalid())
324     return llvm::None;
325 
326   for (const Node *Child : ExtZone.Parent->Children)
327     ExtZone.RootStmts.insert(Child->ASTNode.get<Stmt>());
328 
329   return ExtZone;
330 }
331 
332 // Stores information about the extracted function and provides methods for
333 // rendering it.
334 struct NewFunction {
335   struct Parameter {
336     std::string Name;
337     QualType TypeInfo;
338     bool PassByReference;
339     unsigned OrderPriority; // Lower value parameters are preferred first.
340     std::string render(const DeclContext *Context) const;
341     bool operator<(const Parameter &Other) const {
342       return OrderPriority < Other.OrderPriority;
343     }
344   };
345   std::string Name = "extracted";
346   QualType ReturnType;
347   std::vector<Parameter> Parameters;
348   SourceRange BodyRange;
349   SourceLocation InsertionPoint;
350   const DeclContext *EnclosingFuncContext;
351   bool CallerReturnsValue = false;
352   // Decides whether the extracted function body and the function call need a
353   // semicolon after extraction.
354   tooling::ExtractionSemicolonPolicy SemicolonPolicy;
355   NewFunction(tooling::ExtractionSemicolonPolicy SemicolonPolicy)
356       : SemicolonPolicy(SemicolonPolicy) {}
357   // Render the call for this function.
358   std::string renderCall() const;
359   // Render the definition for this function.
360   std::string renderDefinition(const SourceManager &SM) const;
361 
362 private:
363   std::string renderParametersForDefinition() const;
364   std::string renderParametersForCall() const;
365   // Generate the function body.
366   std::string getFuncBody(const SourceManager &SM) const;
367 };
368 
369 std::string NewFunction::renderParametersForDefinition() const {
370   std::string Result;
371   bool NeedCommaBefore = false;
372   for (const Parameter &P : Parameters) {
373     if (NeedCommaBefore)
374       Result += ", ";
375     NeedCommaBefore = true;
376     Result += P.render(EnclosingFuncContext);
377   }
378   return Result;
379 }
380 
381 std::string NewFunction::renderParametersForCall() const {
382   std::string Result;
383   bool NeedCommaBefore = false;
384   for (const Parameter &P : Parameters) {
385     if (NeedCommaBefore)
386       Result += ", ";
387     NeedCommaBefore = true;
388     Result += P.Name;
389   }
390   return Result;
391 }
392 
393 std::string NewFunction::renderCall() const {
394   return std::string(
395       llvm::formatv("{0}{1}({2}){3}", CallerReturnsValue ? "return " : "", Name,
396                     renderParametersForCall(),
397                     (SemicolonPolicy.isNeededInOriginalFunction() ? ";" : "")));
398 }
399 
400 std::string NewFunction::renderDefinition(const SourceManager &SM) const {
401   return std::string(llvm::formatv(
402       "{0} {1}({2}) {\n{3}\n}\n", printType(ReturnType, *EnclosingFuncContext),
403       Name, renderParametersForDefinition(), getFuncBody(SM)));
404 }
405 
406 std::string NewFunction::getFuncBody(const SourceManager &SM) const {
407   // FIXME: Generate tooling::Replacements instead of std::string to
408   // - hoist decls
409   // - add return statement
410   // - Add semicolon
411   return toSourceCode(SM, BodyRange).str() +
412          (SemicolonPolicy.isNeededInExtractedFunction() ? ";" : "");
413 }
414 
415 std::string NewFunction::Parameter::render(const DeclContext *Context) const {
416   return printType(TypeInfo, *Context) + (PassByReference ? " &" : " ") + Name;
417 }
418 
419 // Stores captured information about Extraction Zone.
420 struct CapturedZoneInfo {
421   struct DeclInformation {
422     const Decl *TheDecl;
423     ZoneRelative DeclaredIn;
424     // index of the declaration or first reference.
425     unsigned DeclIndex;
426     bool IsReferencedInZone = false;
427     bool IsReferencedInPostZone = false;
428     // FIXME: Capture mutation information
429     DeclInformation(const Decl *TheDecl, ZoneRelative DeclaredIn,
430                     unsigned DeclIndex)
431         : TheDecl(TheDecl), DeclaredIn(DeclaredIn), DeclIndex(DeclIndex){};
432     // Marks the occurence of a reference for this declaration
433     void markOccurence(ZoneRelative ReferenceLoc);
434   };
435   // Maps Decls to their DeclInfo
436   llvm::DenseMap<const Decl *, DeclInformation> DeclInfoMap;
437   bool HasReturnStmt = false; // Are there any return statements in the zone?
438   bool AlwaysReturns = false; // Does the zone always return?
439   // Control flow is broken if we are extracting a break/continue without a
440   // corresponding parent loop/switch
441   bool BrokenControlFlow = false;
442   // FIXME: capture TypeAliasDecl and UsingDirectiveDecl
443   // FIXME: Capture type information as well.
444   DeclInformation *createDeclInfo(const Decl *D, ZoneRelative RelativeLoc);
445   DeclInformation *getDeclInfoFor(const Decl *D);
446 };
447 
448 CapturedZoneInfo::DeclInformation *
449 CapturedZoneInfo::createDeclInfo(const Decl *D, ZoneRelative RelativeLoc) {
450   // The new Decl's index is the size of the map so far.
451   auto InsertionResult = DeclInfoMap.insert(
452       {D, DeclInformation(D, RelativeLoc, DeclInfoMap.size())});
453   // Return the newly created DeclInfo
454   return &InsertionResult.first->second;
455 }
456 
457 CapturedZoneInfo::DeclInformation *
458 CapturedZoneInfo::getDeclInfoFor(const Decl *D) {
459   // If the Decl doesn't exist, we
460   auto Iter = DeclInfoMap.find(D);
461   if (Iter == DeclInfoMap.end())
462     return nullptr;
463   return &Iter->second;
464 }
465 
466 void CapturedZoneInfo::DeclInformation::markOccurence(
467     ZoneRelative ReferenceLoc) {
468   switch (ReferenceLoc) {
469   case ZoneRelative::Inside:
470     IsReferencedInZone = true;
471     break;
472   case ZoneRelative::After:
473     IsReferencedInPostZone = true;
474     break;
475   default:
476     break;
477   }
478 }
479 
480 bool isLoop(const Stmt *S) {
481   return isa<ForStmt>(S) || isa<DoStmt>(S) || isa<WhileStmt>(S) ||
482          isa<CXXForRangeStmt>(S);
483 }
484 
485 // Captures information from Extraction Zone
486 CapturedZoneInfo captureZoneInfo(const ExtractionZone &ExtZone) {
487   // We use the ASTVisitor instead of using the selection tree since we need to
488   // find references in the PostZone as well.
489   // FIXME: Check which statements we don't allow to extract.
490   class ExtractionZoneVisitor
491       : public clang::RecursiveASTVisitor<ExtractionZoneVisitor> {
492   public:
493     ExtractionZoneVisitor(const ExtractionZone &ExtZone) : ExtZone(ExtZone) {
494       TraverseDecl(const_cast<FunctionDecl *>(ExtZone.EnclosingFunction));
495     }
496 
497     bool TraverseStmt(Stmt *S) {
498       if (!S)
499         return true;
500       bool IsRootStmt = ExtZone.isRootStmt(const_cast<const Stmt *>(S));
501       // If we are starting traversal of a RootStmt, we are somewhere inside
502       // ExtractionZone
503       if (IsRootStmt)
504         CurrentLocation = ZoneRelative::Inside;
505       addToLoopSwitchCounters(S, 1);
506       // Traverse using base class's TraverseStmt
507       RecursiveASTVisitor::TraverseStmt(S);
508       addToLoopSwitchCounters(S, -1);
509       // We set the current location as after since next stmt will either be a
510       // RootStmt (handled at the beginning) or after extractionZone
511       if (IsRootStmt)
512         CurrentLocation = ZoneRelative::After;
513       return true;
514     }
515 
516     // Add Increment to CurNumberOf{Loops,Switch} if statement is
517     // {Loop,Switch} and inside Extraction Zone.
518     void addToLoopSwitchCounters(Stmt *S, int Increment) {
519       if (CurrentLocation != ZoneRelative::Inside)
520         return;
521       if (isLoop(S))
522         CurNumberOfNestedLoops += Increment;
523       else if (isa<SwitchStmt>(S))
524         CurNumberOfSwitch += Increment;
525     }
526 
527     bool VisitDecl(Decl *D) {
528       Info.createDeclInfo(D, CurrentLocation);
529       return true;
530     }
531 
532     bool VisitDeclRefExpr(DeclRefExpr *DRE) {
533       // Find the corresponding Decl and mark it's occurrence.
534       const Decl *D = DRE->getDecl();
535       auto *DeclInfo = Info.getDeclInfoFor(D);
536       // If no Decl was found, the Decl must be outside the enclosingFunc.
537       if (!DeclInfo)
538         DeclInfo = Info.createDeclInfo(D, ZoneRelative::OutsideFunc);
539       DeclInfo->markOccurence(CurrentLocation);
540       // FIXME: check if reference mutates the Decl being referred.
541       return true;
542     }
543 
544     bool VisitReturnStmt(ReturnStmt *Return) {
545       if (CurrentLocation == ZoneRelative::Inside)
546         Info.HasReturnStmt = true;
547       return true;
548     }
549 
550     bool VisitBreakStmt(BreakStmt *Break) {
551       // Control flow is broken if break statement is selected without any
552       // parent loop or switch statement.
553       if (CurrentLocation == ZoneRelative::Inside &&
554           !(CurNumberOfNestedLoops || CurNumberOfSwitch))
555         Info.BrokenControlFlow = true;
556       return true;
557     }
558 
559     bool VisitContinueStmt(ContinueStmt *Continue) {
560       // Control flow is broken if Continue statement is selected without any
561       // parent loop
562       if (CurrentLocation == ZoneRelative::Inside && !CurNumberOfNestedLoops)
563         Info.BrokenControlFlow = true;
564       return true;
565     }
566     CapturedZoneInfo Info;
567     const ExtractionZone &ExtZone;
568     ZoneRelative CurrentLocation = ZoneRelative::Before;
569     // Number of {loop,switch} statements that are currently in the traversal
570     // stack inside Extraction Zone. Used to check for broken control flow.
571     unsigned CurNumberOfNestedLoops = 0;
572     unsigned CurNumberOfSwitch = 0;
573   };
574   ExtractionZoneVisitor Visitor(ExtZone);
575   CapturedZoneInfo Result = std::move(Visitor.Info);
576   Result.AlwaysReturns = alwaysReturns(ExtZone);
577   return Result;
578 }
579 
580 // Adds parameters to ExtractedFunc.
581 // Returns true if able to find the parameters successfully and no hoisting
582 // needed.
583 // FIXME: Check if the declaration has a local/anonymous type
584 bool createParameters(NewFunction &ExtractedFunc,
585                       const CapturedZoneInfo &CapturedInfo) {
586   for (const auto &KeyVal : CapturedInfo.DeclInfoMap) {
587     const auto &DeclInfo = KeyVal.second;
588     // If a Decl was Declared in zone and referenced in post zone, it
589     // needs to be hoisted (we bail out in that case).
590     // FIXME: Support Decl Hoisting.
591     if (DeclInfo.DeclaredIn == ZoneRelative::Inside &&
592         DeclInfo.IsReferencedInPostZone)
593       return false;
594     if (!DeclInfo.IsReferencedInZone)
595       continue; // no need to pass as parameter, not referenced
596     if (DeclInfo.DeclaredIn == ZoneRelative::Inside ||
597         DeclInfo.DeclaredIn == ZoneRelative::OutsideFunc)
598       continue; // no need to pass as parameter, still accessible.
599     // Parameter specific checks.
600     const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(DeclInfo.TheDecl);
601     // Can't parameterise if the Decl isn't a ValueDecl or is a FunctionDecl
602     // (this includes the case of recursive call to EnclosingFunc in Zone).
603     if (!VD || isa<FunctionDecl>(DeclInfo.TheDecl))
604       return false;
605     // Parameter qualifiers are same as the Decl's qualifiers.
606     QualType TypeInfo = VD->getType().getNonReferenceType();
607     // FIXME: Need better qualifier checks: check mutated status for
608     // Decl(e.g. was it assigned, passed as nonconst argument, etc)
609     // FIXME: check if parameter will be a non l-value reference.
610     // FIXME: We don't want to always pass variables of types like int,
611     // pointers, etc by reference.
612     bool IsPassedByReference = true;
613     // We use the index of declaration as the ordering priority for parameters.
614     ExtractedFunc.Parameters.push_back({std::string(VD->getName()), TypeInfo,
615                                         IsPassedByReference,
616                                         DeclInfo.DeclIndex});
617   }
618   llvm::sort(ExtractedFunc.Parameters);
619   return true;
620 }
621 
622 // Clangd uses open ranges while ExtractionSemicolonPolicy (in Clang Tooling)
623 // uses closed ranges. Generates the semicolon policy for the extraction and
624 // extends the ZoneRange if necessary.
625 tooling::ExtractionSemicolonPolicy
626 getSemicolonPolicy(ExtractionZone &ExtZone, const SourceManager &SM,
627                    const LangOptions &LangOpts) {
628   // Get closed ZoneRange.
629   SourceRange FuncBodyRange = {ExtZone.ZoneRange.getBegin(),
630                                ExtZone.ZoneRange.getEnd().getLocWithOffset(-1)};
631   auto SemicolonPolicy = tooling::ExtractionSemicolonPolicy::compute(
632       ExtZone.getLastRootStmt()->ASTNode.get<Stmt>(), FuncBodyRange, SM,
633       LangOpts);
634   // Update ZoneRange.
635   ExtZone.ZoneRange.setEnd(FuncBodyRange.getEnd().getLocWithOffset(1));
636   return SemicolonPolicy;
637 }
638 
639 // Generate return type for ExtractedFunc. Return false if unable to do so.
640 bool generateReturnProperties(NewFunction &ExtractedFunc,
641                               const FunctionDecl &EnclosingFunc,
642                               const CapturedZoneInfo &CapturedInfo) {
643   // If the selected code always returns, we preserve those return statements.
644   // The return type should be the same as the enclosing function.
645   // (Others are possible if there are conversions, but this seems clearest).
646   if (CapturedInfo.HasReturnStmt) {
647     // If the return is conditional, neither replacing the code with
648     // `extracted()` nor `return extracted()` is correct.
649     if (!CapturedInfo.AlwaysReturns)
650       return false;
651     QualType Ret = EnclosingFunc.getReturnType();
652     // Once we support members, it'd be nice to support e.g. extracting a method
653     // of Foo<T> that returns T. But it's not clear when that's safe.
654     if (Ret->isDependentType())
655       return false;
656     ExtractedFunc.ReturnType = Ret;
657     return true;
658   }
659   // FIXME: Generate new return statement if needed.
660   ExtractedFunc.ReturnType = EnclosingFunc.getParentASTContext().VoidTy;
661   return true;
662 }
663 
664 // FIXME: add support for adding other function return types besides void.
665 // FIXME: assign the value returned by non void extracted function.
666 llvm::Expected<NewFunction> getExtractedFunction(ExtractionZone &ExtZone,
667                                                  const SourceManager &SM,
668                                                  const LangOptions &LangOpts) {
669   CapturedZoneInfo CapturedInfo = captureZoneInfo(ExtZone);
670   // Bail out if any break of continue exists
671   if (CapturedInfo.BrokenControlFlow)
672     return error("Cannot extract break/continue without corresponding "
673                  "loop/switch statement.");
674   NewFunction ExtractedFunc(getSemicolonPolicy(ExtZone, SM, LangOpts));
675   ExtractedFunc.BodyRange = ExtZone.ZoneRange;
676   ExtractedFunc.InsertionPoint = ExtZone.getInsertionPoint();
677   ExtractedFunc.EnclosingFuncContext =
678       ExtZone.EnclosingFunction->getDeclContext();
679   ExtractedFunc.CallerReturnsValue = CapturedInfo.AlwaysReturns;
680   if (!createParameters(ExtractedFunc, CapturedInfo) ||
681       !generateReturnProperties(ExtractedFunc, *ExtZone.EnclosingFunction,
682                                 CapturedInfo))
683     return error("Too complex to extract.");
684   return ExtractedFunc;
685 }
686 
687 class ExtractFunction : public Tweak {
688 public:
689   const char *id() const override final;
690   bool prepare(const Selection &Inputs) override;
691   Expected<Effect> apply(const Selection &Inputs) override;
692   std::string title() const override { return "Extract to function"; }
693   llvm::StringLiteral kind() const override {
694     return CodeAction::REFACTOR_KIND;
695   }
696 
697 private:
698   ExtractionZone ExtZone;
699 };
700 
701 REGISTER_TWEAK(ExtractFunction)
702 tooling::Replacement replaceWithFuncCall(const NewFunction &ExtractedFunc,
703                                          const SourceManager &SM,
704                                          const LangOptions &LangOpts) {
705   std::string FuncCall = ExtractedFunc.renderCall();
706   return tooling::Replacement(
707       SM, CharSourceRange(ExtractedFunc.BodyRange, false), FuncCall, LangOpts);
708 }
709 
710 tooling::Replacement createFunctionDefinition(const NewFunction &ExtractedFunc,
711                                               const SourceManager &SM) {
712   std::string FunctionDef = ExtractedFunc.renderDefinition(SM);
713   return tooling::Replacement(SM, ExtractedFunc.InsertionPoint, 0, FunctionDef);
714 }
715 
716 // Returns true if ExtZone contains any ReturnStmts.
717 bool hasReturnStmt(const ExtractionZone &ExtZone) {
718   class ReturnStmtVisitor
719       : public clang::RecursiveASTVisitor<ReturnStmtVisitor> {
720   public:
721     bool VisitReturnStmt(ReturnStmt *Return) {
722       Found = true;
723       return false; // We found the answer, abort the scan.
724     }
725     bool Found = false;
726   };
727 
728   ReturnStmtVisitor V;
729   for (const Stmt *RootStmt : ExtZone.RootStmts) {
730     V.TraverseStmt(const_cast<Stmt *>(RootStmt));
731     if (V.Found)
732       break;
733   }
734   return V.Found;
735 }
736 
737 bool ExtractFunction::prepare(const Selection &Inputs) {
738   const LangOptions &LangOpts = Inputs.AST->getLangOpts();
739   if (!LangOpts.CPlusPlus)
740     return false;
741   const Node *CommonAnc = Inputs.ASTSelection.commonAncestor();
742   const SourceManager &SM = Inputs.AST->getSourceManager();
743   auto MaybeExtZone = findExtractionZone(CommonAnc, SM, LangOpts);
744   if (!MaybeExtZone ||
745       (hasReturnStmt(*MaybeExtZone) && !alwaysReturns(*MaybeExtZone)))
746     return false;
747 
748   // FIXME: Get rid of this check once we support hoisting.
749   if (MaybeExtZone->requiresHoisting(SM, Inputs.AST->getHeuristicResolver()))
750     return false;
751 
752   ExtZone = std::move(*MaybeExtZone);
753   return true;
754 }
755 
756 Expected<Tweak::Effect> ExtractFunction::apply(const Selection &Inputs) {
757   const SourceManager &SM = Inputs.AST->getSourceManager();
758   const LangOptions &LangOpts = Inputs.AST->getLangOpts();
759   auto ExtractedFunc = getExtractedFunction(ExtZone, SM, LangOpts);
760   // FIXME: Add more types of errors.
761   if (!ExtractedFunc)
762     return ExtractedFunc.takeError();
763   tooling::Replacements Result;
764   if (auto Err = Result.add(createFunctionDefinition(*ExtractedFunc, SM)))
765     return std::move(Err);
766   if (auto Err = Result.add(replaceWithFuncCall(*ExtractedFunc, SM, LangOpts)))
767     return std::move(Err);
768   return Effect::mainFileEdit(SM, std::move(Result));
769 }
770 
771 } // namespace
772 } // namespace clangd
773 } // namespace clang
774