Skip to content

Commit

Permalink
* feat(FSharp.Editor): add InternalOptionBuilder module
Browse files Browse the repository at this point in the history
* refactor(AddExplicitReturnType.fs, RemoveExplicitReturnType.fs): use InternalOptionBuilder for option handling
* feat(FSharp.Editor.fsproj): include InternalOptionBuilder.fs in project compilation
  • Loading branch information
SebastianAtWork committed Oct 29, 2023
1 parent ec723c8 commit 407572f
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 42 deletions.
13 changes: 13 additions & 0 deletions vsintegration/src/FSharp.Editor/Common/InternalOptionBuilder.fs
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<Compile Include="Common\FSharpCodeAnalysisExtensions.fs" />
<Compile Include="Common\CodeAnalysisExtensions.fs" />
<Compile Include="Common\Vs.fs" />
<Compile Include="Common\InternalOptionBuilder.fs" />
<Compile Include="Options\SettingsStore.fs" />
<Compile Include="Options\UIHelpers.fs" />
<Compile Include="Options\EditorOptions.fs" />
Expand Down
58 changes: 36 additions & 22 deletions vsintegration/src/FSharp.Editor/Refactor/AddExplicitReturnType.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ open Microsoft.CodeAnalysis.CodeRefactorings
open Microsoft.CodeAnalysis.CodeActions
open CancellableTasks
open System.Diagnostics
open InternalOptionBuilder

[<ExportCodeRefactoringProvider(FSharpConstants.FSharpLanguageName, Name = "AddExplicitReturnType"); Shared>]
type internal AddExplicitReturnType [<ImportingConstructor>] () =
inherit CodeRefactoringProvider()

static member isValidMethodWithoutTypeAnnotation
(funcOrValue: FSharpMemberOrFunctionOrValue)
(symbolUse: FSharpSymbolUse)
(parseFileResults: FSharpParseFileResults)
(funcOrValue: FSharpMemberOrFunctionOrValue)
=
let typeAnnotationRange =
parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false)
Expand All @@ -36,10 +37,15 @@ type internal AddExplicitReturnType [<ImportingConstructor>] () =
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)
Expand Down Expand Up @@ -76,6 +82,11 @@ type internal AddExplicitReturnType [<ImportingConstructor>] () =

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
Expand All @@ -96,23 +107,26 @@ type internal AddExplicitReturnType [<ImportingConstructor>] () =
|> 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
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ open Microsoft.CodeAnalysis.CodeActions
open CancellableTasks
open System.Diagnostics
open Microsoft.CodeAnalysis.Text
open InternalOptionBuilder

[<ExportCodeRefactoringProvider(FSharpConstants.FSharpLanguageName, Name = "RemoveExplicitReturnType"); Shared>]
type internal RemoveExplicitReturnType [<ImportingConstructor>] () =
Expand Down Expand Up @@ -65,9 +66,9 @@ type internal RemoveExplicitReturnType [<ImportingConstructor>] () =
newSpan

static member isValidMethodWithoutTypeAnnotation
(funcOrValue: FSharpMemberOrFunctionOrValue)
(symbolUse: FSharpSymbolUse)
(parseFileResults: FSharpParseFileResults)
(funcOrValue: FSharpMemberOrFunctionOrValue)
=
let returnTypeHintAlreadyPresent =
parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false)
Expand All @@ -77,8 +78,13 @@ type internal RemoveExplicitReturnType [<ImportingConstructor>] () =
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)
Expand Down Expand Up @@ -114,6 +120,11 @@ type internal RemoveExplicitReturnType [<ImportingConstructor>] () =

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
Expand All @@ -134,23 +145,26 @@ type internal RemoveExplicitReturnType [<ImportingConstructor>] () =
|> 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
}

0 comments on commit 407572f

Please sign in to comment.