@@ -4,8 +4,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor
44
55open System
66open System.Composition
7- open System.Threading .Tasks
8- open System.Threading
97open System.Collections .Immutable
108
119open Microsoft.CodeAnalysis .Text
@@ -14,6 +12,7 @@ open Microsoft.CodeAnalysis.CodeFixes
1412open FSharp.Compiler .EditorServices
1513open FSharp.Compiler .Text
1614open FSharp.Compiler .Symbols
15+
1716open CancellableTasks
1817
1918[<ExportCodeFixProvider( FSharpConstants.FSharpLanguageName, Name = CodeFix.AddTypeAnnotationToObjectOfIndeterminateType); Shared>]
@@ -24,88 +23,98 @@ type internal AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [<Importin
2423
2524 override _.FixableDiagnosticIds = ImmutableArray.Create( " FS0072" , " FS3245" )
2625
27- override _.RegisterCodeFixesAsync context : Task =
28- asyncMaybe {
29-
30- let document = context.Document
31- let position = context.Span.Start
32-
33- let! sourceText = document.GetTextAsync( context.CancellationToken)
34- let textLine = sourceText.Lines.GetLineFromPosition position
35- let textLinePos = sourceText.Lines.GetLinePosition position
36- let fcsTextLineNumber = Line.fromZ textLinePos.Line
37-
38- let! lexerSymbol =
39- document.TryFindFSharpLexerSymbolAsync(
40- position,
41- SymbolLookupKind.Greedy,
42- false ,
43- false ,
44- nameof ( AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider)
45- )
46-
47- let! _ , checkFileResults =
48- document.GetFSharpParseAndCheckResultsAsync( nameof ( AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider))
49- |> CancellableTask.start context.CancellationToken
50- |> Async.AwaitTask
51- |> liftAsync
52-
53- let decl =
54- checkFileResults.GetDeclarationLocation(
55- fcsTextLineNumber,
56- lexerSymbol.Ident.idRange.EndColumn,
57- textLine.ToString(),
58- lexerSymbol.FullIsland,
59- false
60- )
61-
62- match decl with
63- | FindDeclResult.DeclFound declRange when declRange.FileName = document.FilePath ->
64- let! declSpan = RoslynHelpers.TryFSharpRangeToTextSpan( sourceText, declRange)
65- let declTextLine = sourceText.Lines.GetLineFromPosition declSpan.Start
66-
67- let! symbolUse =
68- checkFileResults.GetSymbolUseAtLocation(
69- declRange.StartLine,
70- declRange.EndColumn,
71- declTextLine.ToString(),
72- lexerSymbol.FullIsland
26+ override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix this
27+
28+ interface IFSharpCodeFixProvider with
29+ member _.GetCodeFixIfAppliesAsync context =
30+ cancellableTask {
31+ let document = context.Document
32+ let position = context.Span.Start
33+
34+ let! lexerSymbolOpt =
35+ document.TryFindFSharpLexerSymbolAsync(
36+ position,
37+ SymbolLookupKind.Greedy,
38+ false ,
39+ false ,
40+ nameof AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider
7341 )
7442
75- match symbolUse.Symbol with
76- | : ? FSharpMemberOrFunctionOrValue as mfv ->
77- let typeString = mfv.FullType.FormatWithConstraints symbolUse.DisplayContext
78-
79- let alreadyWrappedInParens =
80- let rec leftLoop ch pos =
81- if not ( Char.IsWhiteSpace( ch)) then
82- ch = '('
83- else
84- leftLoop sourceText.[ pos - 1 ] ( pos - 1 )
85-
86- let rec rightLoop ch pos =
87- if not ( Char.IsWhiteSpace( ch)) then
88- ch = ')'
89- else
90- rightLoop sourceText.[ pos + 1 ] ( pos + 1 )
91-
92- let hasLeftParen = leftLoop sourceText.[ declSpan.Start - 1 ] ( declSpan.Start - 1 )
93- let hasRightParen = rightLoop sourceText.[ declSpan.End] declSpan.End
94- hasLeftParen && hasRightParen
95-
96- let changes =
97- [
98- if alreadyWrappedInParens then
99- TextChange( TextSpan( declSpan.End, 0 ), " : " + typeString)
100- else
101- TextChange( TextSpan( declSpan.Start, 0 ), " (" )
102- TextChange( TextSpan( declSpan.End + 1 , 0 ), " : " + typeString + " )" )
103- ]
104-
105- context.RegisterFsharpFix( CodeFix.AddTypeAnnotationToObjectOfIndeterminateType, title, changes)
106-
107- | _ -> ()
108- | _ -> ()
109- }
110- |> Async.Ignore
111- |> RoslynHelpers.StartAsyncUnitAsTask( context.CancellationToken)
43+ match lexerSymbolOpt with
44+ | None -> return ValueNone
45+ | Some lexerSymbol ->
46+ let! sourceText = context.GetSourceTextAsync()
47+ let textLine = sourceText.Lines.GetLineFromPosition position
48+ let textLinePos = sourceText.Lines.GetLinePosition position
49+ let fcsTextLineNumber = Line.fromZ textLinePos.Line
50+
51+ let! _ , checkFileResults =
52+ document.GetFSharpParseAndCheckResultsAsync( nameof AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider)
53+
54+ let decl =
55+ checkFileResults.GetDeclarationLocation(
56+ fcsTextLineNumber,
57+ lexerSymbol.Ident.idRange.EndColumn,
58+ textLine.ToString(),
59+ lexerSymbol.FullIsland,
60+ false
61+ )
62+
63+ match decl with
64+ | FindDeclResult.DeclFound declRange when declRange.FileName = document.FilePath ->
65+ let declSpan = RoslynHelpers.FSharpRangeToTextSpan( sourceText, declRange)
66+ let declTextLine = sourceText.Lines.GetLineFromPosition declSpan.Start
67+
68+ let symbolUseOpt =
69+ checkFileResults.GetSymbolUseAtLocation(
70+ declRange.StartLine,
71+ declRange.EndColumn,
72+ declTextLine.ToString(),
73+ lexerSymbol.FullIsland
74+ )
75+
76+ match symbolUseOpt with
77+ | None -> return ValueNone
78+ | Some symbolUse ->
79+ match symbolUse.Symbol with
80+ | : ? FSharpMemberOrFunctionOrValue as mfv when not mfv .FullType .IsGenericParameter ->
81+ let typeString = mfv.FullType.FormatWithConstraints symbolUse.DisplayContext
82+
83+ let alreadyWrappedInParens =
84+ let rec leftLoop ch pos =
85+ if not ( Char.IsWhiteSpace( ch)) then
86+ ch = '('
87+ else
88+ leftLoop sourceText[ pos - 1 ] ( pos - 1 )
89+
90+ let rec rightLoop ch pos =
91+ if not ( Char.IsWhiteSpace( ch)) then
92+ ch = ')'
93+ else
94+ rightLoop sourceText[ pos + 1 ] ( pos + 1 )
95+
96+ let hasLeftParen = leftLoop sourceText[ declSpan.Start - 1 ] ( declSpan.Start - 1 )
97+ let hasRightParen = rightLoop sourceText[ declSpan.End] declSpan.End
98+ hasLeftParen && hasRightParen
99+
100+ let changes =
101+ [
102+ if alreadyWrappedInParens then
103+ TextChange( TextSpan( declSpan.End, 0 ), " : " + typeString)
104+ else
105+ TextChange( TextSpan( declSpan.Start, 0 ), " (" )
106+ TextChange( TextSpan( declSpan.End, 0 ), " : " + typeString + " )" )
107+ ]
108+
109+ return
110+ ValueSome
111+ {
112+ Name = CodeFix.AddTypeAnnotationToObjectOfIndeterminateType
113+ Message = title
114+ Changes = changes
115+ }
116+
117+ | _ -> return ValueNone
118+
119+ | _ -> return ValueNone
120+ }
0 commit comments