Skip to content
This repository has been archived by the owner on Dec 23, 2024. It is now read-only.

Commit

Permalink
Add "Add type annotation to parameter" refactoring + remove dangling …
Browse files Browse the repository at this point in the history
…file lost in recent refactorings (dotnet#10937)

Co-authored-by: Chet Husk <baronfel@users.noreply.github.com>
  • Loading branch information
cartermp and baronfel authored Mar 13, 2021
1 parent 1840eb2 commit b2e654c
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 0 deletions.
1 change: 1 addition & 0 deletions FSharp.Editor.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<Compile Include="Commands\HelpContextService.fs" />
<Compile Include="Commands\FsiCommandService.fs" />
<Compile Include="Commands\XmlDocCommandService.fs" />
<Compile Include="Refactor\AddExplicitTypeToParameter.fs" />
<Compile Include="CodeFix\CodeFixHelpers.fs" />
<Compile Include="CodeFix\AddMissingRecToMutuallyRecFunctions.fs" />
<Compile Include="CodeFix\ConvertCSharpLambdaToFSharpLambda.fs" />
Expand Down
3 changes: 3 additions & 0 deletions FSharp.Editor.resx
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,7 @@
<data name="ConvertToNotEqualsEqualityExpression" xml:space="preserve">
<value>Use '&lt;&gt;' for inequality check</value>
</data>
<data name="AddTypeAnnotation" xml:space="preserve">
<value>Add type annotation</value>
</data>
</root>
102 changes: 102 additions & 0 deletions Refactor/AddExplicitTypeToParameter.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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 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

[<ExportCodeRefactoringProvider(FSharpConstants.FSharpLanguageName, Name = "AddExplicitTypeToParameter"); Shared>]
type internal FSharpAddExplicitTypeToParameterRefactoring
[<ImportingConstructor>]
(
checkerProvider: FSharpCheckerProvider,
projectInfoManager: FSharpProjectOptionsManager
) =
inherit CodeRefactoringProvider()

static let userOpName = "AddExplicitTypeToParameter"

override _.ComputeRefactoringsAsync context =
asyncMaybe {
let document = context.Document
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! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland)

let isValidParameterWithoutTypeAnnotation (funcOrValue: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) =
let isLambdaIfFunction =
funcOrValue.IsFunction &&
parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start

(funcOrValue.IsValue || isLambdaIfFunction) &&
parseFileResults.IsPositionContainedInACurriedParameter symbolUse.Range.Start &&
not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) &&
not funcOrValue.IsMember &&
not funcOrValue.IsMemberThisValue &&
not funcOrValue.IsConstructorThisValue &&
not (PrettyNaming.IsOperatorName funcOrValue.DisplayName)

match symbolUse.Symbol with
| :? FSharpMemberOrFunctionOrValue as v when isValidParameterWithoutTypeAnnotation v symbolUse ->
let typeString = v.FullType.FormatWithConstraints symbolUse.DisplayContext
let title = SR.AddTypeAnnotation()

let! symbolSpan = RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, symbolUse.Range)

let alreadyWrappedInParens =
let rec leftLoop ch pos =
if not (Char.IsWhiteSpace(ch)) then
ch = '('
else
leftLoop sourceText.[pos - 1] (pos - 1)

let rec rightLoop ch pos =
if not (Char.IsWhiteSpace(ch)) then
ch = ')'
else
rightLoop sourceText.[pos + 1] (pos + 1)

let hasLeftParen = leftLoop sourceText.[symbolSpan.Start - 1] (symbolSpan.Start - 1)
let hasRightParen = rightLoop sourceText.[symbolSpan.End] symbolSpan.End
hasLeftParen && hasRightParen

let getChangedText (sourceText: SourceText) =
if alreadyWrappedInParens then
sourceText.WithChanges(TextChange(TextSpan(symbolSpan.End, 0), ": " + typeString))
else
sourceText.WithChanges(TextChange(TextSpan(symbolSpan.Start, 0), "("))
.WithChanges(TextChange(TextSpan(symbolSpan.End + 1, 0), ": " + typeString + ")"))

let codeAction =
CodeAction.Create(
title,
(fun (cancellationToken: CancellationToken) ->
async {
let! sourceText = context.Document.GetTextAsync(cancellationToken) |> Async.AwaitTask
return context.Document.WithText(getChangedText sourceText)
} |> RoslynHelpers.StartAsyncAsTask(cancellationToken)),
title)
context.RegisterRefactoring(codeAction)
| _ -> ()
}
|> Async.Ignore
|> RoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Přidejte klíčové slovo new.</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Převést na anonymní záznam</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Schlüsselwort "new" hinzufügen</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">In anonymen Datensatz konvertieren</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Agregar "nueva" palabra clave</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Convertir en registro anónimo</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Ajouter le mot clé 'new'</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Convertir en enregistrement anonyme</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Aggiungi la parola chiave 'new'</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Converti in record anonimo</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">'new' キーワードを追加する</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">匿名レコードに変換</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">'new' 키워드 추가</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">익명 레코드로 변환</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Dodaj słowo kluczowe „new”</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Konwertuj na rekord anonimowy</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Adicionar a palavra-chave 'new'</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Converter em Registro Anônimo</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.ru.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">Добавить ключевое слово "new"</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Преобразовать в анонимную запись</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.tr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">'new' anahtar sözcüğünü ekleme</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">Anonim Kayda Dönüştür</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.zh-Hans.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">添加“新”关键字</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">转换为匿名记录</target>
Expand Down
5 changes: 5 additions & 0 deletions xlf/FSharp.Editor.zh-Hant.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<target state="translated">新增 'new' 關鍵字</target>
<note />
</trans-unit>
<trans-unit id="AddTypeAnnotation">
<source>Add type annotation</source>
<target state="new">Add type annotation</target>
<note />
</trans-unit>
<trans-unit id="ConvertToAnonymousRecord">
<source>Convert to Anonymous Record</source>
<target state="translated">轉換為匿名記錄</target>
Expand Down

0 comments on commit b2e654c

Please sign in to comment.