@@ -4,79 +4,92 @@ namespace Microsoft.VisualStudio.FSharp.Editor
4
4
5
5
open System
6
6
open System.Composition
7
- open System.Threading .Tasks
8
7
open System.Collections .Immutable
9
8
10
9
open Microsoft.CodeAnalysis .Text
11
10
open Microsoft.CodeAnalysis .CodeFixes
12
11
13
12
open FSharp.Compiler .Symbols
14
- open FSharp. Compiler . Text
13
+
15
14
open CancellableTasks
16
15
17
16
[<ExportCodeFixProvider( FSharpConstants.FSharpLanguageName, Name = CodeFix.UseMutationWhenValueIsMutable); Shared>]
18
17
type internal UseMutationWhenValueIsMutableCodeFixProvider [<ImportingConstructor>] () =
19
18
inherit CodeFixProvider()
20
19
21
20
static let title = SR.UseMutationWhenValueIsMutable()
22
- override _.FixableDiagnosticIds = ImmutableArray.Create( " FS0020" )
23
-
24
- override _.RegisterCodeFixesAsync context : Task =
25
- asyncMaybe {
26
- let document = context.Document
27
- do ! Option.guard ( not ( isSignatureFile document.FilePath))
28
-
29
- let! sourceText = document.GetTextAsync( context.CancellationToken)
30
-
31
- let adjustedPosition =
32
- let rec loop ch pos =
33
- if Char.IsWhiteSpace( ch) then
34
- pos
35
- else
36
- loop sourceText.[ pos + 1 ] ( pos + 1 )
37
-
38
- loop sourceText.[ context.Span.Start] context.Span.Start
39
-
40
- let textLine = sourceText.Lines.GetLineFromPosition adjustedPosition
41
- let textLinePos = sourceText.Lines.GetLinePosition adjustedPosition
42
- let fcsTextLineNumber = Line.fromZ textLinePos.Line
43
-
44
- let! lexerSymbol =
45
- document.TryFindFSharpLexerSymbolAsync(
46
- adjustedPosition,
47
- SymbolLookupKind.Greedy,
48
- false ,
49
- false ,
50
- nameof ( UseMutationWhenValueIsMutableCodeFixProvider)
51
- )
52
-
53
- let! _ , checkFileResults =
54
- document.GetFSharpParseAndCheckResultsAsync( nameof ( UseMutationWhenValueIsMutableCodeFixProvider))
55
- |> CancellableTask.start context.CancellationToken
56
- |> Async.AwaitTask
57
- |> liftAsync
58
-
59
- let! symbolUse =
60
- checkFileResults.GetSymbolUseAtLocation(
61
- fcsTextLineNumber,
62
- lexerSymbol.Ident.idRange.EndColumn,
63
- textLine.ToString(),
64
- lexerSymbol.FullIsland
65
- )
66
-
67
- match symbolUse.Symbol with
68
- | : ? FSharpMemberOrFunctionOrValue as mfv when mfv .IsMutable || mfv .HasSetterMethod ->
69
- let! symbolSpan = RoslynHelpers.TryFSharpRangeToTextSpan( sourceText, symbolUse.Range)
70
- let mutable pos = symbolSpan.End
71
- let mutable ch = sourceText.[ pos]
72
-
73
- // We're looking for the possibly erroneous '='
74
- while pos <= context.Span.Length && ch <> '=' do
75
- pos <- pos + 1
76
- ch <- sourceText.[ pos]
77
-
78
- do context.RegisterFsharpFix( CodeFix.UseMutationWhenValueIsMutable, title, [| TextChange( TextSpan( pos + 1 , 1 ), " <-" ) |])
79
- | _ -> ()
80
- }
81
- |> Async.Ignore
82
- |> RoslynHelpers.StartAsyncUnitAsTask( context.CancellationToken)
21
+
22
+ override _.FixableDiagnosticIds = ImmutableArray.Create " FS0020"
23
+
24
+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix this
25
+
26
+ interface IFSharpCodeFixProvider with
27
+ member _.GetCodeFixIfAppliesAsync context =
28
+ cancellableTask {
29
+ let document = context.Document
30
+
31
+ if isSignatureFile document.FilePath then
32
+ return ValueNone
33
+ else
34
+ let! sourceText = context.GetSourceTextAsync()
35
+
36
+ let adjustedPosition =
37
+ let rec loop ch pos =
38
+ if Char.IsWhiteSpace( ch) then
39
+ pos
40
+ else
41
+ loop sourceText[ pos + 1 ] ( pos + 1 )
42
+
43
+ loop sourceText[ context.Span.Start] context.Span.Start
44
+
45
+ let! lexerSymbolOpt =
46
+ document.TryFindFSharpLexerSymbolAsync(
47
+ adjustedPosition,
48
+ SymbolLookupKind.Greedy,
49
+ false ,
50
+ false ,
51
+ nameof UseMutationWhenValueIsMutableCodeFixProvider
52
+ )
53
+
54
+ match lexerSymbolOpt with
55
+ | None -> return ValueNone
56
+ | Some lexerSymbol ->
57
+ let fcsTextLineNumber , textLine =
58
+ MutableCodeFixHelper.getLineNumberAndText sourceText adjustedPosition
59
+
60
+ let! _ , checkFileResults =
61
+ document.GetFSharpParseAndCheckResultsAsync( nameof UseMutationWhenValueIsMutableCodeFixProvider)
62
+
63
+ let symbolUseOpt =
64
+ checkFileResults.GetSymbolUseAtLocation(
65
+ fcsTextLineNumber,
66
+ lexerSymbol.Ident.idRange.EndColumn,
67
+ textLine,
68
+ lexerSymbol.FullIsland
69
+ )
70
+
71
+ let isValidCase ( symbol : FSharpSymbol ) =
72
+ match symbol with
73
+ | : ? FSharpMemberOrFunctionOrValue as mfv when mfv .IsMutable || mfv .HasSetterMethod -> true
74
+ | _ -> false
75
+
76
+ match symbolUseOpt with
77
+ | Some symbolUse when isValidCase symbolUse.Symbol ->
78
+ let symbolSpan = RoslynHelpers.FSharpRangeToTextSpan( sourceText, symbolUse.Range)
79
+ let mutable pos = symbolSpan.End
80
+ let mutable ch = sourceText[ pos]
81
+
82
+ // We're looking for the possibly erroneous '='
83
+ while pos <= context.Span.Length && ch <> '=' do
84
+ pos <- pos + 1
85
+ ch <- sourceText[ pos]
86
+
87
+ return
88
+ ValueSome
89
+ {
90
+ Name = CodeFix.UseMutationWhenValueIsMutable
91
+ Message = title
92
+ Changes = [ TextChange( TextSpan( pos + 1 , 1 ), " <-" ) ]
93
+ }
94
+ | _ -> return ValueNone
95
+ }
0 commit comments