From b0cf6d06d004a45689d2c394a30509e2b09f17b7 Mon Sep 17 00:00:00 2001 From: cartermp Date: Mon, 16 Nov 2020 15:12:53 -0800 Subject: [PATCH 1/2] Add MakeDeclarationMutable code fix --- src/fsharp/service/ServiceUntypedParse.fs | 26 +++++++ src/fsharp/service/ServiceUntypedParse.fsi | 3 + .../CodeFix/MakeDeclarationMutable.fs | 73 +++++++++++++++++++ .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/FSharp.Editor.resx | 3 + .../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 ++ 18 files changed, 171 insertions(+) create mode 100644 vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs diff --git a/src/fsharp/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs index bd24fef3fad..3bbdb512499 100755 --- a/src/fsharp/service/ServiceUntypedParse.fs +++ b/src/fsharp/service/ServiceUntypedParse.fs @@ -104,6 +104,32 @@ type FSharpParseFileResults(errors: FSharpErrorInfo[], input: ParsedInput option match input with | Some input -> FSharpNoteworthyParamInfoLocations.Find(pos, input) | _ -> None + + member scope.IsPositionContainedInACurriedParameter pos = + match input with + | Some input -> + let result = + AstTraversal.Traverse(pos, input, { new AstTraversal.AstVisitorBase<_>() with + member __.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = + defaultTraverse(expr) + + override __.VisitBinding (_, binding) = + match binding with + | Binding(_, _, _, _, _, _, valData, _, _, _, range, _) when rangeContainsPos range pos -> + let info = valData.SynValInfo.CurriedArgInfos + let mutable found = false + for group in info do + for arg in group do + match arg.Ident with + | Some ident when rangeContainsPos ident.idRange pos -> + found <- true + | _ -> () + if found then Some range else None + | _ -> + None + }) + result.IsSome + | _ -> false /// Get declared items and the selected item at the specified location member private scope.GetNavigationItemsImpl() = diff --git a/src/fsharp/service/ServiceUntypedParse.fsi b/src/fsharp/service/ServiceUntypedParse.fsi index b88bc0efec3..b92a0e2bb2a 100755 --- a/src/fsharp/service/ServiceUntypedParse.fsi +++ b/src/fsharp/service/ServiceUntypedParse.fsi @@ -22,6 +22,9 @@ type public FSharpParseFileResults = /// Notable parse info for ParameterInfo at a given location member FindNoteworthyParamInfoLocations : pos:pos -> FSharpNoteworthyParamInfoLocations option + /// Determines if the given position is contained within a curried parameter in a binding. + member IsPositionContainedInACurriedParameter: pos: pos -> bool + /// Name of the file for which this information were created member FileName : string diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs b/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs new file mode 100644 index 00000000000..52287c96298 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System.Composition +open System.Threading +open System.Threading.Tasks + +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.CodeFixes + +open FSharp.Compiler.Range +open FSharp.Compiler.SourceCodeServices +open FSharp.Compiler.AbstractIL.Internal.Library + +[] +type internal FSharpMakeDeclarationMutableFixProvider + [] + ( + checkerProvider: FSharpCheckerProvider, + projectInfoManager: FSharpProjectOptionsManager + ) = + inherit CodeFixProvider() + + static let userOpName = "MakeDeclarationMutable" + + let fixableDiagnosticIds = set ["FS0027"] + + override _.FixableDiagnosticIds = Seq.toImmutableArray fixableDiagnosticIds + + override _.RegisterCodeFixesAsync context : Task = + asyncMaybe { + let diagnostics = + context.Diagnostics + |> Seq.filter (fun x -> fixableDiagnosticIds |> Set.contains x.Id) + |> Seq.toImmutableArray + + let document = context.Document + do! Option.guard (not(isSignatureFile document.FilePath)) + let position = context.Span.Start + let checker = checkerProvider.Checker + let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None, userOpName) + let! sourceText = document.GetTextAsync () |> liftTaskAsync + let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions + let textLine = sourceText.Lines.GetLineFromPosition position + let textLinePos = sourceText.Lines.GetLinePosition position + let fcsTextLineNumber = Line.fromZ textLinePos.Line + let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, sourceText=sourceText, userOpName=userOpName) + let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) + let decl = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, false) + + match decl with + // Only do this for symbols in the same file. That covers almost all cases anyways. + // We really shouldn't encourage making values mutable outside of local scopes anyways. + | FSharpFindDeclResult.DeclFound declRange when declRange.FileName = document.FilePath -> + let! span = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, declRange) + + // Bail if it's a parameter, because like, that ain't allowed + do! Option.guard (not (parseFileResults.IsPositionContainedInACurriedParameter declRange.Start)) + + let title = SR.MakeDeclarationMutable() + let codeFix = + CodeFixHelpers.createTextChangeCodeFix( + title, + context, + (fun () -> asyncMaybe.Return [| TextChange(TextSpan(span.Start, 0), "mutable ") |])) + + context.RegisterCodeFix(codeFix, diagnostics) + | _ -> + () + } + |> Async.Ignore + |> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken) \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 8bc59c35a19..3d7c4ed5b1e 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -89,6 +89,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 8440136cf33..0641031fbc4 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -219,4 +219,7 @@ F# Dispostable Values (top-level) + + Make declaration 'mutable' + \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index acac2c13bf4..2e2959191ce 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -37,6 +37,11 @@ Implementujte rozhraní bez anotace typu. + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore Před {0} vložte podtržítko. diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index 639a34858b9..81227ce9e19 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -37,6 +37,11 @@ Schnittstelle ohne Typanmerkung implementieren + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore "{0}" einen Unterstrich voranstellen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 5f1297eab36..0f987f81caf 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -37,6 +37,11 @@ Implementar interfaz sin anotación de tipos + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore Colocar un carácter de subrayado delante de "{0}" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 3ae9d25817a..fe934fdb049 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -37,6 +37,11 @@ Implémenter l'interface sans annotation de type + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore Faire précéder '{0}' d'un trait de soulignement diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index 8457ca172b1..8b9fa6431fa 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -37,6 +37,11 @@ Implementa l'interfaccia senza annotazione di tipo + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore Anteponi a '{0}' un carattere di sottolineatura diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 614fdea4a51..8ac70dbe3e2 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -37,6 +37,11 @@ 型の注釈を指定しないでインターフェイスを実装する + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore アンダースコアが含まれているプレフィックス '{0}' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 832aaa80b5c..4fec3adb90b 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -37,6 +37,11 @@ 형식 주석 없이 인터페이스 구현 + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore 밑줄이 있는 '{0}' 접두사 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 785230a56bb..d27ad527e16 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -37,6 +37,11 @@ Zaimplementuj interfejs bez adnotacji typu + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore Prefiks „{0}” ze znakiem podkreślenia 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 98636e84fd4..d766f3ad5c4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -37,6 +37,11 @@ Implementar a interface sem a anotação de tipo + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore Prefixo '{0}' sem sublinhado diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index 04891b9acea..1fdf4ed8e91 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -37,6 +37,11 @@ Реализовать интерфейс без заметки с типом + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore Добавить символ подчеркивания как префикс "{0}" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index 0cbe170c6d7..38f66f9bcbe 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -37,6 +37,11 @@ Tür ek açıklaması olmadan arabirim uygulama + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore '{0}' öğesinin önüne alt çizgi ekleme 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 dd827dbfd65..ae603efd75f 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -37,6 +37,11 @@ 无类型批注的实现接口 + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore 带下划线的前缀“{0}” 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 a59aa79970f..9db78dde665 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -37,6 +37,11 @@ 實作沒有類型註釋的介面 + + Make declaration 'mutable' + Make declaration 'mutable' + + Prefix '{0}' with underscore 有底線的前置詞 '{0}' From 41bbbfd847de8bf5d998d924da7c8a7d44134924 Mon Sep 17 00:00:00 2001 From: cartermp Date: Tue, 17 Nov 2020 14:54:32 -0800 Subject: [PATCH 2/2] Surface updates --- tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs index 1f94595981f..7b766f69125 100644 --- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs +++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs @@ -22737,6 +22737,7 @@ FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: FSharp.Compiler.Sourc FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: FSharp.Compiler.SourceCodeServices.FSharpNavigationItems GetNavigationItems() FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Range+range] ValidateBreakpointLocation(pos) FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations] FindNoteworthyParamInfoLocations(pos) +FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Boolean IsPositionContainedInACurriedParameter(pos) FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.SyntaxTree+ParsedInput] ParseTree FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.SyntaxTree+ParsedInput] get_ParseTree() FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: System.String FileName