Fix documentation inheritance for static method overrides on mixin intersection types#3161
Fix documentation inheritance for static method overrides on mixin intersection types#3161
Conversation
When a class extends a mixin that returns an intersection type (e.g., typeof MixinClass & T), overridden static methods lose their inherited documentation because baseType.Symbol() returns nil for intersection types, preventing access to the constructor/static side. Add a fallback that uses heritage clause expressions to get the constructor type directly via GetTypeAtLocation, allowing GetPropertyOfType to find static properties across intersection type constituents. Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes missing inherited hover documentation for overridden static methods when a class extends a mixin whose return type is an intersection (e.g., typeof MixinClass & T), where the base type’s symbol can be nil and prevents static-side doc lookup.
Changes:
- Add a fallback path in hover JSDoc resolution for static members to resolve constructor-side types via heritage clause expressions.
- Add a fourslash test covering hover documentation inheritance for mixin intersection override scenarios.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| internal/ls/hover.go | Adds fallback static-member doc lookup via heritage clause expression type resolution when base type symbols are missing (intersection types). |
| internal/fourslash/tests/hoverMixinOverrideDocumentation_test.go | Adds regression test ensuring hover/QuickInfo shows inherited docs for overridden static methods from mixin intersection bases. |
internal/ls/hover.go
Outdated
| if isStatic { | ||
| for _, superTypeNode := range getAllSuperTypeNodes(node.Parent) { | ||
| if superTypeNode == nil { | ||
| continue | ||
| } | ||
| if expr := superTypeNode.Expression(); expr != nil { | ||
| if prop := c.GetPropertyOfType(c.GetTypeAtLocation(expr), symbol.Name); prop != nil && prop.ValueDeclaration != nil { | ||
| if jsDoc := getJSDocOrTag(c, prop.ValueDeclaration); jsDoc != nil { | ||
| return jsDoc | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
internal/ls/hover.go
Outdated
| // For static members on intersection base types (e.g., from mixins), | ||
| // baseType.Symbol() may be nil, preventing access to the constructor type. | ||
| // Fall back to using heritage clause expressions to get the constructor type directly. | ||
| if isStatic { |
|
@copilot address feedback |
… with foundInBase - Use GetClassExtendsHeritageElement instead of getAllSuperTypeNodes to only look at the extends clause (not implements) for static member doc inheritance. - Track whether the property was found in any base type and only run the fallback when it wasn't, avoiding unnecessary GetTypeAtLocation work in common cases. - Update comment to accurately describe the root cause: GetBaseTypes resolves to the return type of the first construct signature, which may not contain all static members from an intersection constructor type. Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
Addressed both review comments in 9fa5170:
|
When a class extends a mixin returning an intersection type (e.g.,
typeof MixinClass & T), overridden static methods lose inherited documentation. This happens becauseGetBaseTypesresolves the intersection constructor type to the return type of the first construct signature, which may not contain all static members from the full intersection.Changes
internal/ls/hover.go: When the primaryGetBaseTypesloop fails to find a static property in any base type, fall back to resolving theextendsclause expression directly viaGetTypeAtLocation(expr). This yields the full constructor-side intersection type, on whichGetPropertyOfTypecan find static properties across all constituents. The fallback is scoped to only theextendsclause (notimplements) since static members are inherited from the base class, and is guarded by afoundInBasecheck to avoid unnecessary work in common cases.internal/fourslash/tests/hoverMixinOverrideDocumentation_test.go: Test verifying documentation inheritance through mixin overrides.Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.