Repository navigation
Add Extract to function and Extract to private member refactorings - #20538
xperiandri wants to merge 35 commits into
Conversation
✅ Release notes checked
|
9689259 to
dc118df
Compare
This comment has been minimized.
This comment has been minimized.
T-Gro
left a comment
There was a problem hiding this comment.
🤖🕵️ Please shorten the description using this guidance. Focus on the problem and why the change is needed, in simplified technical English. Leave the implementation inventory to the Files tab and retain necessary caveats.
Covered casesOffered
Not offered
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…tion Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- See a byref-like type through a type abbreviation. - Do not offer when the selection reads a generic local function, or a mutable local inside a lambda or other delayed code. - No local function for a selection using this of a struct. - No module function, and no private member for a type parameter of the member, when the selection names a type parameter from outside. - No module function or private member called from an inline function or member that is not private. - No private member where a local of the member hides the self identifier; keep the backticks of the self identifier and type name. - Parenthesize the call that is the receiver of an assignment. - Under WhenNeeded, annotate the arguments of methods and constructors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
T-Gro
left a comment
There was a problem hiding this comment.
The diff is still way too big - apply the NoBloat instructions and CodeCompaction skill.
Especially the massive code comments would benefit not just with drastic reduction, but ideally with well named functions/arguments/bindings/types making the intention clear.
If a well named piece of code just tells what the comment says - delete the comment.
- This diff adds 63 new code comment lines and 5702 new code comment chars.
ComputeRefactoringsAsyncinExtractFunction.fs:370-465reaches 6 nested control-flow levels.- Tests would benefit from deduplicated setup or code-as-test reuse:
ExtractFunctionTests.fsandExtractLetBindingTests.fscopy dozens of single-case[<Fact>]methods with repeatedmodule Msetup instead of using parameterized tests.
…g or a literal The selected expression is bound to a new name in front of the statement that uses it: above a statement that starts its line, or, when the body of a binding, match clause, branch or lambda shares the line with its keyword, on new lines under that keyword. A constant inside a module-level declaration can instead become a [<Literal>] in front of that declaration. The shared selection and placement logic lives in Refactor/RefactoringHelpers.fs, and the refactoring test framework gains helpers that run a provider on a selected span. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
C# offers Introduce Constant without a selection. With a caret alone only the literal is offered; a let binding still needs a selection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A caret between 'fun' and the end of '->' acts as a selection of the parenthesized lambda; in the body a caret offers nothing new. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e of its section Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…on's way The name collector now also records the heads of assignment targets, so the new local cannot shadow a value the selection's statement assigns to. Lines inside multi-line strings of inactive #if branches are found by lexing each inactive branch as the code it is when taken, and are not re-indented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to literal - Annotate an extracted lambda or function expression with the type its context gave it, unless that type has a variable inference introduced. - Do not extract from inside assert, the operand of nameof, or a parenthesized name, address-of or named argument. - Bind an expression of a finally block inside that block. - Indent a body moved under its keyword from the let, match, try, if or loop that starts inside the line. - Offer the literal for decimal constants and not for native integers. - Qualify the generated Literal attribute where another LiteralAttribute hides the FSharp.Core one. - Do not offer the literal where the module-level let does not start its line. - Reserve every identifier of a long pattern when picking a new name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ected inside its parentheses The checker records the type of the parenthesized expression, so a lambda selected without the parentheses around it takes the type from them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion-refactoring Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Replace the explanatory comments with names, keep the document state of an extraction and the registration of its code actions in one record and one function, flatten the provider and the declaration builders to two levels of nesting, and scan the rest of a line for closing brackets without copying it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
One theory per kind of assertion with a scenario name per row. The module wrapper, the selection and caret spans, the refactored text and the offered titles move to the refactoring test framework, where the Extract to function tests can use them too. Every case is kept; tests that asserted several things became one row per assertion, so 64 cases became 74. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Both sides had the same Extract to let binding code; the merge takes the compacted helpers, providers and tests of feature/extract-let-binding-refactoring and keeps the resource strings of both branches. ExtractFunction.fs only follows the renamed target spans and the shared Extraction record; it is compacted in the next commits. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Replace the explanatory comments with names, give the symbol classification of the captures active patterns instead of five nested matches, split the three variants and the provider into functions that nest at most two levels, and drop the duplicated registration, padding and state gathering in favour of the shared Extraction record. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
One theory per kind of assertion with a scenario name per row, on the helpers the Extract to let binding tests share. Every case is kept; tests that asserted several things became one row per assertion, so 35 cases became 38. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Merged the compacted base of #20537 (1711de9) in 5aabbc8 and compacted this PR's own code in 204be8f ( |
T-Gro
left a comment
There was a problem hiding this comment.
🤖🕵️ AI review — verify independently.
| let application = $"{name} {curriedParameters never captures.Parameters}" | ||
|
|
||
| struct {| | ||
| Header = $"{name} {curriedParameters annotate captures.Parameters}" |
There was a problem hiding this comment.
🤖🕵️ Default extraction loses the lambda's contextual type and fails type checking.
let f (xs: string list) =
xs |> List.map (fun x -> x.Length)|
|
||
| match tryCaptures extraction.CheckResults selection declaration extraction.Context.CancellationToken with | ||
| | ValueSome captures when | ||
| not (assignsCapturedValue target.Expr captures.Parameters) |
There was a problem hiding this comment.
🤖🕵️ Extraction copies mutable storage; the result changes from 1 to 0.
let f () =
let mutable n = 0
let bump () = n <- n + 1
(bump (); n)| } | ||
|
|
||
| true | ||
| | (false, _), Some fullType when not (isByRefLike fullType) && value.GenericParameters.Count = 0 -> |
There was a problem hiding this comment.
🤖🕵️ Extraction copies a mutable struct receiver; the result changes from 2 to 1.
[<Struct>]
type S =
val mutable X: int
new(x) = { X = x }
member self.Inc() = self.X <- self.X + 1Port of the dotnet#20537 compaction (feature/extract-let-binding-refactoring 2920e42..1711de9) to all-fixes: - Compact the Extract to let binding code and name what its comments said - Fold the Extract to let binding tests into parameterized theories Extract to function (dotnet#20538) shares RefactoringHelpers.fs, so its callers follow the renames here, as in the pull request's merge of this head. The refactoring test framework carries the helpers of both the Extract and the tuple/record test suites on all-fixes. The caret helper of the Extract suites, which returns a TextSpan and reads a `|` in the marker, is therefore named caretSpanAt; the existing caretAt of the conversion suites keeps returning the index of the marker. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the dotnet#20538 compaction (feature/extract-function-refactoring 838b68d..b4cccb8) to all-fixes. The part of that range which merges the compacted Extract to let binding (dotnet#20537) came with the previous commit; this one carries what is specific to Extract to function: - Compact the Extract to function code and name what its comments said - Fold the Extract to function tests into parameterized theories The tests use caretSpanAt, the name the Extract suites' caret helper has in the shared refactoring test framework on all-fixes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the dotnet#20537 compaction (feature/extract-let-binding-refactoring 2920e42..1711de9) to all-fixes: - Compact the Extract to let binding code and name what its comments said - Fold the Extract to let binding tests into parameterized theories Extract to function (dotnet#20538) shares RefactoringHelpers.fs, so its callers follow the renames here, as in the pull request's merge of this head. The refactoring test framework carries the helpers of both the Extract and the tuple/record test suites on all-fixes. The caret helper of the Extract suites, which returns a TextSpan and reads a `|` in the marker, is therefore named caretSpanAt; the existing caretAt of the conversion suites keeps returning the index of the marker. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the dotnet#20538 compaction (feature/extract-function-refactoring 838b68d..b4cccb8) to all-fixes. The part of that range which merges the compacted Extract to let binding (dotnet#20537) came with the previous commit; this one carries what is specific to Extract to function: - Compact the Extract to function code and name what its comments said - Fold the Extract to function tests into parameterized theories The tests use caretSpanAt, the name the Extract suites' caret helper has in the shared refactoring test framework on all-fixes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the dotnet#20537 compaction (feature/extract-let-binding-refactoring 2920e42..1711de9) to all-fixes: - Compact the Extract to let binding code and name what its comments said - Fold the Extract to let binding tests into parameterized theories Extract to function (dotnet#20538) shares RefactoringHelpers.fs, so its callers follow the renames here, as in the pull request's merge of this head. The refactoring test framework carries the helpers of both the Extract and the tuple/record test suites on all-fixes. The caret helper of the Extract suites, which returns a TextSpan and reads a `|` in the marker, is therefore named caretSpanAt; the existing caretAt of the conversion suites keeps returning the index of the marker. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the dotnet#20538 compaction (feature/extract-function-refactoring 838b68d..b4cccb8) to all-fixes. The part of that range which merges the compacted Extract to let binding (dotnet#20537) came with the previous commit; this one carries what is specific to Extract to function: - Compact the Extract to function code and name what its comments said - Fold the Extract to function tests into parameterized theories The tests use caretSpanAt, the name the Extract suites' caret helper has in the shared refactoring test framework on all-fixes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the dotnet#20537 compaction (feature/extract-let-binding-refactoring 2920e42..1711de9) to all-fixes: - Compact the Extract to let binding code and name what its comments said - Fold the Extract to let binding tests into parameterized theories Extract to function (dotnet#20538) shares RefactoringHelpers.fs, so its callers follow the renames here, as in the pull request's merge of this head. The refactoring test framework carries the helpers of both the Extract and the tuple/record test suites on all-fixes. The caret helper of the Extract suites, which returns a TextSpan and reads a `|` in the marker, is therefore named caretSpanAt; the existing caretAt of the conversion suites keeps returning the index of the marker. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Port of the dotnet#20538 compaction (feature/extract-function-refactoring 838b68d..b4cccb8) to all-fixes. The part of that range which merges the compacted Extract to let binding (dotnet#20537) came with the previous commit; this one carries what is specific to Extract to function: - Compact the Extract to function code and name what its comments said - Fold the Extract to function tests into parameterized theories The tests use caretSpanAt, the name the Extract suites' caret helper has in the shared refactoring test framework on all-fixes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Stacked on #20537.
Offers
Ctrl+.on a selected expression to move it into a local function, a module function, or, when it usesthisorbase, a private member. Values the selection reads from the enclosing function become parameters in first-use order.Parameters are annotated by default because the new function is its own generalization point; the new Parameter types in Extract to function option under Code Fixes can relax that. Not offered when the selection assigns to a captured
mutableor reads a byref value.🤖 Generated with Claude Code