clang-tools 24.0.0git
ExtractFunction.cpp
Go to the documentation of this file.
1//===--- ExtractFunction.cpp -------------------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Extracts statements to a new function and replaces the statements with a
10// call to the new function.
11// Before:
12// void f(int a) {
13// [[if(a < 5)
14// a = 5;]]
15// }
16// After:
17// void extracted(int &a) {
18// if(a < 5)
19// a = 5;
20// }
21// void f(int a) {
22// extracted(a);
23// }
24//
25// - Only extract statements
26// - Extracts from non-templated free functions only.
27// - Parameters that are never (conservatively) mutated in the extracted
28// code become const references, except scalars (arithmetic, pointer,
29// enumeration, ...), which are passed by value instead.
30// - Otherwise passed by non-const reference
31// - In C, which has no references, a parameter that would otherwise need
32// one becomes a real pointer instead (except array types, which decay to
33// a pointer on their own): the call site takes its address, and every
34// use inside the extracted body is rewritten into a dereference.
35// - Void return type
36// - Cannot extract declarations that will be needed in the original function
37// after extraction.
38// - Checks for broken control flow (break/continue without loop/switch)
39//
40// 1. ExtractFunction is the tweak subclass
41// - Prepare does basic analysis of the selection and is therefore fast.
42// Successful prepare doesn't always mean we can apply the tweak.
43// - Apply does a more detailed analysis and can be slower. In case of
44// failure, we let the user know that we are unable to perform extraction.
45// 2. ExtractionZone store information about the range being extracted and the
46// enclosing function.
47// 3. NewFunction stores properties of the extracted function and provides
48// methods for rendering it.
49// 4. CapturedZoneInfo uses a RecursiveASTVisitor to capture information about
50// the extraction like declarations, existing return statements, etc.
51// 5. getExtractedFunction is responsible for analyzing the CapturedZoneInfo and
52// creating a NewFunction.
53//===----------------------------------------------------------------------===//
54
55#include "AST.h"
56#include "FindTarget.h"
57#include "ParsedAST.h"
58#include "Selection.h"
59#include "SourceCode.h"
60#include "refactor/Tweak.h"
61#include "support/Logger.h"
62#include "clang/AST/ASTContext.h"
63#include "clang/AST/Decl.h"
64#include "clang/AST/DeclBase.h"
65#include "clang/AST/ExprCXX.h"
66#include "clang/AST/NestedNameSpecifier.h"
67#include "clang/AST/RecursiveASTVisitor.h"
68#include "clang/AST/Stmt.h"
69#include "clang/Basic/LangOptions.h"
70#include "clang/Basic/SourceLocation.h"
71#include "clang/Basic/SourceManager.h"
72#include "clang/Tooling/Core/Replacement.h"
73#include "clang/Tooling/Refactoring/Extract/SourceExtraction.h"
74#include "llvm/ADT/STLExtras.h"
75#include "llvm/ADT/SmallSet.h"
76#include "llvm/ADT/SmallVector.h"
77#include "llvm/ADT/StringRef.h"
78#include "llvm/Support/Casting.h"
79#include "llvm/Support/Error.h"
80#include <optional>
81
82namespace clang {
83namespace clangd {
84namespace {
85
86using Node = SelectionTree::Node;
87
88// ExtractionZone is the part of code that is being extracted.
89// EnclosingFunction is the function/method inside which the zone lies.
90// We split the file into 4 parts relative to extraction zone.
91enum class ZoneRelative {
92 Before, // Before Zone and inside EnclosingFunction.
93 Inside, // Inside Zone.
94 After, // After Zone and inside EnclosingFunction.
95 OutsideFunc // Outside EnclosingFunction.
96};
97
98enum FunctionDeclKind {
99 InlineDefinition,
100 ForwardDeclaration,
101 OutOfLineDefinition
102};
103
104// How a captured variable is passed to the extracted function.
105enum class ParamPassKind {
106 Value, // A plain copy: `T name`. Also used for a C array, which
107 // decays to a pointer on its own wherever it's used.
108 Reference, // C++ only: `T &name`.
109 Pointer, // C only (no references there): a real pointer, `T *name`,
110 // with the call site taking the address of the original
111 // variable and every use inside the extracted body rewritten
112 // into a dereference (see createParameters and getFuncBody).
113};
114
115// Whether N, despite being Unselected, may still be a single RootStmt: a
116// DeclStmt can be unselected since VarDecls claim the entire selection range
117// in the selection tree. Similarly, a CXXOperatorCallExpr of a binary
118// operation can be unselected because its children (the operands) claim the
119// entire selection range in the selection tree (e.g. <<).
120bool isUnselectedRootStmtCandidate(const Node *N) {
121 return N->ASTNode.get<DeclStmt>() || N->ASTNode.get<CXXOperatorCallExpr>();
122}
123
124// Whether Child is the condition (or condition-variable declaration) of a
125// control-flow Parent, or the range-expression of a range-based for. These
126// are the only slots whose *value* is actually consumed by the construct
127// itself -- to decide whether to keep looping/branching, or to build the
128// hidden begin/end iterators -- so replacing them with a call to a
129// void-returning extracted function would not compile. Other slots, like a
130// loop's init-statement or increment expression, have their value discarded
131// just like an ordinary expression-statement (and any hazard from
132// extracting a declaration that's used later is already caught by
133// ExtractionZone::requiresHoisting), so they remain extractable.
134//
135// For CXXForRangeStmt, only RangeInit is ever reachable here: clangd's
136// SelectionTree has a custom traversal for range-based for loops (see
137// TraverseCXXForRangeStmt in Selection.cpp) that visits only the
138// init-statement, loop variable, range-expression, and body -- the
139// compiler-synthesized condition/increment/begin/end never become
140// SelectionTree nodes at all.
141bool isConditionClause(const Stmt *Parent, const Stmt *Child) {
142 if (const auto *If = llvm::dyn_cast<IfStmt>(Parent))
143 return Child == If->getCond() ||
144 Child == If->getConditionVariableDeclStmt();
145 if (const auto *For = llvm::dyn_cast<ForStmt>(Parent))
146 return Child == For->getCond() ||
147 Child == For->getConditionVariableDeclStmt();
148 if (const auto *While = llvm::dyn_cast<WhileStmt>(Parent))
149 return Child == While->getCond() ||
150 Child == While->getConditionVariableDeclStmt();
151 if (const auto *Do = llvm::dyn_cast<DoStmt>(Parent))
152 return Child == Do->getCond();
153 if (const auto *Switch = llvm::dyn_cast<SwitchStmt>(Parent))
154 return Child == Switch->getCond() ||
155 Child == Switch->getConditionVariableDeclStmt();
156 if (const auto *ForRange = llvm::dyn_cast<CXXForRangeStmt>(Parent))
157 return Child == ForRange->getRangeInit();
158 return false;
159}
160
161// A RootStmt is a statement that's fully selected including all its children
162// and its parent is unselected.
163// Check if a node is a root statement.
164bool isRootStmt(const Node *N) {
165 const Stmt *S = N->ASTNode.get<Stmt>();
166 if (!S)
167 return false;
168 // Root statement cannot be partially selected.
169 if (N->Selected == SelectionTree::Partial)
170 return false;
171 if (N->Selected == SelectionTree::Unselected &&
172 !isUnselectedRootStmtCandidate(N))
173 return false;
174 if (const Stmt *Parent = N->Parent ? N->Parent->ASTNode.get<Stmt>() : nullptr)
175 if (isConditionClause(Parent, S))
176 return false;
177 return true;
178}
179
180// Given a Child that is itself a single RootStmt (either because it's
181// completely selected, or because it's an isUnselectedRootStmtCandidate),
182// returns Child's enclosing statement, which is where we'll look for
183// Child's RootStmt siblings.
184//
185// If parent is a DeclStmt, even though it's unselected, we consider it a
186// root statement and return its parent instead. This is done because the
187// VarDecls claim the entire selection range of the Declaration and DeclStmt
188// is always unselected.
189//
190// Returns null if the (possibly DeclStmt-adjusted) parent isn't a "plain"
191// Stmt, or is an Expr: this means Child is merely a subexpression of a
192// larger expression or declaration rather than a genuine standalone
193// statement, and extracting it would produce broken code. This covers two
194// distinct cases:
195// - Parent is an Expr, e.g. selecting just the "3" in `stream << 3;`
196// (Child is a subexpression of a larger expression).
197// - Parent isn't a Stmt at all, e.g. selecting just the "func()" in
198// `auto A = func();` (Child is a VarDecl's initializer, so Parent is
199// that VarDecl -- a Decl, not a Stmt).
200const Node *getEnclosingStmt(const Node *Child) {
201 const Node *Parent = Child->Parent;
202 if (Parent->ASTNode.get<DeclStmt>())
203 Parent = Parent->Parent;
204 if (!Parent->ASTNode.get<Stmt>() || Parent->ASTNode.get<Expr>())
205 return nullptr;
206 return Parent;
207}
208
209// Returns the (unselected) parent of all RootStmts given the commonAncestor.
210// Returns null if:
211// 1. any node is partially selected
212// 2. If all completely selected nodes don't have the same common parent
213// 3. Any child of Parent isn't a RootStmt.
214// Returns null if any child is not a RootStmt.
215// We only support extraction of RootStmts since it allows us to extract without
216// having to change the selection range. Also, this means that any scope that
217// begins in selection range, ends in selection range and any scope that begins
218// outside the selection range, ends outside as well.
219const Node *getParentOfRootStmts(const Node *CommonAnc) {
220 if (!CommonAnc)
221 return nullptr;
222 const Node *Parent = nullptr;
223 switch (CommonAnc->Selected) {
225 // Typically a block, with the { and } unselected, could also be ForStmt
226 // etc. However, CommonAnc may instead be a single statement that is
227 // itself Unselected only because all of its own tokens are claimed by
228 // its children (see isUnselectedRootStmtCandidate); in that case it's a
229 // root statement in its own right, and we need its actual parent, same
230 // as in the Complete case below.
231 if (isUnselectedRootStmtCandidate(CommonAnc)) {
232 Parent = getEnclosingStmt(CommonAnc);
233 break;
234 }
235 // Ensure all Children are RootStmts.
236 Parent = CommonAnc;
237 break;
239 // Only a fully-selected single statement can be selected.
240 return nullptr;
242 Parent = getEnclosingStmt(CommonAnc);
243 break;
244 }
245 if (!Parent)
246 return nullptr;
247 // Ensure all Children are RootStmts.
248 return llvm::all_of(Parent->Children, isRootStmt) ? Parent : nullptr;
249}
250
251// The ExtractionZone class forms a view of the code wrt Zone.
252struct ExtractionZone {
253 // Parent of RootStatements being extracted.
254 const Node *Parent = nullptr;
255 // The half-open file range of the code being extracted.
256 SourceRange ZoneRange;
257 // The function inside which our zone resides.
258 const FunctionDecl *EnclosingFunction = nullptr;
259 // The half-open file range of the enclosing function.
260 SourceRange EnclosingFuncRange;
261 // Set of statements that form the ExtractionZone.
262 llvm::DenseSet<const Stmt *> RootStmts;
263
264 SourceLocation getInsertionPoint() const {
265 return EnclosingFuncRange.getBegin();
266 }
267 bool isRootStmt(const Stmt *S) const;
268 // The last root statement is important to decide where we need to insert a
269 // semicolon after the extraction.
270 const Node *getLastRootStmt() const { return Parent->Children.back(); }
271
272 // Checks if declarations inside extraction zone are accessed afterwards.
273 //
274 // This performs a partial AST traversal proportional to the size of the
275 // enclosing function, so it is possibly expensive.
276 bool requiresHoisting(const SourceManager &SM,
277 const HeuristicResolver *Resolver) const {
278 // First find all the declarations that happened inside extraction zone.
279 llvm::SmallPtrSet<const Decl *, 1> DeclsInExtZone;
280 for (auto *RootStmt : RootStmts) {
282 RootStmt,
283 [&DeclsInExtZone](const ReferenceLoc &Loc) {
284 if (!Loc.IsDecl)
285 return;
286 DeclsInExtZone.insert(Loc.Targets.front());
287 },
288 Resolver);
289 }
290 // Early exit without performing expensive traversal below.
291 if (DeclsInExtZone.empty())
292 return false;
293 // Then make sure they are not used outside the zone.
294 for (const auto *S : EnclosingFunction->getBody()->children()) {
295 if (SM.isBeforeInTranslationUnit(S->getSourceRange().getEnd(),
296 ZoneRange.getEnd()))
297 continue;
298 bool HasPostUse = false;
300 S,
301 [&](const ReferenceLoc &Loc) {
302 if (HasPostUse ||
303 SM.isBeforeInTranslationUnit(Loc.NameLoc, ZoneRange.getEnd()))
304 return;
305 HasPostUse = llvm::any_of(Loc.Targets,
306 [&DeclsInExtZone](const Decl *Target) {
307 return DeclsInExtZone.contains(Target);
308 });
309 },
310 Resolver);
311 if (HasPostUse)
312 return true;
313 }
314 return false;
315 }
316};
317
318// Whether the code in the extraction zone is guaranteed to return, assuming
319// no broken control flow (unbound break/continue).
320// This is a very naive check (does it end with a return stmt).
321// Doing some rudimentary control flow analysis would cover more cases.
322bool alwaysReturns(const ExtractionZone &EZ) {
323 const Stmt *Last = EZ.getLastRootStmt()->ASTNode.get<Stmt>();
324 // Unwrap enclosing (unconditional) compound statement.
325 while (const auto *CS = llvm::dyn_cast<CompoundStmt>(Last)) {
326 if (CS->body_empty())
327 return false;
328 Last = CS->body_back();
329 }
330 return llvm::isa<ReturnStmt>(Last);
331}
332
333bool ExtractionZone::isRootStmt(const Stmt *S) const {
334 return RootStmts.contains(S);
335}
336
337// Finds the function in which the zone lies.
338const FunctionDecl *findEnclosingFunction(const Node *CommonAnc) {
339 // Walk up the SelectionTree until we find a function Decl
340 for (const Node *CurNode = CommonAnc; CurNode; CurNode = CurNode->Parent) {
341 // Don't extract from lambdas
342 if (CurNode->ASTNode.get<LambdaExpr>())
343 return nullptr;
344 if (const FunctionDecl *Func = CurNode->ASTNode.get<FunctionDecl>()) {
345 // FIXME: Support extraction from templated functions.
346 if (Func->isTemplated())
347 return nullptr;
348 if (!Func->getBody())
349 return nullptr;
350 for (const auto *S : Func->getBody()->children()) {
351 // During apply phase, we perform semantic analysis (e.g. figure out
352 // what variables requires hoisting). We cannot perform those when the
353 // body has invalid statements, so fail up front.
354 if (!S)
355 return nullptr;
356 }
357 return Func;
358 }
359 }
360 return nullptr;
361}
362
363// Zone Range is the union of SourceRanges of all child Nodes in Parent since
364// all child Nodes are RootStmts
365std::optional<SourceRange> findZoneRange(const Node *Parent,
366 const SourceManager &SM,
367 const LangOptions &LangOpts) {
368 SourceRange SR;
369 if (auto BeginFileRange = toHalfOpenFileRange(
370 SM, LangOpts, Parent->Children.front()->ASTNode.getSourceRange()))
371 SR.setBegin(BeginFileRange->getBegin());
372 else
373 return std::nullopt;
374 if (auto EndFileRange = toHalfOpenFileRange(
375 SM, LangOpts, Parent->Children.back()->ASTNode.getSourceRange()))
376 SR.setEnd(EndFileRange->getEnd());
377 else
378 return std::nullopt;
379 return SR;
380}
381
382// Compute the range spanned by the enclosing function.
383// FIXME: check if EnclosingFunction has any attributes as the AST doesn't
384// always store the source range of the attributes and thus we end up extracting
385// between the attributes and the EnclosingFunction.
386std::optional<SourceRange>
387computeEnclosingFuncRange(const FunctionDecl *EnclosingFunction,
388 const SourceManager &SM,
389 const LangOptions &LangOpts) {
390 return toHalfOpenFileRange(SM, LangOpts, EnclosingFunction->getSourceRange());
391}
392
393// Whether D would need to become a forwarded parameter of the extracted
394// function if referenced from inside the extraction zone: a name (a
395// parameter, local variable, or structured-binding) declared inside the
396// enclosing function. Such a name is only visible within that function,
397// regardless of storage duration -- unlike hasLocalStorage(), this is
398// also true of a function-scope `static` or `thread_local` variable,
399// which (unlike a namespace-scope global or a static data member, both
400// reachable via a qualified name from anywhere) isn't visible wherever
401// the extracted function ends up.
402bool mustBeForwarded(const Decl *D) {
403 if (!isa<VarDecl, BindingDecl>(D))
404 return false;
405 return D->getDeclContext()->isFunctionOrMethod();
406}
407
408// Whether E, as an operand of a call being considered by isTrivialExtraction,
409// is a bare (parenthesized/implicitly cast) reference to a Decl that would
410// need to become a parameter, forwarded unchanged -- and if so, that Decl.
411// Returns null otherwise: a literal, a reference to an already-visible
412// global, or any non-bare expression all mean this operand alone justifies
413// offering the extraction, since it hardcodes or computes something a
414// plain rename wouldn't.
415const Decl *bareForwardedDecl(const Expr *E) {
416 const auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
417 if (!DRE || !mustBeForwarded(DRE->getDecl()))
418 return nullptr;
419 return DRE->getDecl();
420}
421
422// The operands of Call relevant to isTrivialExtraction: the receiver of
423// a method call, a non-method callee that isn't a plain reference to a
424// fixed function (e.g. a function-pointer variable instead), and every
425// explicit argument. An operator call's operands are already included in
426// its own arguments() (clang models e.g. `a + b` as `operator+(a, b)`),
427// so its callee -- always a reference to the operator function/overload
428// itself, never itself customizable -- is always excluded.
429llvm::SmallVector<const Expr *, 4> relevantCallOperands(const CallExpr *Call) {
430 llvm::SmallVector<const Expr *, 4> Operands;
431 if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
432 // getImplicitObjectArgument() can itself be null (its FIXME notes
433 // this isn't fully handled for all cases); other clang analyses
434 // (e.g. LiveVariables, dataflow's Environment::pushCall) guard it
435 // the same way rather than assume it's always present.
436 if (const Expr *ImplicitObject = MCE->getImplicitObjectArgument()) {
437 // `this` (implicit or explicit) always refers to the same object
438 // -- the extracted function becomes a sibling member itself, so
439 // `this` stays implicit there too, never becoming a parameter --
440 // so, like an ordinary function name, it's excluded rather than
441 // required to be "bare".
442 if (!isa<CXXThisExpr>(ImplicitObject->IgnoreParenImpCasts()))
443 Operands.push_back(ImplicitObject);
444 }
445 // A pointer-to-member call (`(s.*pmf)(x)`) has no statically known
446 // method to exclude the way an ordinary method call's name is
447 // excluded below: which member is invoked is itself a real,
448 // customizable operand here (e.g. the `pmf` it's called through),
449 // not inherent to what the wrapper does.
450 if (!MCE->getMethodDecl())
451 Operands.push_back(MCE->getCallee());
452 } else if (!isa<CXXOperatorCallExpr>(Call)) {
453 const Expr *Callee = Call->getCallee()->IgnoreParenImpCasts();
454 if (!(isa<DeclRefExpr>(Callee) &&
455 isa<FunctionDecl>(cast<DeclRefExpr>(Callee)->getDecl())))
456 Operands.push_back(Call->getCallee());
457 }
458 // An omitted argument filled in from the callee's own default isn't
459 // something this call site wrote or hardcoded: it's inherent to
460 // calling the function at all, same as the function's name, so it's
461 // excluded rather than required to be "bare". Default arguments are
462 // always trailing, so the first one found marks the end of the
463 // explicitly-written ones.
464 auto Args = Call->arguments();
465 auto FirstDefault = llvm::find_if(
466 Args, [](const Expr *Arg) { return isa<CXXDefaultArgExpr>(Arg); });
467 Operands.append(Args.begin(), FirstDefault);
468 return Operands;
469}
470
471// Whether extracting S on its own, as a single root statement, would add
472// no real abstraction over leaving it where it is:
473// - A value-less `return;` has nothing to abstract over at all.
474// - A call (to a function, method, or operator), or a return of one, is
475// a pure 1:1 forwarding wrapper if every relevant operand (see
476// relevantCallOperands) is already exactly the parameter value it
477// would become, unchanged (or there are none). Extracting e.g.
478// `foo();`, `foo(x)` (x a local), or `return foo(x);` this way would
479// just rename the call; `foo(100)`, `foo(globalVar)`, or `foo(x + y)`
480// would not, since each does something a plain rename wouldn't
481// (hardcode a value/global, or compute one). For the return case, the
482// returned value may be parenthesized and/or need an implicit
483// conversion to the enclosing function's own return type (e.g. foo
484// returns int, the enclosing function long); IgnoreParenImpCasts()
485// looks through both -- neither changes the verdict, since the
486// extracted function would perform the exact same conversion
487// internally.
488// - Using the same captured Decl in more than one operand (e.g.
489// `foo(A, A)`) is, despite every individual operand being bare,
490// *not* pure forwarding: it constrains a relationship (both slots
491// must hold the same value) that a plain rename wouldn't, the same
492// kind of real specialization as hardcoding a literal.
493// - createParameters orders the extracted function's own parameters by
494// each captured Decl's declaration order in the *enclosing* function,
495// not by how they're used in this call. So if a later operand here
496// refers to a Decl declared *earlier* than an operand before it (e.g.
497// `foo(B, A)` inside `bar(int A, int B)`), the parameters end up
498// reordered relative to this call: `extracted(int A, int B) { foo(B,
499// A); }`. That's not a transparent pass-through either, even though
500// this one call site still behaves the same after the compensating
501// reorder at the call site (`extracted(A, B)`) -- `extracted`'s own
502// signature no longer predicts its behavior the way a plain rename's
503// would, since it silently permutes its own parameters internally.
504bool isTrivialExtraction(const Stmt *S, const SourceManager &SM) {
505 if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
506 if (!RS->getRetValue())
507 return true;
508 S = RS->getRetValue()->IgnoreParenImpCasts();
509 }
510 const auto *Call = dyn_cast<CallExpr>(S);
511 if (!Call)
512 return false;
513 llvm::SmallPtrSet<const Decl *, 4> SeenDecls;
514 SourceLocation LastDeclLoc;
515 for (const Expr *Operand : relevantCallOperands(Call)) {
516 const Decl *D = bareForwardedDecl(Operand);
517 if (!D || !SeenDecls.insert(D).second)
518 return false;
519 SourceLocation DeclLoc = D->getLocation();
520 if (LastDeclLoc.isValid() &&
521 !SM.isBeforeInTranslationUnit(LastDeclLoc, DeclLoc))
522 return false;
523 LastDeclLoc = DeclLoc;
524 }
525 return true;
526}
527
528// returns true if Child can be a single RootStmt being extracted from
529// EnclosingFunc.
530bool validSingleChild(const Node *Child, const FunctionDecl *EnclosingFunc,
531 const SourceManager &SM) {
532 // Extracting the body of EnclosingFunc would remove it's definition.
533 assert(EnclosingFunc->hasBody() &&
534 "We should always be extracting from a function body.");
535 const Stmt *S = Child->ASTNode.get<Stmt>();
536 if (S == EnclosingFunc->getBody())
537 return false;
538 if (isTrivialExtraction(S, SM))
539 return false;
540 return true;
541}
542
543std::optional<ExtractionZone> findExtractionZone(const Node *CommonAnc,
544 const SourceManager &SM,
545 const LangOptions &LangOpts) {
546 ExtractionZone ExtZone;
547 ExtZone.Parent = getParentOfRootStmts(CommonAnc);
548 if (!ExtZone.Parent || ExtZone.Parent->Children.empty())
549 return std::nullopt;
550 ExtZone.EnclosingFunction = findEnclosingFunction(ExtZone.Parent);
551 if (!ExtZone.EnclosingFunction)
552 return std::nullopt;
553 // When there is a single RootStmt, we must check if it's valid for
554 // extraction.
555 if (ExtZone.Parent->Children.size() == 1 &&
556 !validSingleChild(ExtZone.getLastRootStmt(), ExtZone.EnclosingFunction,
557 SM))
558 return std::nullopt;
559 if (auto FuncRange =
560 computeEnclosingFuncRange(ExtZone.EnclosingFunction, SM, LangOpts))
561 ExtZone.EnclosingFuncRange = *FuncRange;
562 if (auto ZoneRange = findZoneRange(ExtZone.Parent, SM, LangOpts))
563 ExtZone.ZoneRange = *ZoneRange;
564 if (ExtZone.EnclosingFuncRange.isInvalid() || ExtZone.ZoneRange.isInvalid())
565 return std::nullopt;
566
567 for (const Node *Child : ExtZone.Parent->Children)
568 ExtZone.RootStmts.insert(Child->ASTNode.get<Stmt>());
569
570 return ExtZone;
571}
572
573// Stores information about the extracted function and provides methods for
574// rendering it.
575struct NewFunction {
576 struct Parameter {
577 std::string Name;
578 QualType TypeInfo;
579 ParamPassKind Kind;
580 unsigned OrderPriority; // Lower value parameters are preferred first.
581 std::string render(const DeclContext &Context) const;
582 bool operator<(const Parameter &Other) const {
583 return OrderPriority < Other.OrderPriority;
584 }
585 };
586 std::string Name = "extracted";
587 QualType ReturnType;
588 std::vector<Parameter> Parameters;
589 SourceRange BodyRange;
590 SourceLocation DefinitionPoint;
591 std::optional<SourceLocation> ForwardDeclarationPoint;
592 const CXXRecordDecl *EnclosingClass = nullptr;
593 NestedNameSpecifier DefinitionQualifier = std::nullopt;
594 const DeclContext *SemanticDC = nullptr;
595 const DeclContext *SyntacticDC = nullptr;
596 const DeclContext *ForwardDeclarationSyntacticDC = nullptr;
597 bool CallerReturnsValue = false;
598 bool Static = false;
599 ConstexprSpecKind Constexpr = ConstexprSpecKind::Unspecified;
600 bool Const = false;
601
602 // For C only: describes how to rewrite a single in-body reference to a
603 // parameter that had to become a real pointer instead of a reference (C
604 // has none), because its corresponding Parameter::Kind is Pointer. See
605 // createParameters and getFuncBody.
606 struct PointerRewriteSite {
607 SourceLocation Loc; // Location of the identifier itself.
608 unsigned NameLength;
609 // Set when this occurrence is the base of a non-arrow member access
610 // (`name.member`) immediately following it: that reads more
611 // naturally rewritten as `name->member` than `(*name).member`. Holds
612 // the location of the '.' token to replace with "->"; the identifier
613 // itself is then left untouched. Unset otherwise, in which case the
614 // identifier is instead wrapped in "(*...)".
615 std::optional<SourceLocation> DotLoc;
616 };
617 std::vector<PointerRewriteSite> PointerRewriteSites;
618
619 // Decides whether the extracted function body and the function call need a
620 // semicolon after extraction.
621 tooling::ExtractionSemicolonPolicy SemicolonPolicy;
622 const LangOptions *LangOpts;
623 NewFunction(tooling::ExtractionSemicolonPolicy SemicolonPolicy,
624 const LangOptions *LangOpts)
625 : SemicolonPolicy(SemicolonPolicy), LangOpts(LangOpts) {}
626 // Render the call for this function.
627 std::string renderCall() const;
628 // Render the definition for this function.
629 llvm::Expected<std::string> renderDeclaration(FunctionDeclKind K,
630 const DeclContext &SemanticDC,
631 const DeclContext &SyntacticDC,
632 const SourceManager &SM) const;
633
634private:
635 std::string
636 renderParametersForDeclaration(const DeclContext &Enclosing) const;
637 std::string renderParametersForCall() const;
638 std::string renderSpecifiers(FunctionDeclKind K) const;
639 std::string renderQualifiers() const;
640 std::string renderDeclarationName(FunctionDeclKind K) const;
641 // Generate the function body.
642 llvm::Expected<std::string> getFuncBody(const SourceManager &SM) const;
643};
644
645std::string NewFunction::renderParametersForDeclaration(
646 const DeclContext &Enclosing) const {
647 std::string Result;
648 bool NeedCommaBefore = false;
649 for (const Parameter &P : Parameters) {
650 if (NeedCommaBefore)
651 Result += ", ";
652 NeedCommaBefore = true;
653 Result += P.render(Enclosing);
654 }
655 return Result;
656}
657
658std::string NewFunction::renderParametersForCall() const {
659 std::string Result;
660 bool NeedCommaBefore = false;
661 for (const Parameter &P : Parameters) {
662 if (NeedCommaBefore)
663 Result += ", ";
664 NeedCommaBefore = true;
665 if (P.Kind == ParamPassKind::Pointer)
666 Result += "&";
667 Result += P.Name;
668 }
669 return Result;
670}
671
672std::string NewFunction::renderSpecifiers(FunctionDeclKind K) const {
673 std::string Attributes;
674
675 if (Static && K != FunctionDeclKind::OutOfLineDefinition) {
676 Attributes += "static ";
677 }
678
679 switch (Constexpr) {
680 case ConstexprSpecKind::Unspecified:
681 case ConstexprSpecKind::Constinit:
682 break;
683 case ConstexprSpecKind::Constexpr:
684 Attributes += "constexpr ";
685 break;
686 case ConstexprSpecKind::Consteval:
687 Attributes += "consteval ";
688 break;
689 }
690
691 return Attributes;
692}
693
694std::string NewFunction::renderQualifiers() const {
695 std::string Attributes;
696
697 if (Const) {
698 Attributes += " const";
699 }
700
701 return Attributes;
702}
703
704std::string NewFunction::renderDeclarationName(FunctionDeclKind K) const {
705 if (!DefinitionQualifier || K != OutOfLineDefinition)
706 return Name;
707
708 std::string QualifierName;
709 llvm::raw_string_ostream Oss(QualifierName);
710 DefinitionQualifier.print(Oss, *LangOpts);
711 return llvm::formatv("{0}{1}", QualifierName, Name);
712}
713
714std::string NewFunction::renderCall() const {
715 return std::string(
716 llvm::formatv("{0}{1}({2}){3}", CallerReturnsValue ? "return " : "", Name,
717 renderParametersForCall(),
718 (SemicolonPolicy.isNeededInOriginalFunction() ? ";" : "")));
719}
720
721llvm::Expected<std::string> NewFunction::renderDeclaration(
722 FunctionDeclKind K, const DeclContext &SemanticDC,
723 const DeclContext &SyntacticDC, const SourceManager &SM) const {
724 std::string Declaration = std::string(llvm::formatv(
725 "{0}{1} {2}({3}){4}", renderSpecifiers(K),
726 printType(ReturnType, SyntacticDC), renderDeclarationName(K),
727 renderParametersForDeclaration(SemanticDC), renderQualifiers()));
728
729 switch (K) {
730 case ForwardDeclaration:
731 return std::string(llvm::formatv("{0};\n", Declaration));
732 case OutOfLineDefinition:
733 case InlineDefinition: {
734 llvm::Expected<std::string> Body = getFuncBody(SM);
735 if (!Body)
736 return Body.takeError();
737 return std::string(llvm::formatv("{0} {\n{1}\n}\n", Declaration, *Body));
738 }
739 }
740 llvm_unreachable("Unsupported FunctionDeclKind enum");
741}
742
743llvm::Expected<std::string>
744NewFunction::getFuncBody(const SourceManager &SM) const {
745 // FIXME: Generate tooling::Replacements instead of std::string to
746 // - hoist decls
747 // - add return statement
748 // - Add semicolon
749 std::string Body = toSourceCode(SM, BodyRange).str();
750 if (PointerRewriteSites.empty())
751 return Body + (SemicolonPolicy.isNeededInExtractedFunction() ? ";" : "");
752
753 // Splice in each site's rewrite. These are all independent
754 // insertions/single-token replacements at distinct, non-overlapping
755 // source locations (two DeclRefExprs can't share a location, and a dot
756 // always follows its own identifier), so none of this should actually
757 // be able to fail -- but if that assumption is ever wrong, surface it
758 // as an extraction failure instead of silently emitting broken code.
759 tooling::Replacements Repls;
760 unsigned BodyBeginOffset = SM.getFileOffset(BodyRange.getBegin());
761 for (const auto &Site : PointerRewriteSites) {
762 unsigned SiteOffset = SM.getFileOffset(Site.Loc) - BodyBeginOffset;
763 if (Site.DotLoc) {
764 // Leave the identifier itself untouched; turn the member access
765 // that follows it into "->" instead of wrapping in a dereference.
766 unsigned DotOffset = SM.getFileOffset(*Site.DotLoc) - BodyBeginOffset;
767 if (auto Err = Repls.add(tooling::Replacement("", DotOffset, 1, "->")))
768 return std::move(Err);
769 } else {
770 if (auto Err = Repls.add(tooling::Replacement("", SiteOffset, 0, "(*")))
771 return std::move(Err);
772 if (auto Err = Repls.add(
773 tooling::Replacement("", SiteOffset + Site.NameLength, 0, ")")))
774 return std::move(Err);
775 }
776 }
777 llvm::Expected<std::string> NewBody =
778 tooling::applyAllReplacements(Body, Repls);
779 if (!NewBody)
780 return NewBody.takeError();
781 return *NewBody + (SemicolonPolicy.isNeededInExtractedFunction() ? ";" : "");
782}
783
784std::string NewFunction::Parameter::render(const DeclContext &Context) const {
785 // Passing Name as printType()'s declarator placeholder (rather than just
786 // appending it after the printed type) lets clang's own type printer
787 // place it correctly for declarator syntax that doesn't simply put the
788 // name after the type, e.g. a function pointer (`void (*name)(int)`, not
789 // `void (*)(int) name`). This only threads correctly through an outer
790 // pointer or reference, though, not through a bare array type on its
791 // own (confirmed empirically: it prints as `int[5] name`, not the
792 // intended `int name[5]`) -- harmless here, since createParameters
793 // never leaves TypeInfo as a bare array: it's always either decayed
794 // to a pointer (in C) or wrapped in the reference built just below
795 // (in C++). For that reference case, building the actual reference
796 // QualType (rather than just prepending "&" to the placeholder
797 // string) is what lets the printer correctly parenthesize a
798 // reference-to-array (`int (&name)[5]`, not the invalid
799 // `int &name[5]`).
800 QualType RenderedType =
801 Kind == ParamPassKind::Reference
802 ? Context.getParentASTContext().getLValueReferenceType(TypeInfo)
803 : TypeInfo;
804 return printType(RenderedType, Context, Name);
805}
806
807// Stores captured information about Extraction Zone.
808struct CapturedZoneInfo {
809 struct DeclInformation {
810 const Decl *TheDecl;
811 ZoneRelative DeclaredIn;
812 // index of the declaration or first reference.
813 unsigned DeclIndex;
814 bool IsReferencedInZone = false;
815 bool IsReferencedInPostZone = false;
816 // Conservatively: could this Decl be mutated somewhere in the zone? See
817 // ExtractionZoneVisitor::markPossiblyMutated() for what "conservatively"
818 // means here.
819 bool IsPossiblyMutated = false;
820 // Describes one reference to this Decl inside the zone (not
821 // before/after it). Used to rewrite each use if this ends up becoming
822 // a C pointer-adapter parameter (see createParameters): C has no
823 // references, so a parameter that needs reference semantics there
824 // becomes a real pointer instead, and every use of it in the
825 // copied-out body must be adjusted accordingly.
826 struct Occurrence {
827 SourceLocation Loc; // Location of the identifier itself.
828 // Set when this occurrence is the base of a non-arrow member access
829 // (`name.member`) immediately following it: holds the location of
830 // the '.' token, so it can be turned into "->" instead of wrapping
831 // the identifier in a dereference. See
832 // NewFunction::PointerRewriteSite.
833 std::optional<SourceLocation> DotLoc;
834 };
835 llvm::SmallVector<Occurrence, 1> ZoneOccurrences;
836 // Whether this Decl is ever the direct operand of a trait that
837 // depends on its exact, undecayed type: `sizeof`/`alignof`/`typeof`
838 // and their spelling variants (e.g. `sizeof arr`/`sizeof(arr)`, as
839 // opposed to `sizeof(T)`, which doesn't reference arr's Decl at all).
840 // If this Decl is an array and ends up decaying to a pointer for a C
841 // pointer-adapter parameter (see createParameters), such a use would
842 // silently start reporting the pointer's properties instead of the
843 // array's (e.g. 8 instead of 20 for `sizeof` on a 5-element `int`
844 // array on a 64-bit target), so that decay is refused whenever this
845 // is set.
846 bool HasUnsafeTypeQueryUseInZone = false;
847 DeclInformation(const Decl *TheDecl, ZoneRelative DeclaredIn,
848 unsigned DeclIndex)
849 : TheDecl(TheDecl), DeclaredIn(DeclaredIn), DeclIndex(DeclIndex){};
850 // Marks the occurence of a reference for this declaration
851 void markOccurence(ZoneRelative ReferenceLoc);
852 };
853 // Maps Decls to their DeclInfo
854 llvm::DenseMap<const Decl *, DeclInformation> DeclInfoMap;
855 bool HasReturnStmt = false; // Are there any return statements in the zone?
856 bool AlwaysReturns = false; // Does the zone always return?
857 // Control flow is broken if we are extracting a break/continue without a
858 // corresponding parent loop/switch
859 bool BrokenControlFlow = false;
860 // FIXME: capture TypeAliasDecl and UsingDirectiveDecl
861 // FIXME: Capture type information as well.
862 DeclInformation *createDeclInfo(const Decl *D, ZoneRelative RelativeLoc);
863 DeclInformation *getDeclInfoFor(const Decl *D);
864};
865
866CapturedZoneInfo::DeclInformation *
867CapturedZoneInfo::createDeclInfo(const Decl *D, ZoneRelative RelativeLoc) {
868 // The new Decl's index is the size of the map so far.
869 auto InsertionResult = DeclInfoMap.insert(
870 {D, DeclInformation(D, RelativeLoc, DeclInfoMap.size())});
871 // Return the newly created DeclInfo
872 return &InsertionResult.first->second;
873}
874
875CapturedZoneInfo::DeclInformation *
876CapturedZoneInfo::getDeclInfoFor(const Decl *D) {
877 // If the Decl doesn't exist, we
878 auto Iter = DeclInfoMap.find(D);
879 if (Iter == DeclInfoMap.end())
880 return nullptr;
881 return &Iter->second;
882}
883
884void CapturedZoneInfo::DeclInformation::markOccurence(
885 ZoneRelative ReferenceLoc) {
886 switch (ReferenceLoc) {
887 case ZoneRelative::Inside:
888 IsReferencedInZone = true;
889 break;
890 case ZoneRelative::After:
891 IsReferencedInPostZone = true;
892 break;
893 default:
894 break;
895 }
896}
897
898bool isLoop(const Stmt *S) {
899 return isa<ForStmt>(S) || isa<DoStmt>(S) || isa<WhileStmt>(S) ||
900 isa<CXXForRangeStmt>(S);
901}
902
903// Strips E down to the Decl(s) whose storage it ultimately refers to,
904// chaining through parens, casts, and member/array-element access (e.g.
905// `a.b[i]` resolves to `a`), but only when that access reaches through
906// value semantics: mutating `a.b` mutates `a`'s own storage, so we keep
907// chaining. We deliberately stop at a pointer-typed base (e.g. `p->b`,
908// `p[i]`, `p->*pmf`): that only mutates `*p`, never `p`'s own binding, so
909// chaining through it would incorrectly require `p` to stay non-const. For
910// the same reason, a dereference (`*p = 1`) is intentionally not handled
911// at all: it only ever mutates the pointee, never the pointer itself.
912//
913// A genuine array subscript (`arr[i]` where `arr` is an array, not a
914// pointer) also stops here: the base is always wrapped in an
915// ArrayToPointerDecay cast, indistinguishable at this point from
916// subscripting a real pointer. That's fine because createParameters()
917// never makes an array-typed capture const in the first place, regardless
918// of what we compute here.
919//
920// A conditional expression (e.g. `(cond ? a : b).m`) could resolve to
921// either branch at runtime, so both are collected -- this can only grow
922// the result, never replace it, which is why this appends to Decls rather
923// than returning a single Decl the way the rest of this function might
924// suggest. This has to be handled at every level of the chain, not just
925// the top: `(cond ? a : b).m = 1` reaches the conditional through a
926// MemberExpr base, not directly.
927//
928// Appends nothing if E isn't ultimately grounded in a variable this way
929// (e.g. it's a temporary, a call result, or reached through a pointer).
930void collectUnderlyingDecls(const Expr *E,
931 llvm::SmallVectorImpl<const Decl *> &Decls) {
932 if (!E)
933 return;
934 E = E->IgnoreParenCasts();
935 if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
936 Decls.push_back(DRE->getDecl());
937 return;
938 }
939 if (const auto *ME = dyn_cast<MemberExpr>(E)) {
940 if (!ME->getBase()->getType()->isPointerType())
941 collectUnderlyingDecls(ME->getBase(), Decls);
942 return;
943 }
944 if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
945 if (!ASE->getBase()->getType()->isPointerType())
946 collectUnderlyingDecls(ASE->getBase(), Decls);
947 return;
948 }
949 if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
950 // Only BO_PtrMemD (`.*`) is handled: its LHS is always an object, by
951 // grammar, so the chain always continues (matching MemberExpr's `.`
952 // above). BO_PtrMemI (`->*`) is excluded: its LHS is always a pointer,
953 // by grammar, so the chain should never continue (matching
954 // MemberExpr's `->` above).
955 if (BO->getOpcode() == BO_PtrMemD)
956 collectUnderlyingDecls(BO->getLHS(), Decls);
957 return;
958 }
959 if (const auto *CO = dyn_cast<AbstractConditionalOperator>(E)) {
960 collectUnderlyingDecls(CO->getTrueExpr(), Decls);
961 collectUnderlyingDecls(CO->getFalseExpr(), Decls);
962 }
963}
964
965// Captures information from Extraction Zone
966CapturedZoneInfo captureZoneInfo(const ExtractionZone &ExtZone) {
967 // We use the ASTVisitor instead of using the selection tree since we need to
968 // find references in the PostZone as well.
969 // FIXME: Check which statements we don't allow to extract.
970 class ExtractionZoneVisitor
971 : public clang::RecursiveASTVisitor<ExtractionZoneVisitor> {
972 public:
973 ExtractionZoneVisitor(const ExtractionZone &ExtZone) : ExtZone(ExtZone) {
974 TraverseDecl(const_cast<FunctionDecl *>(ExtZone.EnclosingFunction));
975 }
976
977 bool TraverseStmt(Stmt *S) {
978 if (!S)
979 return true;
980 bool IsRootStmt = ExtZone.isRootStmt(const_cast<const Stmt *>(S));
981 // If we are starting traversal of a RootStmt, we are somewhere inside
982 // ExtractionZone
983 if (IsRootStmt)
984 CurrentLocation = ZoneRelative::Inside;
985 addToLoopSwitchCounters(S, 1);
986 // Traverse using base class's TraverseStmt
987 RecursiveASTVisitor::TraverseStmt(S);
988 addToLoopSwitchCounters(S, -1);
989 // We set the current location as after since next stmt will either be a
990 // RootStmt (handled at the beginning) or after extractionZone
991 if (IsRootStmt)
992 CurrentLocation = ZoneRelative::After;
993 return true;
994 }
995
996 // Add Increment to CurNumberOf{Loops,Switch} if statement is
997 // {Loop,Switch} and inside Extraction Zone.
998 void addToLoopSwitchCounters(Stmt *S, int Increment) {
999 if (CurrentLocation != ZoneRelative::Inside)
1000 return;
1001 if (isLoop(S))
1002 CurNumberOfNestedLoops += Increment;
1003 else if (isa<SwitchStmt>(S))
1004 CurNumberOfSwitch += Increment;
1005 }
1006
1007 bool VisitDecl(Decl *D) {
1008 Info.createDeclInfo(D, CurrentLocation);
1009 return true;
1010 }
1011
1012 // Set by VisitMemberExpr right before traversing into a non-arrow
1013 // MemberExpr's base, when that base is (possibly parenthesized)
1014 // exactly a DeclRefExpr: since that base is always traversed
1015 // immediately afterwards (it's the MemberExpr's only child),
1016 // VisitDeclRefExpr can rely on this still describing itself, and
1017 // must always consume (reset) it, matched or not, so it never leaks
1018 // into an unrelated, later DeclRefExpr.
1019 std::optional<SourceLocation> PendingMemberDotLoc;
1020
1021 bool VisitMemberExpr(MemberExpr *ME) {
1022 if (!ME->isArrow() && isa<DeclRefExpr>(ME->getBase()->IgnoreParens()))
1023 PendingMemberDotLoc = ME->getOperatorLoc();
1024 return true;
1025 }
1026
1027 // Marks D as having an unsafe, type-dependent use in the zone (see
1028 // DeclInformation::HasUnsafeTypeQueryUseInZone) if it's reached
1029 // through a plain (possibly parenthesized) DeclRefExpr -- e.g. not
1030 // through a cast, which would already observe the decayed type rather
1031 // than the Decl's own declared type.
1032 void markUnsafeTypeQueryOperand(const Expr *E) {
1033 if (CurrentLocation != ZoneRelative::Inside)
1034 return;
1035 if (const auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
1036 if (auto *DeclInfo = Info.getDeclInfoFor(DRE->getDecl()))
1037 DeclInfo->HasUnsafeTypeQueryUseInZone = true;
1038 }
1039
1040 // Covers sizeof/alignof/__alignof/_Countof and their variants: all
1041 // share this one node type, distinguished only by getKind().
1042 bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
1043 if (!E->isArgumentType())
1044 markUnsafeTypeQueryOperand(E->getArgumentExpr());
1045 return true;
1046 }
1047
1048 // Covers typeof/typeof_unqual/__typeof__ (decltype itself is C++
1049 // only, so can't appear in the C code this matters for, but is
1050 // included for completeness/robustness).
1051 bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
1052 markUnsafeTypeQueryOperand(TL.getUnderlyingExpr());
1053 return true;
1054 }
1055 bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
1056 markUnsafeTypeQueryOperand(TL.getUnderlyingExpr());
1057 return true;
1058 }
1059
1060 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
1061 // Find the corresponding Decl and mark it's occurrence.
1062 const Decl *D = DRE->getDecl();
1063 auto *DeclInfo = Info.getDeclInfoFor(D);
1064 // If no Decl was found, the Decl must be outside the enclosingFunc.
1065 if (!DeclInfo)
1066 DeclInfo = Info.createDeclInfo(D, ZoneRelative::OutsideFunc);
1067 DeclInfo->markOccurence(CurrentLocation);
1068 if (CurrentLocation == ZoneRelative::Inside)
1069 DeclInfo->ZoneOccurrences.push_back(
1070 {DRE->getLocation(), PendingMemberDotLoc});
1071 PendingMemberDotLoc.reset();
1072 return true;
1073 }
1074
1075 // Conservatively marks D as possibly mutated: used both for actual
1076 // direct mutations (assignment, increment/decrement, ...) and for
1077 // constructs that alias D in a way we don't want to trace further (a
1078 // reference bound to D, D's address taken, D captured by reference in a
1079 // lambda, ...). We never try to determine whether such an alias is
1080 // itself later mutated -- that would require searching beyond this one
1081 // occurrence, which is exactly the cost this design avoids (and what
1082 // makes ExprMutationAnalyzer prohibitively slow). The price is
1083 // that we sometimes keep a parameter non-const where a full alias
1084 // analysis could prove it safe to const; we never get this wrong in the
1085 // other, unsafe direction.
1086 void markPossiblyMutated(const Decl *D) {
1087 if (!D || CurrentLocation != ZoneRelative::Inside)
1088 return;
1089 if (auto *DeclInfo = Info.getDeclInfoFor(D))
1090 DeclInfo->IsPossiblyMutated = true;
1091 }
1092 void markPossiblyMutated(const Expr *E) {
1093 llvm::SmallVector<const Decl *, 2> Decls;
1094 collectUnderlyingDecls(E, Decls);
1095 for (const Decl *D : Decls)
1096 markPossiblyMutated(D);
1097 }
1098
1099 bool VisitBinaryOperator(BinaryOperator *BO) {
1100 if (BO->isAssignmentOp())
1101 markPossiblyMutated(BO->getLHS());
1102 return true;
1103 }
1104
1105 bool VisitUnaryOperator(UnaryOperator *UO) {
1106 // FIXME: Try to track where the result of the address operator
1107 // ends up. If it's a const pointer, this is not a mutating access.
1108 if (UO->isIncrementDecrementOp() || UO->getOpcode() == UO_AddrOf)
1109 markPossiblyMutated(UO->getSubExpr());
1110 return true;
1111 }
1112
1113 bool VisitExplicitCastExpr(ExplicitCastExpr *ECE) {
1114 // An explicit cast to a non-const reference type allows mutating the
1115 // result as if it were a plain non-const reference.
1116 if (ECE->getType()->isReferenceType() &&
1117 !ECE->getType()->getPointeeType().isConstQualified())
1118 markPossiblyMutated(ECE->getSubExpr());
1119 return true;
1120 }
1121
1122 // Marks the object a non-const member function is (or may be) called
1123 // on, whether through `.`, `->`, or an overloaded operator. A static
1124 // method (possible since C++23 for operator() and operator[]) has no
1125 // `this` at all, so it never touches Object regardless of constness.
1126 void markPossiblyMutatedCallee(const Expr *Object,
1127 const CXXMethodDecl *Method) {
1128 if (Method && !Method->isStatic() && !Method->isConst())
1129 markPossiblyMutated(Object);
1130 }
1131
1132 // Marks the arguments of a call that bind to a non-const reference
1133 // parameter of Callee (a FunctionDecl or CXXConstructorDecl). If Callee
1134 // is null (e.g. a call through a function pointer), conservatively marks
1135 // every argument, since we don't know the parameter types.
1136 void markPossiblyMutatedArgs(ArrayRef<const Expr *> Args,
1137 const FunctionDecl *Callee) {
1138 for (unsigned I = 0; I < Args.size(); ++I) {
1139 if (!Callee || I >= Callee->getNumParams() ||
1140 (Callee->getParamDecl(I)->getType()->isReferenceType() &&
1141 !Callee->getParamDecl(I)
1142 ->getType()
1143 ->getPointeeType()
1144 .isConstQualified()))
1145 markPossiblyMutated(Args[I]);
1146 }
1147 }
1148
1149 bool VisitCXXMemberCallExpr(CXXMemberCallExpr *MCE) {
1150 markPossiblyMutatedCallee(MCE->getImplicitObjectArgument(),
1151 MCE->getMethodDecl());
1152 // getArgs() here is just the explicit argument list, without the
1153 // implicit object handled above, so it aligns directly with the
1154 // method's own parameters.
1155 markPossiblyMutatedArgs(
1156 llvm::ArrayRef<const Expr *>(MCE->getArgs(), MCE->getNumArgs()),
1157 MCE->getMethodDecl());
1158 return true;
1159 }
1160
1161 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *OCE) {
1162 // Unlike CXXMemberCallExpr, a member operator's implicit object is
1163 // args[0], not split out separately; args[1:] are the real
1164 // parameters. A non-member (free function) operator overload has no
1165 // implicit object at all, so all args align directly with params.
1166 // Every operator has at least one operand, but guard anyway since
1167 // the arithmetic below would underflow on an empty argument list.
1168 if (OCE->getNumArgs() == 0)
1169 return true;
1170 const auto *Method =
1171 dyn_cast_or_null<CXXMethodDecl>(OCE->getCalleeDecl());
1172 if (Method) {
1173 markPossiblyMutatedCallee(OCE->getArg(0), Method);
1174 markPossiblyMutatedArgs(llvm::ArrayRef<const Expr *>(
1175 OCE->getArgs() + 1, OCE->getNumArgs() - 1),
1176 Method);
1177 } else {
1178 markPossiblyMutatedArgs(
1179 llvm::ArrayRef<const Expr *>(OCE->getArgs(), OCE->getNumArgs()),
1180 OCE->getDirectCallee());
1181 }
1182 return true;
1183 }
1184
1185 bool VisitCallExpr(CallExpr *CE) {
1186 // Both are already fully handled by their own visitors above,
1187 // including their arguments: skip CXXMemberCallExpr here to avoid
1188 // redundant work (its getArgs()/getDirectCallee() would otherwise
1189 // align fine on their own), and skip CXXOperatorCallExpr because its
1190 // getArgs() includes the implicit object as args[0], which would
1191 // misalign against a member operator's real parameter list if
1192 // checked here too.
1193 if (isa<CXXMemberCallExpr>(CE) || isa<CXXOperatorCallExpr>(CE))
1194 return true;
1195 markPossiblyMutatedArgs(
1196 llvm::ArrayRef<const Expr *>(CE->getArgs(), CE->getNumArgs()),
1197 CE->getDirectCallee());
1198 return true;
1199 }
1200
1201 bool VisitCXXConstructExpr(CXXConstructExpr *CCE) {
1202 markPossiblyMutatedArgs(
1203 llvm::ArrayRef<const Expr *>(CCE->getArgs(), CCE->getNumArgs()),
1204 CCE->getConstructor());
1205 return true;
1206 }
1207
1208 bool VisitVarDecl(VarDecl *VD) {
1209 // A non-const reference bound to a captured Decl aliases it: treat any
1210 // such binding as a possible mutation, without checking whether the
1211 // reference itself is later mutated (see markPossiblyMutated). This
1212 // also covers reference structured bindings (DecompositionDecl is a
1213 // VarDecl), since binding `auto &[a, b] = x` conservatively counts as
1214 // aliasing all of `x`.
1215 if (VD->getType()->isReferenceType() &&
1216 !VD->getType()->getPointeeType().isConstQualified() && VD->hasInit())
1217 markPossiblyMutated(VD->getInit()->IgnoreParens());
1218 return true;
1219 }
1220
1221 bool VisitLambdaExpr(LambdaExpr *LE) {
1222 // Init-captures (`[r = x]`/`[&r = x]`) are handled by VisitVarDecl
1223 // above, since they introduce a real VarDecl visited independently.
1224 // This only needs to handle plain captures (`[&x]`/`[&]`), which don't.
1225 for (const LambdaCapture &C : LE->captures())
1226 if (C.capturesVariable() && C.getCaptureKind() == LCK_ByRef)
1227 markPossiblyMutated(C.getCapturedVar());
1228 return true;
1229 }
1230
1231 bool VisitCXXForRangeStmt(CXXForRangeStmt *FRS) {
1232 // Conservatively: a non-const reference (or pointer) loop variable
1233 // could mutate the range expression's elements, which -- like a
1234 // member/array-element write -- requires the range expression's own
1235 // Decl to be non-const if it's a value type (e.g. a plain array).
1236 // We don't check whether the loop variable is actually mutated, and we
1237 // don't special-case containers with const-qualified begin()/end():
1238 // those are visited like any other (possibly non-const) member call.
1239 QualType LoopVarType = FRS->getLoopVariable()->getType();
1240 if ((LoopVarType->isReferenceType() &&
1241 !LoopVarType->getPointeeType().isConstQualified()) ||
1242 (LoopVarType->isPointerType() &&
1243 !LoopVarType->getPointeeType().isConstQualified()))
1244 if (const Expr *RangeInit = FRS->getRangeInit())
1245 markPossiblyMutated(RangeInit);
1246 return true;
1247 }
1248
1249 bool VisitReturnStmt(ReturnStmt *Return) {
1250 if (CurrentLocation == ZoneRelative::Inside) {
1251 Info.HasReturnStmt = true;
1252 // Conservatively treat returning a captured Decl as a possible
1253 // mutation, regardless of whether the return is actually by value
1254 // (safe) or by non-const reference (not safe). Telling these apart
1255 // needs the extracted function's return type, which is only
1256 // decided later in generateReturnProperties(); duplicating its
1257 // logic here would couple two distant functions for little gain,
1258 // since directly returning a capture is rare.
1259 if (const Expr *RV = Return->getRetValue())
1260 markPossiblyMutated(RV);
1261 }
1262 return true;
1263 }
1264
1265 bool VisitBreakStmt(BreakStmt *Break) {
1266 // Control flow is broken if break statement is selected without any
1267 // parent loop or switch statement.
1268 if (CurrentLocation == ZoneRelative::Inside &&
1269 !(CurNumberOfNestedLoops || CurNumberOfSwitch))
1270 Info.BrokenControlFlow = true;
1271 return true;
1272 }
1273
1274 bool VisitContinueStmt(ContinueStmt *Continue) {
1275 // Control flow is broken if Continue statement is selected without any
1276 // parent loop
1277 if (CurrentLocation == ZoneRelative::Inside && !CurNumberOfNestedLoops)
1278 Info.BrokenControlFlow = true;
1279 return true;
1280 }
1281 CapturedZoneInfo Info;
1282 const ExtractionZone &ExtZone;
1283 ZoneRelative CurrentLocation = ZoneRelative::Before;
1284 // Number of {loop,switch} statements that are currently in the traversal
1285 // stack inside Extraction Zone. Used to check for broken control flow.
1286 unsigned CurNumberOfNestedLoops = 0;
1287 unsigned CurNumberOfSwitch = 0;
1288 };
1289 ExtractionZoneVisitor Visitor(ExtZone);
1290 CapturedZoneInfo Result = std::move(Visitor.Info);
1291 Result.AlwaysReturns = alwaysReturns(ExtZone);
1292 return Result;
1293}
1294
1295// Adds parameters to ExtractedFunc.
1296// Returns true if able to find the parameters successfully and no hoisting
1297// needed.
1298// FIXME: Check if the declaration has a local/anonymous type
1299bool createParameters(NewFunction &ExtractedFunc,
1300 const CapturedZoneInfo &CapturedInfo,
1301 const ASTContext &Context, const LangOptions &LangOpts) {
1302 for (const auto &KeyVal : CapturedInfo.DeclInfoMap) {
1303 const auto &DeclInfo = KeyVal.second;
1304 // If a Decl was Declared in zone and referenced in post zone, it
1305 // needs to be hoisted (we bail out in that case).
1306 // FIXME: Support Decl Hoisting.
1307 if (DeclInfo.DeclaredIn == ZoneRelative::Inside &&
1308 DeclInfo.IsReferencedInPostZone)
1309 return false;
1310 if (!DeclInfo.IsReferencedInZone)
1311 continue; // no need to pass as parameter, not referenced
1312 if (DeclInfo.DeclaredIn == ZoneRelative::Inside ||
1313 DeclInfo.DeclaredIn == ZoneRelative::OutsideFunc)
1314 continue; // no need to pass as parameter, still accessible.
1315 // Parameter specific checks.
1316 const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(DeclInfo.TheDecl);
1317 // Can't parameterise if the Decl isn't a ValueDecl or is a FunctionDecl
1318 // (this includes the case of recursive call to EnclosingFunc in Zone).
1319 if (!VD || isa<FunctionDecl>(DeclInfo.TheDecl))
1320 return false;
1321 // Parameter qualifiers are same as the Decl's qualifiers.
1322 QualType FullTypeInfo = VD->getType();
1323 QualType TypeInfo = FullTypeInfo.getNonReferenceType();
1324
1325 // A variably-modified type is rejected outright unless it's a plain
1326 // array being extracted in C: a reference's (or any other wrapping,
1327 // e.g. a further pointer indirection's) declared type still spells
1328 // out the bound at every level, so it keeps mentioning a name
1329 // (typically some other variable's) that isn't in scope in the
1330 // extracted function's declaration. A plain array in C is the one
1331 // case this doesn't apply to as-is, since its outer dimension is
1332 // specifically not a problem once decayed to a pointer -- that
1333 // gets a narrower, more precise check further down instead.
1334 if (TypeInfo->isVariablyModifiedType() &&
1335 (LangOpts.CPlusPlus || !TypeInfo->isArrayType()))
1336 return false;
1337
1338 // FIXME: check if parameter will be a non l-value reference.
1339 ParamPassKind Kind = ParamPassKind::Reference;
1340 if (!DeclInfo.IsPossiblyMutated) {
1341 auto WordSize = Context.getTypeSizeInChars(Context.VoidPtrTy);
1342 // A scalar (arithmetic, pointer, enumeration, ...) is at least as
1343 // cheap to copy as to pass by reference, and less noisy.
1344 if (TypeInfo->isScalarType() && !TypeInfo.isVolatileQualified() &&
1345 !FullTypeInfo->isReferenceType() &&
1346 Context.getTypeSizeInChars(TypeInfo) <= 2 * WordSize) {
1347 Kind = ParamPassKind::Value;
1348 } else if (!TypeInfo->isArrayType() && !TypeInfo->isFunctionType()) {
1349 // Still passed by reference to avoid a copy, but the reference
1350 // doesn't need to be mutable. Array types are never made const:
1351 // mutating array elements through a non-const-ref loop variable
1352 // or a decayed pointer argument is common and easy to miss
1353 // conservatively, so we don't try. A (non-pointer) function type
1354 // can't be cv-qualified at all -- doing so anyway produces
1355 // unparseable output, e.g. `void (const &F)(int)` for a
1356 // captured function reference.
1357 TypeInfo.addConst();
1358 }
1359 }
1360
1361 // C has no references. A parameter that would otherwise need one
1362 // becomes a real pointer instead: the call site takes the address of
1363 // the original variable explicitly, and every use of it in the
1364 // copied-out body is rewritten into a dereference (see
1365 // NewFunction::getFuncBody). Array types are the exception: they decay
1366 // to a pointer on their own wherever they're used, so no rewriting or
1367 // address-of is needed for them at all -- except that TypeInfo itself
1368 // must still be decayed explicitly (confirmed empirically): unlike a
1369 // pointer or reference, printType()'s declarator placeholder doesn't
1370 // thread correctly through a *bare* array type on its own, printing
1371 // the uncompilable `int[5] name` instead of `int name[5]`.
1372 if (Kind == ParamPassKind::Reference && !LangOpts.CPlusPlus) {
1373 if (TypeInfo->isArrayType()) {
1374 // A decayed pointer no longer reports the array's own size,
1375 // alignment, or type: bail out rather than silently break a
1376 // sizeof/alignof/typeof (or similar) on it.
1377 if (DeclInfo.HasUnsafeTypeQueryUseInZone)
1378 return false;
1379 QualType Decayed = Context.getArrayDecayedType(TypeInfo);
1380 // The array's own outermost dimension is never a problem, VLA
1381 // or not: once decayed, it no longer appears in the type at
1382 // all (`int A[N]` decays to plain `int *A`). An inner
1383 // dimension that's still variable-length (e.g. the `N` in
1384 // `int A[2][N]`, which decays to `int (*A)[N]`) is the actual
1385 // hazard: its bound is an arbitrary expression, typically just
1386 // some other variable's name, that isn't necessarily (and
1387 // often isn't) also a parameter of the extracted function, and
1388 // even if it is, a mutated one would itself have been turned
1389 // into a pointer, which the bound expression can't account for
1390 // either way. Bail out rather than risk printing a parameter
1391 // type that references a name meaningless (or absent) in the
1392 // new scope.
1393 if (Decayed->getPointeeType()->isVariablyModifiedType())
1394 return false;
1395 TypeInfo = Decayed;
1396 Kind = ParamPassKind::Value;
1397 } else {
1398 // Bail out rather than rewrite a use whose location (or, for a
1399 // member-access rewrite, whose dot's location) can't be mapped
1400 // back to a single, unambiguous spot in the source (e.g. one
1401 // produced by macro expansion) -- the dot can be a macro
1402 // expansion even when the identifier itself isn't, e.g.
1403 // `#define DOT .` used as `s DOT x`.
1404 if (llvm::any_of(
1405 DeclInfo.ZoneOccurrences,
1406 [](const CapturedZoneInfo::DeclInformation::Occurrence &O) {
1407 return O.Loc.isMacroID() ||
1408 (O.DotLoc && O.DotLoc->isMacroID());
1409 }))
1410 return false;
1411 TypeInfo = Context.getPointerType(TypeInfo);
1412 Kind = ParamPassKind::Pointer;
1413 unsigned NameLength = VD->getName().size();
1414 for (const auto &Occ : DeclInfo.ZoneOccurrences)
1415 ExtractedFunc.PointerRewriteSites.push_back(
1416 {Occ.Loc, NameLength, Occ.DotLoc});
1417 }
1418 }
1419
1420 // We use the index of declaration as the ordering priority for parameters.
1421 ExtractedFunc.Parameters.push_back(
1422 {std::string(VD->getName()), TypeInfo, Kind, DeclInfo.DeclIndex});
1423 }
1424 llvm::sort(ExtractedFunc.Parameters);
1425 return true;
1426}
1427
1428// Clangd uses open ranges while ExtractionSemicolonPolicy (in Clang Tooling)
1429// uses closed ranges. Generates the semicolon policy for the extraction and
1430// extends the ZoneRange if necessary.
1431tooling::ExtractionSemicolonPolicy
1432getSemicolonPolicy(ExtractionZone &ExtZone, const SourceManager &SM,
1433 const LangOptions &LangOpts) {
1434 // Get closed ZoneRange.
1435 SourceRange FuncBodyRange = {ExtZone.ZoneRange.getBegin(),
1436 ExtZone.ZoneRange.getEnd().getLocWithOffset(-1)};
1437 auto SemicolonPolicy = tooling::ExtractionSemicolonPolicy::compute(
1438 ExtZone.getLastRootStmt()->ASTNode.get<Stmt>(), FuncBodyRange, SM,
1439 LangOpts);
1440 // Update ZoneRange.
1441 ExtZone.ZoneRange.setEnd(FuncBodyRange.getEnd().getLocWithOffset(1));
1442 return SemicolonPolicy;
1443}
1444
1445// Generate return type for ExtractedFunc. Return false if unable to do so.
1446bool generateReturnProperties(NewFunction &ExtractedFunc,
1447 const FunctionDecl &EnclosingFunc,
1448 const CapturedZoneInfo &CapturedInfo) {
1449 // If the selected code always returns, we preserve those return statements.
1450 // The return type should be the same as the enclosing function.
1451 // (Others are possible if there are conversions, but this seems clearest).
1452 if (CapturedInfo.HasReturnStmt) {
1453 // If the return is conditional, neither replacing the code with
1454 // `extracted()` nor `return extracted()` is correct.
1455 if (!CapturedInfo.AlwaysReturns)
1456 return false;
1457 QualType Ret = EnclosingFunc.getReturnType();
1458 // Once we support members, it'd be nice to support e.g. extracting a method
1459 // of Foo<T> that returns T. But it's not clear when that's safe.
1460 if (Ret->isDependentType())
1461 return false;
1462 ExtractedFunc.ReturnType = Ret;
1463 return true;
1464 }
1465 // FIXME: Generate new return statement if needed.
1466 ExtractedFunc.ReturnType = EnclosingFunc.getParentASTContext().VoidTy;
1467 return true;
1468}
1469
1470void captureMethodInfo(NewFunction &ExtractedFunc,
1471 const CXXMethodDecl *Method) {
1472 ExtractedFunc.Static = Method->isStatic();
1473 ExtractedFunc.Const = Method->isConst();
1474 ExtractedFunc.EnclosingClass = Method->getParent();
1475}
1476
1477// FIXME: add support for adding other function return types besides void.
1478// FIXME: assign the value returned by non void extracted function.
1479llvm::Expected<NewFunction> getExtractedFunction(ExtractionZone &ExtZone,
1480 const SourceManager &SM,
1481 const LangOptions &LangOpts) {
1482 CapturedZoneInfo CapturedInfo = captureZoneInfo(ExtZone);
1483 // Bail out if any break of continue exists
1484 if (CapturedInfo.BrokenControlFlow)
1485 return error("Cannot extract break/continue without corresponding "
1486 "loop/switch statement.");
1487 NewFunction ExtractedFunc(getSemicolonPolicy(ExtZone, SM, LangOpts),
1488 &LangOpts);
1489
1490 ExtractedFunc.SyntacticDC =
1491 ExtZone.EnclosingFunction->getLexicalDeclContext();
1492 ExtractedFunc.SemanticDC = ExtZone.EnclosingFunction->getDeclContext();
1493 ExtractedFunc.DefinitionQualifier = ExtZone.EnclosingFunction->getQualifier();
1494 ExtractedFunc.Constexpr = ExtZone.EnclosingFunction->getConstexprKind();
1495
1496 // A free function declared `static` has internal linkage: an extracted
1497 // sibling should keep that, or it'd default to external linkage instead.
1498 // Checked on the canonical (first) declaration, not this one: a
1499 // definition following an earlier `static` forward declaration doesn't
1500 // need to (and often doesn't) repeat `static` itself, but is still
1501 // static. For a method, this gets overridden just below by the more
1502 // precise (and differently-meaning) CXXMethodDecl::isStatic().
1503 ExtractedFunc.Static =
1504 ExtZone.EnclosingFunction->getCanonicalDecl()->getStorageClass() ==
1505 SC_Static;
1506 if (const auto *Method =
1507 llvm::dyn_cast<CXXMethodDecl>(ExtZone.EnclosingFunction))
1508 captureMethodInfo(ExtractedFunc, Method);
1509
1510 if (ExtZone.EnclosingFunction->isOutOfLine()) {
1511 // FIXME: Put the extracted method in a private section if it's a class or
1512 // maybe in an anonymous namespace
1513 const auto *FirstOriginalDecl =
1514 ExtZone.EnclosingFunction->getCanonicalDecl();
1515 auto DeclPos =
1516 toHalfOpenFileRange(SM, LangOpts, FirstOriginalDecl->getSourceRange());
1517 if (!DeclPos)
1518 return error("Declaration is inside a macro");
1519 ExtractedFunc.ForwardDeclarationPoint = DeclPos->getBegin();
1520 ExtractedFunc.ForwardDeclarationSyntacticDC = ExtractedFunc.SemanticDC;
1521 }
1522
1523 ExtractedFunc.BodyRange = ExtZone.ZoneRange;
1524 ExtractedFunc.DefinitionPoint = ExtZone.getInsertionPoint();
1525
1526 ExtractedFunc.CallerReturnsValue = CapturedInfo.AlwaysReturns;
1527 if (!createParameters(ExtractedFunc, CapturedInfo,
1528 ExtZone.EnclosingFunction->getASTContext(), LangOpts) ||
1529 !generateReturnProperties(ExtractedFunc, *ExtZone.EnclosingFunction,
1530 CapturedInfo))
1531 return error("Too complex to extract.");
1532 return ExtractedFunc;
1533}
1534
1535class ExtractFunction : public Tweak {
1536public:
1537 const char *id() const final;
1538 bool prepare(const Selection &Inputs) override;
1539 Expected<Effect> apply(const Selection &Inputs) override;
1540 std::string title() const override { return "Extract to function"; }
1541 llvm::StringLiteral kind() const override {
1542 return CodeAction::REFACTOR_KIND;
1543 }
1544
1545private:
1546 ExtractionZone ExtZone;
1547};
1548
1549REGISTER_TWEAK(ExtractFunction)
1550tooling::Replacement replaceWithFuncCall(const NewFunction &ExtractedFunc,
1551 const SourceManager &SM,
1552 const LangOptions &LangOpts) {
1553 std::string FuncCall = ExtractedFunc.renderCall();
1554 return tooling::Replacement(
1555 SM, CharSourceRange(ExtractedFunc.BodyRange, false), FuncCall, LangOpts);
1556}
1557
1558llvm::Expected<tooling::Replacement>
1559createFunctionDefinition(const NewFunction &ExtractedFunc,
1560 const SourceManager &SM) {
1561 FunctionDeclKind DeclKind = InlineDefinition;
1562 if (ExtractedFunc.ForwardDeclarationPoint)
1563 DeclKind = OutOfLineDefinition;
1564 llvm::Expected<std::string> FunctionDef = ExtractedFunc.renderDeclaration(
1565 DeclKind, *ExtractedFunc.SemanticDC, *ExtractedFunc.SyntacticDC, SM);
1566 if (!FunctionDef)
1567 return FunctionDef.takeError();
1568
1569 return tooling::Replacement(SM, ExtractedFunc.DefinitionPoint, 0,
1570 *FunctionDef);
1571}
1572
1573llvm::Expected<tooling::Replacement>
1574createForwardDeclaration(const NewFunction &ExtractedFunc,
1575 const SourceManager &SM) {
1576 llvm::Expected<std::string> FunctionDecl = ExtractedFunc.renderDeclaration(
1577 ForwardDeclaration, *ExtractedFunc.SemanticDC,
1578 *ExtractedFunc.ForwardDeclarationSyntacticDC, SM);
1579 if (!FunctionDecl)
1580 return FunctionDecl.takeError();
1581 SourceLocation DeclPoint = *ExtractedFunc.ForwardDeclarationPoint;
1582
1583 return tooling::Replacement(SM, DeclPoint, 0, *FunctionDecl);
1584}
1585
1586// Returns true if ExtZone contains any ReturnStmts.
1587bool hasReturnStmt(const ExtractionZone &ExtZone) {
1588 class ReturnStmtVisitor
1589 : public clang::RecursiveASTVisitor<ReturnStmtVisitor> {
1590 public:
1591 bool VisitReturnStmt(ReturnStmt *Return) {
1592 Found = true;
1593 return false; // We found the answer, abort the scan.
1594 }
1595 bool Found = false;
1596 };
1597
1598 ReturnStmtVisitor V;
1599 for (const Stmt *RootStmt : ExtZone.RootStmts) {
1600 V.TraverseStmt(const_cast<Stmt *>(RootStmt));
1601 if (V.Found)
1602 break;
1603 }
1604 return V.Found;
1605}
1606
1607bool ExtractFunction::prepare(const Selection &Inputs) {
1608 const LangOptions &LangOpts = Inputs.AST->getLangOpts();
1609 const Node *CommonAnc = Inputs.ASTSelection.commonAncestor();
1610 const SourceManager &SM = Inputs.AST->getSourceManager();
1611 auto MaybeExtZone = findExtractionZone(CommonAnc, SM, LangOpts);
1612 if (!MaybeExtZone ||
1613 (hasReturnStmt(*MaybeExtZone) && !alwaysReturns(*MaybeExtZone)))
1614 return false;
1615
1616 // FIXME: Get rid of this check once we support hoisting.
1617 if (MaybeExtZone->requiresHoisting(SM, Inputs.AST->getHeuristicResolver()))
1618 return false;
1619
1620 ExtZone = std::move(*MaybeExtZone);
1621 return true;
1622}
1623
1624Expected<Tweak::Effect> ExtractFunction::apply(const Selection &Inputs) {
1625 const SourceManager &SM = Inputs.AST->getSourceManager();
1626 const LangOptions &LangOpts = Inputs.AST->getLangOpts();
1627 auto ExtractedFunc = getExtractedFunction(ExtZone, SM, LangOpts);
1628 // FIXME: Add more types of errors.
1629 if (!ExtractedFunc)
1630 return ExtractedFunc.takeError();
1631 tooling::Replacements Edit;
1632 auto FuncDef = createFunctionDefinition(*ExtractedFunc, SM);
1633 if (!FuncDef)
1634 return FuncDef.takeError();
1635 if (auto Err = Edit.add(*FuncDef))
1636 return std::move(Err);
1637 if (auto Err = Edit.add(replaceWithFuncCall(*ExtractedFunc, SM, LangOpts)))
1638 return std::move(Err);
1639
1640 if (auto FwdLoc = ExtractedFunc->ForwardDeclarationPoint) {
1641 // If the fwd-declaration goes in the same file, merge into Replacements.
1642 // Otherwise it needs to be a separate file edit.
1643 if (SM.isWrittenInSameFile(ExtractedFunc->DefinitionPoint, *FwdLoc)) {
1644 auto FwdDecl = createForwardDeclaration(*ExtractedFunc, SM);
1645 if (!FwdDecl)
1646 return FwdDecl.takeError();
1647 if (auto Err = Edit.add(*FwdDecl))
1648 return std::move(Err);
1649 } else {
1650 auto MultiFileEffect = Effect::mainFileEdit(SM, std::move(Edit));
1651 if (!MultiFileEffect)
1652 return MultiFileEffect.takeError();
1653
1654 auto FwdDecl = createForwardDeclaration(*ExtractedFunc, SM);
1655 if (!FwdDecl)
1656 return FwdDecl.takeError();
1657 tooling::Replacements OtherEdit(*FwdDecl);
1658 if (auto PathAndEdit =
1659 Tweak::Effect::fileEdit(SM, SM.getFileID(*FwdLoc), OtherEdit))
1660 MultiFileEffect->ApplyEdits.try_emplace(PathAndEdit->first,
1661 PathAndEdit->second);
1662 else
1663 return PathAndEdit.takeError();
1664 return MultiFileEffect;
1665 }
1666 }
1667 return Effect::mainFileEdit(SM, std::move(Edit));
1668}
1669
1670} // namespace
1671} // namespace clangd
1672} // namespace clang
#define REGISTER_TWEAK(Subclass)
Definition Tweak.h:129
llvm::Error error(std::error_code, std::string &&)
Definition Logger.cpp:80
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
@ Info
An information message.
Definition Protocol.h:755
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
std::string printType(const QualType QT, const DeclContext &CurContext, const llvm::StringRef Placeholder, bool FullyQualify)
Returns a QualType as string.
Definition AST.cpp:417
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R)
Returns the source code covered by the source range.
bool operator<(const Ref &L, const Ref &R)
Definition Ref.h:98
@ Parameter
An inlay hint that is for a parameter.
Definition Protocol.h:1752
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//