From b38874eac70944659e0228a9d4123cad4fa6c958 Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 18 Sep 2023 17:33:48 +0200 Subject: [PATCH 1/5] Fix a bug in a code fix (#15973) --- .../CodeFixes/UseMutationWhenValueIsMutable.fs | 6 +++++- .../CodeFixes/UseMutationWhenValueIsMutableTests.fs | 13 +++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs b/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs index 27ad14755a2..e4f6e595252 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs @@ -35,7 +35,11 @@ type internal UseMutationWhenValueIsMutableCodeFixProvider [] -let ``Doesn't fix unrelated FS0020`` () = - let code = - """ +[] +[] +[] +let ``Doesn't fix unrelated FS0020`` code = let expected = None let actual = codeFix |> tryFix code Auto From e31702c94894fb879044f37fbc922ac11ecb0d6b Mon Sep 17 00:00:00 2001 From: Petr Date: Mon, 18 Sep 2023 17:36:39 +0200 Subject: [PATCH 2/5] Small cleanup in code fixes + tests for a legacy code fix (#15934) * Small cleanup in code fixes * revert breaking * add tests * up * Update FixIndexerAccessLegacy.fs --- ...peAnnotationToObjectOfIndeterminateType.fs | 7 +-- .../FSharp.Editor/CodeFixes/CodeFixHelpers.fs | 47 +++++++++---------- .../CodeFixes/FixIndexerAccessLegacy.fs | 34 +++++++------- .../CodeFixes/MakeDeclarationMutable.fs | 3 +- .../CodeFixes/ReplaceWithSuggestion.fs | 5 +- .../UseMutationWhenValueIsMutable.fs | 3 +- .../CodeFixes/FixIndexerAccessLegacyTests.fs | 33 +++++++++++++ .../FSharp.Editor.Tests.fsproj | 1 + 8 files changed, 78 insertions(+), 55 deletions(-) create mode 100644 vsintegration/tests/FSharp.Editor.Tests/CodeFixes/FixIndexerAccessLegacyTests.fs diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/AddTypeAnnotationToObjectOfIndeterminateType.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddTypeAnnotationToObjectOfIndeterminateType.fs index b14f080aea9..4accffe94bd 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/AddTypeAnnotationToObjectOfIndeterminateType.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddTypeAnnotationToObjectOfIndeterminateType.fs @@ -10,7 +10,6 @@ open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.CodeFixes open FSharp.Compiler.EditorServices -open FSharp.Compiler.Text open FSharp.Compiler.Symbols open CancellableTasks @@ -43,10 +42,7 @@ type internal AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [ return ValueNone | Some lexerSymbol -> - let! sourceText = context.GetSourceTextAsync() - let textLine = sourceText.Lines.GetLineFromPosition position - let textLinePos = sourceText.Lines.GetLinePosition position - let fcsTextLineNumber = Line.fromZ textLinePos.Line + let! fcsTextLineNumber, textLine = context.GetLineNumberAndText position let! _, checkFileResults = document.GetFSharpParseAndCheckResultsAsync(nameof AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider) @@ -62,6 +58,7 @@ type internal AddTypeAnnotationToObjectOfIndeterminateTypeFixProvider [ + let! sourceText = context.GetSourceTextAsync() let declSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, declRange) let declTextLine = sourceText.Lines.GetLineFromPosition declSpan.Start diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs b/vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs index 426715ee4ca..0a54de176dd 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/CodeFixHelpers.fs @@ -3,7 +3,6 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System -open System.Threading open System.Collections.Immutable open System.Diagnostics @@ -20,13 +19,6 @@ open FSharp.Compiler.Text open CancellableTasks -module internal MutableCodeFixHelper = - let getLineNumberAndText (sourceText: SourceText) position = - let textLine = sourceText.Lines.GetLineFromPosition position - let textLinePos = sourceText.Lines.GetLinePosition position - let fcsTextLineNumber = Line.fromZ textLinePos.Line - fcsTextLineNumber, textLine.ToString() - module internal UnusedCodeFixHelper = let getUnusedSymbol textSpan (document: Document) (sourceText: SourceText) codeFixName = let ident = sourceText.ToString textSpan @@ -80,34 +72,30 @@ module internal CodeFixHelpers = TelemetryReporter.ReportSingleEvent(TelemetryEvents.CodefixActivated, props) - let createTextChangeCodeFix (name: string, title: string, context: CodeFixContext, changes: TextChange seq) = + let createTextChangeCodeFix (codeFix, context: CodeFixContext) = CodeAction.Create( - title, - (fun (cancellationToken: CancellationToken) -> - backgroundTask { - let! sourceText = context.Document.GetTextAsync(cancellationToken) - let doc = context.Document.WithText(sourceText.WithChanges(changes)) - reportCodeFixTelemetry context.Diagnostics context.Document name [||] + codeFix.Message, + (fun cancellationToken -> + cancellableTask { + let! sourceText = context.Document.GetTextAsync cancellationToken + let doc = context.Document.WithText(sourceText.WithChanges(codeFix.Changes)) + reportCodeFixTelemetry context.Diagnostics context.Document codeFix.Name [||] return doc - }), - name + } + |> CancellableTask.start cancellationToken), + codeFix.Name ) [] module internal CodeFixExtensions = type CodeFixContext with - member ctx.RegisterFsharpFix(staticName, title, changes, ?diagnostics) = - let codeAction = - CodeFixHelpers.createTextChangeCodeFix (staticName, title, ctx, changes) - - let diag = diagnostics |> Option.defaultValue ctx.Diagnostics - ctx.RegisterCodeFix(codeAction, diag) - member ctx.RegisterFsharpFix(codeFix: IFSharpCodeFixProvider) = cancellableTask { match! codeFix.GetCodeFixIfAppliesAsync ctx with - | ValueSome codeFix -> ctx.RegisterFsharpFix(codeFix.Name, codeFix.Message, codeFix.Changes) + | ValueSome codeFix -> + let codeAction = CodeFixHelpers.createTextChangeCodeFix (codeFix, ctx) + ctx.RegisterCodeFix(codeAction, ctx.Diagnostics) | ValueNone -> () } |> CancellableTask.startAsTask ctx.CancellationToken @@ -130,6 +118,15 @@ module internal CodeFixExtensions = return RoslynHelpers.TextSpanToFSharpRange(ctx.Document.FilePath, ctx.Span, sourceText) } + member ctx.GetLineNumberAndText position = + cancellableTask { + let! sourceText = ctx.GetSourceTextAsync() + let textLine = sourceText.Lines.GetLineFromPosition position + let textLinePos = sourceText.Lines.GetLinePosition position + let fcsTextLineNumber = Line.fromZ textLinePos.Line + return fcsTextLineNumber, textLine.ToString() + } + // This cannot be an extension on the code fix context // because the underlying GetFixAllProvider method doesn't take the context in. #nowarn "3511" // state machine not statically compilable diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/FixIndexerAccessLegacy.fs b/vsintegration/src/FSharp.Editor/CodeFixes/FixIndexerAccessLegacy.fs index 9b37c396473..aefd2df9ebd 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/FixIndexerAccessLegacy.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/FixIndexerAccessLegacy.fs @@ -4,26 +4,27 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System.Composition open System.Collections.Immutable -open System.Threading.Tasks open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.CodeFixes open FSharp.Compiler.Diagnostics +open CancellableTasks + [] type internal LegacyFixAddDotToIndexerAccessCodeFixProvider() = inherit CodeFixProvider() static let title = CompilerDiagnostics.GetErrorMessage FSharpDiagnosticKind.AddIndexerDot - override _.FixableDiagnosticIds = ImmutableArray.Create("FS3217") + override _.FixableDiagnosticIds = ImmutableArray.Create "FS3217" - override _.RegisterCodeFixesAsync context : Task = - async { - let! sourceText = context.Document.GetTextAsync() |> Async.AwaitTask + override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix this - context.Diagnostics - |> Seq.iter (fun diagnostic -> + interface IFSharpCodeFixProvider with + member _.GetCodeFixIfAppliesAsync context = + cancellableTask { + let! sourceText = context.GetSourceTextAsync() let span, replacement = try @@ -31,7 +32,7 @@ type internal LegacyFixAddDotToIndexerAccessCodeFixProvider() = let notStartOfBracket (span: TextSpan) = let t = sourceText.GetSubText(TextSpan(span.Start, span.Length + 1)) - t.[t.Length - 1] <> '[' + t[t.Length - 1] <> '[' // skip all braces and blanks until we find [ while span.End < sourceText.Length && notStartOfBracket span do @@ -41,12 +42,11 @@ type internal LegacyFixAddDotToIndexerAccessCodeFixProvider() = with _ -> context.Span, sourceText.GetSubText(context.Span).ToString() - do - context.RegisterFsharpFix( - CodeFix.FixIndexerAccess, - title, - [| TextChange(span, replacement.TrimEnd() + ".") |], - ImmutableArray.Create(diagnostic) - )) - } - |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken) + return + ValueSome + { + Name = CodeFix.FixIndexerAccess + Message = title + Changes = [ TextChange(span, replacement.TrimEnd() + ".") ] + } + } diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/MakeDeclarationMutable.fs b/vsintegration/src/FSharp.Editor/CodeFixes/MakeDeclarationMutable.fs index 3de1e34fb72..307b8ad0be1 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/MakeDeclarationMutable.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/MakeDeclarationMutable.fs @@ -46,8 +46,7 @@ type internal MakeDeclarationMutableCodeFixProvider [] () | Some lexerSymbol -> let! sourceText = context.GetSourceTextAsync() - let fcsTextLineNumber, textLine = - MutableCodeFixHelper.getLineNumberAndText sourceText position + let! fcsTextLineNumber, textLine = context.GetLineNumberAndText position let! parseFileResults, checkFileResults = document.GetFSharpParseAndCheckResultsAsync(nameof MakeDeclarationMutableCodeFixProvider) diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs b/vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs index 6c0b5ef77db..3807848630e 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/ReplaceWithSuggestion.fs @@ -12,7 +12,6 @@ open Microsoft.CodeAnalysis.CodeFixes open FSharp.Compiler.Diagnostics open FSharp.Compiler.EditorServices open FSharp.Compiler.Syntax -open FSharp.Compiler.Text open CancellableTasks @@ -38,9 +37,7 @@ type internal ReplaceWithSuggestionCodeFixProvider [] () = let! unresolvedIdentifierText = context.GetSquigglyTextAsync() let pos = context.Span.End let caretLinePos = sourceText.Lines.GetLinePosition(pos) - let caretLine = sourceText.Lines.GetLineFromPosition(pos) - let fcsCaretLineNumber = Line.fromZ caretLinePos.Line - let lineText = caretLine.ToString() + let! fcsCaretLineNumber, lineText = context.GetLineNumberAndText pos let partialName = QuickParse.GetPartialLongNameEx(lineText, caretLinePos.Character - 1) diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs b/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs index e4f6e595252..9b4ee1721e0 100644 --- a/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs +++ b/vsintegration/src/FSharp.Editor/CodeFixes/UseMutationWhenValueIsMutable.fs @@ -58,8 +58,7 @@ type internal UseMutationWhenValueIsMutableCodeFixProvider [ return ValueNone | Some lexerSymbol -> - let fcsTextLineNumber, textLine = - MutableCodeFixHelper.getLineNumberAndText sourceText adjustedPosition + let! fcsTextLineNumber, textLine = context.GetLineNumberAndText adjustedPosition let! _, checkFileResults = document.GetFSharpParseAndCheckResultsAsync(nameof UseMutationWhenValueIsMutableCodeFixProvider) diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/FixIndexerAccessLegacyTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/FixIndexerAccessLegacyTests.fs new file mode 100644 index 00000000000..e23b25dfb73 --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/FixIndexerAccessLegacyTests.fs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +module FSharp.Editor.Tests.CodeFixes.FixIndexerAccessLegacyTests + +open Microsoft.VisualStudio.FSharp.Editor +open Xunit + +open CodeFixTestFramework + +let private codeFix = LegacyFixAddDotToIndexerAccessCodeFixProvider() + +[] +let ``Fixes FS3217`` () = + let code = + """ +let list = [ 1; 2; 3 ] +let first = list[2] +""" + + let expected = + Some + { + Message = "Add . for indexer access." + FixedCode = + """ +let list = [ 1; 2; 3 ] +let first = list.[2] +""" + } + + let actual = codeFix |> tryFix code (WithOption "--langversion:5") + + Assert.Equal(expected, actual) diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 415567694a6..e8d25a75fb9 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -53,6 +53,7 @@ + From 6e9022acc988e0cdaf636d4556e254d4503bf765 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:13:52 +0200 Subject: [PATCH 3/5] [main] Update dependencies from dotnet/source-build-reference-packages (#15949) * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230907.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23455.3 -> To Version 8.0.0-alpha.1.23457.1 --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2a15c4c7091..b6b294bf6bf 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/source-build-reference-packages - 75ec14a961f43446d952c64b5b3330df750db54f + eeb7f1b24a845eebf3e0885a4650b8df67741d4a From 468b3b6c201faae34356684bd93c1655f786602a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:14:22 +0200 Subject: [PATCH 4/5] [main] Update dependencies from dotnet/arcade (#15975) * Update dependencies from https://github.com/dotnet/arcade build 20230913.1 Microsoft.DotNet.Arcade.Sdk From Version 8.0.0-beta.23461.2 -> To Version 8.0.0-beta.23463.1 * Update dependencies from https://github.com/dotnet/arcade build 20230913.1 Microsoft.DotNet.Arcade.Sdk From Version 8.0.0-beta.23461.2 -> To Version 8.0.0-beta.23463.1 * Update dependencies from https://github.com/dotnet/arcade build 20230913.1 Microsoft.DotNet.Arcade.Sdk From Version 8.0.0-beta.23461.2 -> To Version 8.0.0-beta.23463.1 * Update dependencies from https://github.com/dotnet/arcade build 20230913.1 Microsoft.DotNet.Arcade.Sdk From Version 8.0.0-beta.23461.2 -> To Version 8.0.0-beta.23463.1 * Update dependencies from https://github.com/dotnet/arcade build 20230913.1 Microsoft.DotNet.Arcade.Sdk From Version 8.0.0-beta.23461.2 -> To Version 8.0.0-beta.23463.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b6b294bf6bf..e9b234ae567 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -29,9 +29,9 @@ - + https://github.com/dotnet/arcade - 4a908c64757841121e67fda7adaf776c93893163 + 1d451c32dda2314c721adbf8829e1c0cd4e681ff diff --git a/global.json b/global.json index 551f4bb5205..94d29541e32 100644 --- a/global.json +++ b/global.json @@ -18,7 +18,7 @@ "perl": "5.38.0.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23461.2", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23463.1", "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2" } } From 5c491463a3800ede2c53eae1ad45d996eca04a52 Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Mon, 18 Sep 2023 18:50:18 +0200 Subject: [PATCH 5/5] Fix for AllUsesOfAllSymbols missing when using change notifications (#15966) --- src/Compiler/Service/IncrementalBuild.fs | 2 +- .../FSharpChecker/CommonWorkflows.fs | 34 +++++++++++++++++++ .../ProjectGeneration.fs | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 646bf2c4396..a76b51d9199 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -1069,7 +1069,7 @@ type IncrementalBuilderState with HasSignature = hasSignature Stamp = DateTime.MinValue LogicalStamp = DateTime.MinValue - Notified = false + Notified = true SyntaxTree = syntaxTree BoundModel = model } diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs index 551fa15eb8a..d13efc2169a 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/CommonWorkflows.fs @@ -9,6 +9,13 @@ open Xunit open FSharp.Test.ProjectGeneration open FSharp.Compiler.Text open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.Diagnostics + +open OpenTelemetry +open OpenTelemetry.Resources +open OpenTelemetry.Trace + +#nowarn "57" let makeTestProject () = SyntheticProject.Create( @@ -132,3 +139,30 @@ let ``Using getSource and notifications instead of filesystem`` () = checkFile middle expectSignatureChanged checkFile last expectSignatureChanged } + +[] +let GetAllUsesOfAllSymbols() = + let traceProvider = + Sdk.CreateTracerProviderBuilder() + .AddSource("fsc") + .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName="F#", serviceVersion = "1")) + .AddJaegerExporter() + .Build() + + use _ = Activity.start "GetAllUsesOfAllSymbols" [ ] + + let result = + async { + let project = makeTestProject() + let checker = ProjectWorkflowBuilder(project, useGetSource=true, useChangeNotifications = true).Checker + do! saveProject project false checker + let options = project.GetProjectOptions checker + let! checkProjectResults = checker.ParseAndCheckProject(options) + return checkProjectResults.GetAllUsesOfAllSymbols() + } |> Async.RunSynchronously + + + traceProvider.ForceFlush() |> ignore + traceProvider.Dispose() + + Assert.Equal(80, result.Length) diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index ee5e2bcb736..94a0ec80f77 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -806,7 +806,7 @@ type ProjectWorkflowBuilder defaultArg checker (FSharpChecker.Create( - keepAllBackgroundSymbolUses = false, + keepAllBackgroundSymbolUses = true, enableBackgroundItemKeyStoreAndSemanticClassification = true, enablePartialTypeChecking = true, captureIdentifiersWhenParsing = true,