xref: /llvm-project/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp (revision c9974ae4a0601a9e9f5842114ecd899ab9142786)
1 //===--- ExtractVariable.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 #include "AST.h"
9 #include "ParsedAST.h"
10 #include "Protocol.h"
11 #include "Selection.h"
12 #include "SourceCode.h"
13 #include "refactor/Tweak.h"
14 #include "clang/AST/ASTContext.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/Expr.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/AST/LambdaCapture.h"
20 #include "clang/AST/OperationKinds.h"
21 #include "clang/AST/RecursiveASTVisitor.h"
22 #include "clang/AST/Stmt.h"
23 #include "clang/AST/StmtCXX.h"
24 #include "clang/Basic/LangOptions.h"
25 #include "clang/Basic/SourceLocation.h"
26 #include "clang/Basic/SourceManager.h"
27 #include "clang/Tooling/Core/Replacement.h"
28 #include "llvm/ADT/SmallVector.h"
29 #include "llvm/ADT/StringRef.h"
30 #include "llvm/Support/Casting.h"
31 #include "llvm/Support/Error.h"
32 #include "llvm/Support/raw_ostream.h"
33 
34 namespace clang {
35 namespace clangd {
36 namespace {
37 // information regarding the Expr that is being extracted
38 class ExtractionContext {
39 public:
40   ExtractionContext(const SelectionTree::Node *Node, const SourceManager &SM,
41                     const ASTContext &Ctx);
42   const clang::Expr *getExpr() const { return Expr; }
43   const SelectionTree::Node *getExprNode() const { return ExprNode; }
44   bool isExtractable() const { return Extractable; }
45   // The half-open range for the expression to be extracted.
46   SourceRange getExtractionChars() const;
47   // Generate Replacement for replacing selected expression with given VarName
48   tooling::Replacement replaceWithVar(SourceRange Chars,
49                                       llvm::StringRef VarName) const;
50   // Generate Replacement for declaring the selected Expr as a new variable
51   tooling::Replacement insertDeclaration(llvm::StringRef VarName,
52                                          SourceRange InitChars) const;
53 
54 private:
55   bool Extractable = false;
56   const clang::Expr *Expr;
57   QualType VarType;
58   const SelectionTree::Node *ExprNode;
59   // Stmt before which we will extract
60   const clang::Stmt *InsertionPoint = nullptr;
61   const SourceManager &SM;
62   const ASTContext &Ctx;
63   // Decls referenced in the Expr
64   std::vector<clang::Decl *> ReferencedDecls;
65   // returns true if the Expr doesn't reference any variable declared in scope
66   bool exprIsValidOutside(const clang::Stmt *Scope) const;
67   // computes the Stmt before which we will extract out Expr
68   const clang::Stmt *computeInsertionPoint() const;
69 };
70 
71 // Returns all the Decls referenced inside the given Expr
72 static std::vector<clang::Decl *>
73 computeReferencedDecls(const clang::Expr *Expr) {
74   // RAV subclass to find all DeclRefs in a given Stmt
75   class FindDeclRefsVisitor
76       : public clang::RecursiveASTVisitor<FindDeclRefsVisitor> {
77   public:
78     std::vector<Decl *> ReferencedDecls;
79     bool VisitDeclRefExpr(DeclRefExpr *DeclRef) { // NOLINT
80       // Stop the call operator of lambdas from being marked as a referenced
81       // DeclRefExpr in immediately invoked lambdas.
82       if (const auto *const Method =
83               llvm::dyn_cast<CXXMethodDecl>(DeclRef->getDecl());
84           Method != nullptr && Method->getParent()->isLambda()) {
85         return true;
86       }
87       ReferencedDecls.push_back(DeclRef->getDecl());
88       return true;
89     }
90 
91     // Local variables declared inside of the selected lambda cannot go out of
92     // scope. The DeclRefExprs that are important are the variables captured,
93     // the DeclRefExprs inside the initializers of init-capture variables,
94     // variables mentioned in trailing return types, constraints and explicit
95     // defaulted template parameters.
96     bool TraverseLambdaExpr(LambdaExpr *LExpr) {
97       for (const auto &[Capture, Initializer] :
98            llvm::zip(LExpr->captures(), LExpr->capture_inits())) {
99         TraverseLambdaCapture(LExpr, &Capture, Initializer);
100       }
101 
102       if (clang::Expr *const RequiresClause =
103               LExpr->getTrailingRequiresClause()) {
104         TraverseStmt(RequiresClause);
105       }
106 
107       for (auto *const TemplateParam : LExpr->getExplicitTemplateParameters())
108         TraverseDecl(TemplateParam);
109 
110       if (auto *const CallOperator = LExpr->getCallOperator()) {
111         TraverseType(CallOperator->getDeclaredReturnType());
112 
113         for (auto *const Param : CallOperator->parameters()) {
114           TraverseParmVarDecl(Param);
115         }
116 
117         for (auto *const Attr : CallOperator->attrs()) {
118           TraverseAttr(Attr);
119         }
120       }
121 
122       return true;
123     }
124   };
125 
126   FindDeclRefsVisitor Visitor;
127   Visitor.TraverseStmt(const_cast<Stmt *>(cast<Stmt>(Expr)));
128   return Visitor.ReferencedDecls;
129 }
130 
131 static QualType computeVariableType(const Expr *Expr, const ASTContext &Ctx) {
132   if (Ctx.getLangOpts().CPlusPlus11)
133     return Ctx.getAutoDeductType();
134 
135   if (Expr->hasPlaceholderType(BuiltinType::PseudoObject)) {
136     if (const auto *PR = dyn_cast<ObjCPropertyRefExpr>(Expr)) {
137       if (PR->isMessagingSetter()) {
138         // Don't support extracting a compound reference like `self.prop += 1`
139         // since the meaning changes after extraction since we'll no longer call
140         // the setter. Non compound access like `self.prop = 1` is invalid since
141         // it returns nil (setter method must have a void return type).
142         return QualType();
143       } else if (PR->isMessagingGetter()) {
144         if (PR->isExplicitProperty())
145           return PR->getExplicitProperty()->getType();
146         else
147           return PR->getImplicitPropertyGetter()->getReturnType();
148       }
149     } else {
150       return QualType();
151     }
152   }
153   return Expr->getType();
154 }
155 
156 ExtractionContext::ExtractionContext(const SelectionTree::Node *Node,
157                                      const SourceManager &SM,
158                                      const ASTContext &Ctx)
159     : ExprNode(Node), SM(SM), Ctx(Ctx) {
160   Expr = Node->ASTNode.get<clang::Expr>();
161   ReferencedDecls = computeReferencedDecls(Expr);
162   InsertionPoint = computeInsertionPoint();
163   if (InsertionPoint)
164     Extractable = true;
165   VarType = computeVariableType(Expr, Ctx);
166   if (VarType.isNull())
167     Extractable = false;
168   else
169     // Strip the outer nullability since it's not common for local variables.
170     AttributedType::stripOuterNullability(VarType);
171 }
172 
173 // checks whether extracting before InsertionPoint will take a
174 // variable reference out of scope
175 bool ExtractionContext::exprIsValidOutside(const clang::Stmt *Scope) const {
176   SourceLocation ScopeBegin = Scope->getBeginLoc();
177   SourceLocation ScopeEnd = Scope->getEndLoc();
178   for (const Decl *ReferencedDecl : ReferencedDecls) {
179     if (ReferencedDecl->getBeginLoc().isValid() &&
180         SM.isPointWithin(ReferencedDecl->getBeginLoc(), ScopeBegin, ScopeEnd) &&
181         SM.isPointWithin(ReferencedDecl->getEndLoc(), ScopeBegin, ScopeEnd))
182       return false;
183   }
184   return true;
185 }
186 
187 // Return the Stmt before which we need to insert the extraction.
188 // To find the Stmt, we go up the AST Tree and if the Parent of the current
189 // Stmt is a CompoundStmt, we can extract inside this CompoundStmt just before
190 // the current Stmt. We ALWAYS insert before a Stmt whose parent is a
191 // CompoundStmt
192 //
193 // FIXME: Extraction from label, switch and case statements
194 // FIXME: Doens't work for FoldExpr
195 // FIXME: Ensure extraction from loops doesn't change semantics.
196 const clang::Stmt *ExtractionContext::computeInsertionPoint() const {
197   // returns true if we can extract before InsertionPoint
198   auto CanExtractOutside =
199       [](const SelectionTree::Node *InsertionPoint) -> bool {
200     if (const clang::Stmt *Stmt = InsertionPoint->ASTNode.get<clang::Stmt>()) {
201       if (isa<clang::Expr>(Stmt)) {
202         // Do not allow extraction from the initializer of a defaulted parameter
203         // to a local variable (e.g. a function-local lambda).
204         if (InsertionPoint->Parent->ASTNode.get<ParmVarDecl>() != nullptr) {
205           return false;
206         }
207 
208         return true;
209       }
210 
211       // We don't yet allow extraction from switch/case stmt as we would need to
212       // jump over the switch stmt even if there is a CompoundStmt inside the
213       // switch. And there are other Stmts which we don't care about (e.g.
214       // continue and break) as there can never be anything to extract from
215       // them.
216       return isa<AttributedStmt>(Stmt) || isa<CompoundStmt>(Stmt) ||
217              isa<CXXForRangeStmt>(Stmt) || isa<DeclStmt>(Stmt) ||
218              isa<DoStmt>(Stmt) || isa<ForStmt>(Stmt) || isa<IfStmt>(Stmt) ||
219              isa<ReturnStmt>(Stmt) || isa<WhileStmt>(Stmt);
220     }
221     if (InsertionPoint->ASTNode.get<VarDecl>())
222       return true;
223     return false;
224   };
225   for (const SelectionTree::Node *CurNode = getExprNode();
226        CurNode->Parent && CanExtractOutside(CurNode);
227        CurNode = CurNode->Parent) {
228     const clang::Stmt *CurInsertionPoint = CurNode->ASTNode.get<Stmt>();
229     // give up if extraction will take a variable out of scope
230     if (CurInsertionPoint && !exprIsValidOutside(CurInsertionPoint))
231       break;
232     if (const clang::Stmt *CurParent = CurNode->Parent->ASTNode.get<Stmt>()) {
233       if (isa<CompoundStmt>(CurParent)) {
234         // Ensure we don't write inside a macro.
235         if (CurParent->getBeginLoc().isMacroID())
236           continue;
237         return CurInsertionPoint;
238       }
239     }
240   }
241   return nullptr;
242 }
243 
244 // returns the replacement for substituting the extraction with VarName
245 tooling::Replacement
246 ExtractionContext::replaceWithVar(SourceRange Chars,
247                                   llvm::StringRef VarName) const {
248   unsigned ExtractionLength =
249       SM.getFileOffset(Chars.getEnd()) - SM.getFileOffset(Chars.getBegin());
250   return tooling::Replacement(SM, Chars.getBegin(), ExtractionLength, VarName);
251 }
252 // returns the Replacement for declaring a new variable storing the extraction
253 tooling::Replacement
254 ExtractionContext::insertDeclaration(llvm::StringRef VarName,
255                                      SourceRange InitializerChars) const {
256   llvm::StringRef ExtractionCode = toSourceCode(SM, InitializerChars);
257   const SourceLocation InsertionLoc =
258       toHalfOpenFileRange(SM, Ctx.getLangOpts(),
259                           InsertionPoint->getSourceRange())
260           ->getBegin();
261   std::string ExtractedVarDecl =
262       printType(VarType, ExprNode->getDeclContext(), VarName) + " = " +
263       ExtractionCode.str() + "; ";
264   return tooling::Replacement(SM, InsertionLoc, 0, ExtractedVarDecl);
265 }
266 
267 // Helpers for handling "binary subexpressions" like a + [[b + c]] + d.
268 //
269 // These are special, because the formal AST doesn't match what users expect:
270 // - the AST is ((a + b) + c) + d, so the ancestor expression is `a + b + c`.
271 // - but extracting `b + c` is reasonable, as + is (mathematically) associative.
272 //
273 // So we try to support these cases with some restrictions:
274 //  - the operator must be associative
275 //  - no mixing of operators is allowed
276 //  - we don't look inside macro expansions in the subexpressions
277 //  - we only adjust the extracted range, so references in the unselected parts
278 //    of the AST expression (e.g. `a`) are still considered referenced for
279 //    the purposes of calculating the insertion point.
280 //    FIXME: it would be nice to exclude these references, by micromanaging
281 //    the computeReferencedDecls() calls around the binary operator tree.
282 
283 // Information extracted about a binary operator encounted in a SelectionTree.
284 // It can represent either an overloaded or built-in operator.
285 struct ParsedBinaryOperator {
286   BinaryOperatorKind Kind;
287   SourceLocation ExprLoc;
288   llvm::SmallVector<const SelectionTree::Node *> SelectedOperands;
289 
290   // If N is a binary operator, populate this and return true.
291   bool parse(const SelectionTree::Node &N) {
292     SelectedOperands.clear();
293 
294     if (const BinaryOperator *Op =
295             llvm::dyn_cast_or_null<BinaryOperator>(N.ASTNode.get<Expr>())) {
296       Kind = Op->getOpcode();
297       ExprLoc = Op->getExprLoc();
298       SelectedOperands = N.Children;
299       return true;
300     }
301     if (const CXXOperatorCallExpr *Op =
302             llvm::dyn_cast_or_null<CXXOperatorCallExpr>(
303                 N.ASTNode.get<Expr>())) {
304       if (!Op->isInfixBinaryOp())
305         return false;
306 
307       Kind = BinaryOperator::getOverloadedOpcode(Op->getOperator());
308       ExprLoc = Op->getExprLoc();
309       // Not all children are args, there's also the callee (operator).
310       for (const auto *Child : N.Children) {
311         const Expr *E = Child->ASTNode.get<Expr>();
312         assert(E && "callee and args should be Exprs!");
313         if (E == Op->getArg(0) || E == Op->getArg(1))
314           SelectedOperands.push_back(Child);
315       }
316       return true;
317     }
318     return false;
319   }
320 
321   bool associative() const {
322     // Must also be left-associative, or update getBinaryOperatorRange()!
323     switch (Kind) {
324     case BO_Add:
325     case BO_Mul:
326     case BO_And:
327     case BO_Or:
328     case BO_Xor:
329     case BO_LAnd:
330     case BO_LOr:
331       return true;
332     default:
333       return false;
334     }
335   }
336 
337   bool crossesMacroBoundary(const SourceManager &SM) {
338     FileID F = SM.getFileID(ExprLoc);
339     for (const SelectionTree::Node *Child : SelectedOperands)
340       if (SM.getFileID(Child->ASTNode.get<Expr>()->getExprLoc()) != F)
341         return true;
342     return false;
343   }
344 };
345 
346 // If have an associative operator at the top level, then we must find
347 // the start point (rightmost in LHS) and end point (leftmost in RHS).
348 // We can only descend into subtrees where the operator matches.
349 //
350 // e.g. for a + [[b + c]] + d
351 //        +
352 //       / \
353 //  N-> +   d
354 //     / \
355 //    +   c <- End
356 //   / \
357 //  a   b <- Start
358 const SourceRange getBinaryOperatorRange(const SelectionTree::Node &N,
359                                          const SourceManager &SM,
360                                          const LangOptions &LangOpts) {
361   // If N is not a suitable binary operator, bail out.
362   ParsedBinaryOperator Op;
363   if (!Op.parse(N.ignoreImplicit()) || !Op.associative() ||
364       Op.crossesMacroBoundary(SM) || Op.SelectedOperands.size() != 2)
365     return SourceRange();
366   BinaryOperatorKind OuterOp = Op.Kind;
367 
368   // Because the tree we're interested in contains only one operator type, and
369   // all eligible operators are left-associative, the shape of the tree is
370   // very restricted: it's a linked list along the left edges.
371   // This simplifies our implementation.
372   const SelectionTree::Node *Start = Op.SelectedOperands.front(); // LHS
373   const SelectionTree::Node *End = Op.SelectedOperands.back();    // RHS
374   // End is already correct: it can't be an OuterOp (as it's left-associative).
375   // Start needs to be pushed down int the subtree to the right spot.
376   while (Op.parse(Start->ignoreImplicit()) && Op.Kind == OuterOp &&
377          !Op.crossesMacroBoundary(SM)) {
378     assert(!Op.SelectedOperands.empty() && "got only operator on one side!");
379     if (Op.SelectedOperands.size() == 1) { // Only Op.RHS selected
380       Start = Op.SelectedOperands.back();
381       break;
382     }
383     // Op.LHS is (at least partially) selected, so descend into it.
384     Start = Op.SelectedOperands.front();
385   }
386 
387   return SourceRange(
388       toHalfOpenFileRange(SM, LangOpts, Start->ASTNode.getSourceRange())
389           ->getBegin(),
390       toHalfOpenFileRange(SM, LangOpts, End->ASTNode.getSourceRange())
391           ->getEnd());
392 }
393 
394 SourceRange ExtractionContext::getExtractionChars() const {
395   // Special case: we're extracting an associative binary subexpression.
396   SourceRange BinaryOperatorRange =
397       getBinaryOperatorRange(*ExprNode, SM, Ctx.getLangOpts());
398   if (BinaryOperatorRange.isValid())
399     return BinaryOperatorRange;
400 
401   // Usual case: we're extracting the whole expression.
402   return *toHalfOpenFileRange(SM, Ctx.getLangOpts(), Expr->getSourceRange());
403 }
404 
405 // Find the CallExpr whose callee is the (possibly wrapped) DeclRef
406 const SelectionTree::Node *getCallExpr(const SelectionTree::Node *DeclRef) {
407   const SelectionTree::Node &MaybeCallee = DeclRef->outerImplicit();
408   const SelectionTree::Node *MaybeCall = MaybeCallee.Parent;
409   if (!MaybeCall)
410     return nullptr;
411   const CallExpr *CE =
412       llvm::dyn_cast_or_null<CallExpr>(MaybeCall->ASTNode.get<Expr>());
413   if (!CE)
414     return nullptr;
415   if (CE->getCallee() != MaybeCallee.ASTNode.get<Expr>())
416     return nullptr;
417   return MaybeCall;
418 }
419 
420 // Returns true if Inner (which is a direct child of Outer) is appearing as
421 // a statement rather than an expression whose value can be used.
422 bool childExprIsStmt(const Stmt *Outer, const Expr *Inner) {
423   if (!Outer || !Inner)
424     return false;
425   // Exclude the most common places where an expr can appear but be unused.
426   if (llvm::isa<CompoundStmt>(Outer))
427     return true;
428   if (llvm::isa<SwitchCase>(Outer))
429     return true;
430   // Control flow statements use condition etc, but not the body.
431   if (const auto *WS = llvm::dyn_cast<WhileStmt>(Outer))
432     return Inner == WS->getBody();
433   if (const auto *DS = llvm::dyn_cast<DoStmt>(Outer))
434     return Inner == DS->getBody();
435   if (const auto *FS = llvm::dyn_cast<ForStmt>(Outer))
436     return Inner == FS->getBody();
437   if (const auto *FS = llvm::dyn_cast<CXXForRangeStmt>(Outer))
438     return Inner == FS->getBody();
439   if (const auto *IS = llvm::dyn_cast<IfStmt>(Outer))
440     return Inner == IS->getThen() || Inner == IS->getElse();
441   // Assume all other cases may be actual expressions.
442   // This includes the important case of subexpressions (where Outer is Expr).
443   return false;
444 }
445 
446 // check if N can and should be extracted (e.g. is not void-typed).
447 bool eligibleForExtraction(const SelectionTree::Node *N) {
448   const Expr *E = N->ASTNode.get<Expr>();
449   if (!E)
450     return false;
451 
452   // Void expressions can't be assigned to variables.
453   const Type *ExprType = E->getType().getTypePtrOrNull();
454   if (!ExprType || ExprType->isVoidType())
455     return false;
456 
457   // A plain reference to a name (e.g. variable) isn't  worth extracting.
458   // FIXME: really? What if it's e.g. `std::is_same<void, void>::value`?
459   if (llvm::isa<DeclRefExpr>(E))
460     return false;
461 
462   // Similarly disallow extraction for member exprs with an implicit `this`.
463   if (const auto *ME = dyn_cast<MemberExpr>(E))
464     if (const auto *TE = dyn_cast<CXXThisExpr>(ME->getBase()->IgnoreImpCasts()))
465       if (TE->isImplicit())
466         return false;
467 
468   // Extracting Exprs like a = 1 gives placeholder = a = 1 which isn't useful.
469   // FIXME: we could still hoist the assignment, and leave the variable there?
470   ParsedBinaryOperator BinOp;
471   bool IsBinOp = BinOp.parse(*N);
472   if (IsBinOp && BinaryOperator::isAssignmentOp(BinOp.Kind))
473     return false;
474 
475   const SelectionTree::Node &OuterImplicit = N->outerImplicit();
476   const auto *Parent = OuterImplicit.Parent;
477   if (!Parent)
478     return false;
479   // We don't want to extract expressions used as statements, that would leave
480   // a `placeholder;` around that has no effect.
481   // Unfortunately because the AST doesn't have ExprStmt, we have to check in
482   // this roundabout way.
483   if (childExprIsStmt(Parent->ASTNode.get<Stmt>(),
484                       OuterImplicit.ASTNode.get<Expr>()))
485     return false;
486 
487   std::function<bool(const SelectionTree::Node *)> IsFullySelected =
488       [&](const SelectionTree::Node *N) {
489         if (N->ASTNode.getSourceRange().isValid() &&
490             N->Selected != SelectionTree::Complete)
491           return false;
492         for (const auto *Child : N->Children) {
493           if (!IsFullySelected(Child))
494             return false;
495         }
496         return true;
497       };
498   auto ExprIsFullySelectedTargetNode = [&](const Expr *E) {
499     if (E != OuterImplicit.ASTNode.get<Expr>())
500       return false;
501 
502     // The above condition is the only relevant one except for binary operators.
503     // Without the following code, we would fail to offer extraction for e.g.:
504     //   int x = 1 + 2 + [[3 + 4 + 5]];
505     // See the documentation of ParsedBinaryOperator for further details.
506     if (!IsBinOp)
507       return true;
508     return IsFullySelected(N);
509   };
510 
511   // Disable extraction of full RHS on assignment operations, e.g:
512   // x = [[RHS_EXPR]];
513   // This would just result in duplicating the code.
514   if (const auto *BO = Parent->ASTNode.get<BinaryOperator>()) {
515     if (BO->isAssignmentOp() && ExprIsFullySelectedTargetNode(BO->getRHS()))
516       return false;
517   }
518 
519   // The same logic as for assignments applies to initializations.
520   // However, we do allow extracting the RHS of an init capture, as it is
521   // a valid use case to move non-trivial expressions out of the capture clause.
522   // FIXME: In that case, the extracted variable should be captured directly,
523   //        rather than an explicit copy.
524   if (const auto *Decl = Parent->ASTNode.get<VarDecl>()) {
525     if (!Decl->isInitCapture() &&
526         ExprIsFullySelectedTargetNode(Decl->getInit())) {
527       return false;
528     }
529   }
530 
531   return true;
532 }
533 
534 // Find the Expr node that we're going to extract.
535 // We don't want to trigger for assignment expressions and variable/field
536 // DeclRefs. For function/member function, we want to extract the entire
537 // function call.
538 const SelectionTree::Node *computeExtractedExpr(const SelectionTree::Node *N) {
539   if (!N)
540     return nullptr;
541   const SelectionTree::Node *TargetNode = N;
542   const clang::Expr *SelectedExpr = N->ASTNode.get<clang::Expr>();
543   if (!SelectedExpr)
544     return nullptr;
545   // For function and member function DeclRefs, extract the whole call.
546   if (llvm::isa<DeclRefExpr>(SelectedExpr) ||
547       llvm::isa<MemberExpr>(SelectedExpr))
548     if (const SelectionTree::Node *Call = getCallExpr(N))
549       TargetNode = Call;
550   // Extracting Exprs like a = 1 gives placeholder = a = 1 which isn't useful.
551   if (const BinaryOperator *BinOpExpr =
552           dyn_cast_or_null<BinaryOperator>(SelectedExpr)) {
553     if (BinOpExpr->getOpcode() == BinaryOperatorKind::BO_Assign)
554       return nullptr;
555   }
556   if (!TargetNode || !eligibleForExtraction(TargetNode))
557     return nullptr;
558   return TargetNode;
559 }
560 
561 /// Extracts an expression to the variable placeholder
562 /// Before:
563 /// int x = 5 + 4 * 3;
564 ///         ^^^^^
565 /// After:
566 /// auto placeholder = 5 + 4;
567 /// int x = placeholder * 3;
568 class ExtractVariable : public Tweak {
569 public:
570   const char *id() const final;
571   bool prepare(const Selection &Inputs) override;
572   Expected<Effect> apply(const Selection &Inputs) override;
573   std::string title() const override {
574     return "Extract subexpression to variable";
575   }
576   llvm::StringLiteral kind() const override {
577     return CodeAction::REFACTOR_KIND;
578   }
579 
580 private:
581   // the expression to extract
582   std::unique_ptr<ExtractionContext> Target;
583 };
584 REGISTER_TWEAK(ExtractVariable)
585 bool ExtractVariable::prepare(const Selection &Inputs) {
586   // we don't trigger on empty selections for now
587   if (Inputs.SelectionBegin == Inputs.SelectionEnd)
588     return false;
589   const ASTContext &Ctx = Inputs.AST->getASTContext();
590   const SourceManager &SM = Inputs.AST->getSourceManager();
591   if (const SelectionTree::Node *N =
592           computeExtractedExpr(Inputs.ASTSelection.commonAncestor()))
593     Target = std::make_unique<ExtractionContext>(N, SM, Ctx);
594   return Target && Target->isExtractable();
595 }
596 
597 Expected<Tweak::Effect> ExtractVariable::apply(const Selection &Inputs) {
598   tooling::Replacements Result;
599   // FIXME: get variable name from user or suggest based on type
600   std::string VarName = "placeholder";
601   SourceRange Range = Target->getExtractionChars();
602   // insert new variable declaration
603   if (auto Err = Result.add(Target->insertDeclaration(VarName, Range)))
604     return std::move(Err);
605   // replace expression with variable name
606   if (auto Err = Result.add(Target->replaceWithVar(Range, VarName)))
607     return std::move(Err);
608   return Effect::mainFileEdit(Inputs.AST->getSourceManager(),
609                               std::move(Result));
610 }
611 
612 } // namespace
613 } // namespace clangd
614 } // namespace clang
615