Skip to content

Commit 803f0e7

Browse files
authored
Merge main to release/dev17.8 (#16018)
2 parents c57ae10 + 638becf commit 803f0e7

File tree

5 files changed

+103
-34
lines changed

5 files changed

+103
-34
lines changed

vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ module internal CodeFixHelpers =
8282
reportCodeFixTelemetry context.Diagnostics context.Document codeFix.Name [||]
8383
return doc
8484
}
85-
|> CancellableTask.start cancellationToken),
86-
codeFix.Name
85+
|> CancellableTask.start cancellationToken)
8786
)
8887

8988
[<AutoOpen>]
@@ -100,6 +99,16 @@ module internal CodeFixExtensions =
10099
}
101100
|> CancellableTask.startAsTask ctx.CancellationToken
102101

102+
member ctx.RegisterFsharpFixes(codeFix: IFSharpMultiCodeFixProvider) =
103+
cancellableTask {
104+
let! codeFixes = codeFix.GetCodeFixesAsync ctx
105+
106+
for codeFix in codeFixes do
107+
let codeAction = CodeFixHelpers.createTextChangeCodeFix (codeFix, ctx)
108+
ctx.RegisterCodeFix(codeAction, ctx.Diagnostics)
109+
}
110+
|> CancellableTask.startAsTask ctx.CancellationToken
111+
103112
member ctx.GetSourceTextAsync() =
104113
cancellableTask {
105114
let! cancellationToken = CancellableTask.getCancellationToken ()

vsintegration/src/FSharp.Editor/CodeFixes/IFSharpCodeFix.fs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,10 @@ type FSharpCodeFix =
1414
Changes: TextChange list
1515
}
1616

17+
/// Provider can generate at most 1 suggestion.
1718
type IFSharpCodeFixProvider =
1819
abstract member GetCodeFixIfAppliesAsync: context: CodeFixContext -> CancellableTask<FSharpCodeFix voption>
20+
21+
/// Provider can generate multiple suggestions.
22+
type IFSharpMultiCodeFixProvider =
23+
abstract member GetCodeFixesAsync: context: CodeFixContext -> CancellableTask<FSharpCodeFix seq>

vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ type internal ReplaceWithSuggestionCodeFixProvider [<ImportingConstructor>] () =
2323

2424
override this.RegisterCodeFixesAsync context =
2525
if context.Document.Project.IsFSharpCodeFixesSuggestNamesForErrorsEnabled then
26-
context.RegisterFsharpFix this
26+
context.RegisterFsharpFixes this
2727
else
2828
Task.CompletedTask
2929

30-
interface IFSharpCodeFixProvider with
31-
member _.GetCodeFixIfAppliesAsync context =
30+
interface IFSharpMultiCodeFixProvider with
31+
member _.GetCodeFixesAsync context =
3232
cancellableTask {
3333
let! parseFileResults, checkFileResults =
3434
context.Document.GetFSharpParseAndCheckResultsAsync(nameof ReplaceWithSuggestionCodeFixProvider)
@@ -49,20 +49,14 @@ type internal ReplaceWithSuggestionCodeFixProvider [<ImportingConstructor>] () =
4949
for item in declInfo.Items do
5050
addToBuffer item.NameInList
5151

52-
let suggestionOpt =
52+
return
5353
CompilerDiagnostics.GetSuggestedNames addNames unresolvedIdentifierText
54-
|> Seq.tryHead
55-
56-
match suggestionOpt with
57-
| None -> return ValueNone
58-
| Some suggestion ->
59-
let replacement = PrettyNaming.NormalizeIdentifierBackticks suggestion
60-
61-
return
62-
ValueSome
63-
{
64-
Name = CodeFix.ReplaceWithSuggestion
65-
Message = CompilerDiagnostics.GetErrorMessage(FSharpDiagnosticKind.ReplaceWithSuggestion suggestion)
66-
Changes = [ TextChange(context.Span, replacement) ]
67-
}
54+
|> Seq.map (fun suggestion ->
55+
let replacement = PrettyNaming.NormalizeIdentifierBackticks suggestion
56+
57+
{
58+
Name = CodeFix.ReplaceWithSuggestion
59+
Message = CompilerDiagnostics.GetErrorMessage(FSharpDiagnosticKind.ReplaceWithSuggestion suggestion)
60+
Changes = [ TextChange(context.Span, replacement) ]
61+
})
6862
}

vsintegration/tests/FSharp.Editor.Tests/CodeFixes/CodeFixTestFramework.fs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,13 @@ let getRelevantDiagnostics (document: Document) =
5656
|> CancellableTask.startWithoutCancellation
5757
|> fun task -> task.Result
5858

