diff --git a/vsintegration/src/FSharp.Editor/Hints/HintService.fs b/vsintegration/src/FSharp.Editor/Hints/HintService.fs index 2ec037a04d3..6b23fe78506 100644 --- a/vsintegration/src/FSharp.Editor/Hints/HintService.fs +++ b/vsintegration/src/FSharp.Editor/Hints/HintService.fs @@ -19,7 +19,7 @@ module HintService = | :? FSharpMemberOrFunctionOrValue as symbol when hintKinds |> Set.contains HintKind.ParameterNameHint - && InlineParameterNameHints.isMemberOrFunctionOrValueValidForHint symbol -> + && InlineParameterNameHints.isMemberOrFunctionOrValueValidForHint symbol symbolUse -> InlineParameterNameHints.getHintsForMemberOrFunctionOrValue parseResults symbol symbolUse diff --git a/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs b/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs index 42ad4252e75..d28df0c53ef 100644 --- a/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs +++ b/vsintegration/src/FSharp.Editor/Hints/InlineParameterNameHints.fs @@ -30,14 +30,19 @@ module InlineParameterNameHints = let private doesFieldNameExist (field: FSharpField) = not field.IsNameGenerated - let isMemberOrFunctionOrValueValidForHint (symbol: FSharpMemberOrFunctionOrValue) = - // is there a better way? - let isNotBuiltInOperator = - symbol.DeclaringEntity - |> Option.exists (fun entity -> entity.CompiledName <> "Operators") - - symbol.IsFunction - && isNotBuiltInOperator // arguably, hints for those would be rather useless + let isMemberOrFunctionOrValueValidForHint (symbol: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) = + // make sure we're looking at a call site and not the definition + if symbolUse.IsFromUse then + // is there a better way? + let isNotBuiltInOperator = + symbol.DeclaringEntity + |> Option.exists (fun entity -> entity.CompiledName <> "Operators") + + (symbol.IsFunction && isNotBuiltInOperator) // arguably, hints for those would be rather useless + || symbol.IsConstructor + || symbol.IsMethod + else + false let isUnionCaseValidForHint (symbol: FSharpUnionCase) (symbolUse: FSharpSymbolUse) = // is the union case being used as a constructor and is it not Cons diff --git a/vsintegration/tests/UnitTests/InlineParameterNameHintTests.fs b/vsintegration/tests/UnitTests/InlineParameterNameHintTests.fs index 323c0fd88b8..8333f5ca689 100644 --- a/vsintegration/tests/UnitTests/InlineParameterNameHintTests.fs +++ b/vsintegration/tests/UnitTests/InlineParameterNameHintTests.fs @@ -134,29 +134,68 @@ let c = "javascript" === "javascript" Assert.IsEmpty(result) [] -let ``Hints are not (yet) shown for method parameters`` () = +let ``Hints are shown for method parameters`` () = let code = """ let theAnswer = System.Console.WriteLine 42 """ let document = getFsDocument code - let result = getParameterNameHints document + let expected = [ + { Content = "value = "; Location = (1, 42) } + ] - Assert.IsEmpty(result) + let actual = getParameterNameHints document + + Assert.AreEqual(expected, actual) [] -let ``Hints are not (yet) shown for constructor parameters`` () = +let ``Hints are shown for parameters of overloaded and curried methods`` () = let code = """ -type WrappedThing(x) = - let unwrapped = x +type C () = + member _.Normal (alone: string) = 1 + member _.Normal (what: string, what2: int) = 1 + member _.Curried (curr1: string, curr2: int) (x: int) = 1 -let wrapped = WrappedThing 42 +let c = C () + +let a = c.Curried ("hmm", 2) 1 +let a = c.Normal ("hmm", 2) +let a = c.Normal "hmm" """ let document = getFsDocument code - let result = getParameterNameHints document + let expected = [ + { Content = "curr1 = "; Location = (8, 20) } + { Content = "curr2 = "; Location = (8, 27) } + { Content = "x = "; Location = (8, 30) } + { Content = "what = "; Location = (9, 19) } + { Content = "what2 = "; Location = (9, 26) } + { Content = "alone = "; Location = (10, 18) } + ] - Assert.IsEmpty(result) + let actual = getParameterNameHints document + + Assert.AreEqual(expected, actual) + +[] +let ``Hints are shown for constructor parameters`` () = + let code = """ +type C (blahFirst: int) = + new (blah: int, blah2: string) = C blah + +let a = C (1, "") +""" + let document = getFsDocument code + + let expected = [ + { Content = "blahFirst = "; Location = (2, 40) } + { Content = "blah = "; Location = (4, 12) } + { Content = "blah2 = "; Location = (4, 15) } + ] + + let actual = getParameterNameHints document + + Assert.AreEqual(expected, actual) [] let ``Hints are shown for discriminated union case fields with explicit names`` () = diff --git a/vsintegration/tests/UnitTests/OverallHintExperienceTests.fs b/vsintegration/tests/UnitTests/OverallHintExperienceTests.fs index 65d47a21029..e28720622a2 100644 --- a/vsintegration/tests/UnitTests/OverallHintExperienceTests.fs +++ b/vsintegration/tests/UnitTests/OverallHintExperienceTests.fs @@ -22,6 +22,12 @@ type Shape = let a = Square 1 let b = Rectangle (1, 2) + +type C (blahFirst: int) = + member _.Normal (what: string) = 1 + +let a = C 1 +let cc = a.Normal "hmm" """ let document = getFsDocument code let expected = [ @@ -33,6 +39,10 @@ let b = Rectangle (1, 2) { Content = "width = "; Location = (11, 20) } { Content = "height = "; Location = (11, 23) } { Content = ": Shape"; Location = (11, 6) } + { Content = "blahFirst = "; Location = (16, 11) } + { Content = ": C"; Location = (16, 6) } + { Content = "what = "; Location = (17, 19) } + { Content = ": int"; Location = (17, 7) } ] let actual = getAllHints document