Skip to content

[WIP] Tooltips for types should show direct base types only #18586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
7 changes: 6 additions & 1 deletion src/Compiler/Checking/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2028,6 +2028,7 @@ module TastDefinitionPrinting =
GetIntrinsicConstructorInfosOfType infoReader m ty
|> List.filter (fun minfo -> IsMethInfoAccessible amap m ad minfo && not minfo.IsClassConstructor && shouldShow minfo.ArbitraryValRef)

// Get base interfaces (either direct or all, depending on settings)
let iimpls =
if suppressInheritanceAndInterfacesForTyInSimplifiedDisplays g amap m ty then
[]
Expand All @@ -2036,7 +2037,11 @@ module TastDefinitionPrinting =
|> List.filter (fun (_, compgen, _) -> not compgen)
|> List.map p13
else
GetImmediateInterfacesOfType SkipUnrefInterfaces.Yes g amap m ty
// Use immediate interfaces when showOnlyDirectBaseTypes=true, otherwise show all interfaces
if denv.showOnlyDirectBaseTypes then
GetImmediateInterfacesOfType SkipUnrefInterfaces.Yes g amap m ty
else
AllInterfacesOfType g amap m AllowMultiIntfInstantiations.Yes ty

let iimplsLs =
iimpls
Expand Down
4 changes: 3 additions & 1 deletion src/Compiler/Service/ServiceDeclarationLists.fs
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ module DeclarationListHelpers =
// tooltips are space-constrained, so don't include xml doc comments
// on types/members. The doc comments for the actual member will still
// be shown in the tip.
showDocumentation = false }
showDocumentation = false
// only show direct base types in tooltips
showOnlyDirectBaseTypes = true }
let layout = NicePrint.layoutTyconDefn denv infoReader ad m (* width *) tcref.Deref
let layout = PrintUtilities.squashToWidth width layout
let remarks = OutputFullName displayFullName pubpathOfTyconRef fullDisplayTextOfTyconRefAsLayout tcref
Expand Down
5 changes: 4 additions & 1 deletion src/Compiler/TypedTree/TypedTreeOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3173,7 +3173,7 @@
| Suffix

[<NoEquality; NoComparison>]
type DisplayEnv =

Check failure on line 3176 in src/Compiler/TypedTree/TypedTreeOps.fs

View workflow job for this annotation

GitHub Actions / copilot

