Skip to content

Commit 92fd65a

Browse files
authored
Fix methods tagged as Member instead of Method in tooltips (#19507)
1 parent d5b8050 commit 92fd65a

4 files changed

Lines changed: 223 additions & 2 deletions

File tree

docs/release-notes/.FSharp.Compiler.Service/11.0.100.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* Fix signature generation: backtick escaping for identifiers containing backticks. ([Issue #15389](https://github.com/dotnet/fsharp/issues/15389), [PR #19586](https://github.com/dotnet/fsharp/pull/19586))
3535
* Fix signature generation: `private` keyword placement for prefix-style type abbreviations. ([Issue #15560](https://github.com/dotnet/fsharp/issues/15560), [PR #19586](https://github.com/dotnet/fsharp/pull/19586))
3636
* Fix signature generation: missing `[<Class>]` attribute for types without visible constructors. ([Issue #16531](https://github.com/dotnet/fsharp/issues/16531), [PR #19586](https://github.com/dotnet/fsharp/pull/19586))
37+
* Fix methods being tagged as `Member` instead of `Method` in tooltips. ([Issue #10540](https://github.com/dotnet/fsharp/issues/10540), [PR #19507](https://github.com/dotnet/fsharp/pull/19507))
3738

3839
### Added
3940

src/Compiler/Checking/NicePrint.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,8 @@ module PrintTastMemberOrVals =
13851385
let resL =
13861386
if short then tauL
13871387
else
1388-
let nameL = layoutMemberName denv vref niceMethodTypars argInfos tagMember vref.DisplayNameCoreMangled true
1388+
let tag = if isNil argInfos then tagMember else tagMethod
1389+
let nameL = layoutMemberName denv vref niceMethodTypars argInfos tag vref.DisplayNameCoreMangled true
13891390
let nameL = if short then nameL else mkInlineL denv vref.Deref nameL
13901391
stat --- ((nameL |> addColonL) ^^ tauL)
13911392
prettyTyparInst, resL

src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1449,7 +1449,22 @@ module internal MemberRepresentation =
14491449
| SynMemberKind.PropertyGetSet -> tagProperty vref.DisplayName
14501450
| SynMemberKind.ClassConstructor
14511451
| SynMemberKind.Constructor -> tagMethod vref.DisplayName
1452-
| SynMemberKind.Member -> tagMember vref.DisplayName
1452+
| SynMemberKind.Member ->
1453+
match vref.ValReprInfo with
1454+
| Some valReprInfo ->
1455+
let numArgGroups = valReprInfo.ArgInfos.Length
1456+
1457+
let isMethod =
1458+
if memberInfo.MemberFlags.IsInstance then
1459+
numArgGroups > 1
1460+
else
1461+
numArgGroups > 0
1462+
1463+
if isMethod then
1464+
tagMethod vref.DisplayName
1465+
else
1466+
tagMember vref.DisplayName
1467+
| None -> tagMember vref.DisplayName
14531468

14541469
match fullNameOfParentOfValRefAsLayout vref with
14551470
| ValueNone -> wordL n

tests/FSharp.Compiler.Service.Tests/TooltipTests.fs

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,17 @@ let assertAndGetSingleToolTipText items =
388388
let text,_xml,_remarks = assertAndExtractTooltip items
389389
text
390390

391+
let getMainDescriptionTags (ToolTipText(items)) =
392+
match items with
393+
| ToolTipElement.Group [ singleElement ] :: _ -> singleElement.MainDescription
394+
| _ -> failwith $"Expected single group in tooltip, got {items}"
395+
396+
let assertNameTagInTooltip expectedTag expectedName (tooltip: ToolTipText) =
397+
let tags = getMainDescriptionTags tooltip
398+
let found = tags |> Array.exists (fun t -> t.Tag = expectedTag && t.Text = expectedName)
399+
let desc = tags |> Array.map (fun t -> sprintf "(%A, %s)" t.Tag t.Text) |> String.concat ", "
400+
Assert.True(found, sprintf "Expected tag %A with text '%s' in tooltip, but found: %s" expectedTag expectedName desc)
401+
391402
let normalize (s: string) = s.Replace("\r\n", "\n").Replace("\n\n", "\n")
392403

393404
[<Fact>]
@@ -602,3 +613,196 @@ let normaliz{caret}e' x = x + 1
602613
"""
603614

604615
testXmlDocFallbackToSigFileWhileInImplFile sigSource implSource "Normalize with a prime"
616+
617+
// https://github.com/dotnet/fsharp/issues/10540
618+
[<Fact>]
619+
let ``Instance method should be tagged as Method in tooltip`` () =
620+
Checker.getTooltip """
621+
type T() =
622+
member x.Metho{caret}d() = ()
623+
"""
624+
|> assertNameTagInTooltip TextTag.Method "Method"
625+
626+
// https://github.com/dotnet/fsharp/issues/10540
627+
[<Fact>]
628+
let ``Instance method with parameters should be tagged as Method in tooltip`` () =
629+
Checker.getTooltip """
630+
type T() =
631+
member x.Ad{caret}d(a: int, b: int) = a + b
632+
"""
633+
|> assertNameTagInTooltip TextTag.Method "Add"
634+
635+
// https://github.com/dotnet/fsharp/issues/10540
636+
[<Fact>]
637+
let ``Static method should be tagged as Method in tooltip`` () =
638+
Checker.getTooltip """
639+
type T() =
640+
static member Creat{caret}e() = T()
641+
"""
642+
|> assertNameTagInTooltip TextTag.Method "Create"
643+
644+
// https://github.com/dotnet/fsharp/issues/10540
645+
[<Fact>]
646+
let ``Property-like member should be tagged as Property`` () =
647+
Checker.getTooltip """
648+
type T() =
649+
member x.Valu{caret}e = 42
650+
"""
651+
|> assertNameTagInTooltip TextTag.Property "Value"
652+
653+
// https://github.com/dotnet/fsharp/issues/10540
654+
[<Fact>]
655+
let ``Auto property should be tagged as Property`` () =
656+
Checker.getTooltip """
657+
namespace Foo
658+
659+
type Bar() =
660+
member val Fo{caret}o = "bla" with get, set
661+
"""
662+
|> assertNameTagInTooltip TextTag.Property "Foo"
663+
664+
// https://github.com/dotnet/fsharp/issues/10540
665+
[<Fact>]
666+
let ``Indexer should be tagged as Property`` () =
667+
Checker.getTooltip """
668+
type T() =
669+
member x.Ite{caret}m with get(i: int) = i
670+
"""
671+
|> assertNameTagInTooltip TextTag.Property "Item"
672+
673+
// https://github.com/dotnet/fsharp/issues/10540
674+
[<Fact>]
675+
let ``Indexer with getter and setter should be tagged as Property`` () =
676+
Checker.getTooltip """
677+
type T() =
678+
let mutable data = [| 0; 1; 2 |]
679+
member x.Ite{caret}m
680+
with get(i: int) = data.[i]
681+
and set (i: int) (v: int) = data.[i] <- v
682+
"""
683+
|> assertNameTagInTooltip TextTag.Property "Item"
684+
685+
// https://github.com/dotnet/fsharp/issues/10540
686+
[<Fact>]
687+
let ``Property with explicit getter should be tagged as Property`` () =
688+
Checker.getTooltip """
689+
type T() =
690+
member x.Valu{caret}e with get() = 42
691+
"""
692+
|> assertNameTagInTooltip TextTag.Property "Value"
693+
694+
// https://github.com/dotnet/fsharp/issues/10540
695+
[<Fact>]
696+
let ``Static property should be tagged as Property`` () =
697+
Checker.getTooltip """
698+
type T() =
699+
static member Defaul{caret}t = T()
700+
"""
701+
|> assertNameTagInTooltip TextTag.Property "Default"
702+
703+
// https://github.com/dotnet/fsharp/issues/10540
704+
[<Fact>]
705+
let ``Named indexed property with getter should be tagged as Property`` () =
706+
Checker.getTooltip """
707+
type T() =
708+
member x.Valu{caret}e with get(key: string) = key
709+
"""
710+
|> assertNameTagInTooltip TextTag.Property "Value"
711+
712+
// https://github.com/dotnet/fsharp/issues/10540
713+
[<Fact>]
714+
let ``Named indexed property with getter and setter should be tagged as Property`` () =
715+
Checker.getTooltip """
716+
type T() =
717+
let mutable store = Map.empty<string, int>
718+
member x.Valu{caret}e
719+
with get(key: string) = store.[key]
720+
and set (key: string) (v: int) = store <- store.Add(key, v)
721+
"""
722+
|> assertNameTagInTooltip TextTag.Property "Value"
723+
724+
// https://github.com/dotnet/fsharp/issues/10540
725+
[<Fact>]
726+
let ``Indexer with setter only (1 arg) should be tagged as Property`` () =
727+
Checker.getTooltip """
728+
type T() =
729+
let mutable data = [| 0 |]
730+
member x.Ite{caret}m
731+
with set (i: int) (v: int) = data.[i] <- v
732+
"""
733+
|> assertNameTagInTooltip TextTag.Property "Item"
734+
735+
// https://github.com/dotnet/fsharp/issues/10540
736+
[<Fact>]
737+
let ``Indexer with getter only (2 args) should be tagged as Property`` () =
738+
Checker.getTooltip """
739+
type T() =
740+
member x.Ite{caret}m with get (i: int, j: int) = i + j
741+
"""
742+
|> assertNameTagInTooltip TextTag.Property "Item"
743+
744+
// https://github.com/dotnet/fsharp/issues/10540
745+
[<Fact>]
746+
let ``Indexer with setter only (2 args) should be tagged as Property`` () =
747+
Checker.getTooltip """
748+
type T() =
749+
let store = System.Collections.Generic.Dictionary<int * int, int>()
750+
member x.Ite{caret}m
751+
with set (i: int, j: int) (v: int) = store[(i, j)] <- v
752+
"""
753+
|> assertNameTagInTooltip TextTag.Property "Item"
754+
755+
// https://github.com/dotnet/fsharp/issues/10540
756+
[<Fact>]
757+
let ``Indexer with getter and setter (2 args) should be tagged as Property`` () =
758+
Checker.getTooltip """
759+
type T() =
760+
let store = System.Collections.Generic.Dictionary<int * int, int>()
761+
member x.Ite{caret}m
762+
with get (i: int, j: int) = store[(i, j)]
763+
and set (i: int, j: int) (v: int) = store[(i, j)] <- v
764+
"""
765+
|> assertNameTagInTooltip TextTag.Property "Item"
766+
767+
// https://github.com/dotnet/fsharp/issues/10540
768+
[<Fact>]
769+
let ``Named indexed property with setter only (1 arg) should be tagged as Property`` () =
770+
Checker.getTooltip """
771+
type T() =
772+
let mutable store = Map.empty<string, int>
773+
member x.Valu{caret}e
774+
with set (key: string) (v: int) = store <- store.Add(key, v)
775+
"""
776+
|> assertNameTagInTooltip TextTag.Property "Value"
777+
778+
// https://github.com/dotnet/fsharp/issues/10540
779+
[<Fact>]
780+
let ``Named indexed property with getter only (2 args) should be tagged as Property`` () =
781+
Checker.getTooltip """
782+
type T() =
783+
member x.Valu{caret}e with get (a: string, b: string) = a + b
784+
"""
785+
|> assertNameTagInTooltip TextTag.Property "Value"
786+
787+
// https://github.com/dotnet/fsharp/issues/10540
788+
[<Fact>]
789+
let ``Named indexed property with setter only (2 args) should be tagged as Property`` () =
790+
Checker.getTooltip """
791+
type T() =
792+
let mutable store = Map.empty<string * string, int>
793+
member x.Valu{caret}e
794+
with set (a: string, b: string) (v: int) = store <- store.Add((a, b), v)
795+
"""
796+
|> assertNameTagInTooltip TextTag.Property "Value"
797+
798+
// https://github.com/dotnet/fsharp/issues/10540
799+
[<Fact>]
800+
let ``Named indexed property with getter and setter (2 args) should be tagged as Property`` () =
801+
Checker.getTooltip """
802+
type T() =
803+
let mutable store = Map.empty<string * string, int>
804+
member x.Valu{caret}e
805+
with get (a: string, b: string) = store[(a, b)]
806+
and set (a: string, b: string) (v: int) = store <- store.Add((a, b), v)
807+
"""
808+
|> assertNameTagInTooltip TextTag.Property "Value"

0 commit comments

Comments
 (0)