mirror of https://github.com/golang/go.git
godoc: fix addNames for generics
The type of a function receiver can now also be a IndexExpr. Fixes golang/go#50413 Change-Id: I5ac7bee8ea6b594be00d00c7fed2e2a9fe260b10 Reviewed-on: https://go-review.googlesource.com/c/tools/+/373857 Trust: Than McIntosh <thanm@google.com> Run-TryBot: Alessandro Arzilli <alessandro.arzilli@gmail.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
d4d432564f
commit
4754748303
|
|
@ -30,6 +30,7 @@ import (
|
|||
"golang.org/x/tools/godoc/analysis"
|
||||
"golang.org/x/tools/godoc/util"
|
||||
"golang.org/x/tools/godoc/vfs"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// handlerServer is a migration from an old godoc http Handler type.
|
||||
|
|
@ -462,12 +463,19 @@ func addNames(names map[string]bool, decl ast.Decl) {
|
|||
case *ast.FuncDecl:
|
||||
name := d.Name.Name
|
||||
if d.Recv != nil {
|
||||
r := d.Recv.List[0].Type
|
||||
if rr, isstar := r.(*ast.StarExpr); isstar {
|
||||
r = rr.X
|
||||
}
|
||||
|
||||
var typeName string
|
||||
switch r := d.Recv.List[0].Type.(type) {
|
||||
case *ast.StarExpr:
|
||||
typeName = r.X.(*ast.Ident).Name
|
||||
switch x := r.(type) {
|
||||
case *ast.Ident:
|
||||
typeName = r.Name
|
||||
typeName = x.Name
|
||||
case *ast.IndexExpr:
|
||||
typeName = x.X.(*ast.Ident).Name
|
||||
case *typeparams.IndexListExpr:
|
||||
typeName = x.X.(*ast.Ident).Name
|
||||
}
|
||||
name = typeName + "_" + name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@
|
|||
package godoc
|
||||
|
||||
import (
|
||||
"go/doc"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/tools/godoc/vfs/mapfs"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// TestIgnoredGoFiles tests the scenario where a folder has no .go or .c files,
|
||||
|
|
@ -128,3 +131,115 @@ func TestMarkdown(t *testing.T) {
|
|||
testServeBody(t, p, "/doc/test.html", "<strong>bold</strong>")
|
||||
testServeBody(t, p, "/doc/test2.html", "<em>template</em>")
|
||||
}
|
||||
|
||||
func TestGenerics(t *testing.T) {
|
||||
if !typeparams.Enabled {
|
||||
t.Skip("type params are not enabled at this Go version")
|
||||
}
|
||||
|
||||
c := NewCorpus(mapfs.New(map[string]string{
|
||||
"blah/blah.go": `package blah
|
||||
|
||||
var A AStruct[int]
|
||||
|
||||
type AStruct[T any] struct {
|
||||
A string
|
||||
X T
|
||||
}
|
||||
|
||||
func (a *AStruct[T]) Method() T {
|
||||
return a.X
|
||||
}
|
||||
|
||||
func (a AStruct[T]) NonPointerMethod() T {
|
||||
return a.X
|
||||
}
|
||||
|
||||
func NewAStruct[T any](arg T) *AStruct[T] {
|
||||
return &AStruct[T]{ X: arg }
|
||||
}
|
||||
|
||||
type NonGenericStruct struct {
|
||||
B int
|
||||
}
|
||||
|
||||
func (b *NonGenericStruct) NonGenericMethod() int {
|
||||
return b.B
|
||||
}
|
||||
|
||||
func NewNonGenericStruct(arg int) *NonGenericStruct {
|
||||
return &NonGenericStruct{arg}
|
||||
}
|
||||
|
||||
type Pair[K, V any] struct {
|
||||
K K
|
||||
V V
|
||||
}
|
||||
|
||||
func (p Pair[K, V]) Apply(kf func(K) K, vf func(V) V) Pair[K, V] {
|
||||
return &Pair{ K: kf(p.K), V: vf(p.V) }
|
||||
}
|
||||
|
||||
func (p *Pair[K, V]) Set(k K, v V) {
|
||||
p.K = k
|
||||
p.V = v
|
||||
}
|
||||
|
||||
func NewPair[K, V any](k K, v V) Pair[K, V] {
|
||||
return Pair[K, V]{ k, v }
|
||||
}
|
||||
`}))
|
||||
|
||||
srv := &handlerServer{
|
||||
p: &Presentation{
|
||||
Corpus: c,
|
||||
},
|
||||
c: c,
|
||||
}
|
||||
pInfo := srv.GetPageInfo("/blah/", "", NoFiltering, "linux", "amd64")
|
||||
t.Logf("%v\n", pInfo)
|
||||
|
||||
findType := func(name string) *doc.Type {
|
||||
for _, typ := range pInfo.PDoc.Types {
|
||||
if typ.Name == name {
|
||||
return typ
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
assertFuncs := func(typ *doc.Type, typFuncs []*doc.Func, funcs ...string) {
|
||||
typfuncs := make([]string, len(typFuncs))
|
||||
for i := range typFuncs {
|
||||
typfuncs[i] = typFuncs[i].Name
|
||||
}
|
||||
sort.Strings(typfuncs)
|
||||
sort.Strings(funcs)
|
||||
if len(typfuncs) != len(funcs) {
|
||||
t.Errorf("function mismatch for type %q, got: %q, want: %q", typ.Name, typfuncs, funcs)
|
||||
return
|
||||
}
|
||||
for i := range funcs {
|
||||
if funcs[i] != typfuncs[i] {
|
||||
t.Errorf("function mismatch for type %q: got: %q, want: %q", typ.Name, typfuncs, funcs)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aStructType := findType("AStruct")
|
||||
assertFuncs(aStructType, aStructType.Funcs, "NewAStruct")
|
||||
assertFuncs(aStructType, aStructType.Methods, "Method", "NonPointerMethod")
|
||||
|
||||
nonGenericStructType := findType("NonGenericStruct")
|
||||
assertFuncs(nonGenericStructType, nonGenericStructType.Funcs, "NewNonGenericStruct")
|
||||
assertFuncs(nonGenericStructType, nonGenericStructType.Methods, "NonGenericMethod")
|
||||
|
||||
pairType := findType("Pair")
|
||||
assertFuncs(pairType, pairType.Funcs, "NewPair")
|
||||
assertFuncs(pairType, pairType.Methods, "Apply", "Set")
|
||||
|
||||
if len(pInfo.PDoc.Funcs) > 0 {
|
||||
t.Errorf("unexpected functions in package documentation")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue