Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 37 additions & 27 deletions vsintegration/src/FSharp.Editor/Hints/HintService.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,48 @@ open Microsoft.CodeAnalysis
open Microsoft.VisualStudio.FSharp.Editor
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Symbols
open FSharp.Compiler.Text
open Hints

module HintService =
let private getHintsForSymbol parseResults hintKinds (longIdEndLocations: Position list) (symbolUse: FSharpSymbolUse) =
match symbolUse.Symbol with
| :? FSharpMemberOrFunctionOrValue as symbol
when hintKinds |> Set.contains HintKind.TypeHint
&& InlineTypeHints.isValidForHint parseResults symbol symbolUse ->

InlineTypeHints.getHints symbol symbolUse,
longIdEndLocations

| :? FSharpMemberOrFunctionOrValue as symbol
when hintKinds |> Set.contains HintKind.ParameterNameHint
&& InlineParameterNameHints.isMemberOrFunctionOrValueValidForHint symbol symbolUse ->

InlineParameterNameHints.getHintsForMemberOrFunctionOrValue parseResults symbol symbolUse longIdEndLocations,
symbolUse.Range.End :: longIdEndLocations
type private NativeHintResolver = FSharpSymbolUse seq -> NativeHint seq

let inline private getTypeHints parseResults symbol: NativeHintResolver =
Seq.filter (InlineTypeHints.isValidForHint parseResults symbol)
>> Seq.collect (InlineTypeHints.getHints symbol)

| :? FSharpUnionCase as symbol
when hintKinds |> Set.contains HintKind.ParameterNameHint
&& InlineParameterNameHints.isUnionCaseValidForHint symbol symbolUse ->
let inline private getHintsForMemberOrFunctionOrValue parseResults symbol: NativeHintResolver =
Seq.filter (InlineParameterNameHints.isMemberOrFunctionOrValueValidForHint symbol)
>> Seq.collect (InlineParameterNameHints.getHintsForMemberOrFunctionOrValue parseResults symbol)

InlineParameterNameHints.getHintsForUnionCase parseResults symbol symbolUse,
longIdEndLocations
let inline private getHintsForUnionCase parseResults symbol: NativeHintResolver =
Seq.filter (InlineParameterNameHints.isUnionCaseValidForHint symbol)
>> Seq.collect (InlineParameterNameHints.getHintsForUnionCase parseResults symbol)

// we'll be adding other stuff gradually here
| _ ->
[],
longIdEndLocations
let private getHintResolvers parseResults hintKinds (symbol: FSharpSymbol): NativeHintResolver seq =
let rec resolve hintKinds resolvers =
match hintKinds with
| [] -> resolvers |> Seq.choose id
| hintKind :: hintKinds ->
match hintKind with
| HintKind.TypeHint ->
match symbol with
| :? FSharpMemberOrFunctionOrValue as symbol -> getTypeHints parseResults symbol |> Some
| _ -> None
| HintKind.ParameterNameHint ->
match symbol with
| :? FSharpMemberOrFunctionOrValue as symbol -> getHintsForMemberOrFunctionOrValue parseResults symbol |> Some
| :? FSharpUnionCase as symbol -> getHintsForUnionCase parseResults symbol |> Some
| _ -> None
// we'll be adding other stuff gradually here
:: resolvers |> resolve hintKinds

in resolve hintKinds []

let private getHintsForSymbol parseResults hintKinds (symbol: FSharpSymbol, symbolUses: FSharpSymbolUse seq) =
symbol
|> getHintResolvers parseResults hintKinds
|> Seq.collect (fun resolve -> resolve symbolUses)

let getHintsForDocument (document: Document) hintKinds userOpName cancellationToken =
async {
Expand All @@ -49,8 +60,7 @@ module HintService =

return
checkResults.GetAllUsesOfAllSymbolsInFile cancellationToken
|> Seq.mapFold (getHintsForSymbol parseResults hintKinds) []
|> fst
|> Seq.concat
|> Seq.groupBy (fun symbolUse -> symbolUse.Symbol)
|> Seq.collect (getHintsForSymbol parseResults (hintKinds |> Set.toList))
|> Seq.toList
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,16 @@ module InlineParameterNameHints =

let private getArgumentLocations
(symbolUse: FSharpSymbolUse)
(longIdEndLocations: Position list)
(parseResults: FSharpParseFileResults) =

let position = Position.mkPos
(symbolUse.Range.End.Line)
(symbolUse.Range.End.Column + 1)

parseResults.FindParameterLocations position
|> Option.filter (fun locations -> longIdEndLocations |> List.contains locations.LongIdEndLocation |> not)
|> Option.map (fun locations -> locations.ArgumentLocations)
|> Option.defaultValue [||]
|> Option.map (fun locations -> locations.ArgumentLocations |> Seq.filter (fun location -> Position.posGeq location.ArgumentRange.Start position))
|> Option.filter (not << Seq.isEmpty)
|> Option.defaultValue Seq.empty

let private getTupleRanges =
Seq.map (fun location -> location.ArgumentRange)
Expand Down Expand Up @@ -83,11 +82,10 @@ module InlineParameterNameHints =
let getHintsForMemberOrFunctionOrValue
(parseResults: FSharpParseFileResults)
(symbol: FSharpMemberOrFunctionOrValue)
(symbolUse: FSharpSymbolUse)
(longIdEndLocations: Position list) =
(symbolUse: FSharpSymbolUse) =

let parameters = symbol.CurriedParameterGroups |> Seq.concat
let argumentLocations = parseResults |> getArgumentLocations symbolUse longIdEndLocations
let argumentLocations = parseResults |> getArgumentLocations symbolUse

let tupleRanges = argumentLocations |> getTupleRanges
let curryRanges = parseResults |> getCurryRanges symbolUse
Expand Down
15 changes: 14 additions & 1 deletion vsintegration/src/FSharp.Editor/Hints/InlineTypeHints.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open Microsoft.VisualStudio.FSharp.Editor
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Symbols
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Position
open Hints

module InlineTypeHints =
Expand Down Expand Up @@ -44,8 +45,20 @@ module InlineTypeHints =
(symbol: FSharpMemberOrFunctionOrValue)
(symbolUse: FSharpSymbolUse) =

let isOptionalParameter =
symbolUse.IsFromDefinition
&& symbol.FullType.IsAbbreviation
&& symbol.FullType.TypeDefinition.DisplayName = "option"

let adjustedRangeStart =
if isOptionalParameter then
// we need the position to start at the '?' symbol
mkPos symbolUse.Range.StartLine (symbolUse.Range.StartColumn - 1)
else
symbolUse.Range.Start

let isNotAnnotatedManually =
not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start)
not (parseFileResults.IsTypeAnnotationGivenAtPosition adjustedRangeStart)

let isNotAfterDot =
symbolUse.IsFromDefinition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,21 @@ type Number<'T when IAddition<'T>>(value: 'T) =
let actual = getTypeHints document

CollectionAssert.AreEquivalent(expected, actual)


[<Test>]
let ``Hints are not shown when type is specified`` () =
let code =
"""
type MyType() =

member _.MyMethod(?beep: int, ?bap: int, ?boop: int) = ()

member this.Foo = this.MyMethod(bap = 3, boop = 4)
"""

let document = getFsDocument code

let result = getTypeHints document

Assert.IsEmpty(result)