59-
let createTestCodeFixContext (code: string) document (mode: Mode) diagnosticIds =
59+
let createTestCodeFixContext (code: string) (mode: Mode) (fixProvider: 'T :> CodeFixProvider) =
6060
cancellableTask {
6161
let! cancellationToken = CancellableTask.getCancellationToken ()
6262

6363
let sourceText = SourceText.From code
64+
let document = getDocument code mode
65+
let diagnosticIds = fixProvider.FixableDiagnosticIds
6466

6567
let diagnostics =
6668
match mode with
@@ -92,12 +94,11 @@ let createTestCodeFixContext (code: string) document (mode: Mode) diagnosticIds
9294
return CodeFixContext(document, textSpan, roslynDiagnostics, mockAction, cancellationToken)
9395
}
9496

95-
let tryFix (code: string) mode (fixProvider: 'T when 'T :> IFSharpCodeFixProvider and 'T :> CodeFixProvider) =
97+
let tryFix (code: string) mode (fixProvider: 'T :> IFSharpCodeFixProvider) =
9698
cancellableTask {
9799
let sourceText = SourceText.From code
98-
let document = getDocument code mode
99100

100-
let! context = createTestCodeFixContext code document mode fixProvider.FixableDiagnosticIds
101+
let! context = createTestCodeFixContext code mode fixProvider
101102

102103
let! result = fixProvider.GetCodeFixIfAppliesAsync context
103104

@@ -112,3 +113,22 @@ let tryFix (code: string) mode (fixProvider: 'T when 'T :> IFSharpCodeFixProvide
112113
}
113114
|> CancellableTask.startWithoutCancellation
114115
|> fun task -> task.Result
116+
117+
let multiFix (code: string) mode (fixProvider: 'T :> IFSharpMultiCodeFixProvider) =
118+
cancellableTask {
119+
let sourceText = SourceText.From code
120+
121+
let! context = createTestCodeFixContext code mode fixProvider
122+
123+
let! result = fixProvider.GetCodeFixesAsync context
124+
125+
return
126+
result
127+
|> Seq.map (fun codeFix ->
128+
{
129+
Message = codeFix.Message
130+
FixedCode = (sourceText.WithChanges codeFix.Changes).ToString()
131+
})
132+
}
133+
|> CancellableTask.startWithoutCancellation
134+
|> fun task -> task.Result

vsintegration/tests/FSharp.Editor.Tests/CodeFixes/ReplaceWithSuggestionTests.fs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ let song = { Titel = "Jigsaw Falling Into Place" }
1919
"""
2020

2121
let expected =
22-
Some
22+
[
2323
{
2424
Message = "Replace with 'Title'"
2525
FixedCode =
@@ -29,8 +29,9 @@ type Song = { Title : string }
2929
let song = { Title = "Jigsaw Falling Into Place" }
3030
"""
3131
}
32+
]
3233

33-
let actual = codeFix |> tryFix code Auto
34+
let actual = codeFix |> multiFix code Auto
3435

3536
Assert.Equal(expected, actual)
3637

@@ -44,7 +45,7 @@ let someSong : Wrong = { Title = "The Narcissist" }
4445
"""
4546

4647
let expected =
47-
Some
48+
[
4849
{
4950
Message = "Replace with 'Song'"
5051
FixedCode =
@@ -54,8 +55,47 @@ type Song = { Title : string }
5455
let someSong : Song = { Title = "The Narcissist" }
5556
"""
5657
}
58+
]
5759

58-
let actual = codeFix |> tryFix code Auto
60+
let actual = codeFix |> multiFix code Auto
61+
62+
Assert.Equal(expected, actual)
63+
64+
[<Fact>]
65+
let ``Fixes FS0039 - multiple suggestions`` () =
66+
let code =
67+
"""
68+
type TheType1() = class end
69+
type TheType3() = class end
70+
71+
let test = TheType2()
72+
"""
73+
74+
let expected =
75+
[
76+
{
77+
Message = "Replace with 'TheType1'"
78+
FixedCode =
79+
"""
80+
type TheType1() = class end
81+
type TheType3() = class end
82+
83+
let test = TheType1()
84+
"""
85+
}
86+
{
87+
Message = "Replace with 'TheType3'"
88+
FixedCode =
89+
"""
90+
type TheType1() = class end
91+
type TheType3() = class end
92+
93+
let test = TheType3()
94+
"""
95+
}
96+
]
97+
98+
let actual = codeFix |> multiFix code Auto
5999

60100
Assert.Equal(expected, actual)
61101

@@ -70,9 +110,9 @@ module Module2 =
70110
let song = { Titel = "Jigsaw Falling Into Place" }
71111
"""
72112

73-
let expected = None
113+
let expected = []
74114

75-
let actual = codeFix |> tryFix code Auto
115+
let actual = codeFix |> multiFix code Auto
76116

77117
Assert.Equal(expected, actual)
78118

@@ -83,9 +123,9 @@ let ``Doesn't fix FS0039 for random undefined stuff`` () =
83123
let f = g
84124
"""
85125

86-
let expected = None
126+
let expected = []
87127

88-
let actual = codeFix |> tryFix code Auto
128+
let actual = codeFix |> multiFix code Auto
89129

90130
Assert.Equal(expected, actual)
91131

@@ -100,7 +140,7 @@ let song = Song(titel = "Under The Milky Way")
100140
"""
101141

102142
let expected =
103-
Some
143+
[
104144
{
105145
Message = "Replace with 'title'"
106146
FixedCode =
@@ -111,7 +151,8 @@ type Song(title: string) =
111151
let song = Song(title = "Under The Milky Way")
112152
"""
113153
}
154+
]
114155

115-
let actual = codeFix |> tryFix code Auto
156+
let actual = codeFix |> multiFix code Auto
116157

117158
Assert.Equal(expected, actual)

0 commit comments

Comments
 (0)