The type definitions for type 'DisplayEnv' in the signature and implementation are not compatible because the order of the fields is different in the signature and implementation
{ includeStaticParametersInTypeNames: bool
openTopPathsSorted: InterruptibleLazy<string list list>
openTopPathsRaw: string list list
Expand All @@ -3193,13 +3193,14 @@
showCsharpCodeAnalysisAttributes: bool
showOverrides: bool
showStaticallyResolvedTyparAnnotations: bool
showNullnessAnnotations: bool option

Check failure on line 3196 in src/Compiler/TypedTree/TypedTreeOps.fs

View workflow job for this annotation

GitHub Actions / copilot

The module contains the field� showNullnessAnnotations: bool option �but its signature specifies� showOnlyDirectBaseTypes: bool �The names differ
abbreviateAdditionalConstraints: bool
showTyparDefaultConstraints: bool
showDocumentation: bool
shrinkOverloads: bool
printVerboseSignatures: bool
escapeKeywordNames: bool
showOnlyDirectBaseTypes: bool
g: TcGlobals
contextAccessibility: Accessibility
generatedValueLayout : Val -> Layout option
Expand Down Expand Up @@ -3238,6 +3239,7 @@
shrinkOverloads = true
printVerboseSignatures = false
escapeKeywordNames = false
showOnlyDirectBaseTypes = false
g = tcGlobals
contextAccessibility = taccessPublic
generatedValueLayout = (fun _ -> None)
Expand Down Expand Up @@ -3267,7 +3269,8 @@
showDocumentation = true
shrinkOverloads = false
escapeKeywordNames = true
includeStaticParametersInTypeNames = true }
includeStaticParametersInTypeNames = true
showOnlyDirectBaseTypes = false }
denv.SetOpenPaths
[ FSharpLib.RootPath
FSharpLib.CorePath
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/TypedTree/TypedTreeOps.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,7 @@ type DisplayEnv =
showCsharpCodeAnalysisAttributes: bool
showOverrides: bool
showStaticallyResolvedTyparAnnotations: bool
showOnlyDirectBaseTypes: bool
showNullnessAnnotations: bool option
abbreviateAdditionalConstraints: bool
showTyparDefaultConstraints: bool
Expand Down
104 changes: 103 additions & 1 deletion tests/FSharp.Compiler.Service.Tests/TooltipTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -522,4 +522,106 @@ open System
let doIt(myAction : Action<int>) = myAc{caret}tion.Invoke(42)
"""
|> assertAndGetSingleToolTipText
|> Assert.shouldBeEquivalentTo ("""val myAction: Action<int>""" |> normalize)
|> Assert.shouldBeEquivalentTo ("""val myAction: Action<int>""" |> normalize)

// Tests for direct interfaces in tooltips
[<Fact>]
let ``Tooltip for class with multiple direct interfaces shows all direct interfaces`` () =
let source = """
module DirectInterfaces

// Define multiple interfaces
type IA =
abstract DoA: unit -> unit

type IB =
abstract DoB: unit -> unit

// Class implementing multiple interfaces
type ClassWithMultipleInterfaces() =
interface IA with
member _.DoA() = ()
interface IB with
member _.DoB() = ()

// Create an instance
let obj = ClassWithMultipleInterfaces()
"""
let checkResults = getCheckResults source Array.empty
let tooltip = checkResults.GetToolTip(12, 30, "type ClassWithMultipleInterfaces() =", [ "ClassWithMultipleInterfaces" ], FSharpTokenTag.Identifier)
let tooltipText = tooltip |> assertAndGetSingleToolTipText

// Verify both direct interfaces are shown
Assert.contains "inherit IA" tooltipText
Assert.contains "inherit IB" tooltipText

[<Fact>]
let ``Tooltip for class implementing interface chain shows only direct interface`` () =
let source = """
module InterfaceChain

// Define chained interfaces
type IX =
abstract DoX: unit -> unit

type IY =
inherit IX
abstract DoY: unit -> unit

// Class implementing the most derived interface
type ClassWithChainedInterface() =
interface IY with
member _.DoY() = ()
member _.DoX() = ()

// Create an instance
let obj = ClassWithChainedInterface()
"""
let checkResults = getCheckResults source Array.empty
let tooltip = checkResults.GetToolTip(12, 31, "type ClassWithChainedInterface() =", [ "ClassWithChainedInterface" ], FSharpTokenTag.Identifier)
let tooltipText = tooltip |> assertAndGetSingleToolTipText

// Verify only direct interface is shown
Assert.contains "inherit IY" tooltipText
Assert.doesNotContain "inherit IX" tooltipText

[<Fact>]
let ``Tooltip for class with combined interface hierarchy shows only direct interfaces`` () =
let source = """
module CombinedHierarchy

// Base interfaces
type IBase1 =
abstract DoBase1: unit -> unit

type IBase2 =
abstract DoBase2: unit -> unit

// Derived interfaces
type IDerived1 =
inherit IBase1
abstract DoDerived1: unit -> unit

type IDerived2 =
inherit IBase2
abstract DoDerived2: unit -> unit

// Class implementing multiple interfaces, some in a chain
type ComplexClass() =
interface IDerived1 with
member _.DoDerived1() = ()
member _.DoBase1() = ()
interface IBase2 with
member _.DoBase2() = ()

// Create an instance
let obj = ComplexClass()
"""
let checkResults = getCheckResults source Array.empty
let tooltip = checkResults.GetToolTip(21, 19, "type ComplexClass() =", [ "ComplexClass" ], FSharpTokenTag.Identifier)
let tooltipText = tooltip |> assertAndGetSingleToolTipText

// Verify only direct interfaces are shown
Assert.contains "inherit IDerived1" tooltipText
Assert.contains "inherit IBase2" tooltipText
Assert.doesNotContain "inherit IBase1" tooltipText
Loading