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