internal/lsp/source: use the object as the hover source for type params

Use the type name object as the signature source for type parametes, as
it it efficiently formatted as "type parameter <name> <constraint>".

Fixes golang/go#51116

Change-Id: I3042ff248402dae833e3197c6ac320c2bd103c07
Reviewed-on: https://go-review.googlesource.com/c/tools/+/385018
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Robert Findley 2022-02-10 20:15:56 -05:00
parent 411d04022e
commit adcfb65266
5 changed files with 57 additions and 35 deletions

View File

@ -477,6 +477,13 @@ func objectString(obj types.Object, qf types.Qualifier, inferred *types.Signatur
func FindHoverContext(ctx context.Context, s Snapshot, pkg Package, obj types.Object, pkgNode ast.Node, fullDecl ast.Decl) (*HoverContext, error) {
var info *HoverContext
// Type parameters get their signature from their declaration object.
if _, isTypeName := obj.(*types.TypeName); isTypeName {
if _, isTypeParam := obj.Type().(*typeparams.TypeParam); isTypeParam {
return &HoverContext{signatureSource: obj}, nil
}
}
// This is problematic for a number of reasons. We really need to have a more
// general mechanism to validate the coherency of AST with type information,
// but absent that we must do our best to ensure that we don't use fullNode
@ -555,7 +562,7 @@ func FindHoverContext(ctx context.Context, s Snapshot, pkg Package, obj types.Ob
}
}
info, err = formatGenDecl(node, spec, fullPos, obj)
info, err = hoverGenDecl(node, spec, fullPos, obj)
if err != nil {
return nil, err
}
@ -563,7 +570,7 @@ func FindHoverContext(ctx context.Context, s Snapshot, pkg Package, obj types.Ob
case *ast.TypeSpec:
if obj.Parent() == types.Universe {
if genDecl, ok := fullDecl.(*ast.GenDecl); ok {
info = formatTypeSpec(node, genDecl)
info = hoverTypeSpec(node, genDecl)
}
}
case *ast.FuncDecl:
@ -620,11 +627,11 @@ func isFunctionParam(obj types.Object, node *ast.FuncDecl) bool {
return false
}
// formatGenDecl returns hover information an object declared via spec inside
// hoverGenDecl returns hover information an object declared via spec inside
// of the GenDecl node. obj is the type-checked object corresponding to the
// declaration, but may have been type-checked using a different AST than the
// given nodes; fullPos is the position of obj in node's AST.
func formatGenDecl(node *ast.GenDecl, spec ast.Spec, fullPos token.Pos, obj types.Object) (*HoverContext, error) {
func hoverGenDecl(node *ast.GenDecl, spec ast.Spec, fullPos token.Pos, obj types.Object) (*HoverContext, error) {
if spec == nil {
return nil, errors.Errorf("no spec for node %v at position %v", node, fullPos)
}
@ -632,12 +639,12 @@ func formatGenDecl(node *ast.GenDecl, spec ast.Spec, fullPos token.Pos, obj type
// If we have a field or method.
switch obj.(type) {
case *types.Var, *types.Const, *types.Func:
return formatVar(spec, fullPos, obj, node), nil
return hoverVar(spec, fullPos, obj, node), nil
}
// Handle types.
switch spec := spec.(type) {
case *ast.TypeSpec:
return formatTypeSpec(spec, node), nil
return hoverTypeSpec(spec, node), nil
case *ast.ValueSpec:
return &HoverContext{signatureSource: spec, Comment: spec.Doc}, nil
case *ast.ImportSpec:
@ -646,7 +653,8 @@ func formatGenDecl(node *ast.GenDecl, spec ast.Spec, fullPos token.Pos, obj type
return nil, errors.Errorf("unable to format spec %v (%T)", spec, spec)
}
func formatTypeSpec(spec *ast.TypeSpec, decl *ast.GenDecl) *HoverContext {
// TODO(rfindley): rename this function.
func hoverTypeSpec(spec *ast.TypeSpec, decl *ast.GenDecl) *HoverContext {
comment := spec.Doc
if comment == nil && decl != nil {
comment = decl.Doc
@ -660,7 +668,7 @@ func formatTypeSpec(spec *ast.TypeSpec, decl *ast.GenDecl) *HoverContext {
}
}
func formatVar(node ast.Spec, fullPos token.Pos, obj types.Object, decl *ast.GenDecl) *HoverContext {
func hoverVar(node ast.Spec, fullPos token.Pos, obj types.Object, decl *ast.GenDecl) *HoverContext {
var fieldList *ast.FieldList
switch spec := node.(type) {
case *ast.TypeSpec:

View File

@ -1,11 +1,15 @@
package hover
type value[T any] struct { //@mark(value, "value"),hoverdef("value", value)
type value[T any] struct { //@mark(value, "value"),hoverdef("value", value),mark(valueTdecl, "T"),hoverdef("T",valueTdecl)
val T //@mark(valueTparam, "T"),hoverdef("T", valueTparam)
Q int //@mark(valueQfield, "Q"),hoverdef("Q", valueQfield)
}
type Value[T any] struct {
type Value[T any] struct { //@mark(ValueTdecl, "T"),hoverdef("T",ValueTdecl)
val T //@mark(ValueTparam, "T"),hoverdef("T", ValueTparam)
Q int //@mark(ValueQfield, "Q"),hoverdef("Q", ValueQfield)
}
func F[P interface{ ~int | string }]() { //@mark(Pparam, "P"),hoverdef("P",Pparam)
var _ P //@mark(Pvar, "P"),hoverdef("P",Pvar)
}

View File

@ -5,26 +5,6 @@ type value[T any] struct {
Q int //@mark(valueQfield, "Q"),hoverdef("Q", valueQfield)
}
```
-- valueTparam-hoverdef --
```go
type value[T any] struct {
val T //@mark(valueTparam, "T"),hoverdef("T", valueTparam)
Q int //@mark(valueQfield, "Q"),hoverdef("Q", valueQfield)
}
```
-- valueQfield-hoverdef --
```go
field Q int
```
\@mark\(valueQfield, \"Q\"\),hoverdef\(\"Q\", valueQfield\)
-- ValueTparam-hoverdef --
```go
type Value[T any] struct {
val T //@mark(ValueTparam, "T"),hoverdef("T", ValueTparam)
Q int //@mark(ValueQfield, "Q"),hoverdef("Q", ValueQfield)
}
```
-- ValueQfield-hoverdef --
```go
field Q int
@ -33,3 +13,33 @@ field Q int
[`(hover.Value).Q` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/hover_generics?utm_source=gopls#Value.Q)
\@mark\(ValueQfield, \"Q\"\),hoverdef\(\"Q\", ValueQfield\)
-- ValueTdecl-hoverdef --
```go
type parameter T any
```
-- ValueTparam-hoverdef --
```go
type parameter T any
```
-- valueQfield-hoverdef --
```go
field Q int
```
\@mark\(valueQfield, \"Q\"\),hoverdef\(\"Q\", valueQfield\)
-- valueTdecl-hoverdef --
```go
type parameter T any
```
-- valueTparam-hoverdef --
```go
type parameter T any
```
-- Pparam-hoverdef --
```go
type parameter P interface{~int|string}
```
-- Pvar-hoverdef --
```go
type parameter P interface{~int|string}
```

View File

@ -1,6 +1,6 @@
-- argInfer-hoverdef --
```go
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
```
-- constrInf-hoverdef --
```go
@ -8,13 +8,13 @@ func app(s []int, e int) []int // func[S₁ interface{~[]E₂}, E₂ interface{}
```
-- constrInfer-hoverdef --
```go
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
```
-- instance-hoverdef --
```go
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
```
-- partialInfer-hoverdef --
```go
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
func app(s []int, e int) []int // func[S interface{~[]E}, E interface{}](s S, e E) S
```

View File

@ -16,7 +16,7 @@ SemanticTokenCount = 3
SuggestedFixCount = 61
FunctionExtractionCount = 25
MethodExtractionCount = 6
DefinitionsCount = 104
DefinitionsCount = 108
TypeDefinitionsCount = 18
HighlightsCount = 69
ReferencesCount = 27