brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.1 KiB · c74250c Raw
634 lines · cpp
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-exception6//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 34namespace clang {35namespace clangd {36namespace {37// information regarding the Expr that is being extracted38class ExtractionContext {39public: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 VarName48  tooling::Replacement replaceWithVar(SourceRange Chars,49                                      llvm::StringRef VarName) const;50  // Generate Replacement for declaring the selected Expr as a new variable51  tooling::Replacement insertDeclaration(llvm::StringRef VarName,52                                         SourceRange InitChars,53                                         bool AddSemicolon) const;54 55private:56  bool Extractable = false;57  const clang::Expr *Expr;58  QualType VarType;59  const SelectionTree::Node *ExprNode;60  // Stmt before which we will extract61  const clang::Stmt *InsertionPoint = nullptr;62  const SourceManager &SM;63  const ASTContext &Ctx;64  // Decls referenced in the Expr65  std::vector<clang::Decl *> ReferencedDecls;66  // returns true if the Expr doesn't reference any variable declared in scope67  bool exprIsValidOutside(const clang::Stmt *Scope) const;68  // computes the Stmt before which we will extract out Expr69  const clang::Stmt *computeInsertionPoint() const;70};71 72// Returns all the Decls referenced inside the given Expr73static std::vector<clang::Decl *>74computeReferencedDecls(const clang::Expr *Expr) {75  // RAV subclass to find all DeclRefs in a given Stmt76  class FindDeclRefsVisitor77      : public clang::RecursiveASTVisitor<FindDeclRefsVisitor> {78  public:79    std::vector<Decl *> ReferencedDecls;80    bool VisitDeclRefExpr(DeclRefExpr *DeclRef) { // NOLINT81      // Stop the call operator of lambdas from being marked as a referenced82      // 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 of93    // 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 explicit96    // 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 (const clang::Expr *RequiresClause =104              LExpr->getTrailingRequiresClause().ConstraintExpr) {105        TraverseStmt(const_cast<clang::Expr *>(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 132static 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 call141        // the setter. Non compound access like `self.prop = 1` is invalid since142        // 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        else148          return PR->getImplicitPropertyGetter()->getReturnType();149      }150    } else {151      return QualType();152    }153  }154  return Expr->getType();155}156 157ExtractionContext::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  else170    // 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 a175// variable reference out of scope176bool 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 current190// Stmt is a CompoundStmt, we can extract inside this CompoundStmt just before191// the current Stmt. We ALWAYS insert before a Stmt whose parent is a192// CompoundStmt193//194// FIXME: Extraction from label, switch and case statements195// FIXME: Doens't work for FoldExpr196// FIXME: Ensure extraction from loops doesn't change semantics.197const clang::Stmt *ExtractionContext::computeInsertionPoint() const {198  // returns true if we can extract before InsertionPoint199  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 parameter204        // 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 to213      // jump over the switch stmt even if there is a CompoundStmt inside the214      // 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 from216      // 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 scope231    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 VarName246tooling::Replacement247ExtractionContext::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 extraction254tooling::Replacement255ExtractionContext::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 associative279//  - no mixing of operators is allowed280//  - we don't look inside macro expansions in the subexpressions281//  - we only adjust the extracted range, so references in the unselected parts282//    of the AST expression (e.g. `a`) are still considered referenced for283//    the purposes of calculating the insertion point.284//    FIXME: it would be nice to exclude these references, by micromanaging285//    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.289struct 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 find351// 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]] + d355//        +356//       / \357//  N-> +   d358//     / \359//    +   c <- End360//   / \361//  a   b <- Start362SourceRange 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, and373  // all eligible operators are left-associative, the shape of the tree is374  // very restricted: it's a linked list along the left edges.375  // This simplifies our implementation.376  const SelectionTree::Node *Start = Op.SelectedOperands.front(); // LHS377  const SelectionTree::Node *End = Op.SelectedOperands.back();    // RHS378  // 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 selected384      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 398SourceRange 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) DeclRef410const 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 as425// a statement rather than an expression whose value can be used.426bool 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).449bool 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 lambda519  // expression. We only want to offer the extraction if the entire lambda520  // 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 is526  // 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/field541// DeclRefs. For function/member function, we want to extract the entire542// function call.543const 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 placeholder567/// Before:568/// int x = 5 + 4 * 3;569///         ^^^^^570/// After:571/// auto placeholder = 5 + 4;572/// int x = placeholder * 3;573class ExtractVariable : public Tweak {574public: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 585private:586  // the expression to extract587  std::unique_ptr<ExtractionContext> Target;588};589REGISTER_TWEAK(ExtractVariable)590bool ExtractVariable::prepare(const Selection &Inputs) {591  // we don't trigger on empty selections for now592  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 602Expected<Tweak::Effect> ExtractVariable::apply(const Selection &Inputs) {603  tooling::Replacements Result;604  // FIXME: get variable name from user or suggest based on type605  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 if615  // we are not dealing with an expression statement, which already has616  // 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} // namespace632} // namespace clangd633} // namespace clang634