diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs index 5c2995740fb..ab24ba7faf0 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs @@ -3,13 +3,14 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System.Composition -open System.Threading.Tasks open System.Collections.Immutable open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.CodeFixes open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics +open FSharp.Compiler.Text + open CancellableTasks [] @@ -30,14 +31,19 @@ type internal RemoveUnusedOpensCodeFixProvider [] () = cancellableTask { let! sourceText = context.GetSourceTextAsync() - let span = - sourceText.Lines.GetLineFromPosition(context.Span.Start).SpanIncludingLineBreak + let! unusedOpensOpt = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges context.Document return - ValueSome + unusedOpensOpt + |> ValueOption.map ( + List.map (fun m -> + let span = sourceText.Lines[Line.toZ m.StartLine].SpanIncludingLineBreak + TextChange(span, "")) + ) + |> ValueOption.map (fun changes -> { Name = CodeFix.RemoveUnusedOpens Message = title - Changes = [ TextChange(span, "") ] - } + Changes = changes + }) } diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 3dd0628fa5d..837a4598b01 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -19,23 +19,20 @@ open CancellableTasks [)>] type internal UnusedOpensDiagnosticAnalyzer [] () = - static member GetUnusedOpenRanges(document: Document) : Async> = - asyncMaybe { - do! Option.guard document.Project.IsFSharpCodeFixesUnusedOpensEnabled - let! ct = Async.CancellationToken |> liftAsync - let! sourceText = document.GetTextAsync(ct) - - let! _, checkResults = - document.GetFSharpParseAndCheckResultsAsync(nameof (UnusedOpensDiagnosticAnalyzer)) - |> CancellableTask.start ct - |> Async.AwaitTask - |> liftAsync - - let! unusedOpens = - UnusedOpens.getUnusedOpens (checkResults, (fun lineNumber -> sourceText.Lines.[Line.toZ lineNumber].ToString())) - |> liftAsync - - return unusedOpens + static member GetUnusedOpenRanges(document: Document) = + cancellableTask { + if not document.Project.IsFSharpCodeFixesUnusedOpensEnabled then + return ValueNone + else + let! ct = CancellableTask.getCancellationToken () + let! sourceText = document.GetTextAsync ct + + let! _, checkResults = document.GetFSharpParseAndCheckResultsAsync(nameof UnusedOpensDiagnosticAnalyzer) + + let! unusedOpens = + UnusedOpens.getUnusedOpens (checkResults, (fun lineNumber -> sourceText.Lines[ Line.toZ lineNumber ].ToString())) + + return (ValueSome unusedOpens) } interface IFSharpUnusedOpensDiagnosticAnalyzer with @@ -44,17 +41,16 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = if document.Project.IsFSharpMiscellaneousOrMetadata && not document.IsFSharpScript then Tasks.Task.FromResult(ImmutableArray.Empty) else - - asyncMaybe { + cancellableTask { do Trace.TraceInformation("{0:n3} (start) UnusedOpensAnalyzer", DateTime.Now.TimeOfDay.TotalSeconds) let! sourceText = document.GetTextAsync() - let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges(document) + let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges document return unusedOpens + |> ValueOption.defaultValue List.Empty |> List.map (fun range -> Diagnostic.Create(descriptor, RoslynHelpers.RangeToLocation(range, sourceText, document.FilePath))) |> Seq.toImmutableArray } - |> Async.map (Option.defaultValue ImmutableArray.Empty) - |> RoslynHelpers.StartAsyncAsTask cancellationToken + |> CancellableTask.start cancellationToken diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnusedOpensTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnusedOpensTests.fs index ebce9ed4ba5..0b7fb00a037 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnusedOpensTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnusedOpensTests.fs @@ -10,7 +10,7 @@ open CodeFixTestFramework let private codeFix = RemoveUnusedOpensCodeFixProvider() [] -let ``Fixes IDE0005`` () = +let ``Fixes IDE0005 - one unused declaration`` () = let code = """ open System @@ -28,3 +28,28 @@ open System let actual = codeFix |> tryFix code (Manual("open System", "IDE0005")) Assert.Equal(expected, actual) + +[] +[] +[] +[] +let ``Fixes IDE0005 - multiple unused declarations`` focus = + let code = + """ +open System.Buffers +open System.IO +open System.Text +""" + + let expected = + Some + { + Message = "Remove unused open declarations" + FixedCode = + """ +""" + } + + let actual = codeFix |> tryFix code (Manual(focus, "IDE0005")) + + Assert.Equal(expected, actual)