@@ -9,73 +9,76 @@ open System.Collections.Immutable
9
9
open Microsoft.CodeAnalysis .Text
10
10
open Microsoft.CodeAnalysis .CodeFixes
11
11
12
+ open CancellableTasks
13
+
12
14
[<ExportCodeFixProvider( FSharpConstants.FSharpLanguageName, Name = CodeFix.ConvertCSharpUsingToFSharpOpen); Shared>]
13
15
type internal ConvertCSharpUsingToFSharpOpenCodeFixProvider [<ImportingConstructor>] () =
14
16
inherit CodeFixProvider()
15
17
16
18
static let title = SR.ConvertCSharpUsingToFSharpOpen()
17
19
let usingLength = " using" .Length
18
20
19
- let isCSharpUsingShapeWithPos ( context : CodeFixContext ) ( sourceText : SourceText ) =
21
+ let isCSharpUsingShapeWithPos ( errorSpan : TextSpan ) ( sourceText : SourceText ) =
20
22
// Walk back until whitespace
21
- let mutable pos = context.Span. Start - 1
22
- let mutable ch = sourceText. [ pos]
23
+ let mutable pos = errorSpan. Start
24
+ let mutable ch = sourceText[ pos]
23
25
24
26
while pos > 0 && not ( Char.IsWhiteSpace( ch)) do
25
27
pos <- pos - 1
26
- ch <- sourceText. [ pos]
28
+ ch <- sourceText[ pos]
27
29
28
30
// Walk back whitespace
29
- ch <- sourceText. [ pos]
31
+ ch <- sourceText[ pos]
30
32
31
33
while pos > 0 && Char.IsWhiteSpace( ch) do
32
34
pos <- pos - 1
33
- ch <- sourceText. [ pos]
35
+ ch <- sourceText[ pos]
34
36
35
37
// Take 'using' slice and don't forget that offset because computer math is annoying
36
38
let start = pos - usingLength + 1
37
- let span = TextSpan( start, usingLength)
38
- let slice = sourceText.GetSubText( span) .ToString()
39
- struct ( slice = " using" , start)
40
-
41
- let registerCodeFix ( context : CodeFixContext ) ( str : string ) ( span : TextSpan ) =
42
- let replacement =
43
- let str = str.Replace( " using" , " open" ) .Replace( " ;" , " " )
44
- TextChange( span, str)
45
39
46
- do context.RegisterFsharpFix( CodeFix.ConvertCSharpUsingToFSharpOpen, title, [| replacement |])
40
+ if start < 0 then
41
+ false
42
+ else
43
+ let span = TextSpan( start, usingLength)
44
+ let slice = sourceText.GetSubText( span) .ToString()
45
+ slice = " using"
47
46
48
47
override _.FixableDiagnosticIds = ImmutableArray.Create( " FS0039" , " FS0201" )
49
48
50
- override _.RegisterCodeFixesAsync context =
51
- asyncMaybe {
52
- let! sourceText = context.Document.GetTextAsync( context.CancellationToken)
53
-
54
- // TODO: handle single-line case?
55
- let statementWithSemicolonSpan =
56
- TextSpan( context.Span.Start, context.Span.Length + 1 )
57
-
58
- do ! Option.guard ( sourceText.Length >= statementWithSemicolonSpan.End)
59
-
60
- let statementWithSemicolon =
61
- sourceText.GetSubText( statementWithSemicolonSpan). ToString()
62
-
63
- // Top of the file case -- entire line gets a diagnostic
64
- if
65
- ( statementWithSemicolon.StartsWith( " using" )
66
- && statementWithSemicolon.EndsWith( " ;" ))
67
- then
68
- registerCodeFix context statementWithSemicolon statementWithSemicolonSpan
69
- else
70
- // Only the identifier being opened has a diagnostic, so we try to find the rest of the statement
71
- let struct ( isCSharpUsingShape , start ) =
72
- isCSharpUsingShapeWithPos context sourceText
73
-
74
- if isCSharpUsingShape then
75
- let len = ( context.Span.Start - start) + statementWithSemicolonSpan.Length
76
- let fullSpan = TextSpan( start, len)
77
- let str = sourceText.GetSubText( fullSpan). ToString()
78
- registerCodeFix context str fullSpan
79
- }
80
- |> Async.Ignore
81
- |> RoslynHelpers.StartAsyncUnitAsTask( context.CancellationToken)
49
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix this
50
+
51
+ override this.GetFixAllProvider () = this.RegisterFsharpFixAll()
52
+
53
+ interface IFSharpCodeFixProvider with
54
+ member _.GetCodeFixIfAppliesAsync context =
55
+ cancellableTask {
56
+ let diagnostic = context.Diagnostics[ 0 ]
57
+ let! errorText = context.GetSquigglyTextAsync()
58
+ let! sourceText = context.GetSourceTextAsync()
59
+
60
+ let isValidCase =
61
+ match diagnostic.Id with
62
+ // using is included in the squiggly
63
+ | " FS0201" when errorText.Contains( " using " ) -> true
64
+ // using is not included in the squiqqly
65
+ | " FS0039" when isCSharpUsingShapeWithPos context.Span sourceText -> true
66
+ | _ -> false
67
+
68
+ if isValidCase then
69
+ let lineNumber = sourceText.Lines.GetLinePositionSpan( context.Span). Start.Line
70
+ let line = sourceText.Lines[ lineNumber]
71
+
72
+ let change =
73
+ TextChange( line.Span, line.ToString() .Replace( " using" , " open" ). Replace( " ;" , " " ))
74
+
75
+ return
76
+ ValueSome
77
+ {
78
+ Name = CodeFix.ConvertCSharpUsingToFSharpOpen
79
+ Message = title
80
+ Changes = [ change ]
81
+ }
82
+ else
83
+ return ValueNone
84
+ }
0 commit comments