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 "Logger.h"
51 #include "ParsedAST.h"
52 #include "Selection.h"
53 #include "SourceCode.h"
54 #include "refactor/Tweak.h"
55 #include "clang/AST/ASTContext.h"
56 #include "clang/AST/Decl.h"
57 #include "clang/AST/DeclTemplate.h"
58 #include "clang/AST/RecursiveASTVisitor.h"
59 #include "clang/AST/Stmt.h"
60 #include "clang/Basic/LangOptions.h"
61 #include "clang/Basic/SourceLocation.h"
62 #include "clang/Basic/SourceManager.h"
63 #include "clang/Lex/Lexer.h"
64 #include "clang/Tooling/Core/Replacement.h"
65 #include "clang/Tooling/Refactoring/Extract/SourceExtraction.h"
66 #include "llvm/ADT/None.h"
67 #include "llvm/ADT/Optional.h"
68 #include "llvm/ADT/SmallVector.h"
69 #include "llvm/ADT/StringRef.h"
70 #include "llvm/ADT/iterator_range.h"
71 #include "llvm/Support/Casting.h"
72 #include "llvm/Support/Error.h"
73 
74 namespace clang {
75 namespace clangd {
76 namespace {
77 
78 using Node = SelectionTree::Node;
79 
80 // ExtractionZone is the part of code that is being extracted.
81 // EnclosingFunction is the function/method inside which the zone lies.
82 // We split the file into 4 parts relative to extraction zone.
83 enum class ZoneRelative {
84   Before,     // Before Zone and inside EnclosingFunction.
85   Inside,     // Inside Zone.
86   After,      // After Zone and inside EnclosingFunction.
87   OutsideFunc // Outside EnclosingFunction.
88 };
89 
90 // A RootStmt is a statement that's fully selected including all it's children
91 // and it's parent is unselected.
92 // Check if a node is a root statement.
93 bool isRootStmt(const Node *N) {
94   if (!N->ASTNode.get<Stmt>())
95     return false;
96   // Root statement cannot be partially selected.
97   if (N->Selected == SelectionTree::Partial)
98     return false;
99   // Only DeclStmt can be an unselected RootStmt since VarDecls claim the entire
100   // selection range in selectionTree.
101   if (N->Selected == SelectionTree::Unselected && !N->ASTNode.get<DeclStmt>())
102     return false;
103   return true;
104 }
105 
106 // Returns the (unselected) parent of all RootStmts given the commonAncestor.
107 // We only support extraction of RootStmts since it allows us to extract without
108 // having to change the selection range. Also, this means that any scope that
109 // begins in selection range, ends in selection range and any scope that begins
110 // outside the selection range, ends outside as well.
111 const Node *getParentOfRootStmts(const Node *CommonAnc) {
112   if (!CommonAnc)
113     return nullptr;
114   switch (CommonAnc->Selected) {
115   case SelectionTree::Selection::Unselected:
116     // Ensure all Children are RootStmts.
117     return llvm::all_of(CommonAnc->Children, isRootStmt) ? CommonAnc : nullptr;
118   case SelectionTree::Selection::Partial:
119     // Treat Partially selected VarDecl as completely selected since
120     // SelectionTree doesn't always select VarDecls correctly.
121     // FIXME: Remove this after D66872 is upstream)
122     if (!CommonAnc->ASTNode.get<VarDecl>())
123       return nullptr;
124     LLVM_FALLTHROUGH;
125   case SelectionTree::Selection::Complete:
126     // If the Common Ancestor is completely selected, then it's a root statement
127     // and its parent will be unselected.
128     const Node *Parent = CommonAnc->Parent;
129     // If parent is a DeclStmt, even though it's unselected, we consider it a
130     // root statement and return its parent. This is done because the VarDecls
131     // claim the entire selection range of the Declaration and DeclStmt is
132     // always unselected.
133     return Parent->ASTNode.get<DeclStmt>() ? Parent->Parent : Parent;
134   }
135   llvm_unreachable("Unhandled SelectionTree::Selection enum");
136 }
137 
138 // The ExtractionZone class forms a view of the code wrt Zone.
139 struct ExtractionZone {
140   // Parent of RootStatements being extracted.
141   const Node *Parent = nullptr;
142   // The half-open file range of the code being extracted.
143   SourceRange ZoneRange;
144   // The function inside which our zone resides.
145   const FunctionDecl *EnclosingFunction = nullptr;
146   // The half-open file range of the enclosing function.
147   SourceRange EnclosingFuncRange;
148   SourceLocation getInsertionPoint() const {
149     return EnclosingFuncRange.getBegin();
150   }
151   bool isRootStmt(const Stmt *S) const;
152   // The last root statement is important to decide where we need to insert a
153   // semicolon after the extraction.
154   const Node *getLastRootStmt() const { return Parent->Children.back(); }
155   void generateRootStmts();
156 
157 private:
158   llvm::DenseSet<const Stmt *> RootStmts;
159 };
160 
161 bool ExtractionZone::isRootStmt(const Stmt *S) const {
162   return RootStmts.find(S) != RootStmts.end();
163 }
164 
165 // Generate RootStmts set
166 void ExtractionZone::generateRootStmts() {
167   for (const Node *Child : Parent->Children)
168     RootStmts.insert(Child->ASTNode.get<Stmt>());
169 }
170 
171 // Finds the function in which the zone lies.
172 const FunctionDecl *findEnclosingFunction(const Node *CommonAnc) {
173   // Walk up the SelectionTree until we find a function Decl
174   for (const Node *CurNode = CommonAnc; CurNode; CurNode = CurNode->Parent) {
175     // Don't extract from lambdas
176     if (CurNode->ASTNode.get<LambdaExpr>())
177       return nullptr;
178     if (const FunctionDecl *Func = CurNode->ASTNode.get<FunctionDecl>()) {
179       // FIXME: Support extraction from methods.
180       if (isa<CXXMethodDecl>(Func))
181         return nullptr;
182       // FIXME: Support extraction from templated functions.
183       if (Func->isTemplated())
184         return nullptr;
185       return Func;
186     }
187   }
188   return nullptr;
189 }
190 
191 // Zone Range is the union of SourceRanges of all child Nodes in Parent since
192 // all child Nodes are RootStmts
193 llvm::Optional<SourceRange> findZoneRange(const Node *Parent,
194                                           const SourceManager &SM,
195                                           const LangOptions &LangOpts) {
196   SourceRange SR;
197   if (auto BeginFileRange = toHalfOpenFileRange(
198           SM, LangOpts, Parent->Children.front()->ASTNode.getSourceRange()))
199     SR.setBegin(BeginFileRange->getBegin());
200   else
201     return llvm::None;
202   if (auto EndFileRange = toHalfOpenFileRange(
203           SM, LangOpts, Parent->Children.back()->ASTNode.getSourceRange()))
204     SR.setEnd(EndFileRange->getEnd());
205   else
206     return llvm::None;
207   return SR;
208 }
209 
210 // Compute the range spanned by the enclosing function.
211 // FIXME: check if EnclosingFunction has any attributes as the AST doesn't
212 // always store the source range of the attributes and thus we end up extracting
213 // between the attributes and the EnclosingFunction.
214 llvm::Optional<SourceRange>
215 computeEnclosingFuncRange(const FunctionDecl *EnclosingFunction,
216                           const SourceManager &SM,
217                           const LangOptions &LangOpts) {
218   return toHalfOpenFileRange(SM, LangOpts, EnclosingFunction->getSourceRange());
219 }
220 
221 // FIXME: Check we're not extracting from the initializer/condition of a control
222 // flow structure.
223 // FIXME: Check that we don't extract the compound statement of the
224 // enclosingFunction.
225 llvm::Optional<ExtractionZone> findExtractionZone(const Node *CommonAnc,
226                                                   const SourceManager &SM,
227                                                   const LangOptions &LangOpts) {
228   ExtractionZone ExtZone;
229   ExtZone.Parent = getParentOfRootStmts(CommonAnc);
230   if (!ExtZone.Parent || ExtZone.Parent->Children.empty())
231     return llvm::None;
232   // Don't extract expressions.
233   // FIXME: We should extract expressions that are "statements" i.e. not
234   // subexpressions
235   if (ExtZone.Parent->Children.size() == 1 &&
236       ExtZone.getLastRootStmt()->ASTNode.get<Expr>())
237     return llvm::None;
238   ExtZone.EnclosingFunction = findEnclosingFunction(ExtZone.Parent);
239   if (!ExtZone.EnclosingFunction)
240     return llvm::None;
241   if (auto FuncRange =
242           computeEnclosingFuncRange(ExtZone.EnclosingFunction, SM, LangOpts))
243     ExtZone.EnclosingFuncRange = *FuncRange;
244   if (auto ZoneRange = findZoneRange(ExtZone.Parent, SM, LangOpts))
245     ExtZone.ZoneRange = *ZoneRange;
246   if (ExtZone.EnclosingFuncRange.isInvalid() || ExtZone.ZoneRange.isInvalid())
247     return llvm::None;
248   ExtZone.generateRootStmts();
249   return ExtZone;
250 }
251 
252 // Stores information about the extracted function and provides methods for
253 // rendering it.
254 struct NewFunction {
255   struct Parameter {
256     std::string Name;
257     QualType TypeInfo;
258     bool PassByReference;
259     unsigned OrderPriority; // Lower value parameters are preferred first.
260     std::string render(const DeclContext *Context) const;
261     bool operator<(const Parameter &Other) const {
262       return OrderPriority < Other.OrderPriority;
263     }
264   };
265   std::string Name = "extracted";
266   std::string ReturnType;
267   std::vector<Parameter> Parameters;
268   SourceRange BodyRange;
269   SourceLocation InsertionPoint;
270   const DeclContext *EnclosingFuncContext;
271   // Decides whether the extracted function body and the function call need a
272   // semicolon after extraction.
273   tooling::ExtractionSemicolonPolicy SemicolonPolicy;
274   NewFunction(tooling::ExtractionSemicolonPolicy SemicolonPolicy)
275       : SemicolonPolicy(SemicolonPolicy) {}
276   // Render the call for this function.
277   std::string renderCall() const;
278   // Render the definition for this function.
279   std::string renderDefinition(const SourceManager &SM) const;
280 
281 private:
282   std::string renderParametersForDefinition() const;
283   std::string renderParametersForCall() const;
284   // Generate the function body.
285   std::string getFuncBody(const SourceManager &SM) const;
286 };
287 
288 std::string NewFunction::renderParametersForDefinition() const {
289   std::string Result;
290   bool NeedCommaBefore = false;
291   for (const Parameter &P : Parameters) {
292     if (NeedCommaBefore)
293       Result += ", ";
294     NeedCommaBefore = true;
295     Result += P.render(EnclosingFuncContext);
296   }
297   return Result;
298 }
299 
300 std::string NewFunction::renderParametersForCall() const {
301   std::string Result;
302   bool NeedCommaBefore = false;
303   for (const Parameter &P : Parameters) {
304     if (NeedCommaBefore)
305       Result += ", ";
306     NeedCommaBefore = true;
307     Result += P.Name;
308   }
309   return Result;
310 }
311 
312 std::string NewFunction::renderCall() const {
313   return Name + "(" + renderParametersForCall() + ")" +
314          (SemicolonPolicy.isNeededInOriginalFunction() ? ";" : "");
315 }
316 
317 std::string NewFunction::renderDefinition(const SourceManager &SM) const {
318   return ReturnType + " " + Name + "(" + renderParametersForDefinition() + ")" +
319          " {\n" + getFuncBody(SM) + "\n}\n";
320 }
321 
322 std::string NewFunction::getFuncBody(const SourceManager &SM) const {
323   // FIXME: Generate tooling::Replacements instead of std::string to
324   // - hoist decls
325   // - add return statement
326   // - Add semicolon
327   return toSourceCode(SM, BodyRange).str() +
328          (SemicolonPolicy.isNeededInExtractedFunction() ? ";" : "");
329 }
330 
331 std::string NewFunction::Parameter::render(const DeclContext *Context) const {
332   return printType(TypeInfo, *Context) + (PassByReference ? " &" : " ") + Name;
333 }
334 
335 // Stores captured information about Extraction Zone.
336 struct CapturedZoneInfo {
337   struct DeclInformation {
338     const Decl *TheDecl;
339     ZoneRelative DeclaredIn;
340     // index of the declaration or first reference.
341     unsigned DeclIndex;
342     bool IsReferencedInZone = false;
343     bool IsReferencedInPostZone = false;
344     // FIXME: Capture mutation information
345     DeclInformation(const Decl *TheDecl, ZoneRelative DeclaredIn,
346                     unsigned DeclIndex)
347         : TheDecl(TheDecl), DeclaredIn(DeclaredIn), DeclIndex(DeclIndex){};
348     // Marks the occurence of a reference for this declaration
349     void markOccurence(ZoneRelative ReferenceLoc);
350   };
351   // Maps Decls to their DeclInfo
352   llvm::DenseMap<const Decl *, DeclInformation> DeclInfoMap;
353   // True if there is a return statement in zone.
354   bool HasReturnStmt = false;
355   // Control flow is broken if we are extracting a break/continue without a
356   // corresponding parent loop/switch
357   bool BrokenControlFlow = false;
358   // FIXME: capture TypeAliasDecl and UsingDirectiveDecl
359   // FIXME: Capture type information as well.
360   DeclInformation *createDeclInfo(const Decl *D, ZoneRelative RelativeLoc);
361   DeclInformation *getDeclInfoFor(const Decl *D);
362 };
363 
364 CapturedZoneInfo::DeclInformation *
365 CapturedZoneInfo::createDeclInfo(const Decl *D, ZoneRelative RelativeLoc) {
366   // The new Decl's index is the size of the map so far.
367   auto InsertionResult = DeclInfoMap.insert(
368       {D, DeclInformation(D, RelativeLoc, DeclInfoMap.size())});
369   // Return the newly created DeclInfo
370   return &InsertionResult.first->second;
371 }
372 
373 CapturedZoneInfo::DeclInformation *
374 CapturedZoneInfo::getDeclInfoFor(const Decl *D) {
375   // If the Decl doesn't exist, we
376   auto Iter = DeclInfoMap.find(D);
377   if (Iter == DeclInfoMap.end())
378     return nullptr;
379   return &Iter->second;
380 }
381 
382 void CapturedZoneInfo::DeclInformation::markOccurence(
383     ZoneRelative ReferenceLoc) {
384   switch (ReferenceLoc) {
385   case ZoneRelative::Inside:
386     IsReferencedInZone = true;
387     break;
388   case ZoneRelative::After:
389     IsReferencedInPostZone = true;
390     break;
391   default:
392     break;
393   }
394 }
395 
396 bool isLoop(const Stmt *S) {
397   return isa<ForStmt>(S) || isa<DoStmt>(S) || isa<WhileStmt>(S) ||
398          isa<CXXForRangeStmt>(S);
399 }
400 
401 // Captures information from Extraction Zone
402 CapturedZoneInfo captureZoneInfo(const ExtractionZone &ExtZone) {
403   // We use the ASTVisitor instead of using the selection tree since we need to
404   // find references in the PostZone as well.
405   // FIXME: Check which statements we don't allow to extract.
406   class ExtractionZoneVisitor
407       : public clang::RecursiveASTVisitor<ExtractionZoneVisitor> {
408   public:
409     ExtractionZoneVisitor(const ExtractionZone &ExtZone) : ExtZone(ExtZone) {
410       TraverseDecl(const_cast<FunctionDecl *>(ExtZone.EnclosingFunction));
411     }
412 
413     bool TraverseStmt(Stmt *S) {
414       if (!S)
415         return true;
416       bool IsRootStmt = ExtZone.isRootStmt(const_cast<const Stmt *>(S));
417       // If we are starting traversal of a RootStmt, we are somewhere inside
418       // ExtractionZone
419       if (IsRootStmt)
420         CurrentLocation = ZoneRelative::Inside;
421       addToLoopSwitchCounters(S, 1);
422       // Traverse using base class's TraverseStmt
423       RecursiveASTVisitor::TraverseStmt(S);
424       addToLoopSwitchCounters(S, -1);
425       // We set the current location as after since next stmt will either be a
426       // RootStmt (handled at the beginning) or after extractionZone
427       if (IsRootStmt)
428         CurrentLocation = ZoneRelative::After;
429       return true;
430     }
431 
432     // Add Increment to CurNumberOf{Loops,Switch} if statement is
433     // {Loop,Switch} and inside Extraction Zone.
434     void addToLoopSwitchCounters(Stmt *S, int Increment) {
435       if (CurrentLocation != ZoneRelative::Inside)
436         return;
437       if (isLoop(S))
438         CurNumberOfNestedLoops += Increment;
439       else if (isa<SwitchStmt>(S))
440         CurNumberOfSwitch += Increment;
441     }
442 
443     // Decrement CurNumberOf{NestedLoops,Switch} if statement is {Loop,Switch}
444     // and inside Extraction Zone.
445     void decrementLoopSwitchCounters(Stmt *S) {
446       if (CurrentLocation != ZoneRelative::Inside)
447         return;
448       if (isLoop(S))
449         CurNumberOfNestedLoops--;
450       else if (isa<SwitchStmt>(S))
451         CurNumberOfSwitch--;
452     }
453 
454     bool VisitDecl(Decl *D) {
455       Info.createDeclInfo(D, CurrentLocation);
456       return true;
457     }
458 
459     bool VisitDeclRefExpr(DeclRefExpr *DRE) {
460       // Find the corresponding Decl and mark it's occurence.
461       const Decl *D = DRE->getDecl();
462       auto *DeclInfo = Info.getDeclInfoFor(D);
463       // If no Decl was found, the Decl must be outside the enclosingFunc.
464       if (!DeclInfo)
465         DeclInfo = Info.createDeclInfo(D, ZoneRelative::OutsideFunc);
466       DeclInfo->markOccurence(CurrentLocation);
467       // FIXME: check if reference mutates the Decl being referred.
468       return true;
469     }
470 
471     bool VisitReturnStmt(ReturnStmt *Return) {
472       if (CurrentLocation == ZoneRelative::Inside)
473         Info.HasReturnStmt = true;
474       return true;
475     }
476 
477     bool VisitBreakStmt(BreakStmt *Break) {
478       // Control flow is broken if break statement is selected without any
479       // parent loop or switch statement.
480       if (CurrentLocation == ZoneRelative::Inside &&
481           !(CurNumberOfNestedLoops || CurNumberOfSwitch))
482         Info.BrokenControlFlow = true;
483       return true;
484     }
485 
486     bool VisitContinueStmt(ContinueStmt *Continue) {
487       // Control flow is broken if Continue statement is selected without any
488       // parent loop
489       if (CurrentLocation == ZoneRelative::Inside && !CurNumberOfNestedLoops)
490         Info.BrokenControlFlow = true;
491       return true;
492     }
493     CapturedZoneInfo Info;
494     const ExtractionZone &ExtZone;
495     ZoneRelative CurrentLocation = ZoneRelative::Before;
496     // Number of {loop,switch} statements that are currently in the traversal
497     // stack inside Extraction Zone. Used to check for broken control flow.
498     unsigned CurNumberOfNestedLoops = 0;
499     unsigned CurNumberOfSwitch = 0;
500   };
501   ExtractionZoneVisitor Visitor(ExtZone);
502   return std::move(Visitor.Info);
503 }
504 
505 // Adds parameters to ExtractedFunc.
506 // Returns true if able to find the parameters successfully and no hoisting
507 // needed.
508 // FIXME: Check if the declaration has a local/anonymous type
509 bool createParameters(NewFunction &ExtractedFunc,
510                       const CapturedZoneInfo &CapturedInfo) {
511   for (const auto &KeyVal : CapturedInfo.DeclInfoMap) {
512     const auto &DeclInfo = KeyVal.second;
513     // If a Decl was Declared in zone and referenced in post zone, it
514     // needs to be hoisted (we bail out in that case).
515     // FIXME: Support Decl Hoisting.
516     if (DeclInfo.DeclaredIn == ZoneRelative::Inside &&
517         DeclInfo.IsReferencedInPostZone)
518       return false;
519     if (!DeclInfo.IsReferencedInZone)
520       continue; // no need to pass as parameter, not referenced
521     if (DeclInfo.DeclaredIn == ZoneRelative::Inside ||
522         DeclInfo.DeclaredIn == ZoneRelative::OutsideFunc)
523       continue; // no need to pass as parameter, still accessible.
524     // Parameter specific checks.
525     const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(DeclInfo.TheDecl);
526     // Can't parameterise if the Decl isn't a ValueDecl or is a FunctionDecl
527     // (this includes the case of recursive call to EnclosingFunc in Zone).
528     if (!VD || isa<FunctionDecl>(DeclInfo.TheDecl))
529       return false;
530     // Parameter qualifiers are same as the Decl's qualifiers.
531     QualType TypeInfo = VD->getType().getNonReferenceType();
532     // FIXME: Need better qualifier checks: check mutated status for
533     // Decl(e.g. was it assigned, passed as nonconst argument, etc)
534     // FIXME: check if parameter will be a non l-value reference.
535     // FIXME: We don't want to always pass variables of types like int,
536     // pointers, etc by reference.
537     bool IsPassedByReference = true;
538     // We use the index of declaration as the ordering priority for parameters.
539     ExtractedFunc.Parameters.push_back(
540         {VD->getName(), TypeInfo, IsPassedByReference, DeclInfo.DeclIndex});
541   }
542   llvm::sort(ExtractedFunc.Parameters);
543   return true;
544 }
545 
546 // Clangd uses open ranges while ExtractionSemicolonPolicy (in Clang Tooling)
547 // uses closed ranges. Generates the semicolon policy for the extraction and
548 // extends the ZoneRange if necessary.
549 tooling::ExtractionSemicolonPolicy
550 getSemicolonPolicy(ExtractionZone &ExtZone, const SourceManager &SM,
551                    const LangOptions &LangOpts) {
552   // Get closed ZoneRange.
553   SourceRange FuncBodyRange = {ExtZone.ZoneRange.getBegin(),
554                                ExtZone.ZoneRange.getEnd().getLocWithOffset(-1)};
555   auto SemicolonPolicy = tooling::ExtractionSemicolonPolicy::compute(
556       ExtZone.getLastRootStmt()->ASTNode.get<Stmt>(), FuncBodyRange, SM,
557       LangOpts);
558   // Update ZoneRange.
559   ExtZone.ZoneRange.setEnd(FuncBodyRange.getEnd().getLocWithOffset(1));
560   return SemicolonPolicy;
561 }
562 
563 // Generate return type for ExtractedFunc. Return false if unable to do so.
564 bool generateReturnProperties(NewFunction &ExtractedFunc,
565                               const CapturedZoneInfo &CapturedInfo) {
566 
567   // FIXME: Use Existing Return statements (if present)
568   // FIXME: Generate new return statement if needed.
569   if (CapturedInfo.HasReturnStmt)
570     return false;
571   ExtractedFunc.ReturnType = "void";
572   return true;
573 }
574 
575 // FIXME: add support for adding other function return types besides void.
576 // FIXME: assign the value returned by non void extracted function.
577 llvm::Expected<NewFunction> getExtractedFunction(ExtractionZone &ExtZone,
578                                                  const SourceManager &SM,
579                                                  const LangOptions &LangOpts) {
580   CapturedZoneInfo CapturedInfo = captureZoneInfo(ExtZone);
581   // Bail out if any break of continue exists
582   if (CapturedInfo.BrokenControlFlow)
583     return llvm::createStringError(llvm::inconvertibleErrorCode(),
584                                    +"Cannot extract break/continue without "
585                                     "corresponding loop/switch statement.");
586   NewFunction ExtractedFunc(getSemicolonPolicy(ExtZone, SM, LangOpts));
587   ExtractedFunc.BodyRange = ExtZone.ZoneRange;
588   ExtractedFunc.InsertionPoint = ExtZone.getInsertionPoint();
589   ExtractedFunc.EnclosingFuncContext =
590       ExtZone.EnclosingFunction->getDeclContext();
591   if (!createParameters(ExtractedFunc, CapturedInfo) ||
592       !generateReturnProperties(ExtractedFunc, CapturedInfo))
593     return llvm::createStringError(llvm::inconvertibleErrorCode(),
594                                    +"Too complex to extract.");
595   return ExtractedFunc;
596 }
597 
598 class ExtractFunction : public Tweak {
599 public:
600   const char *id() const override final;
601   bool prepare(const Selection &Inputs) override;
602   Expected<Effect> apply(const Selection &Inputs) override;
603   std::string title() const override { return "Extract to function"; }
604   Intent intent() const override { return Refactor; }
605 
606 private:
607   ExtractionZone ExtZone;
608 };
609 
610 REGISTER_TWEAK(ExtractFunction)
611 tooling::Replacement replaceWithFuncCall(const NewFunction &ExtractedFunc,
612                                          const SourceManager &SM,
613                                          const LangOptions &LangOpts) {
614   std::string FuncCall = ExtractedFunc.renderCall();
615   return tooling::Replacement(
616       SM, CharSourceRange(ExtractedFunc.BodyRange, false), FuncCall, LangOpts);
617 }
618 
619 tooling::Replacement createFunctionDefinition(const NewFunction &ExtractedFunc,
620                                               const SourceManager &SM) {
621   std::string FunctionDef = ExtractedFunc.renderDefinition(SM);
622   return tooling::Replacement(SM, ExtractedFunc.InsertionPoint, 0, FunctionDef);
623 }
624 
625 bool ExtractFunction::prepare(const Selection &Inputs) {
626   const Node *CommonAnc = Inputs.ASTSelection.commonAncestor();
627   const SourceManager &SM = Inputs.AST.getSourceManager();
628   const LangOptions &LangOpts = Inputs.AST.getASTContext().getLangOpts();
629   if (auto MaybeExtZone = findExtractionZone(CommonAnc, SM, LangOpts)) {
630     ExtZone = std::move(*MaybeExtZone);
631     return true;
632   }
633   return false;
634 }
635 
636 Expected<Tweak::Effect> ExtractFunction::apply(const Selection &Inputs) {
637   const SourceManager &SM = Inputs.AST.getSourceManager();
638   const LangOptions &LangOpts = Inputs.AST.getASTContext().getLangOpts();
639   auto ExtractedFunc = getExtractedFunction(ExtZone, SM, LangOpts);
640   // FIXME: Add more types of errors.
641   if (!ExtractedFunc)
642     return ExtractedFunc.takeError();
643   tooling::Replacements Result;
644   if (auto Err = Result.add(createFunctionDefinition(*ExtractedFunc, SM)))
645     return std::move(Err);
646   if (auto Err = Result.add(replaceWithFuncCall(*ExtractedFunc, SM, LangOpts)))
647     return std::move(Err);
648   return Effect::mainFileEdit(SM, std::move(Result));
649 }
650 
651 } // namespace
652 } // namespace clangd
653 } // namespace clang
654