From 55e9d738cb9bddd34e6a530047e27d64d97b8495 Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 18 Sep 2023 21:42:30 +0200 Subject: [PATCH 1/5] Making Remove Unused Opens remove all unused opens again --- .../CodeFixes/RemoveUnusedOpens.fs | 19 ++++++++----- .../CodeFixes/RemoveUnusedOpensTests.fs | 27 ++++++++++++++++++- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs index 5c2995740fb..d1a9e872315 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,20 @@ 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.ofOption + |> 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/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) From 71a96221c92289656a9efe8d77ddd26387b0556e Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 19 Sep 2023 13:53:22 +0200 Subject: [PATCH 2/5] ctasks --- .../UnusedOpensDiagnosticAnalyzer.fs | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 3dd0628fa5d..67e84664e27 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -19,23 +19,21 @@ 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> = + cancellableTask { + if not document.Project.IsFSharpCodeFixesUnusedOpensEnabled + then return None + 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 (Some unusedOpens) } interface IFSharpUnusedOpensDiagnosticAnalyzer with @@ -48,7 +46,10 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = asyncMaybe { 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) + |> CancellableTask.start cancellationToken + |> Async.AwaitTask return unusedOpens From 799e3884a88324aa0a77f7f8e84d65c0414f44ee Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 19 Sep 2023 14:12:17 +0200 Subject: [PATCH 3/5] voption --- .../CodeFixes/RemoveUnusedOpens.fs | 1 - .../UnusedOpensDiagnosticAnalyzer.fs | 28 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs index d1a9e872315..ab24ba7faf0 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/RemoveUnusedOpens.fs @@ -35,7 +35,6 @@ type internal RemoveUnusedOpensCodeFixProvider [] () = return unusedOpensOpt - |> ValueOption.ofOption |> ValueOption.map ( List.map (fun m -> let span = sourceText.Lines[Line.toZ m.StartLine].SpanIncludingLineBreak diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 67e84664e27..c76a90044c3 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -19,10 +19,10 @@ open CancellableTasks [)>] type internal UnusedOpensDiagnosticAnalyzer [] () = - static member GetUnusedOpenRanges(document: Document) : CancellableTask> = + static member GetUnusedOpenRanges(document: Document) : CancellableTask> = cancellableTask { if not document.Project.IsFSharpCodeFixesUnusedOpensEnabled - then return None + then return ValueNone else let! ct = CancellableTask.getCancellationToken() let! sourceText = document.GetTextAsync ct @@ -33,7 +33,7 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = let! unusedOpens = UnusedOpens.getUnusedOpens (checkResults, (fun lineNumber -> sourceText.Lines[Line.toZ lineNumber].ToString())) - return (Some unusedOpens) + return (ValueSome unusedOpens) } interface IFSharpUnusedOpensDiagnosticAnalyzer with @@ -42,20 +42,20 @@ 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) - |> CancellableTask.start cancellationToken - |> Async.AwaitTask + UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges document - return + let test = unusedOpens - |> List.map (fun range -> - Diagnostic.Create(descriptor, RoslynHelpers.RangeToLocation(range, sourceText, document.FilePath))) - |> Seq.toImmutableArray + |> ValueOption.map ( + List.map (fun range -> + Diagnostic.Create(descriptor, RoslynHelpers.RangeToLocation(range, sourceText, document.FilePath)))) + |> ValueOption.map (Seq.toImmutableArray) + |> ValueOption.defaultValue ImmutableArray.Empty + + return test } - |> Async.map (Option.defaultValue ImmutableArray.Empty) - |> RoslynHelpers.StartAsyncAsTask cancellationToken + |> CancellableTask.start cancellationToken From 45ae8f57b70d92ed09739120aeec6f7b221b9a8e Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 19 Sep 2023 14:16:24 +0200 Subject: [PATCH 4/5] cleanup --- .../Diagnostics/UnusedOpensDiagnosticAnalyzer.fs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index c76a90044c3..6b357fd7730 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -19,7 +19,7 @@ open CancellableTasks [)>] type internal UnusedOpensDiagnosticAnalyzer [] () = - static member GetUnusedOpenRanges(document: Document) : CancellableTask> = + static member GetUnusedOpenRanges(document: Document) = cancellableTask { if not document.Project.IsFSharpCodeFixesUnusedOpensEnabled then return ValueNone @@ -48,14 +48,11 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = let! unusedOpens = UnusedOpensDiagnosticAnalyzer.GetUnusedOpenRanges document - let test = + return unusedOpens - |> ValueOption.map ( - List.map (fun range -> - Diagnostic.Create(descriptor, RoslynHelpers.RangeToLocation(range, sourceText, document.FilePath)))) - |> ValueOption.map (Seq.toImmutableArray) - |> ValueOption.defaultValue ImmutableArray.Empty - - return test + |> ValueOption.defaultValue List.Empty + |> List.map (fun range -> + Diagnostic.Create(descriptor, RoslynHelpers.RangeToLocation(range, sourceText, document.FilePath))) + |> Seq.toImmutableArray } |> CancellableTask.start cancellationToken From 75ba965ead57a254336c4529766885345ec4b762 Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 19 Sep 2023 14:16:50 +0200 Subject: [PATCH 5/5] ftms --- .../Diagnostics/UnusedOpensDiagnosticAnalyzer.fs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs index 6b357fd7730..837a4598b01 100644 --- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs +++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs @@ -21,17 +21,16 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = static member GetUnusedOpenRanges(document: Document) = cancellableTask { - if not document.Project.IsFSharpCodeFixesUnusedOpensEnabled - then return ValueNone + if not document.Project.IsFSharpCodeFixesUnusedOpensEnabled then + return ValueNone else - let! ct = CancellableTask.getCancellationToken() + let! ct = CancellableTask.getCancellationToken () let! sourceText = document.GetTextAsync ct - let! _, checkResults = - document.GetFSharpParseAndCheckResultsAsync(nameof UnusedOpensDiagnosticAnalyzer) + let! _, checkResults = document.GetFSharpParseAndCheckResultsAsync(nameof UnusedOpensDiagnosticAnalyzer) let! unusedOpens = - UnusedOpens.getUnusedOpens (checkResults, (fun lineNumber -> sourceText.Lines[Line.toZ lineNumber].ToString())) + UnusedOpens.getUnusedOpens (checkResults, (fun lineNumber -> sourceText.Lines[ Line.toZ lineNumber ].ToString())) return (ValueSome unusedOpens) } @@ -45,8 +44,7 @@ type internal UnusedOpensDiagnosticAnalyzer [] () = 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