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