From e27012e415330385a026fa85967db706385718ac Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 4 Oct 2023 21:22:41 +0200 Subject: [PATCH 01/57] First Draft for AddExplicitReturnType (#15562) with exploration test and resource file entry --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/FSharp.Editor.resx | 3 + .../Refactor/AddExplicitReturnType.fs | 109 ++++++++++++++++++ .../FSharp.Editor.Tests.fsproj | 2 + .../Refactors/AddExplicitReturnType.fs | 52 +++++++++ 5 files changed, 167 insertions(+) create mode 100644 vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs create mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 60e86c9eb96..7282aa2c4e2 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -99,6 +99,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 4b41551aac0..9c12f2a6519 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -352,6 +352,9 @@ Use live (unsaved) buffers for analysis Convert C# 'using' to F# 'open' + + Add explicit return type annotation + Remove unnecessary parentheses diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs new file mode 100644 index 00000000000..c603939f9fe --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Composition +open System.Threading +open System.Threading.Tasks + +open FSharp.Compiler +open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.Symbols +open FSharp.Compiler.Text +open FSharp.Compiler.Syntax + +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.CodeRefactorings +open Microsoft.CodeAnalysis.CodeActions +open CancellableTasks + +[] +type internal AddExplicitReturnType [] () = + inherit CodeRefactoringProvider() + + static member isValidMethodWithoutTypeAnnotation (funcOrValue: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) (parseFileResults:FSharpParseFileResults) = + let isLambdaIfFunction = + funcOrValue.IsFunction + && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start + + (not funcOrValue.IsValue || not isLambdaIfFunction) + && not (funcOrValue.ReturnParameter.Type.IsUnresolved) + && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) + + + static member refactor (context:CodeRefactoringContext) (symbolUse:FSharpSymbolUse,memberFunc:FSharpMemberOrFunctionOrValue,symbolSpan) = + let typeString = memberFunc.FullType.FormatWithConstraints symbolUse.DisplayContext + let title = SR.AddExplicitReturnTypeAnnotation() + + let getChangedText (sourceText: SourceText) = + let debugInfo = $"{sourceText} : {typeString} : {symbolSpan}" + debugInfo + let sub = sourceText.ToString(symbolSpan) + + let newSub = + sub.Replace("=", $" :{memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName}=") + + sourceText.Replace(symbolSpan, newSub) + + let codeActionFunc = (fun (cancellationToken: CancellationToken) -> + backgroundTask { + let! sourceText = context.Document.GetTextAsync(cancellationToken) + let changedText = getChangedText sourceText + return context.Document.WithText(changedText) + } + ) + let codeAction = + CodeAction.Create( + title, + codeActionFunc, + title + ) + + + do context.RegisterRefactoring(codeAction) + + override _.ComputeRefactoringsAsync context = + backgroundTask { + let document = context.Document + let position = context.Span.Start + let! sourceText = document.GetTextAsync() + let textLine = sourceText.Lines.GetLineFromPosition position + let textLinePos = sourceText.Lines.GetLinePosition position + let fcsTextLineNumber = Line.fromZ textLinePos.Line + + let! ct = Async.CancellationToken + + let! lexerSymbol = + document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddExplicitReturnType)) + + + let! (parseFileResults,checkFileResults) = + document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) + |> CancellableTask.start ct + + let res = + lexerSymbol + |> Option.bind(fun lexer -> + checkFileResults.GetSymbolUseAtLocation( + fcsTextLineNumber, + lexer.Ident.idRange.EndColumn, + textLine.ToString(), + lexer.FullIsland + )) + |> Option.bind(fun symbolUse-> + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v + when AddExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults-> + Some (symbolUse,v) + | _ -> None + ) + |> Option.bind(fun (symbolUse,memberFunc)-> + match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.Range) with + | Some span -> Some(symbolUse,memberFunc,span) + | None -> None + ) + |> Option.map(fun (symbolUse,memberFunc,textSpan) -> AddExplicitReturnType.refactor context (symbolUse,memberFunc,textSpan)) + + return res + } diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 77ce57f27e0..606768a9f64 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -12,6 +12,7 @@ + @@ -71,6 +72,7 @@ + diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs new file mode 100644 index 00000000000..14495b8ce07 --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -0,0 +1,52 @@ +module FSharp.Editor.Tests.Refactors.AddExplicitReturnType + +open Microsoft.VisualStudio.FSharp.Editor +open Xunit +open System +open System.Collections.Immutable +open System.Text.RegularExpressions + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CodeFixes +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks + +open FSharp.Compiler.Diagnostics +open FSharp.Editor.Tests.Helpers + +open Microsoft.CodeAnalysis.CodeRefactorings +open NUnit.Framework + + +[] +let ``Refactor changes something`` () = + task { + let code = + """ + let sum a b = a + b + """ + + let! ct = Async.CancellationToken + + let sourceText = SourceText.From code + let document = RoslynTestHelpers.GetFsDocument code + let spanStart = code.IndexOf "sum" + let span = TextSpan(spanStart, 3) + + let mutable refactorContext = + CodeRefactoringContext(document, span, Action(fun a -> ()), ct) + + let refactorProvider = AddExplicitReturnType() + let expected = None + + do! refactorProvider.ComputeRefactoringsAsync refactorContext + let newText = match refactorContext.TextDocument.TryGetText() with + | true,result -> result + | false,_ -> sourceText + + let! text = refactorContext.TextDocument.GetTextAsync( ct) + Assert.AreNotEqual(sourceText.ToString(),newText.ToString(),"") + + () + } From b0fbe672faafb9a38094b7c3a6aacf65ddddda31 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 5 Oct 2023 15:25:24 +0200 Subject: [PATCH 02/57] Added Workspace handling and some debug stuff #15562 --- .../Refactor/AddExplicitReturnType.fs | 13 +++---- .../Refactors/AddExplicitReturnType.fs | 34 +++++++++++++------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index c603939f9fe..1b019803a04 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -32,24 +32,25 @@ type internal AddExplicitReturnType [] () = && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) - static member refactor (context:CodeRefactoringContext) (symbolUse:FSharpSymbolUse,memberFunc:FSharpMemberOrFunctionOrValue,symbolSpan) = + static member refactor (context:CodeRefactoringContext) (symbolUse:FSharpSymbolUse,memberFunc:FSharpMemberOrFunctionOrValue,symbolSpan:TextSpan,textLine:TextLine) = let typeString = memberFunc.FullType.FormatWithConstraints symbolUse.DisplayContext let title = SR.AddExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = - let debugInfo = $"{sourceText} : {typeString} : {symbolSpan}" + let debugInfo = $"{sourceText} : {typeString} : {symbolSpan} : {textLine}" debugInfo - let sub = sourceText.ToString(symbolSpan) + let sub = sourceText.ToString(textLine.Span) let newSub = sub.Replace("=", $" :{memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName}=") - sourceText.Replace(symbolSpan, newSub) + sourceText.Replace(textLine.Span, newSub) let codeActionFunc = (fun (cancellationToken: CancellationToken) -> - backgroundTask { + task { let! sourceText = context.Document.GetTextAsync(cancellationToken) let changedText = getChangedText sourceText + context.Document.Project.Solution.Id return context.Document.WithText(changedText) } ) @@ -103,7 +104,7 @@ type internal AddExplicitReturnType [] () = | Some span -> Some(symbolUse,memberFunc,span) | None -> None ) - |> Option.map(fun (symbolUse,memberFunc,textSpan) -> AddExplicitReturnType.refactor context (symbolUse,memberFunc,textSpan)) + |> Option.map(fun (symbolUse,memberFunc,textSpan) -> AddExplicitReturnType.refactor context (symbolUse,memberFunc,textSpan,textLine)) return res } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 14495b8ce07..9ee0f116aae 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -17,6 +17,9 @@ open FSharp.Editor.Tests.Helpers open Microsoft.CodeAnalysis.CodeRefactorings open NUnit.Framework +open Microsoft.CodeAnalysis.CodeActions +open System.Collections.Generic +open Microsoft.VisualStudio.LanguageServices [] @@ -29,24 +32,35 @@ let ``Refactor changes something`` () = let! ct = Async.CancellationToken - let sourceText = SourceText.From code - let document = RoslynTestHelpers.GetFsDocument code + let solution = RoslynTestHelpers.CreateSolution(code) + let workspace = solution.Workspace + let document = RoslynTestHelpers.GetSingleDocument solution + let spanStart = code.IndexOf "sum" let span = TextSpan(spanStart, 3) + + + let refactorProvider = AddExplicitReturnType() + let refactoringActions= new List() let mutable refactorContext = - CodeRefactoringContext(document, span, Action(fun a -> ()), ct) + CodeRefactoringContext(document, span, (fun a -> refactoringActions.Add (a)), ct) - let refactorProvider = AddExplicitReturnType() - let expected = None do! refactorProvider.ComputeRefactoringsAsync refactorContext - let newText = match refactorContext.TextDocument.TryGetText() with - | true,result -> result - | false,_ -> sourceText - let! text = refactorContext.TextDocument.GetTextAsync( ct) - Assert.AreNotEqual(sourceText.ToString(),newText.ToString(),"") + let! operations = refactoringActions[0].GetOperationsAsync(ct) + + for operation in operations do + operation.Apply (workspace,ct) + + + + let! refactorText = refactorContext.TextDocument.GetTextAsync ct + refactorText + let! text = document.GetTextAsync ct + solution.Id + Assert.AreNotEqual(code,text.ToString(),"") () } From 81d8f0ea94dbc6de724c1d730e0762457db1c69a Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 7 Oct 2023 12:10:39 +0200 Subject: [PATCH 03/57] Added One Way of getting the changed Solution for ExplicitReturnTypes #15562 --- .../Refactor/AddExplicitReturnType.fs | 10 +- .../FSharp.Editor.Tests.fsproj | 1 + .../Refactors/AddExplicitReturnType.fs | 35 ++---- .../Refactors/RefactorTestFramework.fs | 116 ++++++++++++++++++ 4 files changed, 133 insertions(+), 29 deletions(-) create mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 1b019803a04..7dc8430de49 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -17,6 +17,7 @@ open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions open CancellableTasks +open System.Diagnostics [] type internal AddExplicitReturnType [] () = @@ -48,10 +49,15 @@ type internal AddExplicitReturnType [] () = let codeActionFunc = (fun (cancellationToken: CancellationToken) -> task { + let oldDocument = context.Document + let! sourceText = context.Document.GetTextAsync(cancellationToken) let changedText = getChangedText sourceText - context.Document.Project.Solution.Id - return context.Document.WithText(changedText) + + let newDocument = context.Document.WithText(changedText) + let! changes = newDocument.GetTextChangesAsync(oldDocument) + Debugger.Log(0,"",$"{changes}") + return newDocument } ) let codeAction = diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 606768a9f64..5b5e729cb1f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -72,6 +72,7 @@ + diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 9ee0f116aae..b412892a24e 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -20,47 +20,28 @@ open NUnit.Framework open Microsoft.CodeAnalysis.CodeActions open System.Collections.Generic open Microsoft.VisualStudio.LanguageServices +open FSharp.Editor.Tests.Refactors.RefactorTestFramework +open Microsoft.Build.Utilities +open System.Threading [] let ``Refactor changes something`` () = task { + + let ct = CancellationToken false + let code = """ let sum a b = a + b """ - let! ct = Async.CancellationToken - - let solution = RoslynTestHelpers.CreateSolution(code) - let workspace = solution.Workspace - let document = RoslynTestHelpers.GetSingleDocument solution let spanStart = code.IndexOf "sum" - let span = TextSpan(spanStart, 3) - - - let refactorProvider = AddExplicitReturnType() - let refactoringActions= new List() - - let mutable refactorContext = - CodeRefactoringContext(document, span, (fun a -> refactoringActions.Add (a)), ct) + let! result = tryRefactor code spanStart ct (new AddExplicitReturnType()) - do! refactorProvider.ComputeRefactoringsAsync refactorContext - - let! operations = refactoringActions[0].GetOperationsAsync(ct) - - for operation in operations do - operation.Apply (workspace,ct) - - - - let! refactorText = refactorContext.TextDocument.GetTextAsync ct - refactorText - let! text = document.GetTextAsync ct - solution.Id - Assert.AreNotEqual(code,text.ToString(),"") + Assert.AreNotEqual(code,result.ToString(),"") () } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs new file mode 100644 index 00000000000..63e7b07aea7 --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -0,0 +1,116 @@ +module FSharp.Editor.Tests.Refactors.RefactorTestFramework + + +open System +open System.Collections.Immutable +open System.Collections.Generic +open System.Text.RegularExpressions + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CodeFixes +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks + +open FSharp.Compiler.Diagnostics +open FSharp.Editor.Tests.Helpers +open Microsoft.CodeAnalysis.CodeRefactorings +open Microsoft.CodeAnalysis.CodeActions +open System.Collections.Generic +open System.Threading +open Microsoft.CodeAnalysis.Tags +open System.Reflection +open Microsoft.FSharp.Reflection + +type DynamicHelper = + static member MkMethod<'t,'u> (mi:MethodInfo) o : 't -> 'u= + let typ = typeof<'t> + fun t -> + let args = + if (typ = typeof) then [||] + else + if not (FSharpType.IsTuple typ) then [| box t |] + else + FSharpValue.GetTupleFields t + mi.Invoke(o, args) :?> 'u + +let (?) (o:'a) s : 'b = + let ty = o.GetType() + let field = ty.GetField(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic) + if field <> null then field.GetValue(o) :?> 'b + else + let prop = ty.GetProperty(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic) + if prop <> null then prop.GetValue(o, null) :?> 'b + else + let meth = ty.GetMethod(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic) + let d,r = FSharpType.GetFunctionElements(typeof<'b>) + typeof.GetMethod("MkMethod").MakeGenericMethod([|d;r|]).Invoke(null, [| box meth; box o |]) :?> 'b +type TestCodeFix = { Message: string; FixedCode: string } + +type Mode = + | Auto + | WithOption of CustomProjectOption: string + | WithSignature of FsiCode: string + | Manual of Squiggly: string * Diagnostic: string + | WithSettings of CodeFixesOptions + +let inline toOption o = + match o with + | ValueSome v -> Some v + | _ -> None + +let mockAction = + Action>(fun _ _ -> ()) + +let parseDiagnostic diagnostic = + let regex = Regex "([A-Z]+)(\d+)" + let matchGroups = regex.Match(diagnostic).Groups + let prefix = matchGroups[1].Value + let number = int matchGroups[2].Value + number, prefix + +let getDocument code mode = + match mode with + | Auto -> RoslynTestHelpers.GetFsDocument code + | WithOption option -> RoslynTestHelpers.GetFsDocument(code, option) + | WithSignature fsiCode -> RoslynTestHelpers.GetFsiAndFsDocuments fsiCode code |> Seq.last + | Manual _ -> RoslynTestHelpers.GetFsDocument code + | WithSettings settings -> RoslynTestHelpers.GetFsDocument(code, customEditorOptions = settings) + +let getRelevantDiagnostics (document: Document) = + cancellableTask { + let! _, checkFileResults = document.GetFSharpParseAndCheckResultsAsync "test" + + return checkFileResults.Diagnostics + } + |> CancellableTask.startWithoutCancellation + |> fun task -> task.Result + + + +let tryRefactor (code: string) (cursorPosition) (ct) (refactorProvider: 'T when 'T :> CodeRefactoringProvider ) = + cancellableTask { + let refactoringActions= new List() + + let mutable solution = RoslynTestHelpers.CreateSolution(code) + + let document = RoslynTestHelpers.GetSingleDocument solution + + use mutable workspace = solution.Workspace + + let context = CodeRefactoringContext(document, TextSpan(cursorPosition,1), (fun a -> refactoringActions.Add a),ct) + + do! refactorProvider.ComputeRefactoringsAsync context + for action in refactoringActions do + let! operations = action.GetOperationsAsync ct + for operation in operations do + let codeChangeOperation = operation :?> ApplyChangesOperation + codeChangeOperation.Apply(workspace,ct) + solution <- codeChangeOperation.ChangedSolution + () + + + let! changedText = solution.GetDocument(document.Id).GetTextAsync(ct) + return changedText + } + |> CancellableTask.startWithoutCancellation From 25b901e666607dbe9629c6d510b83c96b5863322 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sun, 8 Oct 2023 10:28:01 +0200 Subject: [PATCH 04/57] added language resource files (not translated) #15562 --- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 5 +++++ .../src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf | 5 +++++ .../src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf | 5 +++++ 13 files changed, 65 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 5db40f51628..b80a2c6ac40 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Přidejte do definice typu chybějící =. diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index 31ffc4c8342..b1abace993e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Fehlende "=" zur Typdefinition hinzufügen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index dceb8706e99..2be2317bbf9 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Agregar el carácter "=" que falta a la definición de tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index db53640c9a5..02c7d4c78b4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Ajouter un '=' manquant à la définition de type diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index 97feb5816e2..dcedb50b426 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Aggiungere il carattere '=' mancante alla definizione di tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index f9682a8d5fd..22923fa1f76 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition 不足している '=' を型定義に追加します diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 638099fe0fb..591df2ccb6a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition 형식 정의에 누락된 '=' 추가 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index cc17e6d540e..863bf742b2f 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Dodaj brakujący element znak „=” do definicji typu diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index 492073cacb0..24b5cf709fa 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Adicionar o '=' ausente à definição de tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index b8549511a9f..29bd87400b6 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Добавьте недостающий символ "=" к определению типа. diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index e6e9332dc33..ef5ee782c32 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition Tür tanımına eksik '=' işaretini ekle diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 6df4f779a61..0820f856e7e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition 将缺少的 "=" 添加到类型定义 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index d270271bb75..484be626cdd 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -2,6 +2,11 @@ + + Add explicit return type annotation + Add explicit return type annotation + + Add missing '=' to type definition 將缺少的 '=' 新增至類型定義 From c9baedae76e74f75ab1366e94e6fb4ba54f29750 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 19 Oct 2023 14:56:02 +0200 Subject: [PATCH 05/57] refactor: Create test context and check return type --- .../Refactor/AddExplicitReturnType.fs | 111 +++++++++--------- .../Refactors/AddExplicitReturnType.fs | 58 ++++++++- .../Refactors/RefactorTestFramework.fs | 102 +++++----------- 3 files changed, 139 insertions(+), 132 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 7dc8430de49..6aaaf19d539 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -23,7 +23,14 @@ open System.Diagnostics type internal AddExplicitReturnType [] () = inherit CodeRefactoringProvider() - static member isValidMethodWithoutTypeAnnotation (funcOrValue: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) (parseFileResults:FSharpParseFileResults) = + static member isValidMethodWithoutTypeAnnotation + (funcOrValue: FSharpMemberOrFunctionOrValue) + (symbolUse: FSharpSymbolUse) + (parseFileResults: FSharpParseFileResults) + = + let typeAnnotationRange = + parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) + let isLambdaIfFunction = funcOrValue.IsFunction && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start @@ -31,42 +38,40 @@ type internal AddExplicitReturnType [] () = (not funcOrValue.IsValue || not isLambdaIfFunction) && not (funcOrValue.ReturnParameter.Type.IsUnresolved) && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) + && not typeAnnotationRange.IsNone - - static member refactor (context:CodeRefactoringContext) (symbolUse:FSharpSymbolUse,memberFunc:FSharpMemberOrFunctionOrValue,symbolSpan:TextSpan,textLine:TextLine) = - let typeString = memberFunc.FullType.FormatWithConstraints symbolUse.DisplayContext + static member refactor + (context: CodeRefactoringContext) + (symbolUse: FSharpSymbolUse, memberFunc: FSharpMemberOrFunctionOrValue, parseFileResults: FSharpParseFileResults) + = let title = SR.AddExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = - let debugInfo = $"{sourceText} : {typeString} : {symbolSpan} : {textLine}" - debugInfo - let sub = sourceText.ToString(textLine.Span) - - let newSub = - sub.Replace("=", $" :{memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName}=") - - sourceText.Replace(textLine.Span, newSub) - - let codeActionFunc = (fun (cancellationToken: CancellationToken) -> - task { - let oldDocument = context.Document - - let! sourceText = context.Document.GetTextAsync(cancellationToken) - let changedText = getChangedText sourceText - - let newDocument = context.Document.WithText(changedText) - let! changes = newDocument.GetTextChangesAsync(oldDocument) - Debugger.Log(0,"",$"{changes}") - return newDocument - } - ) - let codeAction = - CodeAction.Create( - title, - codeActionFunc, - title - ) - + let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName + + let rangeOfReturnType = + parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) + + let textChange = + rangeOfReturnType + |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) + |> Option.map (fun textSpan -> TextChange(textSpan, $":{inferredType}")) + + match textChange with + | Some textChange -> sourceText.WithChanges(textChange) + | None -> sourceText + + let codeActionFunc = + (fun (cancellationToken: CancellationToken) -> + task { + let! sourceText = context.Document.GetTextAsync(cancellationToken) + let changedText = getChangedText sourceText + + let newDocument = context.Document.WithText(changedText) + return newDocument + }) + + let codeAction = CodeAction.Create(title, codeActionFunc, title) do context.RegisterRefactoring(codeAction) @@ -83,34 +88,30 @@ type internal AddExplicitReturnType [] () = let! lexerSymbol = document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddExplicitReturnType)) + |> CancellableTask.start ct - - let! (parseFileResults,checkFileResults) = + let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) |> CancellableTask.start ct - let res = + let res = lexerSymbol - |> Option.bind(fun lexer -> + |> Option.bind (fun lexer -> checkFileResults.GetSymbolUseAtLocation( - fcsTextLineNumber, - lexer.Ident.idRange.EndColumn, - textLine.ToString(), - lexer.FullIsland - )) - |> Option.bind(fun symbolUse-> - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v - when AddExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults-> - Some (symbolUse,v) - | _ -> None - ) - |> Option.bind(fun (symbolUse,memberFunc)-> - match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.Range) with - | Some span -> Some(symbolUse,memberFunc,span) - | None -> None - ) - |> Option.map(fun (symbolUse,memberFunc,textSpan) -> AddExplicitReturnType.refactor context (symbolUse,memberFunc,textSpan,textLine)) + fcsTextLineNumber, + lexer.Ident.idRange.EndColumn, + textLine.ToString(), + lexer.FullIsland + )) + |> Option.bind (fun symbolUse -> + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v when + AddExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults + -> + Some(symbolUse, v) + | _ -> None) + |> Option.map (fun (symbolUse, memberFunc) -> + AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults)) return res } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index b412892a24e..be7ea36a922 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -23,25 +23,73 @@ open Microsoft.VisualStudio.LanguageServices open FSharp.Editor.Tests.Refactors.RefactorTestFramework open Microsoft.Build.Utilities open System.Threading - +open FSharp.Test.ReflectionHelper +open Microsoft.Build.Utilities +open FSharp.Test.ProjectGeneration.ProjectOperations [] let ``Refactor changes something`` () = task { - - let ct = CancellationToken false let code = """ let sum a b = a + b """ + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf "sum" + + let! (_, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + + Assert.AreNotEqual(code, text.ToString(), "") + + () + } + +[] +let ``Refactor changes nothing`` () = + task { + + let code = + """ + let sum a b :int= a + b + """ + + use context = TestContext.CreateWithCode code let spanStart = code.IndexOf "sum" - let! result = tryRefactor code spanStart ct (new AddExplicitReturnType()) + let! (_, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + + Assert.AreEqual(code, text.ToString(), "") + + () + } + +[] +let ``Correctly infer int as explicit return type`` () = + task { + + let code = + """ + let sum a b = a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf "sum" + + let! (document, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let! (parseFileResults, checkFileResults) = + document.GetFSharpParseAndCheckResultsAsync "test" + |> CancellableTask.start context.CT + + let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile context.CT + let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = "sum") - Assert.AreNotEqual(code,result.ToString(),"") + text.ToString().Contains(":int=") |> Assert.IsTrue () } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 63e7b07aea7..5cab670e927 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -1,6 +1,5 @@ module FSharp.Editor.Tests.Refactors.RefactorTestFramework - open System open System.Collections.Immutable open System.Collections.Generic @@ -22,95 +21,54 @@ open Microsoft.CodeAnalysis.Tags open System.Reflection open Microsoft.FSharp.Reflection -type DynamicHelper = - static member MkMethod<'t,'u> (mi:MethodInfo) o : 't -> 'u= - let typ = typeof<'t> - fun t -> - let args = - if (typ = typeof) then [||] - else - if not (FSharpType.IsTuple typ) then [| box t |] - else - FSharpValue.GetTupleFields t - mi.Invoke(o, args) :?> 'u - -let (?) (o:'a) s : 'b = - let ty = o.GetType() - let field = ty.GetField(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic) - if field <> null then field.GetValue(o) :?> 'b - else - let prop = ty.GetProperty(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic) - if prop <> null then prop.GetValue(o, null) :?> 'b - else - let meth = ty.GetMethod(s, BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic) - let d,r = FSharpType.GetFunctionElements(typeof<'b>) - typeof.GetMethod("MkMethod").MakeGenericMethod([|d;r|]).Invoke(null, [| box meth; box o |]) :?> 'b type TestCodeFix = { Message: string; FixedCode: string } -type Mode = - | Auto - | WithOption of CustomProjectOption: string - | WithSignature of FsiCode: string - | Manual of Squiggly: string * Diagnostic: string - | WithSettings of CodeFixesOptions +type TestContext(Solution: Solution, CT) = + let mutable _solution = Solution + member this.CT = CT + + member this.Solution + with set value = _solution <- value + and get () = _solution + + interface IDisposable with + member this.Dispose() = Solution.Workspace.Dispose() -let inline toOption o = - match o with - | ValueSome v -> Some v - | _ -> None + static member CreateWithCode(code: string) = + let solution = RoslynTestHelpers.CreateSolution(code) + let ct = CancellationToken false + new TestContext(solution, ct) let mockAction = Action>(fun _ _ -> ()) -let parseDiagnostic diagnostic = - let regex = Regex "([A-Z]+)(\d+)" - let matchGroups = regex.Match(diagnostic).Groups - let prefix = matchGroups[1].Value - let number = int matchGroups[2].Value - number, prefix - -let getDocument code mode = - match mode with - | Auto -> RoslynTestHelpers.GetFsDocument code - | WithOption option -> RoslynTestHelpers.GetFsDocument(code, option) - | WithSignature fsiCode -> RoslynTestHelpers.GetFsiAndFsDocuments fsiCode code |> Seq.last - | Manual _ -> RoslynTestHelpers.GetFsDocument code - | WithSettings settings -> RoslynTestHelpers.GetFsDocument(code, customEditorOptions = settings) - -let getRelevantDiagnostics (document: Document) = +let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = cancellableTask { - let! _, checkFileResults = document.GetFSharpParseAndCheckResultsAsync "test" + let refactoringActions = new List() + let existingDocument = RoslynTestHelpers.GetSingleDocument context.Solution - return checkFileResults.Diagnostics - } - |> CancellableTask.startWithoutCancellation - |> fun task -> task.Result + context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) + let document = RoslynTestHelpers.GetSingleDocument context.Solution + let mutable workspace = context.Solution.Workspace -let tryRefactor (code: string) (cursorPosition) (ct) (refactorProvider: 'T when 'T :> CodeRefactoringProvider ) = - cancellableTask { - let refactoringActions= new List() + let refactoringContext = + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) - let mutable solution = RoslynTestHelpers.CreateSolution(code) + do! refactorProvider.ComputeRefactoringsAsync refactoringContext - let document = RoslynTestHelpers.GetSingleDocument solution - - use mutable workspace = solution.Workspace - - let context = CodeRefactoringContext(document, TextSpan(cursorPosition,1), (fun a -> refactoringActions.Add a),ct) - - do! refactorProvider.ComputeRefactoringsAsync context for action in refactoringActions do - let! operations = action.GetOperationsAsync ct + let! operations = action.GetOperationsAsync context.CT + for operation in operations do let codeChangeOperation = operation :?> ApplyChangesOperation - codeChangeOperation.Apply(workspace,ct) - solution <- codeChangeOperation.ChangedSolution + codeChangeOperation.Apply(workspace, context.CT) + context.Solution <- codeChangeOperation.ChangedSolution () - - let! changedText = solution.GetDocument(document.Id).GetTextAsync(ct) - return changedText + let newDocument = context.Solution.GetDocument(document.Id) + let! changedText = newDocument.GetTextAsync(context.CT) + return (newDocument, changedText) } |> CancellableTask.startWithoutCancellation From 42d67f5546e5e89388ec8c9c78617e40a9a6c0df Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 19 Oct 2023 18:27:10 +0200 Subject: [PATCH 06/57] refactor: Add explicit return type in FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs This commit adds an explicit return type to a function in the `AddExplicitReturnType.fs` file. The function now correctly infers `int` as the return type and includes a test to verify this behavior. --- .../FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index be7ea36a922..819f5a450ff 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -26,6 +26,7 @@ open System.Threading open FSharp.Test.ReflectionHelper open Microsoft.Build.Utilities open FSharp.Test.ProjectGeneration.ProjectOperations +open FSharp.Compiler.Symbols [] let ``Refactor changes something`` () = @@ -89,7 +90,9 @@ let ``Correctly infer int as explicit return type`` () = let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile context.CT let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = "sum") - text.ToString().Contains(":int=") |> Assert.IsTrue + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Assert.AreEqual("int", v.ReturnParameter.Type.TypeDefinition.CompiledName) + | _ -> failwith "Unexpected symbol" () } From 493b374722731a542aece7ba3c2467a1b32adc4c Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 19 Oct 2023 18:37:13 +0200 Subject: [PATCH 07/57] feat: Add function to get return type of symbol This commit adds a new function `GetReturnTypeOfSymbol` which takes a symbol name and a document as input, and returns the return type of the symbol. This function is used in the test case `Correctly infer int as explicit return type` to verify that the inferred return type of the symbol "sum" is "int". --- .../Refactors/AddExplicitReturnType.fs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 819f5a450ff..65d5228b09c 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -68,6 +68,20 @@ let ``Refactor changes nothing`` () = () } +let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = + task { + let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "test" |> CancellableTask.start ct + + let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct + let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) + + return + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Some(v.ReturnParameter.Type.TypeDefinition.CompiledName) + | _ -> None + + } + [] let ``Correctly infer int as explicit return type`` () = task { @@ -83,16 +97,11 @@ let ``Correctly infer int as explicit return type`` () = let! (document, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) - let! (parseFileResults, checkFileResults) = - document.GetFSharpParseAndCheckResultsAsync "test" - |> CancellableTask.start context.CT - - let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile context.CT - let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = "sum") + let! returnType = GetReturnTypeOfSymbol "sum" document context.CT - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v -> Assert.AreEqual("int", v.ReturnParameter.Type.TypeDefinition.CompiledName) - | _ -> failwith "Unexpected symbol" + match returnType with + | Some t -> Assert.AreEqual("int", t) + | None -> failwith "Unexpected symbol" () } From 12d76d4a74e44f3d64f03906ffb04fa8c66188ec Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Fri, 20 Oct 2023 14:53:50 +0200 Subject: [PATCH 08/57] refactor: Remove explicit return type annotation - Added new file "RemoveExplicitReturnType.fs" to the project - Updated "FSharp.Editor.fsproj" and "FSharp.Editor.Tests.fsproj" to include the new file - Modified code in "RemoveExplicitReturnType.fs" to remove explicit return type annotations from F# functions - Updated tests in "AddExplicitReturnType.fs" and "RemoveExplicitReturnType.fs" to reflect the changes --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/FSharp.Editor.resx | 3 + .../Refactor/RemoveExplicitReturnType.fs | 117 ++++++++++++++++++ .../FSharp.Editor.Tests.fsproj | 1 + .../Refactors/AddExplicitReturnType.fs | 25 ++++ .../Refactors/RemoveExplicitReturnType.fs | 68 ++++++++++ 6 files changed, 215 insertions(+) create mode 100644 vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs create mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 7282aa2c4e2..1981a7f39a7 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -100,6 +100,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 9c12f2a6519..27374b00a28 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -355,6 +355,9 @@ Use live (unsaved) buffers for analysis Add explicit return type annotation + + Remove explicit return type annotation + Remove unnecessary parentheses diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs new file mode 100644 index 00000000000..0a53fa35b64 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Composition +open System.Threading +open System.Threading.Tasks + +open FSharp.Compiler +open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.Symbols +open FSharp.Compiler.Text +open FSharp.Compiler.Syntax + +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.CodeRefactorings +open Microsoft.CodeAnalysis.CodeActions +open CancellableTasks +open System.Diagnostics + +[] +type internal RemoveExplicitReturnType [] () = + inherit CodeRefactoringProvider() + + static member isValidMethodWithoutTypeAnnotation + (funcOrValue: FSharpMemberOrFunctionOrValue) + (symbolUse: FSharpSymbolUse) + (parseFileResults: FSharpParseFileResults) + = + let typeAnnotationRange = + parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) + + let isLambdaIfFunction = + funcOrValue.IsFunction + && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start + + (not funcOrValue.IsValue || not isLambdaIfFunction) + && not (funcOrValue.ReturnParameter.Type.IsUnresolved) + && (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) + && typeAnnotationRange.IsNone + + static member refactor + (context: CodeRefactoringContext) + (symbolUse: FSharpSymbolUse, memberFunc: FSharpMemberOrFunctionOrValue, parseFileResults: FSharpParseFileResults) + = + let title = SR.RemoveExplicitReturnTypeAnnotation() + + let getChangedText (sourceText: SourceText) = + let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName + + let rangeOfReturnType = + parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) + + let textChange = + rangeOfReturnType + |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) + |> Option.map (fun textSpan -> TextChange(textSpan, $":{inferredType}")) + + match textChange with + | Some textChange -> sourceText.WithChanges(textChange) + | None -> sourceText + + let codeActionFunc = + (fun (cancellationToken: CancellationToken) -> + task { + let! sourceText = context.Document.GetTextAsync(cancellationToken) + let changedText = getChangedText sourceText + + let newDocument = context.Document.WithText(changedText) + return newDocument + }) + + let codeAction = CodeAction.Create(title, codeActionFunc, title) + + do context.RegisterRefactoring(codeAction) + + override _.ComputeRefactoringsAsync context = + backgroundTask { + let document = context.Document + let position = context.Span.Start + let! sourceText = document.GetTextAsync() + let textLine = sourceText.Lines.GetLineFromPosition position + let textLinePos = sourceText.Lines.GetLinePosition position + let fcsTextLineNumber = Line.fromZ textLinePos.Line + + let! ct = Async.CancellationToken + + let! lexerSymbol = + document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (RemoveExplicitReturnType)) + |> CancellableTask.start ct + + let! (parseFileResults, checkFileResults) = + document.GetFSharpParseAndCheckResultsAsync(nameof (RemoveExplicitReturnType)) + |> CancellableTask.start ct + + let res = + lexerSymbol + |> Option.bind (fun lexer -> + checkFileResults.GetSymbolUseAtLocation( + fcsTextLineNumber, + lexer.Ident.idRange.EndColumn, + textLine.ToString(), + lexer.FullIsland + )) + |> Option.bind (fun symbolUse -> + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v when + RemoveExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults + -> + Some(symbolUse, v) + | _ -> None) + |> Option.map (fun (symbolUse, memberFunc) -> + RemoveExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults)) + + return res + } diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 5b5e729cb1f..05e54a69daf 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -74,6 +74,7 @@ + diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 65d5228b09c..6839d5ea29c 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -105,3 +105,28 @@ let ``Correctly infer int as explicit return type`` () = () } + +[] +let ``Correctly infer custom type that is declared earlier in file`` () = + task { + + let code = + """ + type MyType = { Value: int } + let sum a b = {Value=a+b} + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf "sum" + + let! (document, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let! returnType = GetReturnTypeOfSymbol "sum" document context.CT + + match returnType with + | Some t -> Assert.AreEqual("MyType", t) + | None -> failwith "Unexpected symbol" + + () + } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs new file mode 100644 index 00000000000..36682bbf303 --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -0,0 +1,68 @@ +module FSharp.Editor.Tests.Refactors.RemoveExplicitReturnType + +open Microsoft.VisualStudio.FSharp.Editor +open Xunit +open System +open System.Collections.Immutable +open System.Text.RegularExpressions + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CodeFixes +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks + +open FSharp.Compiler.Diagnostics +open FSharp.Editor.Tests.Helpers + +open Microsoft.CodeAnalysis.CodeRefactorings +open NUnit.Framework +open Microsoft.CodeAnalysis.CodeActions +open System.Collections.Generic +open Microsoft.VisualStudio.LanguageServices +open FSharp.Editor.Tests.Refactors.RefactorTestFramework +open Microsoft.Build.Utilities +open System.Threading +open FSharp.Test.ReflectionHelper +open Microsoft.Build.Utilities +open FSharp.Test.ProjectGeneration.ProjectOperations +open FSharp.Compiler.Symbols + +[] +let ``Refactor changes something`` () = + task { + + let code = + $""" + let sum a b :int= a + b + """ + + use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf "sum" + + let! (_, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + + Assert.AreNotEqual(code, text.ToString(), "") + + () + } + +[] +let ``Refactor changes nothing`` () = + task { + + let code = + $""" + let sum a b = a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf "sum" + + let! (_, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + + Assert.AreEqual(code, text.ToString(), "") + + () + } From b22a519f7a8c2914a9946333fa18f7edcd06331e Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Fri, 20 Oct 2023 14:54:23 +0200 Subject: [PATCH 09/57] chore: committed resources --- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 5 +++++ vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 5 +++++ .../src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf | 5 +++++ .../src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf | 5 +++++ 13 files changed, 65 insertions(+) diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index b80a2c6ac40..d5a236b63aa 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -211,6 +211,11 @@ Tečkované podtržení; Přerušované podtržení; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' Odebrat return diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index b1abace993e..b44197256c1 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -211,6 +211,11 @@ Punkt unterstrichen; Strich unterstrichen; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' "return" entfernen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 2be2317bbf9..1ad994254cb 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -213,6 +213,11 @@ Subrayado de punto; Subrayado de guion; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' Quitar "return" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 02c7d4c78b4..6236bb341a8 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -211,6 +211,11 @@ Soulignement pointé ; Soulignement en tirets ; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' Supprimer 'return' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index dcedb50b426..d97f7bf8d2a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -211,6 +211,11 @@ Sottolineatura a punto; Sottolineatura a trattini; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' Rimuovi 'return' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 22923fa1f76..26615125687 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -211,6 +211,11 @@ F# 構文規則に準拠するよう、改行を追加して指定された幅 ダッシュ下線; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' 'return' の削除 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 591df2ccb6a..8e36f8e1d2c 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -212,6 +212,11 @@ F# 구문 규칙에 맞는 줄바꿈을 추가하여 지정된 너비에 서명 대시 밑줄; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' 'return' 제거 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 863bf742b2f..8e0e80a04eb 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -211,6 +211,11 @@ Podkreślenie kropką; Podkreślenie kreską; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' Usuń element „return” diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index 24b5cf709fa..1f1c8cd3305 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -211,6 +211,11 @@ Ponto sublinhado; Traço sublinhado; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' Remover 'return' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 29bd87400b6..2e0db61f66e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -211,6 +211,11 @@ Dash underline; Штриховое подчеркивание; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' Удалить "return" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index ef5ee782c32..d3db21d3426 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -211,6 +211,11 @@ Nokta alt çizgi; Tire alt çizgisi; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' 'return' öğesini kaldır diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 0820f856e7e..bba7765c221 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -211,6 +211,11 @@ Dash underline; 短划线下划线; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' 删除 "return" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 484be626cdd..71df9aa5c88 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -211,6 +211,11 @@ Dash underline; 虛線底線; + + Remove explicit return type annotation + Remove explicit return type annotation + + Remove 'return' 移除 'return' From a14c0485f34b5f3583414a50a97bbdc23b52de3b Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 23 Oct 2023 18:23:56 +0200 Subject: [PATCH 10/57] * test(FSharp.Editor.Tests): finally got a working test for remove epxlicit return type --- .../Refactor/AddExplicitReturnType.fs | 9 +++--- .../Refactor/RemoveExplicitReturnType.fs | 32 +++++++------------ .../Refactors/RefactorTestFramework.fs | 2 +- .../Refactors/RemoveExplicitReturnType.fs | 25 +-------------- 4 files changed, 18 insertions(+), 50 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 6aaaf19d539..aa1a0477760 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -13,6 +13,7 @@ open FSharp.Compiler.Symbols open FSharp.Compiler.Text open FSharp.Compiler.Syntax +open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions @@ -61,15 +62,15 @@ type internal AddExplicitReturnType [] () = | Some textChange -> sourceText.WithChanges(textChange) | None -> sourceText - let codeActionFunc = - (fun (cancellationToken: CancellationToken) -> + let codeActionFunc: CancellationToken -> Task = + fun (cancellationToken: CancellationToken) -> task { let! sourceText = context.Document.GetTextAsync(cancellationToken) let changedText = getChangedText sourceText let newDocument = context.Document.WithText(changedText) return newDocument - }) + } let codeAction = CodeAction.Create(title, codeActionFunc, title) @@ -114,4 +115,4 @@ type internal AddExplicitReturnType [] () = AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults)) return res - } + } \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index 0a53fa35b64..0ee6a22ba56 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -28,38 +28,29 @@ type internal RemoveExplicitReturnType [] () = (symbolUse: FSharpSymbolUse) (parseFileResults: FSharpParseFileResults) = - let typeAnnotationRange = + let returnTypeHintAlreadyPresent = parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) + |> Option.isNone let isLambdaIfFunction = funcOrValue.IsFunction && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start (not funcOrValue.IsValue || not isLambdaIfFunction) - && not (funcOrValue.ReturnParameter.Type.IsUnresolved) - && (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) - && typeAnnotationRange.IsNone + && returnTypeHintAlreadyPresent - static member refactor - (context: CodeRefactoringContext) - (symbolUse: FSharpSymbolUse, memberFunc: FSharpMemberOrFunctionOrValue, parseFileResults: FSharpParseFileResults) - = + static member refactor (context: CodeRefactoringContext) (memberFunc: FSharpMemberOrFunctionOrValue) = let title = SR.RemoveExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName + inferredType + let rangeOfReturnType = memberFunc.ReturnParameter.DeclarationLocation - let rangeOfReturnType = - parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) - - let textChange = - rangeOfReturnType - |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) - |> Option.map (fun textSpan -> TextChange(textSpan, $":{inferredType}")) + let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, rangeOfReturnType) + let textChange = TextChange(textSpan, $"") - match textChange with - | Some textChange -> sourceText.WithChanges(textChange) - | None -> sourceText + sourceText.WithChanges(textChange) let codeActionFunc = (fun (cancellationToken: CancellationToken) -> @@ -108,10 +99,9 @@ type internal RemoveExplicitReturnType [] () = | :? FSharpMemberOrFunctionOrValue as v when RemoveExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults -> - Some(symbolUse, v) + Some(v) | _ -> None) - |> Option.map (fun (symbolUse, memberFunc) -> - RemoveExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults)) + |> Option.map (fun (memberFunc) -> RemoveExplicitReturnType.refactor context memberFunc) return res } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 5cab670e927..9c6a073c412 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -71,4 +71,4 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor let! changedText = newDocument.GetTextAsync(context.CT) return (newDocument, changedText) } - |> CancellableTask.startWithoutCancellation + |> CancellableTask.startWithoutCancellation \ No newline at end of file diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index 36682bbf303..fb03f7eb043 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -2,31 +2,8 @@ open Microsoft.VisualStudio.FSharp.Editor open Xunit -open System -open System.Collections.Immutable -open System.Text.RegularExpressions - -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.CodeFixes -open Microsoft.CodeAnalysis.Text -open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks - -open FSharp.Compiler.Diagnostics -open FSharp.Editor.Tests.Helpers - -open Microsoft.CodeAnalysis.CodeRefactorings open NUnit.Framework -open Microsoft.CodeAnalysis.CodeActions -open System.Collections.Generic -open Microsoft.VisualStudio.LanguageServices open FSharp.Editor.Tests.Refactors.RefactorTestFramework -open Microsoft.Build.Utilities -open System.Threading -open FSharp.Test.ReflectionHelper -open Microsoft.Build.Utilities -open FSharp.Test.ProjectGeneration.ProjectOperations -open FSharp.Compiler.Symbols [] let ``Refactor changes something`` () = @@ -65,4 +42,4 @@ let ``Refactor changes nothing`` () = Assert.AreEqual(code, text.ToString(), "") () - } + } \ No newline at end of file From 7b317753db2d4376aba907bc500f30a589b6122e Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 24 Oct 2023 10:39:07 +0200 Subject: [PATCH 11/57] =?UTF-8?q?=F0=9F=9A=80feat(tests)=20add=20F#=20edit?= =?UTF-8?q?or=20refactoring=20tests=20=F0=9F=9A=80feat(refactor)=20add=20e?= =?UTF-8?q?xplicit=20return=20type=20=F0=9F=9B=A0=EF=B8=8Frefactor(refacto?= =?UTF-8?q?r)=20remove=20explicit=20return=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Refactors/AddExplicitReturnType.fs | 24 +++++++----- .../Refactors/RemoveExplicitReturnType.fs | 39 +++++++++++++++++-- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 6839d5ea29c..eefd3b7638e 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -27,14 +27,20 @@ open FSharp.Test.ReflectionHelper open Microsoft.Build.Utilities open FSharp.Test.ProjectGeneration.ProjectOperations open FSharp.Compiler.Symbols - -[] -let ``Refactor changes something`` () = +open Xunit +open System.Runtime.InteropServices + +[] +[] +[] +[] +[] +let ``Refactor changes nothing`` (shouldNotTrigger: string) = task { let code = - """ - let sum a b = a + b + $""" + let sum a b {shouldNotTrigger}= a + b """ use context = TestContext.CreateWithCode code @@ -43,18 +49,18 @@ let ``Refactor changes something`` () = let! (_, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) - Assert.AreNotEqual(code, text.ToString(), "") + Assert.AreEqual(code, text.ToString(), "") () } [] -let ``Refactor changes nothing`` () = +let ``Refactor changes something`` () = task { let code = """ - let sum a b :int= a + b + let sum a b = a + b """ use context = TestContext.CreateWithCode code @@ -63,7 +69,7 @@ let ``Refactor changes nothing`` () = let! (_, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) - Assert.AreEqual(code, text.ToString(), "") + Assert.AreNotEqual(code, text.ToString(), "") () } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index fb03f7eb043..9b2cfc3bc53 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -4,14 +4,20 @@ open Microsoft.VisualStudio.FSharp.Editor open Xunit open NUnit.Framework open FSharp.Editor.Tests.Refactors.RefactorTestFramework +open Xunit +open System.Runtime.InteropServices -[] -let ``Refactor changes something`` () = +[] +[] +[] +[] +[] +let ``Refactor changes something`` (toRemove: string) = task { let code = $""" - let sum a b :int= a + b + let sum a b {toRemove}= a + b """ use context = TestContext.CreateWithCode code @@ -20,6 +26,7 @@ let ``Refactor changes something`` () = let! (_, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) Assert.AreNotEqual(code, text.ToString(), "") + //Todo: actually test if there is no return type anymore? () } @@ -42,4 +49,28 @@ let ``Refactor changes nothing`` () = Assert.AreEqual(code, text.ToString(), "") () - } \ No newline at end of file + } + +[] +let ``Refactor should not change anything`` () = + task { + + let code = + """ + type A = { X:int } + type B = { X:int } + + let f (i: int) : A = { X = i } + let sum a b = a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf "sum" + + let! (_, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + + Assert.AreEqual(code, text.ToString(), "") + + () + } From 83bfb1ed07d58e711eea22876ffc815ca24e2fac Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 24 Oct 2023 10:55:45 +0200 Subject: [PATCH 12/57] fix: formatting --- .../src/FSharp.Editor/Refactor/AddExplicitReturnType.fs | 2 +- .../FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index aa1a0477760..a5d0c6c90e0 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -115,4 +115,4 @@ type internal AddExplicitReturnType [] () = AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults)) return res - } \ No newline at end of file + } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 9c6a073c412..5cab670e927 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -71,4 +71,4 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor let! changedText = newDocument.GetTextAsync(context.CT) return (newDocument, changedText) } - |> CancellableTask.startWithoutCancellation \ No newline at end of file + |> CancellableTask.startWithoutCancellation From da2dc258a7b49bf00feed8ccd7a341596671048c Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 24 Oct 2023 11:47:13 +0200 Subject: [PATCH 13/57] * refactor(FSharp.Editor): improve explicit return type removal * test(FSharp.Editor): enhance AddExplicitReturnType test * feat(FSharp.Editor.Tests): add helper functions to RefactorTestFramework * test(FSharp.Editor): improve RemoveExplicitReturnType test --- .../Refactor/RemoveExplicitReturnType.fs | 5 +-- .../Refactors/AddExplicitReturnType.fs | 27 ++++++--------- .../Refactors/RefactorTestFramework.fs | 33 +++++++++++++++++++ .../Refactors/RemoveExplicitReturnType.fs | 14 ++++++-- 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index 0ee6a22ba56..f47ddd7ceb5 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -18,6 +18,7 @@ open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions open CancellableTasks open System.Diagnostics +open Microsoft.CodeAnalysis.Text [] type internal RemoveExplicitReturnType [] () = @@ -48,9 +49,9 @@ type internal RemoveExplicitReturnType [] () = let rangeOfReturnType = memberFunc.ReturnParameter.DeclarationLocation let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, rangeOfReturnType) - let textChange = TextChange(textSpan, $"") + let newSourceText = sourceText.Replace(textSpan, "") - sourceText.WithChanges(textChange) + newSourceText let codeActionFunc = (fun (cancellationToken: CancellationToken) -> diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index eefd3b7638e..029600c8107 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -47,11 +47,18 @@ let ``Refactor changes nothing`` (shouldNotTrigger: string) = let spanStart = code.IndexOf "sum" - let! (_, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + let! (newDoc, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) - Assert.AreEqual(code, text.ToString(), "") + let! testOutput = newDoc.GetTextAsync(context.CT) + testOutput + let! symbol = GetSymbol "sum" newDoc context.CT - () + let stillExists = + symbol + |> Option.map (fun symbol -> GetReturnTypeDeclarationLocation symbol) + |> Option.isSome + + Assert.IsTrue(stillExists) } [] @@ -74,20 +81,6 @@ let ``Refactor changes something`` () = () } -let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = - task { - let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "test" |> CancellableTask.start ct - - let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct - let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) - - return - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v -> Some(v.ReturnParameter.Type.TypeDefinition.CompiledName) - | _ -> None - - } - [] let ``Correctly infer int as explicit return type`` () = task { diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 5cab670e927..2d6bf0712ee 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -20,6 +20,39 @@ open System.Threading open Microsoft.CodeAnalysis.Tags open System.Reflection open Microsoft.FSharp.Reflection +open FSharp.Compiler.Symbols + +let GetSymbol (symbolName: string) (document: Document) ct = + task { + let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "test" |> CancellableTask.start ct + + let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct + let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) + + return + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Some(v) + | _ -> None + + } + +let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = + task { + let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "test" |> CancellableTask.start ct + + let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct + let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) + + return + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Some(v.ReturnParameter.Type.TypeDefinition.CompiledName) + | _ -> None + + } + +let GetReturnTypeDeclarationLocation (symbol: FSharpMemberOrFunctionOrValue) = + let range = symbol.ReturnParameter.DeclarationLocation + if range.Start = range.End then None else Some(range) type TestCodeFix = { Message: string; FixedCode: string } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index 9b2cfc3bc53..9517a004e70 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -23,10 +23,18 @@ let ``Refactor changes something`` (toRemove: string) = use context = TestContext.CreateWithCode code let spanStart = code.IndexOf "sum" - let! (_, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + let! (newDoc, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + + let! testOutput = newDoc.GetTextAsync(context.CT) + testOutput + let! symbol = GetSymbol "sum" newDoc context.CT + + let stillExists = + symbol + |> Option.map (fun symbol -> GetReturnTypeDeclarationLocation symbol) + |> Option.isSome - Assert.AreNotEqual(code, text.ToString(), "") - //Todo: actually test if there is no return type anymore? + Assert.IsFalse(stillExists) () } From 7c4f0392a4cd532d613d82c8f28fdfd9093a8e6b Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 25 Oct 2023 13:30:15 +0200 Subject: [PATCH 14/57] * feat(FSharp.Editor): add RangeOfReturnTypeDefinition and refactor methods in RemoveExplicitReturnType.fs * test(FSharp.Editor.Tests): update tests for RemoveExplicitReturnType and RefactorTestFramework --- .../Refactor/RemoveExplicitReturnType.fs | 66 +++++++++++++++++-- .../Refactors/AddExplicitReturnType.fs | 10 +-- .../Refactors/RefactorTestFramework.fs | 34 +++++++++- .../Refactors/RemoveExplicitReturnType.fs | 19 ++---- 4 files changed, 101 insertions(+), 28 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index f47ddd7ceb5..e4fd34ff985 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -24,6 +24,46 @@ open Microsoft.CodeAnalysis.Text type internal RemoveExplicitReturnType [] () = inherit CodeRefactoringProvider() + static member RangeOfReturnTypeDefinition(input: ParsedInput, symbolUseStart: pos, ?skipLambdas) = + let skipLambdas = defaultArg skipLambdas true + + SyntaxTraversal.Traverse( + symbolUseStart, + input, + { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_path, _traverseSynExpr, defaultTraverse, expr) = defaultTraverse expr + + override _.VisitBinding(_path, defaultTraverse, binding) = + match binding with + | SynBinding(expr = SynExpr.Lambda _) when skipLambdas -> defaultTraverse binding + | SynBinding(expr = SynExpr.DotLambda _) when skipLambdas -> defaultTraverse binding + ////I need the : before the Return Info + //| SynBinding(expr = SynExpr.Typed _) -> defaultTraverse binding + + // Dont skip manually type-annotated bindings + | SynBinding(returnInfo = Some (SynBindingReturnInfo (_, r, _, _))) -> Some r + + // Let binding + | SynBinding (trivia = { EqualsRange = Some equalsRange }; range = range) when range.Start = symbolUseStart -> + Some equalsRange.StartRange + + // Member binding + | SynBinding (headPat = SynPat.LongIdent(longDotId = SynLongIdent(id = _ :: ident :: _)) + trivia = { EqualsRange = Some equalsRange }) when ident.idRange.Start = symbolUseStart -> + Some equalsRange.StartRange + + | _ -> defaultTraverse binding + } + ) + + static member RangeIncludingColon(range: TextSpan, sourceText: SourceText) = + + let lineUntilType = TextSpan.FromBounds(0, range.Start) + + let colonText = sourceText.GetSubText(lineUntilType).ToString() + let newSpan = TextSpan.FromBounds(colonText.LastIndexOf(':'), range.End) + newSpan + static member isValidMethodWithoutTypeAnnotation (funcOrValue: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) @@ -40,18 +80,29 @@ type internal RemoveExplicitReturnType [] () = (not funcOrValue.IsValue || not isLambdaIfFunction) && returnTypeHintAlreadyPresent - static member refactor (context: CodeRefactoringContext) (memberFunc: FSharpMemberOrFunctionOrValue) = + static member refactor + (context: CodeRefactoringContext) + (memberFunc: FSharpMemberOrFunctionOrValue) + (parseFileResults: FSharpParseFileResults) + (symbolUse: FSharpSymbolUse) + = let title = SR.RemoveExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName inferredType - let rangeOfReturnType = memberFunc.ReturnParameter.DeclarationLocation + let symbol2 = symbolUse.Symbol + symbol2 - let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, rangeOfReturnType) - let newSourceText = sourceText.Replace(textSpan, "") + let newSourceText = + RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, symbolUse.Range.Start, false) + |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) + |> Option.map (fun textSpan -> RemoveExplicitReturnType.RangeIncludingColon(textSpan, sourceText)) + |> Option.map (fun textSpan -> sourceText.Replace(textSpan, "")) - newSourceText + match newSourceText with + | Some t -> t + | None -> sourceText let codeActionFunc = (fun (cancellationToken: CancellationToken) -> @@ -100,9 +151,10 @@ type internal RemoveExplicitReturnType [] () = | :? FSharpMemberOrFunctionOrValue as v when RemoveExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults -> - Some(v) + Some(v, symbolUse) | _ -> None) - |> Option.map (fun (memberFunc) -> RemoveExplicitReturnType.refactor context memberFunc) + |> Option.map (fun (memberFunc, symbolUse) -> + RemoveExplicitReturnType.refactor context memberFunc parseFileResults symbolUse) return res } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 029600c8107..782cbb487d4 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -51,14 +51,16 @@ let ``Refactor changes nothing`` (shouldNotTrigger: string) = let! testOutput = newDoc.GetTextAsync(context.CT) testOutput + + let! parseFileResults = newDoc.GetFSharpParseResultsAsync "DoesntMatter" context.CT let! symbol = GetSymbol "sum" newDoc context.CT - let stillExists = + let range = symbol - |> Option.map (fun symbol -> GetReturnTypeDeclarationLocation symbol) - |> Option.isSome + |> Option.bind (fun sym -> + RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, sym.DeclarationLocation.Start, false)) - Assert.IsTrue(stillExists) + Assert.IsTrue(range.IsSome) } [] diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 2d6bf0712ee..6785e04153f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -21,6 +21,7 @@ open Microsoft.CodeAnalysis.Tags open System.Reflection open Microsoft.FSharp.Reflection open FSharp.Compiler.Symbols +open NUnit.Framework let GetSymbol (symbolName: string) (document: Document) ct = task { @@ -50,9 +51,36 @@ let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = } -let GetReturnTypeDeclarationLocation (symbol: FSharpMemberOrFunctionOrValue) = - let range = symbol.ReturnParameter.DeclarationLocation - if range.Start = range.End then None else Some(range) +let TryGetRangeOfExplicitReturnType (symbolName: string) (document: Document) ct = + task { + let! parseFileResults = document.GetFSharpParseResultsAsync "DoesntMatter" ct + let! symbol = GetSymbol symbolName document ct + + let range = + symbol + |> Option.bind (fun sym -> + RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, sym.DeclarationLocation.Start, false)) + + return range + } + +let AssertHasAnyExplicitReturnType (symbolName: string) (document: Document) ct = + task { + let! range = TryGetRangeOfExplicitReturnType symbolName document ct + Assert.IsTrue(range.IsSome) + } + +let AssertHasNoExplicitReturnType (symbolName: string) (document: Document) ct = + task { + let! parseFileResults = document.GetFSharpParseResultsAsync "DoesntMatter" ct + let! symbol = GetSymbol symbolName document ct + + let range = + symbol + |> Option.bind (fun sym -> parseFileResults.TryRangeOfReturnTypeHint(sym.DeclarationLocation.Start, false)) + + Assert.IsTrue(range.IsSome) + } type TestCodeFix = { Message: string; FixedCode: string } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index 9517a004e70..28b66f1c1a5 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -12,8 +12,9 @@ open System.Runtime.InteropServices [] [] [] -let ``Refactor changes something`` (toRemove: string) = +let ``Refactor removes explicit return type`` (toRemove: string) = task { + let symbolName = "sum" let code = $""" @@ -21,22 +22,12 @@ let ``Refactor changes something`` (toRemove: string) = """ use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf "sum" + let spanStart = code.IndexOf symbolName let! (newDoc, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + text - let! testOutput = newDoc.GetTextAsync(context.CT) - testOutput - let! symbol = GetSymbol "sum" newDoc context.CT - - let stillExists = - symbol - |> Option.map (fun symbol -> GetReturnTypeDeclarationLocation symbol) - |> Option.isSome - - Assert.IsFalse(stillExists) - - () + do! AssertHasNoExplicitReturnType symbolName newDoc context.CT } [] From 9e31a4e851363c631b3adac3057fb41227e78520 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 25 Oct 2023 14:16:02 +0200 Subject: [PATCH 15/57] * refactor(FSharp.Editor.Tests): simplify and improve test code readability * feat(RefactorTestFramework.fs): add AssertCodeHasNotChanged and AssertHasSpecificExplicitReturnType functions * refactor(AddExplicitReturnType.fs, RemoveExplicitReturnType.fs): use new assertion functions and simplify test code --- .../Refactors/AddExplicitReturnType.fs | 64 ++++--------------- .../Refactors/RefactorTestFramework.fs | 22 ++++++- .../Refactors/RemoveExplicitReturnType.fs | 18 ++++-- 3 files changed, 44 insertions(+), 60 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 782cbb487d4..dd269c06750 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -37,6 +37,7 @@ open System.Runtime.InteropServices [] let ``Refactor changes nothing`` (shouldNotTrigger: string) = task { + let symbolName = "sum" let code = $""" @@ -45,48 +46,19 @@ let ``Refactor changes nothing`` (shouldNotTrigger: string) = use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf "sum" + let spanStart = code.IndexOf symbolName - let! (newDoc, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - let! testOutput = newDoc.GetTextAsync(context.CT) - testOutput - - let! parseFileResults = newDoc.GetFSharpParseResultsAsync "DoesntMatter" context.CT - let! symbol = GetSymbol "sum" newDoc context.CT - - let range = - symbol - |> Option.bind (fun sym -> - RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, sym.DeclarationLocation.Start, false)) - - Assert.IsTrue(range.IsSome) - } - -[] -let ``Refactor changes something`` () = - task { - - let code = - """ - let sum a b = a + b - """ - - use context = TestContext.CreateWithCode code - - let spanStart = code.IndexOf "sum" - - let! (_, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) - - Assert.AreNotEqual(code, text.ToString(), "") - - () + do! AssertCodeHasNotChanged code newDoc context.CT } [] let ``Correctly infer int as explicit return type`` () = task { + let symbolName = "sum" + let code = """ let sum a b = a + b @@ -94,22 +66,17 @@ let ``Correctly infer int as explicit return type`` () = use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf "sum" - - let! (document, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + let spanStart = code.IndexOf symbolName - let! returnType = GetReturnTypeOfSymbol "sum" document context.CT + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - match returnType with - | Some t -> Assert.AreEqual("int", t) - | None -> failwith "Unexpected symbol" - - () + do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT } [] let ``Correctly infer custom type that is declared earlier in file`` () = task { + let symbolName = "sum" let code = """ @@ -119,15 +86,10 @@ let ``Correctly infer custom type that is declared earlier in file`` () = use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf "sum" - - let! (document, text) = tryRefactor code spanStart context (new AddExplicitReturnType()) + let spanStart = code.IndexOf symbolName - let! returnType = GetReturnTypeOfSymbol "sum" document context.CT + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - match returnType with - | Some t -> Assert.AreEqual("MyType", t) - | None -> failwith "Unexpected symbol" + do! AssertHasSpecificExplicitReturnType symbolName "MyType" newDoc context.CT - () } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 6785e04153f..b45766ec0de 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -20,7 +20,9 @@ open System.Threading open Microsoft.CodeAnalysis.Tags open System.Reflection open Microsoft.FSharp.Reflection +open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols +open FSharp.Compiler.Text open NUnit.Framework let GetSymbol (symbolName: string) (document: Document) ct = @@ -64,12 +66,29 @@ let TryGetRangeOfExplicitReturnType (symbolName: string) (document: Document) ct return range } +let AssertCodeHasNotChanged (code: string) (document: Document) ct = + task { + let! newText = document.GetTextAsync ct + Assert.AreEqual(code, newText.ToString()) + } + let AssertHasAnyExplicitReturnType (symbolName: string) (document: Document) ct = task { let! range = TryGetRangeOfExplicitReturnType symbolName document ct Assert.IsTrue(range.IsSome) } +let AssertHasSpecificExplicitReturnType (symbolName: string) (expectedTypeName: string) (document: Document) ct = + task { + let! returnType = GetReturnTypeOfSymbol symbolName document ct + + match returnType with + | Some t -> Assert.AreEqual(expectedTypeName, t) + | None -> Assert.Fail($"Unexpected type. Expected {expectedTypeName} but was t") + + () + } + let AssertHasNoExplicitReturnType (symbolName: string) (document: Document) ct = task { let! parseFileResults = document.GetFSharpParseResultsAsync "DoesntMatter" ct @@ -129,7 +148,6 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor () let newDocument = context.Solution.GetDocument(document.Id) - let! changedText = newDocument.GetTextAsync(context.CT) - return (newDocument, changedText) + return newDocument } |> CancellableTask.startWithoutCancellation diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index 28b66f1c1a5..ab904ffc7a6 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -4,6 +4,7 @@ open Microsoft.VisualStudio.FSharp.Editor open Xunit open NUnit.Framework open FSharp.Editor.Tests.Refactors.RefactorTestFramework +open Microsoft.CodeAnalysis.Text open Xunit open System.Runtime.InteropServices @@ -24,8 +25,7 @@ let ``Refactor removes explicit return type`` (toRemove: string) = use context = TestContext.CreateWithCode code let spanStart = code.IndexOf symbolName - let! (newDoc, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - text + let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) do! AssertHasNoExplicitReturnType symbolName newDoc context.CT } @@ -34,6 +34,8 @@ let ``Refactor removes explicit return type`` (toRemove: string) = let ``Refactor changes nothing`` () = task { + let symbolName = "sum" + let code = $""" let sum a b = a + b @@ -43,16 +45,17 @@ let ``Refactor changes nothing`` () = let spanStart = code.IndexOf "sum" - let! (_, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - - Assert.AreEqual(code, text.ToString(), "") + let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + do! AssertCodeHasNotChanged code newDoc context.CT + do! AssertHasNoExplicitReturnType symbolName newDoc context.CT () } [] let ``Refactor should not change anything`` () = task { + let symbolName = "sum" let code = """ @@ -67,9 +70,10 @@ let ``Refactor should not change anything`` () = let spanStart = code.IndexOf "sum" - let! (_, text) = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - Assert.AreEqual(code, text.ToString(), "") + do! AssertCodeHasNotChanged code newDoc context.CT + do! AssertHasNoExplicitReturnType symbolName newDoc context.CT () } From 1df0308c0a63de5682c1df9213d2728e6c86befb Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 25 Oct 2023 17:47:32 +0200 Subject: [PATCH 16/57] fix: remove debug lines --- .../src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index e4fd34ff985..f0d35316fa7 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -82,17 +82,13 @@ type internal RemoveExplicitReturnType [] () = static member refactor (context: CodeRefactoringContext) - (memberFunc: FSharpMemberOrFunctionOrValue) + (_: FSharpMemberOrFunctionOrValue) (parseFileResults: FSharpParseFileResults) (symbolUse: FSharpSymbolUse) = let title = SR.RemoveExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = - let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName - inferredType - let symbol2 = symbolUse.Symbol - symbol2 let newSourceText = RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, symbolUse.Range.Start, false) From fefe14bf7e2c9dc219c3255aad7558b0e3011903 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sun, 29 Oct 2023 11:23:07 +0100 Subject: [PATCH 17/57] * refactor(FSharp.Editor.Tests): improve test method names and assertions * feat(RefactorTestFramework.fs): add tryGetRefactoringActions function * refactor(RemoveExplicitReturnType.fs): use tryGetRefactoringActions function --- .../Refactors/AddExplicitReturnType.fs | 6 +++--- .../Refactors/RefactorTestFramework.fs | 20 +++++++++++++++++++ .../Refactors/RemoveExplicitReturnType.fs | 18 ++++++++--------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index dd269c06750..747df01c53b 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -35,7 +35,7 @@ open System.Runtime.InteropServices [] [] [] -let ``Refactor changes nothing`` (shouldNotTrigger: string) = +let ``Refactor should not trigger`` (shouldNotTrigger: string) = task { let symbolName = "sum" @@ -48,9 +48,9 @@ let ``Refactor changes nothing`` (shouldNotTrigger: string) = let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let! actions = tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) - do! AssertCodeHasNotChanged code newDoc context.CT + do Assert.Empty(actions) } [] diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index b45766ec0de..6ca99b907b3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -151,3 +151,23 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor return newDocument } |> CancellableTask.startWithoutCancellation + +let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = + cancellableTask { + let refactoringActions = new List() + let existingDocument = RoslynTestHelpers.GetSingleDocument context.Solution + + context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) + + let document = RoslynTestHelpers.GetSingleDocument context.Solution + + let mutable workspace = context.Solution.Workspace + + let refactoringContext = + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) + + do! refactorProvider.ComputeRefactoringsAsync refactoringContext + + return refactoringActions + } + |> CancellableTask.startWithoutCancellation diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index ab904ffc7a6..b42d4585aa0 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -31,7 +31,7 @@ let ``Refactor removes explicit return type`` (toRemove: string) = } [] -let ``Refactor changes nothing`` () = +let ``Refactor should not be suggested if theres nothing to remove`` () = task { let symbolName = "sum" @@ -43,17 +43,16 @@ let ``Refactor changes nothing`` () = use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf "sum" + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - do! AssertCodeHasNotChanged code newDoc context.CT - do! AssertHasNoExplicitReturnType symbolName newDoc context.CT + do Assert.Empty(actions) () } [] -let ``Refactor should not change anything`` () = +let ``Refactor should not be suggested if it changes the meaning`` () = task { let symbolName = "sum" @@ -68,12 +67,11 @@ let ``Refactor should not change anything`` () = use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf "sum" + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - do! AssertCodeHasNotChanged code newDoc context.CT - do! AssertHasNoExplicitReturnType symbolName newDoc context.CT + do Assert.Empty(actions) () } From 7cf8ab0ffc43f22c31f08c0c76542513e5d051af Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sun, 29 Oct 2023 21:33:53 +0100 Subject: [PATCH 18/57] * feat(FSharp.Editor): add InternalOptionBuilder module * refactor(AddExplicitReturnType.fs, RemoveExplicitReturnType.fs): use InternalOptionBuilder for option handling * feat(FSharp.Editor.fsproj): include InternalOptionBuilder.fs in project compilation --- .../Common/InternalOptionBuilder.fs | 13 +++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../Refactor/AddExplicitReturnType.fs | 58 ++++++++++++------- .../Refactor/RemoveExplicitReturnType.fs | 54 ++++++++++------- 4 files changed, 84 insertions(+), 42 deletions(-) create mode 100644 vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs diff --git a/vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs b/vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs new file mode 100644 index 00000000000..66d78b7845c --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs @@ -0,0 +1,13 @@ +module internal Microsoft.VisualStudio.FSharp.Editor.InternalOptionBuilder + +type InternalOptionBuilder() = + member _.Bind(x, f) = Option.bind f x + member _.Return(x) = Some x + member _.ReturnFrom(x) = x + member _.Zero() = Some() + +let internalOption = InternalOptionBuilder() +let inline (|>>) v f = Option.map f v +let inline (|>!) v f = Option.bind f v +let inline (>->) f g v = f v |>> g +let inline (>=>) f g v = f v >>= g diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 1981a7f39a7..8862d7432a4 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -42,6 +42,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index a5d0c6c90e0..02954e80388 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -19,15 +19,16 @@ open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions open CancellableTasks open System.Diagnostics +open InternalOptionBuilder [] type internal AddExplicitReturnType [] () = inherit CodeRefactoringProvider() static member isValidMethodWithoutTypeAnnotation - (funcOrValue: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) (parseFileResults: FSharpParseFileResults) + (funcOrValue: FSharpMemberOrFunctionOrValue) = let typeAnnotationRange = parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) @@ -36,10 +37,15 @@ type internal AddExplicitReturnType [] () = funcOrValue.IsFunction && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start - (not funcOrValue.IsValue || not isLambdaIfFunction) - && not (funcOrValue.ReturnParameter.Type.IsUnresolved) - && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) - && not typeAnnotationRange.IsNone + let res = + (not funcOrValue.IsValue || not isLambdaIfFunction) + && not (funcOrValue.ReturnParameter.Type.IsUnresolved) + && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) + && not typeAnnotationRange.IsNone + + match res with + | true -> Some funcOrValue + | false -> None static member refactor (context: CodeRefactoringContext) @@ -76,6 +82,11 @@ type internal AddExplicitReturnType [] () = do context.RegisterRefactoring(codeAction) + static member ofFSharpMemberOrFunctionOrValue(symbol: FSharpSymbol) = + match symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Some v + | _ -> None + override _.ComputeRefactoringsAsync context = backgroundTask { let document = context.Document @@ -96,23 +107,26 @@ type internal AddExplicitReturnType [] () = |> CancellableTask.start ct let res = - lexerSymbol - |> Option.bind (fun lexer -> - checkFileResults.GetSymbolUseAtLocation( - fcsTextLineNumber, - lexer.Ident.idRange.EndColumn, - textLine.ToString(), - lexer.FullIsland - )) - |> Option.bind (fun symbolUse -> - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v when - AddExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults - -> - Some(symbolUse, v) - | _ -> None) - |> Option.map (fun (symbolUse, memberFunc) -> - AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults)) + internalOption { + let! lexerSymbol = lexerSymbol + + let! symbolUse = + checkFileResults.GetSymbolUseAtLocation( + fcsTextLineNumber, + lexerSymbol.Ident.idRange.EndColumn, + textLine.ToString(), + lexerSymbol.FullIsland + ) + + let! memberFunc = + symbolUse.Symbol |> AddExplicitReturnType.ofFSharpMemberOrFunctionOrValue + |>! AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults + + let res = + AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults) + + return res + } return res } diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index f0d35316fa7..299f5c12eb1 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -19,6 +19,7 @@ open Microsoft.CodeAnalysis.CodeActions open CancellableTasks open System.Diagnostics open Microsoft.CodeAnalysis.Text +open InternalOptionBuilder [] type internal RemoveExplicitReturnType [] () = @@ -65,9 +66,9 @@ type internal RemoveExplicitReturnType [] () = newSpan static member isValidMethodWithoutTypeAnnotation - (funcOrValue: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) (parseFileResults: FSharpParseFileResults) + (funcOrValue: FSharpMemberOrFunctionOrValue) = let returnTypeHintAlreadyPresent = parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) @@ -77,8 +78,13 @@ type internal RemoveExplicitReturnType [] () = funcOrValue.IsFunction && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start - (not funcOrValue.IsValue || not isLambdaIfFunction) - && returnTypeHintAlreadyPresent + let res = + (not funcOrValue.IsValue || not isLambdaIfFunction) + && returnTypeHintAlreadyPresent + + match res with + | true -> Some funcOrValue + | false -> None static member refactor (context: CodeRefactoringContext) @@ -114,6 +120,11 @@ type internal RemoveExplicitReturnType [] () = do context.RegisterRefactoring(codeAction) + static member ofFSharpMemberOrFunctionOrValue(symbol: FSharpSymbol) = + match symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Some v + | _ -> None + override _.ComputeRefactoringsAsync context = backgroundTask { let document = context.Document @@ -134,23 +145,26 @@ type internal RemoveExplicitReturnType [] () = |> CancellableTask.start ct let res = - lexerSymbol - |> Option.bind (fun lexer -> - checkFileResults.GetSymbolUseAtLocation( - fcsTextLineNumber, - lexer.Ident.idRange.EndColumn, - textLine.ToString(), - lexer.FullIsland - )) - |> Option.bind (fun symbolUse -> - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v when - RemoveExplicitReturnType.isValidMethodWithoutTypeAnnotation v symbolUse parseFileResults - -> - Some(v, symbolUse) - | _ -> None) - |> Option.map (fun (memberFunc, symbolUse) -> - RemoveExplicitReturnType.refactor context memberFunc parseFileResults symbolUse) + internalOption { + let! lexerSymbol = lexerSymbol + + let! symbolUse = + checkFileResults.GetSymbolUseAtLocation( + fcsTextLineNumber, + lexerSymbol.Ident.idRange.EndColumn, + textLine.ToString(), + lexerSymbol.FullIsland + ) + + let! memberFunc = + symbolUse.Symbol |> RemoveExplicitReturnType.ofFSharpMemberOrFunctionOrValue + |>! RemoveExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults + + let res = + RemoveExplicitReturnType.refactor context memberFunc parseFileResults symbolUse + + return res + } return res } From 0c306a38c6e3446694108c915e4289b3aaaac49a Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 30 Oct 2023 13:54:50 +0100 Subject: [PATCH 19/57] * refactor(FSharp.Editor): simplify async tasks in AddExplicitReturnType and RemoveExplicitReturnType * test(FSharp.Editor.Tests): remove redundant unit expressions in RemoveExplicitReturnType tests --- .../FSharp.Editor/Refactor/AddExplicitReturnType.fs | 12 +++++------- .../Refactor/RemoveExplicitReturnType.fs | 12 +++++------- .../Refactors/RemoveExplicitReturnType.fs | 3 --- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 02954e80388..fbdcfec13a1 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -88,7 +88,9 @@ type internal AddExplicitReturnType [] () = | _ -> None override _.ComputeRefactoringsAsync context = - backgroundTask { + let ct = context.CancellationToken + + cancellableTask { let document = context.Document let position = context.Span.Start let! sourceText = document.GetTextAsync() @@ -96,15 +98,10 @@ type internal AddExplicitReturnType [] () = let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! ct = Async.CancellationToken - let! lexerSymbol = document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddExplicitReturnType)) - |> CancellableTask.start ct - let! (parseFileResults, checkFileResults) = - document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) - |> CancellableTask.start ct + let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) let res = internalOption { @@ -130,3 +127,4 @@ type internal AddExplicitReturnType [] () = return res } + |> CancellableTask.startAsTask ct diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index 299f5c12eb1..cde7a490f2b 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -126,7 +126,9 @@ type internal RemoveExplicitReturnType [] () = | _ -> None override _.ComputeRefactoringsAsync context = - backgroundTask { + let ct = context.CancellationToken + + cancellableTask { let document = context.Document let position = context.Span.Start let! sourceText = document.GetTextAsync() @@ -134,15 +136,10 @@ type internal RemoveExplicitReturnType [] () = let textLinePos = sourceText.Lines.GetLinePosition position let fcsTextLineNumber = Line.fromZ textLinePos.Line - let! ct = Async.CancellationToken - let! lexerSymbol = document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (RemoveExplicitReturnType)) - |> CancellableTask.start ct - let! (parseFileResults, checkFileResults) = - document.GetFSharpParseAndCheckResultsAsync(nameof (RemoveExplicitReturnType)) - |> CancellableTask.start ct + let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (RemoveExplicitReturnType)) let res = internalOption { @@ -168,3 +165,4 @@ type internal RemoveExplicitReturnType [] () = return res } + |> CancellableTask.startAsTask ct diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index b42d4585aa0..a369459044e 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -48,7 +48,6 @@ let ``Refactor should not be suggested if theres nothing to remove`` () = let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) do Assert.Empty(actions) - () } [] @@ -72,6 +71,4 @@ let ``Refactor should not be suggested if it changes the meaning`` () = let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) do Assert.Empty(actions) - - () } From 8335c0bd2d87bc2158cfeb9740d3f2575a66e347 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 30 Oct 2023 14:51:29 +0100 Subject: [PATCH 20/57] * feat(FSharp.Editor): update condition for return type hint presence in RemoveExplicitReturnType * refactor(FSharp.Editor.Tests): rename test for clarity in RemoveExplicitReturnType tests * feat(FSharp.Editor.Tests): add new test for return type preservation in RemoveExplicitReturnType tests --- .../Refactor/RemoveExplicitReturnType.fs | 4 +-- .../Refactors/RemoveExplicitReturnType.fs | 26 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index cde7a490f2b..3e7edf612c8 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -71,8 +71,8 @@ type internal RemoveExplicitReturnType [] () = (funcOrValue: FSharpMemberOrFunctionOrValue) = let returnTypeHintAlreadyPresent = - parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) - |> Option.isNone + RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, symbolUse.Range.Start, false) + |> Option.isSome let isLambdaIfFunction = funcOrValue.IsFunction diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index a369459044e..c205172deb9 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -51,7 +51,7 @@ let ``Refactor should not be suggested if theres nothing to remove`` () = } [] -let ``Refactor should not be suggested if it changes the meaning`` () = +let ``Refactor should not be suggested if it changes the return type`` () = task { let symbolName = "sum" @@ -72,3 +72,27 @@ let ``Refactor should not be suggested if it changes the meaning`` () = do Assert.Empty(actions) } + +[] +let ``Refactor should be suggested if it does not changes the return type`` () = + task { + let symbolName = "sum" + + let code = + """ + + type B = { X:int } + type A = { X:int } + + let f (i: int) : A = { X = i } + let sum a b = a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) + + do Assert.NotEmpty(actions) + } From 0918cfb17b844cfecd88082e4be04f9ea207331e Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 1 Nov 2023 15:02:42 +0100 Subject: [PATCH 21/57] * feat(FSharp.Editor.Tests): add new test cases for AddExplicitReturnType and RemoveExplicitReturnType * refactor(RefactorTestFramework.fs): replace hardcoded string with symbolName in async calls --- .../Refactors/AddExplicitReturnType.fs | 85 +++++++++++++++++++ .../Refactors/RefactorTestFramework.fs | 12 ++- .../Refactors/RemoveExplicitReturnType.fs | 42 ++++++++- 3 files changed, 134 insertions(+), 5 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 747df01c53b..44541350b76 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -73,6 +73,91 @@ let ``Correctly infer int as explicit return type`` () = do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT } +[] +[] +[] +let ``Infer explicit return type`` (functionHeader: string) (returnType: string) = + task { + + let symbolName = "sum" + + let code = + $""" + let sum {functionHeader}= a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf(symbolName) + + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + do Assert.NotNull(code) + do! AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT + } + +[] +let ``Infer on rec method`` () = + task { + + let symbolName = "fib" + + let code = + $""" + let rec fib n = + if n < 2 then 1 else fib (n - 1) + fib (n - 2) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT + } + +[] +let ``Infer with function parameter method`` () = + task { + + let symbolName = "apply1" + + let code = + $""" + let apply1 (transform: int -> int) y = transform y + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT + } + +[] +let ``Infer on member function`` () = + task { + + let symbolName = "SomeMethod" + + let code = + $""" + type SomeType(factor0: int) = + let factor = factor0 + member this.SomeMethod(a, b, c) = (a + b + c) * factor + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT + } + [] let ``Correctly infer custom type that is declared earlier in file`` () = task { diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 6ca99b907b3..bb13844726e 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -27,7 +27,9 @@ open NUnit.Framework let GetSymbol (symbolName: string) (document: Document) ct = task { - let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "test" |> CancellableTask.start ct + let! (_, checkFileResults) = + document.GetFSharpParseAndCheckResultsAsync symbolName + |> CancellableTask.start ct let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) @@ -41,7 +43,9 @@ let GetSymbol (symbolName: string) (document: Document) ct = let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = task { - let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "test" |> CancellableTask.start ct + let! (_, checkFileResults) = + document.GetFSharpParseAndCheckResultsAsync symbolName + |> CancellableTask.start ct let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) @@ -55,7 +59,7 @@ let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = let TryGetRangeOfExplicitReturnType (symbolName: string) (document: Document) ct = task { - let! parseFileResults = document.GetFSharpParseResultsAsync "DoesntMatter" ct + let! parseFileResults = document.GetFSharpParseResultsAsync symbolName ct let! symbol = GetSymbol symbolName document ct let range = @@ -91,7 +95,7 @@ let AssertHasSpecificExplicitReturnType (symbolName: string) (expectedTypeName: let AssertHasNoExplicitReturnType (symbolName: string) (document: Document) ct = task { - let! parseFileResults = document.GetFSharpParseResultsAsync "DoesntMatter" ct + let! parseFileResults = document.GetFSharpParseResultsAsync symbolName ct let! symbol = GetSymbol symbolName document ct let range = diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index c205172deb9..76621edb0de 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -10,10 +10,29 @@ open System.Runtime.InteropServices [] [] +[] +let ``Removes explicit return type`` (toRemove: string) = + task { + let symbolName = "sum" + + let code = + $""" + let sum a b {toRemove}= a + b + """ + + use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf symbolName + + let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + + do! AssertHasNoExplicitReturnType symbolName newDoc context.CT + } + +[] [] [] [] -let ``Refactor removes explicit return type`` (toRemove: string) = +let ``Empty Space doesnt matter`` (toRemove: string) = task { let symbolName = "sum" @@ -30,6 +49,27 @@ let ``Refactor removes explicit return type`` (toRemove: string) = do! AssertHasNoExplicitReturnType symbolName newDoc context.CT } +[] +[] +[] +let ``Different Formatting`` (functionHeader: string) = + task { + let symbolName = "sum" + + let code = + $""" + let sum {functionHeader}= + a + b + """ + + use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf symbolName + + let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + + do! AssertHasNoExplicitReturnType symbolName newDoc context.CT + } + [] let ``Refactor should not be suggested if theres nothing to remove`` () = task { From 0a8c9520eda115690b8e12d577c82209cab9c998 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 2 Nov 2023 11:03:26 +0100 Subject: [PATCH 22/57] * feat(FSharp.Editor.Tests): add AsyncBugReproduction.fs to test suite * fix(AddExplicitReturnType.fs): remove unnecessary assertion * fix(RefactorTestFramework.fs): convert symbols sequence to list --- .../FSharp.Editor.Tests.fsproj | 1 + .../Refactors/AddExplicitReturnType.fs | 2 +- .../Refactors/AsyncBugReproduction.fs | 77 +++++++++++++++++++ .../Refactors/RefactorTestFramework.fs | 2 +- 4 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 05e54a69daf..449193bc682 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -75,6 +75,7 @@ + diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 44541350b76..39e038217af 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -91,7 +91,7 @@ let ``Infer explicit return type`` (functionHeader: string) (returnType: string) let spanStart = code.IndexOf(symbolName) let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - do Assert.NotNull(code) + do! AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT } diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs new file mode 100644 index 00000000000..efce9acc97e --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs @@ -0,0 +1,77 @@ +module FSharp.Editor.Tests.Refactors.AsyncBugReproduction + +open Microsoft.VisualStudio.FSharp.Editor +open Xunit +open System +open System.Collections.Immutable +open System.Text.RegularExpressions + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.CodeFixes +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor +open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks + +open FSharp.Compiler.Diagnostics +open FSharp.Editor.Tests.Helpers + +open Microsoft.CodeAnalysis.CodeRefactorings +open NUnit.Framework +open Microsoft.CodeAnalysis.CodeActions +open System.Collections.Generic +open Microsoft.VisualStudio.LanguageServices +open FSharp.Editor.Tests.Refactors.RefactorTestFramework +open Microsoft.Build.Utilities +open System.Threading +open FSharp.Test.ReflectionHelper +open Microsoft.Build.Utilities +open FSharp.Test.ProjectGeneration.ProjectOperations +open FSharp.Compiler.Symbols +open Xunit +open System.Runtime.InteropServices + +[] +[] +[] +let ``Reproducing code null spanStart Bug`` (functionHeader: string) (returnType: string) = + task { + + let symbolName = "sum" + + let code = + $""" + let sum {functionHeader}= a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf(symbolName) + + let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + do! AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT + } + +[] +[] +[] +let ``But works when not async`` (functionHeader: string) (returnType: string) = + + let symbolName = "sum" + + let code = + $""" + let sum {functionHeader}= a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf(symbolName) + + let newDocTask = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = newDocTask.GetAwaiter().GetResult() + + let assertTask = + AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT + + do assertTask.GetAwaiter().GetResult() diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index bb13844726e..125832743f6 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -47,7 +47,7 @@ let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = document.GetFSharpParseAndCheckResultsAsync symbolName |> CancellableTask.start ct - let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct + let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct |> List.ofSeq let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) return From ac3cb243577addaf553f4c0e51cb0e0a650b5bdc Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 2 Nov 2023 11:21:41 +0100 Subject: [PATCH 23/57] bug: boiled bug down more --- .../Refactors/AsyncBugReproduction.fs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs index efce9acc97e..7af64f5a8eb 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs @@ -32,7 +32,6 @@ open System.Runtime.InteropServices [] [] -[] let ``Reproducing code null spanStart Bug`` (functionHeader: string) (returnType: string) = task { @@ -46,15 +45,12 @@ let ``Reproducing code null spanStart Bug`` (functionHeader: string) (returnType use context = TestContext.CreateWithCode code let spanStart = code.IndexOf(symbolName) - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - - do! AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT + Console.WriteLine("Test") } [] [] -[] let ``But works when not async`` (functionHeader: string) (returnType: string) = let symbolName = "sum" @@ -71,7 +67,4 @@ let ``But works when not async`` (functionHeader: string) (returnType: string) = let newDocTask = tryRefactor code spanStart context (new AddExplicitReturnType()) let newDoc = newDocTask.GetAwaiter().GetResult() - let assertTask = - AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT - - do assertTask.GetAwaiter().GetResult() + Console.WriteLine("Test") From 168dc63898e4fffa7e06aaac3f97b89da3595130 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 2 Nov 2023 11:38:54 +0100 Subject: [PATCH 24/57] * feat(FSharpParseFileResults.fs): add RangeOfReturnTypeDefinition method * refactor(RemoveExplicitReturnType.fs, RefactorTestFramework.fs): replace local RangeOfReturnTypeDefinition with FSharpParseFileResults method --- .../Service/FSharpParseFileResults.fs | 32 +++++++++++++++++ .../Service/FSharpParseFileResults.fsi | 2 ++ .../Refactor/RemoveExplicitReturnType.fs | 36 ++----------------- .../Refactors/RefactorTestFramework.fs | 3 +- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/Compiler/Service/FSharpParseFileResults.fs b/src/Compiler/Service/FSharpParseFileResults.fs index 46a5753ba3f..33b203aa056 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fs +++ b/src/Compiler/Service/FSharpParseFileResults.fs @@ -1063,3 +1063,35 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, member scope.ValidateBreakpointLocation pos = // This does not need to be run on the background thread scope.ValidateBreakpointLocationImpl pos + + member _.RangeOfReturnTypeDefinition(symbolUseStart: pos, ?skipLambdas) = + let skipLambdas = defaultArg skipLambdas true + + SyntaxTraversal.Traverse( + symbolUseStart, + input, + { new SyntaxVisitorBase<_>() with + member _.VisitExpr(_path, _traverseSynExpr, defaultTraverse, expr) = defaultTraverse expr + + override _.VisitBinding(_path, defaultTraverse, binding) = + match binding with + | SynBinding(expr = SynExpr.Lambda _) when skipLambdas -> defaultTraverse binding + | SynBinding(expr = SynExpr.DotLambda _) when skipLambdas -> defaultTraverse binding + ////I need the : before the Return Info + //| SynBinding(expr = SynExpr.Typed _) -> defaultTraverse binding + + // Dont skip manually type-annotated bindings + | SynBinding(returnInfo = Some (SynBindingReturnInfo (_, r, _, _))) -> Some r + + // Let binding + | SynBinding (trivia = { EqualsRange = Some equalsRange }; range = range) when range.Start = symbolUseStart -> + Some equalsRange.StartRange + + // Member binding + | SynBinding (headPat = SynPat.LongIdent(longDotId = SynLongIdent(id = _ :: ident :: _)) + trivia = { EqualsRange = Some equalsRange }) when ident.idRange.Start = symbolUseStart -> + Some equalsRange.StartRange + + | _ -> defaultTraverse binding + } + ) diff --git a/src/Compiler/Service/FSharpParseFileResults.fsi b/src/Compiler/Service/FSharpParseFileResults.fsi index e892c78aa89..7232ab74cc5 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fsi +++ b/src/Compiler/Service/FSharpParseFileResults.fsi @@ -95,6 +95,8 @@ type public FSharpParseFileResults = /// Indicates if any errors occurred during the parse member ParseHadErrors: bool + member RangeOfReturnTypeDefinition: symbolUseStart: pos * ?skipLambdas: bool -> range option + internal new: diagnostics: FSharpDiagnostic[] * input: ParsedInput * parseHadErrors: bool * dependencyFiles: string[] -> FSharpParseFileResults diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs index 3e7edf612c8..1ad3aa39495 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs @@ -25,38 +25,6 @@ open InternalOptionBuilder type internal RemoveExplicitReturnType [] () = inherit CodeRefactoringProvider() - static member RangeOfReturnTypeDefinition(input: ParsedInput, symbolUseStart: pos, ?skipLambdas) = - let skipLambdas = defaultArg skipLambdas true - - SyntaxTraversal.Traverse( - symbolUseStart, - input, - { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_path, _traverseSynExpr, defaultTraverse, expr) = defaultTraverse expr - - override _.VisitBinding(_path, defaultTraverse, binding) = - match binding with - | SynBinding(expr = SynExpr.Lambda _) when skipLambdas -> defaultTraverse binding - | SynBinding(expr = SynExpr.DotLambda _) when skipLambdas -> defaultTraverse binding - ////I need the : before the Return Info - //| SynBinding(expr = SynExpr.Typed _) -> defaultTraverse binding - - // Dont skip manually type-annotated bindings - | SynBinding(returnInfo = Some (SynBindingReturnInfo (_, r, _, _))) -> Some r - - // Let binding - | SynBinding (trivia = { EqualsRange = Some equalsRange }; range = range) when range.Start = symbolUseStart -> - Some equalsRange.StartRange - - // Member binding - | SynBinding (headPat = SynPat.LongIdent(longDotId = SynLongIdent(id = _ :: ident :: _)) - trivia = { EqualsRange = Some equalsRange }) when ident.idRange.Start = symbolUseStart -> - Some equalsRange.StartRange - - | _ -> defaultTraverse binding - } - ) - static member RangeIncludingColon(range: TextSpan, sourceText: SourceText) = let lineUntilType = TextSpan.FromBounds(0, range.Start) @@ -71,7 +39,7 @@ type internal RemoveExplicitReturnType [] () = (funcOrValue: FSharpMemberOrFunctionOrValue) = let returnTypeHintAlreadyPresent = - RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, symbolUse.Range.Start, false) + parseFileResults.RangeOfReturnTypeDefinition(symbolUse.Range.Start, false) |> Option.isSome let isLambdaIfFunction = @@ -97,7 +65,7 @@ type internal RemoveExplicitReturnType [] () = let getChangedText (sourceText: SourceText) = let newSourceText = - RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, symbolUse.Range.Start, false) + parseFileResults.RangeOfReturnTypeDefinition(symbolUse.Range.Start, false) |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) |> Option.map (fun textSpan -> RemoveExplicitReturnType.RangeIncludingColon(textSpan, sourceText)) |> Option.map (fun textSpan -> sourceText.Replace(textSpan, "")) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 125832743f6..8d940869b6d 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -64,8 +64,7 @@ let TryGetRangeOfExplicitReturnType (symbolName: string) (document: Document) ct let range = symbol - |> Option.bind (fun sym -> - RemoveExplicitReturnType.RangeOfReturnTypeDefinition(parseFileResults.ParseTree, sym.DeclarationLocation.Start, false)) + |> Option.bind (fun sym -> parseFileResults.RangeOfReturnTypeDefinition(sym.DeclarationLocation.Start, false)) return range } From 5978ad55eb183846cf4f29885b4864ac894cb58a Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 7 Nov 2023 10:46:34 +0100 Subject: [PATCH 25/57] * refactor(FSharp.Editor.Tests): remove async tasks from test cases and simplify code * feat(RefactorTestFramework.fs): add GetTaskResult function to handle task results * fix(RemoveExplicitReturnType.fs, AddExplicitReturnType.fs): refactor test cases to use GetTaskResult function * feat(RefactorTestFramework.fs): update tryRefactor and tryGetRefactoringActions to return task result directly * fix(FSharp.Editor.Tests.fsproj): remove AsyncBugReproduction.fs from project * feat(FSharp.Editor.Tests): delete AsyncBugReproduction.fs test file --- .../FSharp.Editor.Tests.fsproj | 1 - .../Refactors/AddExplicitReturnType.fs | 152 ++++++++---------- .../Refactors/AsyncBugReproduction.fs | 70 -------- .../Refactors/RefactorTestFramework.fs | 42 +++-- .../Refactors/RemoveExplicitReturnType.fs | 138 ++++++++-------- 5 files changed, 151 insertions(+), 252 deletions(-) delete mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 449193bc682..05e54a69daf 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -75,7 +75,6 @@ - diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index 39e038217af..fe0379b6859 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -36,145 +36,127 @@ open System.Runtime.InteropServices [] [] let ``Refactor should not trigger`` (shouldNotTrigger: string) = - task { - let symbolName = "sum" + let symbolName = "sum" - let code = - $""" + let code = + $""" let sum a b {shouldNotTrigger}= a + b """ - use context = TestContext.CreateWithCode code + use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + let spanStart = code.IndexOf symbolName - let! actions = tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) + let actions = + tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) - do Assert.Empty(actions) - } + do Assert.Empty(actions) [] let ``Correctly infer int as explicit return type`` () = - task { + let symbolName = "sum" - let symbolName = "sum" + let code = + """ + let sum a b = a + b + """ - let code = - """ - let sum a b = a + b - """ + use context = TestContext.CreateWithCode code - use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf symbolName - let spanStart = code.IndexOf symbolName + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - - do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT - } + AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT [] [] [] let ``Infer explicit return type`` (functionHeader: string) (returnType: string) = - task { + let symbolName = "sum" - let symbolName = "sum" + let code = + $""" + let sum {functionHeader}= a + b + """ - let code = - $""" - let sum {functionHeader}= a + b - """ + use context = TestContext.CreateWithCode code - use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf(symbolName) - let spanStart = code.IndexOf(symbolName) + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let text = newDoc.GetTextAsync() |> GetTaskResult - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - - do! AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT - } + AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT [] let ``Infer on rec method`` () = - task { - - let symbolName = "fib" + let symbolName = "fib" - let code = - $""" - let rec fib n = - if n < 2 then 1 else fib (n - 1) + fib (n - 2) - """ + let code = + $""" + let rec fib n = + if n < 2 then 1 else fib (n - 1) + fib (n - 2) + """ - use context = TestContext.CreateWithCode code + use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT - } + AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT [] let ``Infer with function parameter method`` () = - task { + let symbolName = "apply1" - let symbolName = "apply1" + let code = + $""" + let apply1 (transform: int -> int) y = transform y + """ - let code = - $""" - let apply1 (transform: int -> int) y = transform y - """ - - use context = TestContext.CreateWithCode code + use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT - } + AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT [] let ``Infer on member function`` () = - task { + let symbolName = "SomeMethod" - let symbolName = "SomeMethod" - - let code = - $""" - type SomeType(factor0: int) = - let factor = factor0 - member this.SomeMethod(a, b, c) = (a + b + c) * factor - """ + let code = + $""" + type SomeType(factor0: int) = + let factor = factor0 + member this.SomeMethod(a, b, c) = (a + b + c) * factor + """ - use context = TestContext.CreateWithCode code + use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - do! AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT - } + AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT [] let ``Correctly infer custom type that is declared earlier in file`` () = - task { - let symbolName = "sum" - - let code = - """ - type MyType = { Value: int } - let sum a b = {Value=a+b} - """ + let symbolName = "sum" - use context = TestContext.CreateWithCode code + let code = + """ + type MyType = { Value: int } + let sum a b = {Value=a+b} + """ - let spanStart = code.IndexOf symbolName + use context = TestContext.CreateWithCode code - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let spanStart = code.IndexOf symbolName - do! AssertHasSpecificExplicitReturnType symbolName "MyType" newDoc context.CT + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - } + AssertHasSpecificExplicitReturnType symbolName "MyType" newDoc context.CT diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs deleted file mode 100644 index 7af64f5a8eb..00000000000 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AsyncBugReproduction.fs +++ /dev/null @@ -1,70 +0,0 @@ -module FSharp.Editor.Tests.Refactors.AsyncBugReproduction - -open Microsoft.VisualStudio.FSharp.Editor -open Xunit -open System -open System.Collections.Immutable -open System.Text.RegularExpressions - -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.CodeFixes -open Microsoft.CodeAnalysis.Text -open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks - -open FSharp.Compiler.Diagnostics -open FSharp.Editor.Tests.Helpers - -open Microsoft.CodeAnalysis.CodeRefactorings -open NUnit.Framework -open Microsoft.CodeAnalysis.CodeActions -open System.Collections.Generic -open Microsoft.VisualStudio.LanguageServices -open FSharp.Editor.Tests.Refactors.RefactorTestFramework -open Microsoft.Build.Utilities -open System.Threading -open FSharp.Test.ReflectionHelper -open Microsoft.Build.Utilities -open FSharp.Test.ProjectGeneration.ProjectOperations -open FSharp.Compiler.Symbols -open Xunit -open System.Runtime.InteropServices - -[] -[] -let ``Reproducing code null spanStart Bug`` (functionHeader: string) (returnType: string) = - task { - - let symbolName = "sum" - - let code = - $""" - let sum {functionHeader}= a + b - """ - - use context = TestContext.CreateWithCode code - - let spanStart = code.IndexOf(symbolName) - let! newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - Console.WriteLine("Test") - } - -[] -[] -let ``But works when not async`` (functionHeader: string) (returnType: string) = - - let symbolName = "sum" - - let code = - $""" - let sum {functionHeader}= a + b - """ - - use context = TestContext.CreateWithCode code - - let spanStart = code.IndexOf(symbolName) - - let newDocTask = tryRefactor code spanStart context (new AddExplicitReturnType()) - let newDoc = newDocTask.GetAwaiter().GetResult() - - Console.WriteLine("Test") diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 8d940869b6d..622869bfa7a 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -25,11 +25,11 @@ open FSharp.Compiler.Symbols open FSharp.Compiler.Text open NUnit.Framework +let GetTaskResult (task: Tasks.Task<'T>) = task.GetAwaiter().GetResult() + let GetSymbol (symbolName: string) (document: Document) ct = task { - let! (_, checkFileResults) = - document.GetFSharpParseAndCheckResultsAsync symbolName - |> CancellableTask.start ct + let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "" |> CancellableTask.start ct let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) @@ -42,20 +42,17 @@ let GetSymbol (symbolName: string) (document: Document) ct = } let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = - task { - let! (_, checkFileResults) = - document.GetFSharpParseAndCheckResultsAsync symbolName - |> CancellableTask.start ct + let (_, checkFileResults) = + document.GetFSharpParseAndCheckResultsAsync "" + |> CancellableTask.start ct + |> GetTaskResult - let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct |> List.ofSeq - let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) + let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct |> List.ofSeq + let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) - return - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v -> Some(v.ReturnParameter.Type.TypeDefinition.CompiledName) - | _ -> None - - } + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Some(v.ReturnParameter.Type.TypeDefinition.CompiledName) + | _ -> None let TryGetRangeOfExplicitReturnType (symbolName: string) (document: Document) ct = task { @@ -82,15 +79,14 @@ let AssertHasAnyExplicitReturnType (symbolName: string) (document: Document) ct } let AssertHasSpecificExplicitReturnType (symbolName: string) (expectedTypeName: string) (document: Document) ct = - task { - let! returnType = GetReturnTypeOfSymbol symbolName document ct - match returnType with - | Some t -> Assert.AreEqual(expectedTypeName, t) - | None -> Assert.Fail($"Unexpected type. Expected {expectedTypeName} but was t") + let returnType = GetReturnTypeOfSymbol symbolName document ct - () - } + match returnType with + | Some t -> Assert.AreEqual(expectedTypeName, t) + | None -> Assert.Fail($"Unexpected type. Expected {expectedTypeName} but was t") + + () let AssertHasNoExplicitReturnType (symbolName: string) (document: Document) ct = task { @@ -154,6 +150,7 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor return newDocument } |> CancellableTask.startWithoutCancellation + |> fun task -> task.Result let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = cancellableTask { @@ -174,3 +171,4 @@ let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestConte return refactoringActions } |> CancellableTask.startWithoutCancellation + |> fun task -> task.Result diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs index 76621edb0de..e915e1f4a00 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs @@ -12,127 +12,117 @@ open System.Runtime.InteropServices [] [] let ``Removes explicit return type`` (toRemove: string) = - task { - let symbolName = "sum" + let symbolName = "sum" - let code = - $""" - let sum a b {toRemove}= a + b - """ + let code = + $""" + let sum a b {toRemove}= a + b + """ - use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - do! AssertHasNoExplicitReturnType symbolName newDoc context.CT - } + AssertHasNoExplicitReturnType symbolName newDoc context.CT |> GetTaskResult [] [] [] [] let ``Empty Space doesnt matter`` (toRemove: string) = - task { - let symbolName = "sum" + let symbolName = "sum" - let code = - $""" - let sum a b {toRemove}= a + b - """ + let code = + $""" + let sum a b {toRemove}= a + b + """ - use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - do! AssertHasNoExplicitReturnType symbolName newDoc context.CT - } + AssertHasNoExplicitReturnType symbolName newDoc context.CT |> GetTaskResult [] [] [] let ``Different Formatting`` (functionHeader: string) = - task { - let symbolName = "sum" + let symbolName = "sum" - let code = - $""" - let sum {functionHeader}= - a + b - """ + let code = + $""" + let sum {functionHeader}= + a + b + """ - use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf symbolName - let! newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - do! AssertHasNoExplicitReturnType symbolName newDoc context.CT - } + AssertHasNoExplicitReturnType symbolName newDoc context.CT |> GetTaskResult [] let ``Refactor should not be suggested if theres nothing to remove`` () = - task { + let symbolName = "sum" - let symbolName = "sum" + let code = + $""" + let sum a b = a + b + """ - let code = - $""" - let sum a b = a + b - """ + use context = TestContext.CreateWithCode code - use context = TestContext.CreateWithCode code + let spanStart = code.IndexOf symbolName - let spanStart = code.IndexOf symbolName + let actions = + tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - - do Assert.Empty(actions) - } + Assert.Empty(actions) [] let ``Refactor should not be suggested if it changes the return type`` () = - task { - let symbolName = "sum" + let symbolName = "sum" - let code = - """ - type A = { X:int } - type B = { X:int } + let code = + """ + type A = { X:int } + type B = { X:int } - let f (i: int) : A = { X = i } - let sum a b = a + b - """ + let f (i: int) : A = { X = i } + let sum a b = a + b + """ - use context = TestContext.CreateWithCode code + use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + let spanStart = code.IndexOf symbolName - let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) + let actions = + tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - do Assert.Empty(actions) - } + Assert.Empty(actions) [] let ``Refactor should be suggested if it does not changes the return type`` () = - task { - let symbolName = "sum" + let symbolName = "sum" - let code = - """ + let code = + """ - type B = { X:int } - type A = { X:int } + type B = { X:int } + type A = { X:int } - let f (i: int) : A = { X = i } - let sum a b = a + b - """ + let f (i: int) : A = { X = i } + let sum a b = a + b + """ - use context = TestContext.CreateWithCode code + use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName + let spanStart = code.IndexOf symbolName - let! actions = tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) + let actions = + tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - do Assert.NotEmpty(actions) - } + Assert.NotEmpty(actions) From c6ea3fc8ed4104a94365d52a2083e55dcce91c5b Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 7 Nov 2023 14:15:55 +0100 Subject: [PATCH 26/57] * refactor(FSharp.Editor): simplify refactoring process in AddExplicitReturnType.fs and RefactorTestFramework.fs * test(FSharp.Editor.Tests): update tests to match new refactoring process in AddExplicitReturnType.fs --- .../Refactor/AddExplicitReturnType.fs | 5 +- .../Refactors/AddExplicitReturnType.fs | 65 +++++++++++++++---- .../Refactors/RefactorTestFramework.fs | 40 ++++++------ 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index fbdcfec13a1..5e94e9cb16b 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -119,10 +119,9 @@ type internal AddExplicitReturnType [] () = symbolUse.Symbol |> AddExplicitReturnType.ofFSharpMemberOrFunctionOrValue |>! AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults - let res = - AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults) + do AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults) - return res + return () } return res diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index fe0379b6859..ff6baccd142 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -67,27 +67,36 @@ let ``Correctly infer int as explicit return type`` () = let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT + let expectedCode = + $""" + let sum a b :int= a + b + """ -[] -[] -[] -let ``Infer explicit return type`` (functionHeader: string) (returnType: string) = + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle Parantheses on the arguments`` () = let symbolName = "sum" let code = - $""" - let sum {functionHeader}= a + b + """ + let sum (a:float) (b:float) = a + b """ use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf(symbolName) + let spanStart = code.IndexOf symbolName let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - let text = newDoc.GetTextAsync() |> GetTaskResult - AssertHasSpecificExplicitReturnType symbolName returnType newDoc context.CT + let expectedCode = + """ + let sum (a:float) (b:float) :float= a + b + """ + + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) [] let ``Infer on rec method`` () = @@ -105,7 +114,14 @@ let ``Infer on rec method`` () = let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT + let expectedCode = + $""" + let rec fib n :int= + if n < 2 then 1 else fib (n - 1) + fib (n - 2) + """ + + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) [] let ``Infer with function parameter method`` () = @@ -122,7 +138,13 @@ let ``Infer with function parameter method`` () = let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT + let expectedCode = + $""" + let apply1 (transform: int -> int) y :int= transform y + """ + + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) [] let ``Infer on member function`` () = @@ -141,7 +163,15 @@ let ``Infer on member function`` () = let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - AssertHasSpecificExplicitReturnType symbolName "int" newDoc context.CT + let expectedCode = + $""" + type SomeType(factor0: int) = + let factor = factor0 + member this.SomeMethod(a, b, c) :int= (a + b + c) * factor + """ + + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) [] let ``Correctly infer custom type that is declared earlier in file`` () = @@ -159,4 +189,11 @@ let ``Correctly infer custom type that is declared earlier in file`` () = let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) - AssertHasSpecificExplicitReturnType symbolName "MyType" newDoc context.CT + let expectedCode = + """ + type MyType = { Value: int } + let sum a b :MyType= {Value=a+b} + """ + + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 622869bfa7a..de241e0a325 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -122,35 +122,33 @@ let mockAction = Action>(fun _ _ -> ()) let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = - cancellableTask { - let refactoringActions = new List() - let existingDocument = RoslynTestHelpers.GetSingleDocument context.Solution + let refactoringActions = new List() + let existingDocument = RoslynTestHelpers.GetSingleDocument context.Solution - context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) + context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) - let document = RoslynTestHelpers.GetSingleDocument context.Solution + let document = RoslynTestHelpers.GetSingleDocument context.Solution - let mutable workspace = context.Solution.Workspace + let mutable workspace = context.Solution.Workspace - let refactoringContext = - CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) + let refactoringContext = + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) - do! refactorProvider.ComputeRefactoringsAsync refactoringContext + let task = refactorProvider.ComputeRefactoringsAsync refactoringContext + do task.GetAwaiter().GetResult() - for action in refactoringActions do - let! operations = action.GetOperationsAsync context.CT + for action in refactoringActions do + let operationsTask = action.GetOperationsAsync context.CT + let operations = operationsTask |> GetTaskResult - for operation in operations do - let codeChangeOperation = operation :?> ApplyChangesOperation - codeChangeOperation.Apply(workspace, context.CT) - context.Solution <- codeChangeOperation.ChangedSolution - () + for operation in operations do + let codeChangeOperation = operation :?> ApplyChangesOperation + codeChangeOperation.Apply(workspace, context.CT) + context.Solution <- codeChangeOperation.ChangedSolution + () - let newDocument = context.Solution.GetDocument(document.Id) - return newDocument - } - |> CancellableTask.startWithoutCancellation - |> fun task -> task.Result + let newDocument = context.Solution.GetDocument(document.Id) + newDocument let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = cancellableTask { From a135896a0bd90936ebf56bb59aff72a76dbbc20d Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 7 Nov 2023 14:23:17 +0100 Subject: [PATCH 27/57] remove RemoveExplicitReturnType and save for a different PR --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 - .../src/FSharp.Editor/FSharp.Editor.resx | 3 - .../Refactor/RemoveExplicitReturnType.fs | 136 ------------------ .../FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.de.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.es.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.it.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 5 - .../FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 5 - .../xlf/FSharp.Editor.zh-Hans.xlf | 5 - .../xlf/FSharp.Editor.zh-Hant.xlf | 5 - .../FSharp.Editor.Tests.fsproj | 1 - .../Refactors/RemoveExplicitReturnType.fs | 128 ----------------- 18 files changed, 334 deletions(-) delete mode 100644 vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs delete mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 8862d7432a4..2f84e60c4fa 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -101,7 +101,6 @@ - diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 27374b00a28..9c12f2a6519 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -355,9 +355,6 @@ Use live (unsaved) buffers for analysis Add explicit return type annotation - - Remove explicit return type annotation - Remove unnecessary parentheses diff --git a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs deleted file mode 100644 index 1ad3aa39495..00000000000 --- a/vsintegration/src/FSharp.Editor/Refactor/RemoveExplicitReturnType.fs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Microsoft.VisualStudio.FSharp.Editor - -open System -open System.Composition -open System.Threading -open System.Threading.Tasks - -open FSharp.Compiler -open FSharp.Compiler.CodeAnalysis -open FSharp.Compiler.Symbols -open FSharp.Compiler.Text -open FSharp.Compiler.Syntax - -open Microsoft.CodeAnalysis.Text -open Microsoft.CodeAnalysis.CodeRefactorings -open Microsoft.CodeAnalysis.CodeActions -open CancellableTasks -open System.Diagnostics -open Microsoft.CodeAnalysis.Text -open InternalOptionBuilder - -[] -type internal RemoveExplicitReturnType [] () = - inherit CodeRefactoringProvider() - - static member RangeIncludingColon(range: TextSpan, sourceText: SourceText) = - - let lineUntilType = TextSpan.FromBounds(0, range.Start) - - let colonText = sourceText.GetSubText(lineUntilType).ToString() - let newSpan = TextSpan.FromBounds(colonText.LastIndexOf(':'), range.End) - newSpan - - static member isValidMethodWithoutTypeAnnotation - (symbolUse: FSharpSymbolUse) - (parseFileResults: FSharpParseFileResults) - (funcOrValue: FSharpMemberOrFunctionOrValue) - = - let returnTypeHintAlreadyPresent = - parseFileResults.RangeOfReturnTypeDefinition(symbolUse.Range.Start, false) - |> Option.isSome - - let isLambdaIfFunction = - funcOrValue.IsFunction - && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start - - let res = - (not funcOrValue.IsValue || not isLambdaIfFunction) - && returnTypeHintAlreadyPresent - - match res with - | true -> Some funcOrValue - | false -> None - - static member refactor - (context: CodeRefactoringContext) - (_: FSharpMemberOrFunctionOrValue) - (parseFileResults: FSharpParseFileResults) - (symbolUse: FSharpSymbolUse) - = - let title = SR.RemoveExplicitReturnTypeAnnotation() - - let getChangedText (sourceText: SourceText) = - - let newSourceText = - parseFileResults.RangeOfReturnTypeDefinition(symbolUse.Range.Start, false) - |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) - |> Option.map (fun textSpan -> RemoveExplicitReturnType.RangeIncludingColon(textSpan, sourceText)) - |> Option.map (fun textSpan -> sourceText.Replace(textSpan, "")) - - match newSourceText with - | Some t -> t - | None -> sourceText - - let codeActionFunc = - (fun (cancellationToken: CancellationToken) -> - task { - let! sourceText = context.Document.GetTextAsync(cancellationToken) - let changedText = getChangedText sourceText - - let newDocument = context.Document.WithText(changedText) - return newDocument - }) - - let codeAction = CodeAction.Create(title, codeActionFunc, title) - - do context.RegisterRefactoring(codeAction) - - static member ofFSharpMemberOrFunctionOrValue(symbol: FSharpSymbol) = - match symbol with - | :? FSharpMemberOrFunctionOrValue as v -> Some v - | _ -> None - - override _.ComputeRefactoringsAsync context = - let ct = context.CancellationToken - - cancellableTask { - let document = context.Document - let position = context.Span.Start - let! sourceText = document.GetTextAsync() - let textLine = sourceText.Lines.GetLineFromPosition position - let textLinePos = sourceText.Lines.GetLinePosition position - let fcsTextLineNumber = Line.fromZ textLinePos.Line - - let! lexerSymbol = - document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (RemoveExplicitReturnType)) - - let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (RemoveExplicitReturnType)) - - let res = - internalOption { - let! lexerSymbol = lexerSymbol - - let! symbolUse = - checkFileResults.GetSymbolUseAtLocation( - fcsTextLineNumber, - lexerSymbol.Ident.idRange.EndColumn, - textLine.ToString(), - lexerSymbol.FullIsland - ) - - let! memberFunc = - symbolUse.Symbol |> RemoveExplicitReturnType.ofFSharpMemberOrFunctionOrValue - |>! RemoveExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults - - let res = - RemoveExplicitReturnType.refactor context memberFunc parseFileResults symbolUse - - return res - } - - return res - } - |> CancellableTask.startAsTask ct diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index d5a236b63aa..b80a2c6ac40 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -211,11 +211,6 @@ Tečkované podtržení; Přerušované podtržení; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' Odebrat return diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index b44197256c1..b1abace993e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -211,11 +211,6 @@ Punkt unterstrichen; Strich unterstrichen; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' "return" entfernen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 1ad994254cb..2be2317bbf9 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -213,11 +213,6 @@ Subrayado de punto; Subrayado de guion; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' Quitar "return" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 6236bb341a8..02c7d4c78b4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -211,11 +211,6 @@ Soulignement pointé ; Soulignement en tirets ; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' Supprimer 'return' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index d97f7bf8d2a..dcedb50b426 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -211,11 +211,6 @@ Sottolineatura a punto; Sottolineatura a trattini; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' Rimuovi 'return' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 26615125687..22923fa1f76 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -211,11 +211,6 @@ F# 構文規則に準拠するよう、改行を追加して指定された幅 ダッシュ下線; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' 'return' の削除 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 8e36f8e1d2c..591df2ccb6a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -212,11 +212,6 @@ F# 구문 규칙에 맞는 줄바꿈을 추가하여 지정된 너비에 서명 대시 밑줄; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' 'return' 제거 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 8e0e80a04eb..863bf742b2f 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -211,11 +211,6 @@ Podkreślenie kropką; Podkreślenie kreską; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' Usuń element „return” diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index 1f1c8cd3305..24b5cf709fa 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -211,11 +211,6 @@ Ponto sublinhado; Traço sublinhado; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' Remover 'return' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 2e0db61f66e..29bd87400b6 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -211,11 +211,6 @@ Dash underline; Штриховое подчеркивание; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' Удалить "return" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index d3db21d3426..ef5ee782c32 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -211,11 +211,6 @@ Nokta alt çizgi; Tire alt çizgisi; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' 'return' öğesini kaldır diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index bba7765c221..0820f856e7e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -211,11 +211,6 @@ Dash underline; 短划线下划线; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' 删除 "return" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 71df9aa5c88..484be626cdd 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -211,11 +211,6 @@ Dash underline; 虛線底線; - - Remove explicit return type annotation - Remove explicit return type annotation - - Remove 'return' 移除 'return' diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 05e54a69daf..5b5e729cb1f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -74,7 +74,6 @@ - diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs deleted file mode 100644 index e915e1f4a00..00000000000 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RemoveExplicitReturnType.fs +++ /dev/null @@ -1,128 +0,0 @@ -module FSharp.Editor.Tests.Refactors.RemoveExplicitReturnType - -open Microsoft.VisualStudio.FSharp.Editor -open Xunit -open NUnit.Framework -open FSharp.Editor.Tests.Refactors.RefactorTestFramework -open Microsoft.CodeAnalysis.Text -open Xunit -open System.Runtime.InteropServices - -[] -[] -[] -let ``Removes explicit return type`` (toRemove: string) = - let symbolName = "sum" - - let code = - $""" - let sum a b {toRemove}= a + b - """ - - use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName - - let newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - - AssertHasNoExplicitReturnType symbolName newDoc context.CT |> GetTaskResult - -[] -[] -[] -[] -let ``Empty Space doesnt matter`` (toRemove: string) = - let symbolName = "sum" - - let code = - $""" - let sum a b {toRemove}= a + b - """ - - use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName - - let newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - - AssertHasNoExplicitReturnType symbolName newDoc context.CT |> GetTaskResult - -[] -[] -[] -let ``Different Formatting`` (functionHeader: string) = - let symbolName = "sum" - - let code = - $""" - let sum {functionHeader}= - a + b - """ - - use context = TestContext.CreateWithCode code - let spanStart = code.IndexOf symbolName - - let newDoc = tryRefactor code spanStart context (new RemoveExplicitReturnType()) - - AssertHasNoExplicitReturnType symbolName newDoc context.CT |> GetTaskResult - -[] -let ``Refactor should not be suggested if theres nothing to remove`` () = - let symbolName = "sum" - - let code = - $""" - let sum a b = a + b - """ - - use context = TestContext.CreateWithCode code - - let spanStart = code.IndexOf symbolName - - let actions = - tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - - Assert.Empty(actions) - -[] -let ``Refactor should not be suggested if it changes the return type`` () = - let symbolName = "sum" - - let code = - """ - type A = { X:int } - type B = { X:int } - - let f (i: int) : A = { X = i } - let sum a b = a + b - """ - - use context = TestContext.CreateWithCode code - - let spanStart = code.IndexOf symbolName - - let actions = - tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - - Assert.Empty(actions) - -[] -let ``Refactor should be suggested if it does not changes the return type`` () = - let symbolName = "sum" - - let code = - """ - - type B = { X:int } - type A = { X:int } - - let f (i: int) : A = { X = i } - let sum a b = a + b - """ - - use context = TestContext.CreateWithCode code - - let spanStart = code.IndexOf symbolName - - let actions = - tryGetRefactoringActions code spanStart context (new RemoveExplicitReturnType()) - - Assert.NotEmpty(actions) From e4f849cbb8052daf13b7aca8dc0d01c82b5bc810 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 13 Nov 2023 11:24:39 +0100 Subject: [PATCH 28/57] test: fixed test formatting --- .../Refactors/AddExplicitReturnType.fs | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs index ff6baccd142..315c3d94c9e 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs @@ -40,7 +40,7 @@ let ``Refactor should not trigger`` (shouldNotTrigger: string) = let code = $""" - let sum a b {shouldNotTrigger}= a + b +let sum a b {shouldNotTrigger}= a + b """ use context = TestContext.CreateWithCode code @@ -58,7 +58,7 @@ let ``Correctly infer int as explicit return type`` () = let code = """ - let sum a b = a + b +let sum a b = a + b """ use context = TestContext.CreateWithCode code @@ -69,7 +69,7 @@ let ``Correctly infer int as explicit return type`` () = let expectedCode = $""" - let sum a b :int= a + b +let sum a b :int= a + b """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -81,7 +81,7 @@ let ``Handle Parantheses on the arguments`` () = let code = """ - let sum (a:float) (b:float) = a + b +let sum (a:float) (b:float) = a + b """ use context = TestContext.CreateWithCode code @@ -92,7 +92,7 @@ let ``Handle Parantheses on the arguments`` () = let expectedCode = """ - let sum (a:float) (b:float) :float= a + b +let sum (a:float) (b:float) :float= a + b """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -104,8 +104,9 @@ let ``Infer on rec method`` () = let code = $""" - let rec fib n = - if n < 2 then 1 else fib (n - 1) + fib (n - 2) +let rec fib n = + if n < 2 then 1 + else fib (n - 1) + fib (n - 2) """ use context = TestContext.CreateWithCode code @@ -116,8 +117,9 @@ let ``Infer on rec method`` () = let expectedCode = $""" - let rec fib n :int= - if n < 2 then 1 else fib (n - 1) + fib (n - 2) +let rec fib n :int= + if n < 2 then 1 + else fib (n - 1) + fib (n - 2) """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -129,7 +131,7 @@ let ``Infer with function parameter method`` () = let code = $""" - let apply1 (transform: int -> int) y = transform y +let apply1 (transform: int -> int) y = transform y """ use context = TestContext.CreateWithCode code @@ -140,7 +142,7 @@ let ``Infer with function parameter method`` () = let expectedCode = $""" - let apply1 (transform: int -> int) y :int= transform y +let apply1 (transform: int -> int) y :int= transform y """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -152,9 +154,9 @@ let ``Infer on member function`` () = let code = $""" - type SomeType(factor0: int) = - let factor = factor0 - member this.SomeMethod(a, b, c) = (a + b + c) * factor +type SomeType(factor0: int) = + let factor = factor0 + member this.SomeMethod(a, b, c) = (a + b + c) * factor """ use context = TestContext.CreateWithCode code @@ -165,9 +167,9 @@ let ``Infer on member function`` () = let expectedCode = $""" - type SomeType(factor0: int) = - let factor = factor0 - member this.SomeMethod(a, b, c) :int= (a + b + c) * factor +type SomeType(factor0: int) = + let factor = factor0 + member this.SomeMethod(a, b, c) :int= (a + b + c) * factor """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -179,8 +181,8 @@ let ``Correctly infer custom type that is declared earlier in file`` () = let code = """ - type MyType = { Value: int } - let sum a b = {Value=a+b} +type MyType = { Value: int } +let sum a b = {Value=a+b} """ use context = TestContext.CreateWithCode code @@ -191,8 +193,8 @@ let ``Correctly infer custom type that is declared earlier in file`` () = let expectedCode = """ - type MyType = { Value: int } - let sum a b :MyType= {Value=a+b} +type MyType = { Value: int } +let sum a b :MyType= {Value=a+b} """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult From 99e36865001ea394e8c5e3168e88d2a2ae662d60 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 13 Nov 2023 11:31:10 +0100 Subject: [PATCH 29/57] * refactor(FSharp.Editor): remove InternalOptionBuilder.fs and update dependent files --- .../Common/InternalOptionBuilder.fs | 13 ----- .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 - .../Refactor/AddExplicitReturnType.fs | 50 ++++++++++--------- 3 files changed, 26 insertions(+), 38 deletions(-) delete mode 100644 vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs diff --git a/vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs b/vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs deleted file mode 100644 index 66d78b7845c..00000000000 --- a/vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs +++ /dev/null @@ -1,13 +0,0 @@ -module internal Microsoft.VisualStudio.FSharp.Editor.InternalOptionBuilder - -type InternalOptionBuilder() = - member _.Bind(x, f) = Option.bind f x - member _.Return(x) = Some x - member _.ReturnFrom(x) = x - member _.Zero() = Some() - -let internalOption = InternalOptionBuilder() -let inline (|>>) v f = Option.map f v -let inline (|>!) v f = Option.bind f v -let inline (>->) f g v = f v |>> g -let inline (>=>) f g v = f v >>= g diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 2f84e60c4fa..7282aa2c4e2 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -42,7 +42,6 @@ - diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 5e94e9cb16b..bbf15f3f3c5 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -18,8 +18,6 @@ open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions open CancellableTasks -open System.Diagnostics -open InternalOptionBuilder [] type internal AddExplicitReturnType [] () = @@ -103,27 +101,31 @@ type internal AddExplicitReturnType [] () = let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) - let res = - internalOption { - let! lexerSymbol = lexerSymbol - - let! symbolUse = - checkFileResults.GetSymbolUseAtLocation( - fcsTextLineNumber, - lexerSymbol.Ident.idRange.EndColumn, - textLine.ToString(), - lexerSymbol.FullIsland - ) - - let! memberFunc = - symbolUse.Symbol |> AddExplicitReturnType.ofFSharpMemberOrFunctionOrValue - |>! AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults - - do AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults) - - return () - } - - return res + let symbolUseOpt = + lexerSymbol + |> Option.bind (fun lexer -> + checkFileResults.GetSymbolUseAtLocation( + fcsTextLineNumber, + lexer.Ident.idRange.EndColumn, + textLine.ToString(), + lexer.FullIsland + )) + + let memberFuncOpt = + symbolUseOpt + |> Option.bind (fun sym -> sym.Symbol |> AddExplicitReturnType.ofFSharpMemberOrFunctionOrValue) + + match (symbolUseOpt, memberFuncOpt) with + | (Some symbolUse, Some memberFunc) -> + let isValidMethod = + memberFunc + |> AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults + + match isValidMethod with + | Some memberFunc -> do AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults) + | None -> () + | _ -> () + + return () } |> CancellableTask.startAsTask ct From 7274f3eeeaac15f6546d72af063b0cc40e31e618 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 13 Nov 2023 11:34:44 +0100 Subject: [PATCH 30/57] * refactor(FSharp.Editor.Tests): rename AddExplicitReturnType.fs to AddExplicitReturnTypeTests.fs --- .../tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj | 2 +- .../{AddExplicitReturnType.fs => AddExplicitReturnTypeTests.fs} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename vsintegration/tests/FSharp.Editor.Tests/Refactors/{AddExplicitReturnType.fs => AddExplicitReturnTypeTests.fs} (98%) diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 5b5e729cb1f..041d68352b5 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -73,7 +73,7 @@ - + diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs similarity index 98% rename from vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs rename to vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 315c3d94c9e..54dcfb6640a 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnType.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -1,4 +1,4 @@ -module FSharp.Editor.Tests.Refactors.AddExplicitReturnType +module FSharp.Editor.Tests.Refactors.AddExplicitReturnTypeTests open Microsoft.VisualStudio.FSharp.Editor open Xunit From ec5ab9729ff349322fed322261e92474b32dfdaf Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 13 Nov 2023 11:38:15 +0100 Subject: [PATCH 31/57] * refactor(FSharp.Editor): remove unused imports in AddExplicitReturnType.fs, AddExplicitReturnTypeTests.fs and RefactorTestFramework.fs --- .../Refactor/AddExplicitReturnType.fs | 8 +----- .../Refactors/AddExplicitReturnTypeTests.fs | 25 ------------------- .../Refactors/RefactorTestFramework.fs | 8 ------ 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index bbf15f3f3c5..eb17cf352ef 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -1,17 +1,11 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. +namespace Microsoft.VisualStudio.FSharp.Editor -namespace Microsoft.VisualStudio.FSharp.Editor - -open System open System.Composition open System.Threading open System.Threading.Tasks - -open FSharp.Compiler open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols open FSharp.Compiler.Text -open FSharp.Compiler.Syntax open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 54dcfb6640a..b6bd8ef155f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -2,33 +2,8 @@ open Microsoft.VisualStudio.FSharp.Editor open Xunit -open System -open System.Collections.Immutable -open System.Text.RegularExpressions - -open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.CodeFixes -open Microsoft.CodeAnalysis.Text -open Microsoft.VisualStudio.FSharp.Editor -open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks - -open FSharp.Compiler.Diagnostics -open FSharp.Editor.Tests.Helpers - -open Microsoft.CodeAnalysis.CodeRefactorings open NUnit.Framework -open Microsoft.CodeAnalysis.CodeActions -open System.Collections.Generic -open Microsoft.VisualStudio.LanguageServices open FSharp.Editor.Tests.Refactors.RefactorTestFramework -open Microsoft.Build.Utilities -open System.Threading -open FSharp.Test.ReflectionHelper -open Microsoft.Build.Utilities -open FSharp.Test.ProjectGeneration.ProjectOperations -open FSharp.Compiler.Symbols -open Xunit -open System.Runtime.InteropServices [] [] diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index de241e0a325..fe9b4b69621 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -3,24 +3,16 @@ open System open System.Collections.Immutable open System.Collections.Generic -open System.Text.RegularExpressions open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.CodeFixes open Microsoft.CodeAnalysis.Text open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks -open FSharp.Compiler.Diagnostics open FSharp.Editor.Tests.Helpers open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions -open System.Collections.Generic open System.Threading -open Microsoft.CodeAnalysis.Tags -open System.Reflection -open Microsoft.FSharp.Reflection -open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols open FSharp.Compiler.Text open NUnit.Framework From 30b5fe7e3c4c2017fd89caed47cfb2e38aa92f93 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 13 Nov 2023 12:07:20 +0100 Subject: [PATCH 32/57] * refactor(FSharpParseFileResults.fs, FSharpParseFileResults.fsi, RefactorTestFramework.fs): remove unused RangeOfReturnTypeDefinition method --- .../Service/FSharpParseFileResults.fs | 32 -------- .../Service/FSharpParseFileResults.fsi | 2 - .../Refactors/RefactorTestFramework.fs | 75 ------------------- 3 files changed, 109 deletions(-) diff --git a/src/Compiler/Service/FSharpParseFileResults.fs b/src/Compiler/Service/FSharpParseFileResults.fs index 33b203aa056..46a5753ba3f 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fs +++ b/src/Compiler/Service/FSharpParseFileResults.fs @@ -1063,35 +1063,3 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, member scope.ValidateBreakpointLocation pos = // This does not need to be run on the background thread scope.ValidateBreakpointLocationImpl pos - - member _.RangeOfReturnTypeDefinition(symbolUseStart: pos, ?skipLambdas) = - let skipLambdas = defaultArg skipLambdas true - - SyntaxTraversal.Traverse( - symbolUseStart, - input, - { new SyntaxVisitorBase<_>() with - member _.VisitExpr(_path, _traverseSynExpr, defaultTraverse, expr) = defaultTraverse expr - - override _.VisitBinding(_path, defaultTraverse, binding) = - match binding with - | SynBinding(expr = SynExpr.Lambda _) when skipLambdas -> defaultTraverse binding - | SynBinding(expr = SynExpr.DotLambda _) when skipLambdas -> defaultTraverse binding - ////I need the : before the Return Info - //| SynBinding(expr = SynExpr.Typed _) -> defaultTraverse binding - - // Dont skip manually type-annotated bindings - | SynBinding(returnInfo = Some (SynBindingReturnInfo (_, r, _, _))) -> Some r - - // Let binding - | SynBinding (trivia = { EqualsRange = Some equalsRange }; range = range) when range.Start = symbolUseStart -> - Some equalsRange.StartRange - - // Member binding - | SynBinding (headPat = SynPat.LongIdent(longDotId = SynLongIdent(id = _ :: ident :: _)) - trivia = { EqualsRange = Some equalsRange }) when ident.idRange.Start = symbolUseStart -> - Some equalsRange.StartRange - - | _ -> defaultTraverse binding - } - ) diff --git a/src/Compiler/Service/FSharpParseFileResults.fsi b/src/Compiler/Service/FSharpParseFileResults.fsi index 7232ab74cc5..e892c78aa89 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fsi +++ b/src/Compiler/Service/FSharpParseFileResults.fsi @@ -95,8 +95,6 @@ type public FSharpParseFileResults = /// Indicates if any errors occurred during the parse member ParseHadErrors: bool - member RangeOfReturnTypeDefinition: symbolUseStart: pos * ?skipLambdas: bool -> range option - internal new: diagnostics: FSharpDiagnostic[] * input: ParsedInput * parseHadErrors: bool * dependencyFiles: string[] -> FSharpParseFileResults diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index fe9b4b69621..cd32d697d03 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -13,85 +13,10 @@ open FSharp.Editor.Tests.Helpers open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions open System.Threading -open FSharp.Compiler.Symbols open FSharp.Compiler.Text -open NUnit.Framework let GetTaskResult (task: Tasks.Task<'T>) = task.GetAwaiter().GetResult() -let GetSymbol (symbolName: string) (document: Document) ct = - task { - let! (_, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync "" |> CancellableTask.start ct - - let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct - let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) - - return - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v -> Some(v) - | _ -> None - - } - -let GetReturnTypeOfSymbol (symbolName: string) (document: Document) ct = - let (_, checkFileResults) = - document.GetFSharpParseAndCheckResultsAsync "" - |> CancellableTask.start ct - |> GetTaskResult - - let symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile ct |> List.ofSeq - let symbolUse = symbols |> Seq.find (fun s -> s.Symbol.DisplayName = symbolName) - - match symbolUse.Symbol with - | :? FSharpMemberOrFunctionOrValue as v -> Some(v.ReturnParameter.Type.TypeDefinition.CompiledName) - | _ -> None - -let TryGetRangeOfExplicitReturnType (symbolName: string) (document: Document) ct = - task { - let! parseFileResults = document.GetFSharpParseResultsAsync symbolName ct - let! symbol = GetSymbol symbolName document ct - - let range = - symbol - |> Option.bind (fun sym -> parseFileResults.RangeOfReturnTypeDefinition(sym.DeclarationLocation.Start, false)) - - return range - } - -let AssertCodeHasNotChanged (code: string) (document: Document) ct = - task { - let! newText = document.GetTextAsync ct - Assert.AreEqual(code, newText.ToString()) - } - -let AssertHasAnyExplicitReturnType (symbolName: string) (document: Document) ct = - task { - let! range = TryGetRangeOfExplicitReturnType symbolName document ct - Assert.IsTrue(range.IsSome) - } - -let AssertHasSpecificExplicitReturnType (symbolName: string) (expectedTypeName: string) (document: Document) ct = - - let returnType = GetReturnTypeOfSymbol symbolName document ct - - match returnType with - | Some t -> Assert.AreEqual(expectedTypeName, t) - | None -> Assert.Fail($"Unexpected type. Expected {expectedTypeName} but was t") - - () - -let AssertHasNoExplicitReturnType (symbolName: string) (document: Document) ct = - task { - let! parseFileResults = document.GetFSharpParseResultsAsync symbolName ct - let! symbol = GetSymbol symbolName document ct - - let range = - symbol - |> Option.bind (fun sym -> parseFileResults.TryRangeOfReturnTypeHint(sym.DeclarationLocation.Start, false)) - - Assert.IsTrue(range.IsSome) - } - type TestCodeFix = { Message: string; FixedCode: string } type TestContext(Solution: Solution, CT) = From a3d2ce21ac792b37e688087ef12b654aa2b2428e Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 14 Nov 2023 12:15:42 +0100 Subject: [PATCH 33/57] * feat(FSharp.Editor.Tests): add GetLastDocument method in RoslynHelpers.fs * refactor(RefactorTestFramework.fs): replace GetSingleDocument with GetLastDocument * feat(AddExplicitReturnTypeTests.fs): add test for inferring custom type declared earlier in project --- .../Helpers/RoslynHelpers.fs | 5 +++ .../Refactors/AddExplicitReturnTypeTests.fs | 35 ++++++++++++++++++- .../Refactors/RefactorTestFramework.fs | 18 +++++++--- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs b/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs index a0853ed83b9..ca113f72bf3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs @@ -304,6 +304,11 @@ type RoslynTestHelpers private () = let document = project.Documents |> Seq.exactlyOne document + static member GetLastDocument(solution: Solution) = + let project = solution.Projects |> Seq.exactlyOne + let document = project.Documents |> Seq.last + document + static member CreateSolution(syntheticProject: SyntheticProject) = let checker = syntheticProject.SaveAndCheck() diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index b6bd8ef155f..e24c698a7bc 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -2,7 +2,7 @@ open Microsoft.VisualStudio.FSharp.Editor open Xunit -open NUnit.Framework +open System.Linq open FSharp.Editor.Tests.Refactors.RefactorTestFramework [] @@ -174,3 +174,36 @@ let sum a b :MyType= {Value=a+b} let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Correctly infer custom type that is declared earlier in project`` () = + let symbolName = "sum" + + let myModule = + """ +module MyModule +type MyType = { Value: int } + """ + + let code = + """ +open MyModule + +let sum a b = {Value=a+b} + """ + + use context = TestContext.CreateWithCodeAndDependency code myModule + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + """ +open MyModule + +let sum a b :MyType= {Value=a+b} + """ + + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index cd32d697d03..a74c4ee0cf3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -1,6 +1,7 @@ module FSharp.Editor.Tests.Refactors.RefactorTestFramework open System +open System.Linq open System.Collections.Immutable open System.Collections.Generic @@ -35,16 +36,25 @@ type TestContext(Solution: Solution, CT) = let ct = CancellationToken false new TestContext(solution, ct) + static member CreateWithCodeAndDependency (code: string) (codeForPreviousFile: string) = + let mutable solution = RoslynTestHelpers.CreateSolution(codeForPreviousFile) + + let firstProject = solution.Projects.First() + solution <- solution.AddDocument(DocumentId.CreateNewId(firstProject.Id), "test2.fs", code, filePath = "C:\\test2.fs") + + let ct = CancellationToken false + new TestContext(solution, ct) + let mockAction = Action>(fun _ _ -> ()) let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = let refactoringActions = new List() - let existingDocument = RoslynTestHelpers.GetSingleDocument context.Solution + let existingDocument = RoslynTestHelpers.GetLastDocument context.Solution context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) - let document = RoslynTestHelpers.GetSingleDocument context.Solution + let document = RoslynTestHelpers.GetLastDocument context.Solution let mutable workspace = context.Solution.Workspace @@ -70,11 +80,11 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = cancellableTask { let refactoringActions = new List() - let existingDocument = RoslynTestHelpers.GetSingleDocument context.Solution + let existingDocument = RoslynTestHelpers.GetLastDocument context.Solution context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) - let document = RoslynTestHelpers.GetSingleDocument context.Solution + let document = RoslynTestHelpers.GetLastDocument context.Solution let mutable workspace = context.Solution.Workspace From f8bfd0c6dcbf84b2876523899a72a5c7ee808ed0 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 15 Nov 2023 14:00:34 +0100 Subject: [PATCH 34/57] * refactor(RefactorTestFramework.fs): simplify TestContext type and remove unused TestCodeFix type --- .../Refactors/RefactorTestFramework.fs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index a74c4ee0cf3..49afdf83636 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -18,11 +18,9 @@ open FSharp.Compiler.Text let GetTaskResult (task: Tasks.Task<'T>) = task.GetAwaiter().GetResult() -type TestCodeFix = { Message: string; FixedCode: string } - -type TestContext(Solution: Solution, CT) = - let mutable _solution = Solution - member this.CT = CT +type TestContext(Solution: Solution, CancellationToken) = + let mutable _solution = Solution + member this.CT = CancellationToken member this.Solution with set value = _solution <- value From 3a2257f20f9cf75bf05a02fbfab139ae68ce2090 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 15 Nov 2023 14:15:23 +0100 Subject: [PATCH 35/57] * style: add space after colon in type annotations in AddExplicitReturnType.fs and AddExplicitReturnTypeTests.fs --- .../Refactor/AddExplicitReturnType.fs | 2 +- .../Refactors/AddExplicitReturnTypeTests.fs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index eb17cf352ef..7e836f48293 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -54,7 +54,7 @@ type internal AddExplicitReturnType [] () = let textChange = rangeOfReturnType |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) - |> Option.map (fun textSpan -> TextChange(textSpan, $":{inferredType}")) + |> Option.map (fun textSpan -> TextChange(textSpan, $": {inferredType}")) match textChange with | Some textChange -> sourceText.WithChanges(textChange) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index e24c698a7bc..8a45b8396a6 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -44,7 +44,7 @@ let sum a b = a + b let expectedCode = $""" -let sum a b :int= a + b +let sum a b : int= a + b """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -67,7 +67,7 @@ let sum (a:float) (b:float) = a + b let expectedCode = """ -let sum (a:float) (b:float) :float= a + b +let sum (a:float) (b:float) : float= a + b """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -92,7 +92,7 @@ let rec fib n = let expectedCode = $""" -let rec fib n :int= +let rec fib n : int= if n < 2 then 1 else fib (n - 1) + fib (n - 2) """ @@ -117,7 +117,7 @@ let apply1 (transform: int -> int) y = transform y let expectedCode = $""" -let apply1 (transform: int -> int) y :int= transform y +let apply1 (transform: int -> int) y : int= transform y """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -144,7 +144,7 @@ type SomeType(factor0: int) = $""" type SomeType(factor0: int) = let factor = factor0 - member this.SomeMethod(a, b, c) :int= (a + b + c) * factor + member this.SomeMethod(a, b, c) : int= (a + b + c) * factor """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -169,7 +169,7 @@ let sum a b = {Value=a+b} let expectedCode = """ type MyType = { Value: int } -let sum a b :MyType= {Value=a+b} +let sum a b : MyType= {Value=a+b} """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -202,7 +202,7 @@ let sum a b = {Value=a+b} """ open MyModule -let sum a b :MyType= {Value=a+b} +let sum a b : MyType= {Value=a+b} """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult From 1d24e5afca8e10420990bd96101a68d24665fc49 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Thu, 16 Nov 2023 13:28:04 +0100 Subject: [PATCH 36/57] * refactor(AddExplicitReturnType.fs): remove unused CancellationToken and reformat code * feat(AddExplicitReturnTypeTests.fs): add new test cases and dependencies for AddExplicitReturnType --- .../Refactor/AddExplicitReturnType.fs | 8 +++---- .../Refactors/AddExplicitReturnTypeTests.fs | 22 ++++++++++++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 7e836f48293..b7e8afd3ed4 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -80,8 +80,6 @@ type internal AddExplicitReturnType [] () = | _ -> None override _.ComputeRefactoringsAsync context = - let ct = context.CancellationToken - cancellableTask { let document = context.Document let position = context.Span.Start @@ -93,7 +91,8 @@ type internal AddExplicitReturnType [] () = let! lexerSymbol = document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddExplicitReturnType)) - let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) + let! (parseFileResults, checkFileResults) = + document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) let symbolUseOpt = lexerSymbol @@ -121,5 +120,4 @@ type internal AddExplicitReturnType [] () = | _ -> () return () - } - |> CancellableTask.startAsTask ct + } |> CancellableTask.startAsTaskWithoutCancellation diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 8a45b8396a6..fae889553c3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -4,6 +4,9 @@ open Microsoft.VisualStudio.FSharp.Editor open Xunit open System.Linq open FSharp.Editor.Tests.Refactors.RefactorTestFramework +open FSharp.Test.ProjectGeneration +open FSharp.Editor.Tests.Helpers +open System.Threading [] [] @@ -181,18 +184,31 @@ let ``Correctly infer custom type that is declared earlier in project`` () = let myModule = """ -module MyModule type MyType = { Value: int } """ let code = """ -open MyModule +open ModuleFirst let sum a b = {Value=a+b} """ - use context = TestContext.CreateWithCodeAndDependency code myModule + let project = + SyntheticProject.Create( + { sourceFile "First" [] with + Source = myModule + SignatureFile = AutoGenerated + }, + { sourceFile "Second" ["First"] with + Source = code + } + ) + + project.SaveAndCheck() |> ignore + let solution, _ = RoslynTestHelpers.CreateSolution project + let ct = CancellationToken false + let context = new TestContext(solution, ct) let spanStart = code.IndexOf symbolName From c700bf8d6b5982987c60d13b1dc3d76d702d9f25 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Mon, 20 Nov 2023 21:11:15 +0100 Subject: [PATCH 37/57] * feat(FSharp.Editor): add checks for function or value names in AddExplicitReturnType * test(FSharp.Editor.Tests): add tests for refactor triggering on values and member values * fix(FSharp.Editor.Tests): trim expected and result text in test assertions * refactor(FSharp.Editor.Tests): remove unused mutable workspace in RefactorTestFramework --- .../Refactor/AddExplicitReturnType.fs | 4 +- .../Refactors/AddExplicitReturnTypeTests.fs | 41 ++++++++++++++++++- .../Refactors/RefactorTestFramework.fs | 3 -- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index b7e8afd3ed4..f8b728f6ef0 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -30,7 +30,9 @@ type internal AddExplicitReturnType [] () = && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start let res = - (not funcOrValue.IsValue || not isLambdaIfFunction) + funcOrValue.CompiledName = funcOrValue.DisplayName + && not funcOrValue.IsValue + && (not funcOrValue.IsValue || not isLambdaIfFunction) && not (funcOrValue.ReturnParameter.Type.IsUnresolved) && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) && not typeAnnotationRange.IsNone diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index fae889553c3..5e6edf79e95 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -29,6 +29,43 @@ let sum a b {shouldNotTrigger}= a + b tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) do Assert.Empty(actions) + +[] +let ``Refactor should not trigger on values`` () = + let symbolName = "example2" + + let code = + """ +let example2 = 42 // value + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let actions = + tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) + + do Assert.Empty(actions) + +[] +let ``Refactor should not trigger on member values`` () = + let symbolName = "SomeProp" + + let code = + """ +type Example3() = + member _.SomeProp = 42 // property + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let actions = + tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) + + do Assert.Empty(actions) [] let ``Correctly infer int as explicit return type`` () = @@ -216,10 +253,10 @@ let sum a b = {Value=a+b} let expectedCode = """ -open MyModule +open ModuleFirst let sum a b : MyType= {Value=a+b} """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult - Assert.Equal(expectedCode, resultText.ToString()) + Assert.Equal(expectedCode.Trim(' ','\r','\n'), resultText.ToString().Trim(' ','\r','\n')) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 49afdf83636..2e2f3abfd42 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -83,9 +83,6 @@ let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestConte context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) let document = RoslynTestHelpers.GetLastDocument context.Solution - - let mutable workspace = context.Solution.Workspace - let refactoringContext = CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) From 9bb4545819d568d5082c987432a91560b550e693 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 21 Nov 2023 15:04:26 +0100 Subject: [PATCH 38/57] * refactor(AddExplicitReturnTypeTests.fs): remove unused System.Linq import --- .../FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 5e6edf79e95..cfcebf0ed76 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -2,7 +2,6 @@ open Microsoft.VisualStudio.FSharp.Editor open Xunit -open System.Linq open FSharp.Editor.Tests.Refactors.RefactorTestFramework open FSharp.Test.ProjectGeneration open FSharp.Editor.Tests.Helpers From 867803dbaf3c5cc5745c52f452a1b131b312f26b Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 21 Nov 2023 15:05:22 +0100 Subject: [PATCH 39/57] * refactor(RefactorTestFramework.fs): remove unused import Microsoft.VisualStudio.FSharp.Editor --- .../tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 2e2f3abfd42..ae37e990b5b 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -7,7 +7,6 @@ open System.Collections.Generic open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text -open Microsoft.VisualStudio.FSharp.Editor open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks open FSharp.Editor.Tests.Helpers From 77987ca7b5ae4e18f72e5cb1b323a8bb00ba340b Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 21 Nov 2023 15:13:15 +0100 Subject: [PATCH 40/57] I dont know this file type --- .../Visualizers/attribcache140.bin | Bin 0 -> 8367 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Visual Studio 2022/Visualizers/attribcache140.bin diff --git a/Visual Studio 2022/Visualizers/attribcache140.bin b/Visual Studio 2022/Visualizers/attribcache140.bin new file mode 100644 index 0000000000000000000000000000000000000000..b78cc56bee10b6a7670b40f502e6d5682d043c24 GIT binary patch literal 8367 zcmeGhU6bQRQKkZQbs=!MyBv2%0Obe)l0D~kljEo>wkUt@iueo5>)j*@M3%?iVP(mT zq}_E~E*>c!dFO>UUZ~EOnfUl{!dAO81m_myucit?U5^L#QXR$SXAmQP*BD;^Pt zFlrUGniEV2GY2;LeE-wlXCF1G#az!F`Ncl<0@K$0U`X9!l?;OMn6NlOh(NzsH*3V0 z$8b-yJ+)7m2XY+lKPx`Lzdf}Q*nYssp+f?nnf9LA2?jQ`J|eT8dqJGT!IKY0Pe;#2 z`}@PEPs|U@S72km-=VO&8!(HEvPBlVCpsOHT?l_Kwv4(|4QxqyRT!%`n-Zn)jxleU z6QUlf{CA<&1KXA}5?(BjQ2Aw!nL&+x(+)_-r0nwprSQO*e>#WBJ?GDhJ$25%A^cg$ z>Xu+tySB&_9Y!g9*OAeE+5FqDaCx%l@bJ{yC}Iesqkn^qm> zQHr1)`0Y{GbjBo?>|sPk{qqU&sg;W^#j4UvaE0>h6T;kF0;!}bn9cR;Zr}`a@qZ%Z z(VQW<-f|Ce4b8bUZ91%&-gdfelF5Lul4XHebA^(-ZW9089d1GJBe4s#T9=FnBaW4C z2T7s(rghQ2By426SGhvn6KjM&xv0|f@JuyaGj4$&#N7J%91-wzr950~7wgo{Cq;x9 zX=KNcG{g4El~d%8#pXbHB4ihrV8%99Pv=`wJ;Vwa^=Cz00J)m_zM!fSn~Y5#BG6p} zjy;+kV^9czc4U;Qn!Xujn^$c+8V?ZKbmKJuGQvG;U3>M=r=sX$y!@aA#0`f)c|0VC?~{(s5hv7S4l zP}N{n&N%8WE){o9J9QNm6*J5CWLRS66?Mip{`1>E{^j+rZ$7_?7X~Ft)#2A--F1AW z@MikXp@X6i=lEaLMGul(IbGeHP!3%7oeXZ>e)j57=J$&=uzH_qu1Bt%WAMH@VnrHa8IzI*!gf}3H6i?{c~K70}J(- z(DAvC6Ct!lB@t5)CCHcb;v&o5Ieg zWDxn9hnsenllZ2$pQ{A zZ#1CaazIERFFQipD@;VMN-$Om4~@CzK>JGSDjEoWKi?n}(v=u7xeI4X^otD~__mPE zdKP=zuvj`1GVWY0ykXA4UfdJhElNa_NZC;kqy*J9f#PNUHaasox`>uQ?-EDHLH>5VrWb@VihU zV+Iok$04*(yY3YZ;YUanxp87=l7C31`!mdZko1pbY!Eu66jKlVGw? zo8~nx13!Em7ChOi7acnA#M&ivKuc`wDTN@T! z_YCYsqhF%T0u=P`$Y7U{8gM!c+m=f;hD<;myq*LE1asAg>8%2->x+c?;Gp9NbZC@D z!h(}*g(kPNWt7O)1rp)YV|0KQI;7dG6Pa`S zl57n#YMpP0joCR6Vi3Vg(jSa@8D9-NZbJ?&)KiyTz;zCb7@Up`7ix#miOFU-FTjOb zC70CV?P;7|j)aP{4Hnjl@T$XKQFxq!w8{9X;J`wyIlS71AHgX*59;thbaxK@G%b`3VW3h01^VZ8C(! zHnLCo20O~9q-1F5Q8-gd0iufLfC?ba;~pfOtF|74w~!Zd@N9EnkD%oaA?s%+>+G!9 zf5EJX4V8ZtHg!~D52LYuPv-37%vrdv?V_1t)SeriZu_WPYN~auQPYjSe(>brz^JsF z&35aVp;c=FuATL2EnRE3bfeQK_3G_z)2P Date: Tue, 21 Nov 2023 15:25:37 +0100 Subject: [PATCH 41/57] * refactor(AddExplicitReturnType.fs): simplify match expressions and refactor refactor function parameters --- .../Refactor/AddExplicitReturnType.fs | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index f8b728f6ef0..36f17376c88 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -37,30 +37,22 @@ type internal AddExplicitReturnType [] () = && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) && not typeAnnotationRange.IsNone - match res with - | true -> Some funcOrValue - | false -> None + match (res,typeAnnotationRange) with + | (true,Some tr) -> Some (funcOrValue,tr) + | (_,_) -> None static member refactor (context: CodeRefactoringContext) - (symbolUse: FSharpSymbolUse, memberFunc: FSharpMemberOrFunctionOrValue, parseFileResults: FSharpParseFileResults) + (memberFunc: FSharpMemberOrFunctionOrValue,typeRange:Range) = let title = SR.AddExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName - let rangeOfReturnType = - parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) - - let textChange = - rangeOfReturnType - |> Option.map (fun range -> RoslynHelpers.FSharpRangeToTextSpan(sourceText, range)) - |> Option.map (fun textSpan -> TextChange(textSpan, $": {inferredType}")) - - match textChange with - | Some textChange -> sourceText.WithChanges(textChange) - | None -> sourceText + let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, typeRange) + let textChange = TextChange(textSpan, $": {inferredType}") + sourceText.WithChanges(textChange) let codeActionFunc: CancellationToken -> Task = fun (cancellationToken: CancellationToken) -> @@ -117,7 +109,7 @@ type internal AddExplicitReturnType [] () = |> AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults match isValidMethod with - | Some memberFunc -> do AddExplicitReturnType.refactor context (symbolUse, memberFunc, parseFileResults) + | Some (memberFunc,typeRange) -> do AddExplicitReturnType.refactor context (memberFunc,typeRange) | None -> () | _ -> () From 5d004ebee928f64477fda82299213c0694f77bf2 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Fri, 1 Dec 2023 14:30:20 +0100 Subject: [PATCH 42/57] fixed: AddExplicitReturnTypeTests - Fixed creating the right SyntheticProject structure --- .../Refactors/AddExplicitReturnTypeTests.fs | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index cfcebf0ed76..7c5c7d668b5 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -28,42 +28,42 @@ let sum a b {shouldNotTrigger}= a + b tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) do Assert.Empty(actions) - + [] let ``Refactor should not trigger on values`` () = let symbolName = "example2" - + let code = - """ + """ let example2 = 42 // value """ - + use context = TestContext.CreateWithCode code - + let spanStart = code.IndexOf symbolName - + let actions = tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) - + do Assert.Empty(actions) - + [] let ``Refactor should not trigger on member values`` () = let symbolName = "SomeProp" - + let code = - """ + """ type Example3() = member _.SomeProp = 42 // property """ - + use context = TestContext.CreateWithCode code - + let spanStart = code.IndexOf symbolName - + let actions = tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) - + do Assert.Empty(actions) [] @@ -220,28 +220,31 @@ let ``Correctly infer custom type that is declared earlier in project`` () = let myModule = """ +module ModuleFirst type MyType = { Value: int } """ let code = """ +module ModuleSecond + open ModuleFirst let sum a b = {Value=a+b} """ let project = - SyntheticProject.Create( - { sourceFile "First" [] with - Source = myModule - SignatureFile = AutoGenerated - }, - { sourceFile "Second" ["First"] with - Source = code - } - ) - - project.SaveAndCheck() |> ignore + { SyntheticProject.Create( + { sourceFile "First" [] with + Source = myModule + }, + { sourceFile "Second" [ "First" ] with + Source = code + } + ) with + AutoAddModules = false + } + let solution, _ = RoslynTestHelpers.CreateSolution project let ct = CancellationToken false let context = new TestContext(solution, ct) @@ -252,10 +255,12 @@ let sum a b = {Value=a+b} let expectedCode = """ +module ModuleSecond + open ModuleFirst let sum a b : MyType= {Value=a+b} """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult - Assert.Equal(expectedCode.Trim(' ','\r','\n'), resultText.ToString().Trim(' ','\r','\n')) + Assert.Equal(expectedCode.Trim(' ', '\r', '\n'), resultText.ToString().Trim(' ', '\r', '\n')) From 3edc9d07e4ab807460f4d89bd0ab5c137b27cd07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:53:39 +0000 Subject: [PATCH 43/57] Automated command ran: fantomas Co-authored-by: psfinaki <5451366+psfinaki@users.noreply.github.com> --- .../Refactor/AddExplicitReturnType.fs | 19 ++++++++----------- .../Refactors/RefactorTestFramework.fs | 3 ++- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 36f17376c88..a59795447e3 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -37,14 +37,11 @@ type internal AddExplicitReturnType [] () = && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) && not typeAnnotationRange.IsNone - match (res,typeAnnotationRange) with - | (true,Some tr) -> Some (funcOrValue,tr) - | (_,_) -> None + match (res, typeAnnotationRange) with + | (true, Some tr) -> Some(funcOrValue, tr) + | (_, _) -> None - static member refactor - (context: CodeRefactoringContext) - (memberFunc: FSharpMemberOrFunctionOrValue,typeRange:Range) - = + static member refactor (context: CodeRefactoringContext) (memberFunc: FSharpMemberOrFunctionOrValue, typeRange: Range) = let title = SR.AddExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = @@ -85,8 +82,7 @@ type internal AddExplicitReturnType [] () = let! lexerSymbol = document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddExplicitReturnType)) - let! (parseFileResults, checkFileResults) = - document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) + let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) let symbolUseOpt = lexerSymbol @@ -109,9 +105,10 @@ type internal AddExplicitReturnType [] () = |> AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults match isValidMethod with - | Some (memberFunc,typeRange) -> do AddExplicitReturnType.refactor context (memberFunc,typeRange) + | Some(memberFunc, typeRange) -> do AddExplicitReturnType.refactor context (memberFunc, typeRange) | None -> () | _ -> () return () - } |> CancellableTask.startAsTaskWithoutCancellation + } + |> CancellableTask.startAsTaskWithoutCancellation diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index ae37e990b5b..dacf63bdebe 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -18,7 +18,7 @@ open FSharp.Compiler.Text let GetTaskResult (task: Tasks.Task<'T>) = task.GetAwaiter().GetResult() type TestContext(Solution: Solution, CancellationToken) = - let mutable _solution = Solution + let mutable _solution = Solution member this.CT = CancellationToken member this.Solution @@ -82,6 +82,7 @@ let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestConte context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) let document = RoslynTestHelpers.GetLastDocument context.Solution + let refactoringContext = CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) From e59af4794ddca9ed168a86ab2f802e32af0ab1ac Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 2 Dec 2023 10:56:57 +0100 Subject: [PATCH 44/57] * fix: add space before equals sign in type annotations in AddExplicitReturnType.fs and AddExplicitReturnTypeTests.fs --- .../Refactor/AddExplicitReturnType.fs | 2 +- .../Refactors/AddExplicitReturnTypeTests.fs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index a59795447e3..10fa171fd4f 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -48,7 +48,7 @@ type internal AddExplicitReturnType [] () = let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, typeRange) - let textChange = TextChange(textSpan, $": {inferredType}") + let textChange = TextChange(textSpan, $": {inferredType} ") sourceText.WithChanges(textChange) let codeActionFunc: CancellationToken -> Task = diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 7c5c7d668b5..629853758e1 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -83,7 +83,7 @@ let sum a b = a + b let expectedCode = $""" -let sum a b : int= a + b +let sum a b : int = a + b """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -106,7 +106,7 @@ let sum (a:float) (b:float) = a + b let expectedCode = """ -let sum (a:float) (b:float) : float= a + b +let sum (a:float) (b:float) : float = a + b """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -131,7 +131,7 @@ let rec fib n = let expectedCode = $""" -let rec fib n : int= +let rec fib n : int = if n < 2 then 1 else fib (n - 1) + fib (n - 2) """ @@ -156,7 +156,7 @@ let apply1 (transform: int -> int) y = transform y let expectedCode = $""" -let apply1 (transform: int -> int) y : int= transform y +let apply1 (transform: int -> int) y : int = transform y """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -183,7 +183,7 @@ type SomeType(factor0: int) = $""" type SomeType(factor0: int) = let factor = factor0 - member this.SomeMethod(a, b, c) : int= (a + b + c) * factor + member this.SomeMethod(a, b, c) : int = (a + b + c) * factor """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -208,7 +208,7 @@ let sum a b = {Value=a+b} let expectedCode = """ type MyType = { Value: int } -let sum a b : MyType= {Value=a+b} +let sum a b : MyType = {Value=a+b} """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult @@ -259,7 +259,7 @@ module ModuleSecond open ModuleFirst -let sum a b : MyType= {Value=a+b} +let sum a b : MyType = {Value=a+b} """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult From 4c487710b503b549825237983b2c63ff27f677c5 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 2 Dec 2023 11:31:57 +0100 Subject: [PATCH 45/57] * feat(AddExplicitReturnType.fs): add support for generic return types and handle empty inferred types * test(AddExplicitReturnTypeTests.fs): add test for binding another method --- .../Refactor/AddExplicitReturnType.fs | 21 ++++++++++++---- .../Refactors/AddExplicitReturnTypeTests.fs | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 10fa171fd4f..1e5f0f71abc 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -45,11 +45,22 @@ type internal AddExplicitReturnType [] () = let title = SR.AddExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = - let inferredType = memberFunc.ReturnParameter.Type.TypeDefinition.DisplayName - - let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, typeRange) - let textChange = TextChange(textSpan, $": {inferredType} ") - sourceText.WithChanges(textChange) + let returnType = memberFunc.ReturnParameter.Type + + let inferredType = + if returnType.HasTypeDefinition then + returnType.TypeDefinition.DisplayName + else if returnType.GenericArguments.Count > 0 then + returnType.GenericArguments[0].TypeDefinition.DisplayName + else + "" + + if inferredType = "" then + sourceText + else + let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, typeRange) + let textChange = TextChange(textSpan, $": {inferredType} ") + sourceText.WithChanges(textChange) let codeActionFunc: CancellationToken -> Task = fun (cancellationToken: CancellationToken) -> diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 629853758e1..9d3aeb65aa1 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -89,6 +89,31 @@ let sum a b : int = a + b let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) +[] +let ``Should not throw exception when binding another method`` () = + let symbolName = "addThings" + + let code = + """ +let add x y = x + y +let addThings = add + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + $""" +let add x y = x + y +let addThings : int = add + """ + + let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + [] let ``Handle Parantheses on the arguments`` () = let symbolName = "sum" From 79603fb267ba118deefdf3334b1b41dbefef077a Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 2 Dec 2023 12:25:33 +0100 Subject: [PATCH 46/57] * refactor(AddExplicitReturnType.fs): improve inferredType calculation and refactor method signature * test(AddExplicitReturnTypeTests.fs): update test cases to reflect changes in AddExplicitReturnType.fs --- .../Refactor/AddExplicitReturnType.fs | 24 +++++++++---------- .../Refactors/AddExplicitReturnTypeTests.fs | 6 ++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 1e5f0f71abc..3e98331f641 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -41,26 +41,26 @@ type internal AddExplicitReturnType [] () = | (true, Some tr) -> Some(funcOrValue, tr) | (_, _) -> None - static member refactor (context: CodeRefactoringContext) (memberFunc: FSharpMemberOrFunctionOrValue, typeRange: Range) = + static member refactor + (context: CodeRefactoringContext) + (memberFunc: FSharpMemberOrFunctionOrValue, typeRange: Range, symbolUse: FSharpSymbolUse) + = let title = SR.AddExplicitReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = let returnType = memberFunc.ReturnParameter.Type let inferredType = + let res = returnType.Format symbolUse.DisplayContext + if returnType.HasTypeDefinition then - returnType.TypeDefinition.DisplayName - else if returnType.GenericArguments.Count > 0 then - returnType.GenericArguments[0].TypeDefinition.DisplayName + res else - "" + $"({res})".Replace(" ", "") - if inferredType = "" then - sourceText - else - let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, typeRange) - let textChange = TextChange(textSpan, $": {inferredType} ") - sourceText.WithChanges(textChange) + let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, typeRange) + let textChange = TextChange(textSpan, $": {inferredType} ") + sourceText.WithChanges(textChange) let codeActionFunc: CancellationToken -> Task = fun (cancellationToken: CancellationToken) -> @@ -116,7 +116,7 @@ type internal AddExplicitReturnType [] () = |> AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults match isValidMethod with - | Some(memberFunc, typeRange) -> do AddExplicitReturnType.refactor context (memberFunc, typeRange) + | Some(memberFunc, typeRange) -> do AddExplicitReturnType.refactor context (memberFunc, typeRange, symbolUse) | None -> () | _ -> () diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 9d3aeb65aa1..0d9143194a1 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -95,7 +95,7 @@ let ``Should not throw exception when binding another method`` () = let code = """ -let add x y = x + y +let add (x:int) (y:int) = (float(x + y)) + 0.1 let addThings = add """ @@ -107,8 +107,8 @@ let addThings = add let expectedCode = $""" -let add x y = x + y -let addThings : int = add +let add (x:int) (y:int) = (float(x + y)) + 0.1 +let addThings : (int->int->float) = add """ let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult From d0940c27232b706f22ec25ca0742a10737a548f3 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 2 Dec 2023 12:28:16 +0100 Subject: [PATCH 47/57] fix: remove strange artifact --- .../Visualizers/attribcache140.bin | Bin 8367 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Visual Studio 2022/Visualizers/attribcache140.bin diff --git a/Visual Studio 2022/Visualizers/attribcache140.bin b/Visual Studio 2022/Visualizers/attribcache140.bin deleted file mode 100644 index b78cc56bee10b6a7670b40f502e6d5682d043c24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8367 zcmeGhU6bQRQKkZQbs=!MyBv2%0Obe)l0D~kljEo>wkUt@iueo5>)j*@M3%?iVP(mT zq}_E~E*>c!dFO>UUZ~EOnfUl{!dAO81m_myucit?U5^L#QXR$SXAmQP*BD;^Pt zFlrUGniEV2GY2;LeE-wlXCF1G#az!F`Ncl<0@K$0U`X9!l?;OMn6NlOh(NzsH*3V0 z$8b-yJ+)7m2XY+lKPx`Lzdf}Q*nYssp+f?nnf9LA2?jQ`J|eT8dqJGT!IKY0Pe;#2 z`}@PEPs|U@S72km-=VO&8!(HEvPBlVCpsOHT?l_Kwv4(|4QxqyRT!%`n-Zn)jxleU z6QUlf{CA<&1KXA}5?(BjQ2Aw!nL&+x(+)_-r0nwprSQO*e>#WBJ?GDhJ$25%A^cg$ z>Xu+tySB&_9Y!g9*OAeE+5FqDaCx%l@bJ{yC}Iesqkn^qm> zQHr1)`0Y{GbjBo?>|sPk{qqU&sg;W^#j4UvaE0>h6T;kF0;!}bn9cR;Zr}`a@qZ%Z z(VQW<-f|Ce4b8bUZ91%&-gdfelF5Lul4XHebA^(-ZW9089d1GJBe4s#T9=FnBaW4C z2T7s(rghQ2By426SGhvn6KjM&xv0|f@JuyaGj4$&#N7J%91-wzr950~7wgo{Cq;x9 zX=KNcG{g4El~d%8#pXbHB4ihrV8%99Pv=`wJ;Vwa^=Cz00J)m_zM!fSn~Y5#BG6p} zjy;+kV^9czc4U;Qn!Xujn^$c+8V?ZKbmKJuGQvG;U3>M=r=sX$y!@aA#0`f)c|0VC?~{(s5hv7S4l zP}N{n&N%8WE){o9J9QNm6*J5CWLRS66?Mip{`1>E{^j+rZ$7_?7X~Ft)#2A--F1AW z@MikXp@X6i=lEaLMGul(IbGeHP!3%7oeXZ>e)j57=J$&=uzH_qu1Bt%WAMH@VnrHa8IzI*!gf}3H6i?{c~K70}J(- z(DAvC6Ct!lB@t5)CCHcb;v&o5Ieg zWDxn9hnsenllZ2$pQ{A zZ#1CaazIERFFQipD@;VMN-$Om4~@CzK>JGSDjEoWKi?n}(v=u7xeI4X^otD~__mPE zdKP=zuvj`1GVWY0ykXA4UfdJhElNa_NZC;kqy*J9f#PNUHaasox`>uQ?-EDHLH>5VrWb@VihU zV+Iok$04*(yY3YZ;YUanxp87=l7C31`!mdZko1pbY!Eu66jKlVGw? zo8~nx13!Em7ChOi7acnA#M&ivKuc`wDTN@T! z_YCYsqhF%T0u=P`$Y7U{8gM!c+m=f;hD<;myq*LE1asAg>8%2->x+c?;Gp9NbZC@D z!h(}*g(kPNWt7O)1rp)YV|0KQI;7dG6Pa`S zl57n#YMpP0joCR6Vi3Vg(jSa@8D9-NZbJ?&)KiyTz;zCb7@Up`7ix#miOFU-FTjOb zC70CV?P;7|j)aP{4Hnjl@T$XKQFxq!w8{9X;J`wyIlS71AHgX*59;thbaxK@G%b`3VW3h01^VZ8C(! zHnLCo20O~9q-1F5Q8-gd0iufLfC?ba;~pfOtF|74w~!Zd@N9EnkD%oaA?s%+>+G!9 zf5EJX4V8ZtHg!~D52LYuPv-37%vrdv?V_1t)SeriZu_WPYN~auQPYjSe(>brz^JsF z&35aVp;c=FuATL2EnRE3bfeQK_3G_z)2P Date: Sat, 2 Dec 2023 16:08:57 +0100 Subject: [PATCH 48/57] * refactor(FSharp.Editor): rename 'AddExplicitReturnTypeAnnotation' to 'AddReturnTypeAnnotation' in all language files --- vsintegration/src/FSharp.Editor/FSharp.Editor.resx | 2 +- .../src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.de.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.es.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.it.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf | 10 +++++----- .../src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf | 10 +++++----- 14 files changed, 66 insertions(+), 66 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 9c12f2a6519..857d7af8bbd 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -352,7 +352,7 @@ Use live (unsaved) buffers for analysis Convert C# 'using' to F# 'open' - + Add explicit return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index b80a2c6ac40..a1d9e39ef4d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Přidejte do definice typu chybějící =. @@ -27,6 +22,11 @@ Přidejte klíčové slovo new. + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Přidat anotaci typu diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index b1abace993e..66baf3ef6c7 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Fehlende "=" zur Typdefinition hinzufügen @@ -27,6 +22,11 @@ Schlüsselwort "new" hinzufügen + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Typanmerkung hinzufügen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 2be2317bbf9..f02424810a2 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Agregar el carácter "=" que falta a la definición de tipo @@ -27,6 +22,11 @@ Agregar "nueva" palabra clave + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Agregar una anotación de tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 02c7d4c78b4..813fb7e8d45 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Ajouter un '=' manquant à la définition de type @@ -27,6 +22,11 @@ Ajouter le mot clé 'new' + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Ajouter une annotation de type diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index dcedb50b426..ab0f66bf919 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Aggiungere il carattere '=' mancante alla definizione di tipo @@ -27,6 +22,11 @@ Aggiungi la parola chiave 'new' + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Aggiungere l'annotazione di tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 22923fa1f76..2ef81d656b4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition 不足している '=' を型定義に追加します @@ -27,6 +22,11 @@ 'new' キーワードを追加する + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation 型の注釈の追加 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 591df2ccb6a..7aea2ab7b7b 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition 형식 정의에 누락된 '=' 추가 @@ -27,6 +22,11 @@ 'new' 키워드 추가 + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation 형식 주석 추가 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 863bf742b2f..162b563f08d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Dodaj brakujący element znak „=” do definicji typu @@ -27,6 +22,11 @@ Dodaj słowo kluczowe „new” + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Dodaj adnotację typu diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index 24b5cf709fa..248aa88f60a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Adicionar o '=' ausente à definição de tipo @@ -27,6 +22,11 @@ Adicionar a palavra-chave 'new' + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Adicionar uma anotação de tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 29bd87400b6..5a0c109e8a0 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Добавьте недостающий символ "=" к определению типа. @@ -27,6 +22,11 @@ Добавить ключевое слово "new" + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Добавить заметку типа diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index ef5ee782c32..eb44c8ded39 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition Tür tanımına eksik '=' işaretini ekle @@ -27,6 +22,11 @@ 'new' anahtar sözcüğünü ekleme + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation Tür ek açıklaması ekle diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 0820f856e7e..fe75ed8b813 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition 将缺少的 "=" 添加到类型定义 @@ -27,6 +22,11 @@ 添加“新”关键字 + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation 添加类型注释 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 484be626cdd..aa3f3a0b347 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -2,11 +2,6 @@ - - Add explicit return type annotation - Add explicit return type annotation - - Add missing '=' to type definition 將缺少的 '=' 新增至類型定義 @@ -27,6 +22,11 @@ 新增 'new' 關鍵字 + + Add explicit return type annotation + Add explicit return type annotation + + Add type annotation 新增型別註解 From ca88258f938dfce3cc0f22bd7c607388395a13fa Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 2 Dec 2023 18:30:59 +0100 Subject: [PATCH 49/57] * refactor(FSharp.Editor): simplify CancellationToken usage in TestContext * refactor(FSharp.Editor.Tests): remove unnecessary CancellationToken from AddExplicitReturnTypeTests * refactor(RefactorTestFramework): remove unused import and simplify CancellationToken usage * fix(AddExplicitReturnType): rename AddExplicitReturnTypeAnnotation to AddReturnTypeAnnotation --- .../Refactor/AddExplicitReturnType.fs | 2 +- .../Refactors/AddExplicitReturnTypeTests.fs | 20 +++++++------- .../Refactors/RefactorTestFramework.fs | 26 +++++++------------ 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 3e98331f641..648d51d4aac 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -45,7 +45,7 @@ type internal AddExplicitReturnType [] () = (context: CodeRefactoringContext) (memberFunc: FSharpMemberOrFunctionOrValue, typeRange: Range, symbolUse: FSharpSymbolUse) = - let title = SR.AddExplicitReturnTypeAnnotation() + let title = SR.AddReturnTypeAnnotation() let getChangedText (sourceText: SourceText) = let returnType = memberFunc.ReturnParameter.Type diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 0d9143194a1..87f8adb74dd 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -5,7 +5,6 @@ open Xunit open FSharp.Editor.Tests.Refactors.RefactorTestFramework open FSharp.Test.ProjectGeneration open FSharp.Editor.Tests.Helpers -open System.Threading [] [] @@ -86,7 +85,7 @@ let sum a b = a + b let sum a b : int = a + b """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) [] @@ -111,7 +110,7 @@ let add (x:int) (y:int) = (float(x + y)) + 0.1 let addThings : (int->int->float) = add """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) [] @@ -134,7 +133,7 @@ let sum (a:float) (b:float) = a + b let sum (a:float) (b:float) : float = a + b """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) [] @@ -161,7 +160,7 @@ let rec fib n : int = else fib (n - 1) + fib (n - 2) """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) [] @@ -184,7 +183,7 @@ let apply1 (transform: int -> int) y = transform y let apply1 (transform: int -> int) y : int = transform y """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) [] @@ -211,7 +210,7 @@ type SomeType(factor0: int) = member this.SomeMethod(a, b, c) : int = (a + b + c) * factor """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) [] @@ -236,7 +235,7 @@ type MyType = { Value: int } let sum a b : MyType = {Value=a+b} """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) [] @@ -271,8 +270,7 @@ let sum a b = {Value=a+b} } let solution, _ = RoslynTestHelpers.CreateSolution project - let ct = CancellationToken false - let context = new TestContext(solution, ct) + let context = new TestContext(solution) let spanStart = code.IndexOf symbolName @@ -287,5 +285,5 @@ open ModuleFirst let sum a b : MyType = {Value=a+b} """ - let resultText = newDoc.GetTextAsync context.CT |> GetTaskResult + let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode.Trim(' ', '\r', '\n'), resultText.ToString().Trim(' ', '\r', '\n')) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index dacf63bdebe..150ac13f755 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -2,7 +2,6 @@ open System open System.Linq -open System.Collections.Immutable open System.Collections.Generic open Microsoft.CodeAnalysis @@ -17,21 +16,20 @@ open FSharp.Compiler.Text let GetTaskResult (task: Tasks.Task<'T>) = task.GetAwaiter().GetResult() -type TestContext(Solution: Solution, CancellationToken) = +type TestContext(Solution: Solution) = let mutable _solution = Solution - member this.CT = CancellationToken + member _.CancellationToken = CancellationToken.None - member this.Solution + member _.Solution with set value = _solution <- value and get () = _solution interface IDisposable with - member this.Dispose() = Solution.Workspace.Dispose() + member _.Dispose() = Solution.Workspace.Dispose() static member CreateWithCode(code: string) = let solution = RoslynTestHelpers.CreateSolution(code) - let ct = CancellationToken false - new TestContext(solution, ct) + new TestContext(solution) static member CreateWithCodeAndDependency (code: string) (codeForPreviousFile: string) = let mutable solution = RoslynTestHelpers.CreateSolution(codeForPreviousFile) @@ -39,11 +37,7 @@ type TestContext(Solution: Solution, CancellationToken) = let firstProject = solution.Projects.First() solution <- solution.AddDocument(DocumentId.CreateNewId(firstProject.Id), "test2.fs", code, filePath = "C:\\test2.fs") - let ct = CancellationToken false - new TestContext(solution, ct) - -let mockAction = - Action>(fun _ _ -> ()) + new TestContext(solution) let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = let refactoringActions = new List() @@ -56,18 +50,18 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor let mutable workspace = context.Solution.Workspace let refactoringContext = - CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CancellationToken) let task = refactorProvider.ComputeRefactoringsAsync refactoringContext do task.GetAwaiter().GetResult() for action in refactoringActions do - let operationsTask = action.GetOperationsAsync context.CT + let operationsTask = action.GetOperationsAsync context.CancellationToken let operations = operationsTask |> GetTaskResult for operation in operations do let codeChangeOperation = operation :?> ApplyChangesOperation - codeChangeOperation.Apply(workspace, context.CT) + codeChangeOperation.Apply(workspace, context.CancellationToken) context.Solution <- codeChangeOperation.ChangedSolution () @@ -84,7 +78,7 @@ let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestConte let document = RoslynTestHelpers.GetLastDocument context.Solution let refactoringContext = - CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CT) + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CancellationToken) do! refactorProvider.ComputeRefactoringsAsync refactoringContext From 7283db8774162e78b33b8357e0914a0047ee7bb4 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 6 Dec 2023 10:13:06 +0100 Subject: [PATCH 50/57] refactor: Improve code readability and performance - Refactored the `tryRefactor` function to use async/await pattern for better readability. - Replaced synchronous operations with asynchronous ones to improve performance. - Updated variable names for clarity and consistency. --- .../Refactors/RefactorTestFramework.fs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 150ac13f755..d5353a4d42e 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -40,33 +40,36 @@ type TestContext(Solution: Solution) = new TestContext(solution) let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = - let refactoringActions = new List() - let existingDocument = RoslynTestHelpers.GetLastDocument context.Solution + cancellableTask { + let refactoringActions = new List() + let existingDocument = RoslynTestHelpers.GetLastDocument context.Solution - context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) + context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) - let document = RoslynTestHelpers.GetLastDocument context.Solution + let document = RoslynTestHelpers.GetLastDocument context.Solution - let mutable workspace = context.Solution.Workspace + let mutable workspace = context.Solution.Workspace - let refactoringContext = - CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CancellationToken) + let refactoringContext = + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CancellationToken) + + do! refactorProvider.ComputeRefactoringsAsync refactoringContext - let task = refactorProvider.ComputeRefactoringsAsync refactoringContext - do task.GetAwaiter().GetResult() + for action in refactoringActions do + let! operations = action.GetOperationsAsync context.CancellationToken - for action in refactoringActions do - let operationsTask = action.GetOperationsAsync context.CancellationToken - let operations = operationsTask |> GetTaskResult + for operation in operations do + let codeChangeOperation = operation :?> ApplyChangesOperation + codeChangeOperation.Apply(workspace, context.CancellationToken) + context.Solution <- codeChangeOperation.ChangedSolution + () - for operation in operations do - let codeChangeOperation = operation :?> ApplyChangesOperation - codeChangeOperation.Apply(workspace, context.CancellationToken) - context.Solution <- codeChangeOperation.ChangedSolution - () + let newDocument = context.Solution.GetDocument(document.Id) + return newDocument - let newDocument = context.Solution.GetDocument(document.Id) - newDocument + } + |> CancellableTask.startWithoutCancellation + |> GetTaskResult let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = cancellableTask { From 0a5a1939b8d073f2d6a23014eba5f15e14d16cbb Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 6 Dec 2023 10:41:19 +0100 Subject: [PATCH 51/57] refactor: Improve code readability and performance refactor: Improve code readability and performance - Refactored the `tryRefactor` function in `RefactorTestFramework.fs` to improve code readability and performance. - Replaced the usage of a mutable list with a mutable variable to store the `CodeAction`. - Simplified the logic for applying changes. --- .../Refactors/RefactorTestFramework.fs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index d5353a4d42e..4bbb091eca3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -41,7 +41,7 @@ type TestContext(Solution: Solution) = let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = cancellableTask { - let refactoringActions = new List() + let mutable action: CodeAction = null let existingDocument = RoslynTestHelpers.GetLastDocument context.Solution context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) @@ -51,18 +51,17 @@ let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactor let mutable workspace = context.Solution.Workspace let refactoringContext = - CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CancellationToken) + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> action <- a), context.CancellationToken) do! refactorProvider.ComputeRefactoringsAsync refactoringContext - for action in refactoringActions do - let! operations = action.GetOperationsAsync context.CancellationToken + let! operations = action.GetOperationsAsync context.CancellationToken - for operation in operations do - let codeChangeOperation = operation :?> ApplyChangesOperation - codeChangeOperation.Apply(workspace, context.CancellationToken) - context.Solution <- codeChangeOperation.ChangedSolution - () + for operation in operations do + let codeChangeOperation = operation :?> ApplyChangesOperation + codeChangeOperation.Apply(workspace, context.CancellationToken) + context.Solution <- codeChangeOperation.ChangedSolution + () let newDocument = context.Solution.GetDocument(document.Id) return newDocument From d9310a3f7ea39652e34fa697ff0c6cc114a7c677 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Wed, 13 Dec 2023 14:31:22 +0100 Subject: [PATCH 52/57] refactor: Refactored AddExplicitReturnType.fs and AddExplicitReturnTypeTests.fs - In AddExplicitReturnType.fs: - Replaced the codeActionFunc with a cancellableTask to handle cancellation tokens. - Updated the codeActionFunc to use the new cancellableTask and getChangedText functions. - In AddExplicitReturnTypeTests.fs: - Added tests for binding another function and binding linq function without crashing. - Updated the expectedCode for these tests to include explicit return types. --- .../Refactor/AddExplicitReturnType.fs | 18 +++---- .../Refactors/AddExplicitReturnTypeTests.fs | 50 +++++++++++++++++++ 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index 648d51d4aac..bfc9303acef 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -62,15 +62,15 @@ type internal AddExplicitReturnType [] () = let textChange = TextChange(textSpan, $": {inferredType} ") sourceText.WithChanges(textChange) - let codeActionFunc: CancellationToken -> Task = - fun (cancellationToken: CancellationToken) -> - task { - let! sourceText = context.Document.GetTextAsync(cancellationToken) - let changedText = getChangedText sourceText + let codeActionFunc = + cancellableTask { + let! cancellationToken = CancellableTask.getCancellationToken () + let! sourceText = context.Document.GetTextAsync(cancellationToken) + let changedText = getChangedText sourceText - let newDocument = context.Document.WithText(changedText) - return newDocument - } + let newDocument = context.Document.WithText(changedText) + return newDocument + } let codeAction = CodeAction.Create(title, codeActionFunc, title) @@ -122,4 +122,4 @@ type internal AddExplicitReturnType [] () = return () } - |> CancellableTask.startAsTaskWithoutCancellation + |> CancellableTask.startAsTask context.CancellationToken diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 87f8adb74dd..07e84b51022 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -213,6 +213,56 @@ type SomeType(factor0: int) = let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) +[] +let ``Binding another function doesnt crash`` () = + let symbolName = "getNow" + + let code = + $""" +let getNow() = + System.DateTime.Now + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + $""" +let getNow() : System.DateTime = + System.DateTime.Now + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Binding linq function doesnt crash`` () = + let symbolName = "skip1" + + let code = + $""" +let skip1 elements = + System.Linq.Enumerable.Skip(elements, 1) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + $""" +let skip1 elements : System.Collections.Generic.IEnumerable<'a> = + System.Linq.Enumerable.Skip(elements, 1) + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + [] let ``Correctly infer custom type that is declared earlier in file`` () = let symbolName = "sum" From 696b930cf2e4e0c429f5d4c14537006796fa49a2 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Fri, 15 Dec 2023 14:27:05 +0100 Subject: [PATCH 53/57] refactor: Simplify AddExplicitReturnType logic The code changes simplify the logic in the AddExplicitReturnType module. The changes remove unnecessary conditions and improve readability. --- .../src/FSharp.Editor/Refactor/AddExplicitReturnType.fs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs index bfc9303acef..a83ed69d0d8 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs @@ -25,14 +25,10 @@ type internal AddExplicitReturnType [] () = let typeAnnotationRange = parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) - let isLambdaIfFunction = - funcOrValue.IsFunction - && parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start - let res = funcOrValue.CompiledName = funcOrValue.DisplayName - && not funcOrValue.IsValue - && (not funcOrValue.IsValue || not isLambdaIfFunction) + && funcOrValue.IsFunction + && not (parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start) && not (funcOrValue.ReturnParameter.Type.IsUnresolved) && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) && not typeAnnotationRange.IsNone From 323c863733b1487e18dec458893f64af4b207328 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Fri, 15 Dec 2023 14:38:04 +0100 Subject: [PATCH 54/57] refactor: Add explicit return type to sum function - Added a test case to ensure that the refactor correctly infers the return type of the `sum` function when it is defined on the next line. - Removed an unused import in the `RefactorTestFramework.fs` file. refactor: Add explicit return type to sum function --- .../Refactors/AddExplicitReturnTypeTests.fs | 29 ++++++++++++++++++- .../Refactors/RefactorTestFramework.fs | 1 - 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 07e84b51022..49e445ae42e 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -87,6 +87,33 @@ let sum a b : int = a + b let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Correctly infer on next line arguments`` () = + let symbolName = "sum" + + let code = + """ +let sum + x y = + x + y + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + $""" +let sum + x y : int = + x + y + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) [] let ``Should not throw exception when binding another method`` () = @@ -114,7 +141,7 @@ let addThings : (int->int->float) = add Assert.Equal(expectedCode, resultText.ToString()) [] -let ``Handle Parantheses on the arguments`` () = +let ``Handle parantheses on the arguments`` () = let symbolName = "sum" let code = diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs index 4bbb091eca3..849da8c84ec 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -12,7 +12,6 @@ open FSharp.Editor.Tests.Helpers open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions open System.Threading -open FSharp.Compiler.Text let GetTaskResult (task: Tasks.Task<'T>) = task.GetAwaiter().GetResult() From 6fb62dfa57a59068f1917642f883652a0b4e4f03 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Fri, 15 Dec 2023 14:46:22 +0100 Subject: [PATCH 55/57] tests: Added new special test cases for already existing opens --- .../Refactors/AddExplicitReturnTypeTests.fs | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs index 49e445ae42e..8fef4f15e8a 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs @@ -163,6 +163,7 @@ let sum (a:float) (b:float) : float = a + b let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) + [] let ``Infer on rec method`` () = let symbolName = "fib" @@ -264,6 +265,35 @@ let getNow() : System.DateTime = let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle already existing opens for DateTime`` () = + let symbolName = "getNow" + + let code = + $""" +open System + +let getNow() = + DateTime.Now + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + $""" +open System + +let getNow() : DateTime = + DateTime.Now + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) [] let ``Binding linq function doesnt crash`` () = @@ -290,6 +320,67 @@ let skip1 elements : System.Collections.Generic.IEnumerable<'a> = let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle already existing opens on Linq`` () = + let symbolName = "skip1" + + let code = + $""" +open System + +let skip1 elements = + Linq.Enumerable.Skip(elements, 1) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + $""" +open System + +let skip1 elements : Collections.Generic.IEnumerable<'a> = + Linq.Enumerable.Skip(elements, 1) + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle already existing opens on Enumerable`` () = + let symbolName = "skip1" + + let code = + $""" +open System +open System.Linq + +let skip1 elements = + Enumerable.Skip(elements, 1) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + + let expectedCode = + $""" +open System +open System.Linq + +let skip1 elements : Collections.Generic.IEnumerable<'a> = + Enumerable.Skip(elements, 1) + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + [] let ``Correctly infer custom type that is declared earlier in file`` () = let symbolName = "sum" From 8cf85ecda41569401da7f0d296414c16a7a36c05 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 16 Dec 2023 11:04:30 +0100 Subject: [PATCH 56/57] refactor: Update return type annotation in localization files The commit updates the return type annotation in multiple localization files. --- vsintegration/src/FSharp.Editor/FSharp.Editor.resx | 2 +- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf | 4 ++-- vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index c6295428168..ef5f05b3d24 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -354,7 +354,7 @@ Use live (unsaved) buffers for analysis Convert C# 'using' to F# 'open' - Add explicit return type annotation + Add return type annotation Remove unnecessary parentheses diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 3de3adb368e..b4ad96704a9 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index e1201245c7d..7796b6a2fe9 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 6e0fb583f52..c8c15573014 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index f0b5f67407a..c0076a1473e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index 3c257ffd411..fc95d16b038 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index f8df6281951..74d787d914b 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index ae710e7a9f2..816da89d7d7 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 0e8c1aa12ca..f0645a7a1b3 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index bee4d5abdb4..7c05c537e39 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 50bdb1b0939..53d05e963f3 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index 0992d752aae..d8047f179af 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 7a8f6227ef8..7f0aeefc86f 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index ea500ba1fbb..8e5de2d10a5 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -23,8 +23,8 @@ - Add explicit return type annotation - Add explicit return type annotation + Add return type annotation + Add return type annotation From 3a7eac444f2c19e1187f8f8a3de9fe848a02aa17 Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Sat, 16 Dec 2023 11:05:15 +0100 Subject: [PATCH 57/57] refactor: Rename AddExplicitReturnType to AddReturnType - Renamed the file `AddExplicitReturnType.fs` to `AddReturnType.fs`. - Updated references to the renamed file in other files. - Updated test file names and references accordingly. --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 2 +- ...ExplicitReturnType.fs => AddReturnType.fs} | 17 +++---- .../FSharp.Editor.Tests.fsproj | 2 +- ...turnTypeTests.fs => AddReturnTypeTests.fs} | 49 +++++++++---------- 4 files changed, 31 insertions(+), 39 deletions(-) rename vsintegration/src/FSharp.Editor/Refactor/{AddExplicitReturnType.fs => AddReturnType.fs} (86%) rename vsintegration/tests/FSharp.Editor.Tests/Refactors/{AddExplicitReturnTypeTests.fs => AddReturnTypeTests.fs} (84%) diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 7282aa2c4e2..37bb02d43d2 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -99,7 +99,7 @@ - + diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddReturnType.fs similarity index 86% rename from vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs rename to vsintegration/src/FSharp.Editor/Refactor/AddReturnType.fs index a83ed69d0d8..b3c586b445e 100644 --- a/vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs +++ b/vsintegration/src/FSharp.Editor/Refactor/AddReturnType.fs @@ -1,20 +1,17 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System.Composition -open System.Threading -open System.Threading.Tasks open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols open FSharp.Compiler.Text -open Microsoft.CodeAnalysis open Microsoft.CodeAnalysis.Text open Microsoft.CodeAnalysis.CodeRefactorings open Microsoft.CodeAnalysis.CodeActions open CancellableTasks -[] -type internal AddExplicitReturnType [] () = +[] +type internal AddReturnType [] () = inherit CodeRefactoringProvider() static member isValidMethodWithoutTypeAnnotation @@ -87,9 +84,9 @@ type internal AddExplicitReturnType [] () = let fcsTextLineNumber = Line.fromZ textLinePos.Line let! lexerSymbol = - document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddExplicitReturnType)) + document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddReturnType)) - let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddExplicitReturnType)) + let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddReturnType)) let symbolUseOpt = lexerSymbol @@ -103,16 +100,16 @@ type internal AddExplicitReturnType [] () = let memberFuncOpt = symbolUseOpt - |> Option.bind (fun sym -> sym.Symbol |> AddExplicitReturnType.ofFSharpMemberOrFunctionOrValue) + |> Option.bind (fun sym -> sym.Symbol |> AddReturnType.ofFSharpMemberOrFunctionOrValue) match (symbolUseOpt, memberFuncOpt) with | (Some symbolUse, Some memberFunc) -> let isValidMethod = memberFunc - |> AddExplicitReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults + |> AddReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults match isValidMethod with - | Some(memberFunc, typeRange) -> do AddExplicitReturnType.refactor context (memberFunc, typeRange, symbolUse) + | Some(memberFunc, typeRange) -> do AddReturnType.refactor context (memberFunc, typeRange, symbolUse) | None -> () | _ -> () diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 041d68352b5..a180accc43f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -73,7 +73,7 @@ - + diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddReturnTypeTests.fs similarity index 84% rename from vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs rename to vsintegration/tests/FSharp.Editor.Tests/Refactors/AddReturnTypeTests.fs index 8fef4f15e8a..5b81fb996da 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddExplicitReturnTypeTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddReturnTypeTests.fs @@ -1,4 +1,4 @@ -module FSharp.Editor.Tests.Refactors.AddExplicitReturnTypeTests +module FSharp.Editor.Tests.Refactors.AddReturnTypeTests open Microsoft.VisualStudio.FSharp.Editor open Xunit @@ -23,8 +23,7 @@ let sum a b {shouldNotTrigger}= a + b let spanStart = code.IndexOf symbolName - let actions = - tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) + let actions = tryGetRefactoringActions code spanStart context (new AddReturnType()) do Assert.Empty(actions) @@ -41,8 +40,7 @@ let example2 = 42 // value let spanStart = code.IndexOf symbolName - let actions = - tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) + let actions = tryGetRefactoringActions code spanStart context (new AddReturnType()) do Assert.Empty(actions) @@ -60,13 +58,12 @@ type Example3() = let spanStart = code.IndexOf symbolName - let actions = - tryGetRefactoringActions code spanStart context (new AddExplicitReturnType()) + let actions = tryGetRefactoringActions code spanStart context (new AddReturnType()) do Assert.Empty(actions) [] -let ``Correctly infer int as explicit return type`` () = +let ``Correctly infer int as return type`` () = let symbolName = "sum" let code = @@ -78,7 +75,7 @@ let sum a b = a + b let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -87,7 +84,7 @@ let sum a b : int = a + b let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) - + [] let ``Correctly infer on next line arguments`` () = let symbolName = "sum" @@ -103,7 +100,7 @@ let sum let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -129,7 +126,7 @@ let addThings = add let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -153,7 +150,7 @@ let sum (a:float) (b:float) = a + b let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = """ @@ -163,7 +160,6 @@ let sum (a:float) (b:float) : float = a + b let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) - [] let ``Infer on rec method`` () = let symbolName = "fib" @@ -179,7 +175,7 @@ let rec fib n = let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -204,7 +200,7 @@ let apply1 (transform: int -> int) y = transform y let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -229,7 +225,7 @@ type SomeType(factor0: int) = let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -255,7 +251,7 @@ let getNow() = let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -265,7 +261,7 @@ let getNow() : System.DateTime = let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) - + [] let ``Handle already existing opens for DateTime`` () = let symbolName = "getNow" @@ -282,7 +278,7 @@ let getNow() = let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -309,7 +305,7 @@ let skip1 elements = let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -320,7 +316,6 @@ let skip1 elements : System.Collections.Generic.IEnumerable<'a> = let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) - [] let ``Handle already existing opens on Linq`` () = let symbolName = "skip1" @@ -337,7 +332,7 @@ let skip1 elements = let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -349,7 +344,7 @@ let skip1 elements : Collections.Generic.IEnumerable<'a> = let resultText = newDoc.GetTextAsync() |> GetTaskResult Assert.Equal(expectedCode, resultText.ToString()) - + [] let ``Handle already existing opens on Enumerable`` () = let symbolName = "skip1" @@ -367,7 +362,7 @@ let skip1 elements = let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = $""" @@ -395,7 +390,7 @@ let sum a b = {Value=a+b} let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = """ @@ -442,7 +437,7 @@ let sum a b = {Value=a+b} let spanStart = code.IndexOf symbolName - let newDoc = tryRefactor code spanStart context (new AddExplicitReturnType()) + let newDoc = tryRefactor code spanStart context (new AddReturnType()) let expectedCode = """