mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/doc: handle embedded interfaces properly
Changes made:
* Disallow star expression on interfaces as this is not possible.
* Show an embedded "error" in an interface as public similar to
how godoc does it.
* Properly handle selector expressions in both structs and interfaces.
This is possible since a type may refer to something defined in
another package (e.g. io.Reader).
Before:
<<<
$ go doc runtime.Error
type Error interface {
// RuntimeError is a no-op function but
// serves to distinguish types that are run time
// errors from ordinary errors: a type is a
// run time error if it has a RuntimeError method.
RuntimeError()
// Has unexported methods.
}
$ go doc compress/flate Reader
doc: invalid program: unexpected type for embedded field
doc: invalid program: unexpected type for embedded field
type Reader interface {
io.Reader
io.ByteReader
}
>>>
After:
<<<
$ go doc runtime.Error
type Error interface {
error
// RuntimeError is a no-op function but
// serves to distinguish types that are run time
// errors from ordinary errors: a type is a
// run time error if it has a RuntimeError method.
RuntimeError()
}
$ go doc compress/flate Reader
type Reader interface {
io.Reader
io.ByteReader
}
>>>
Fixes #16567
Change-Id: I272dede971eee9f43173966233eb8810e4a8c907
Reviewed-on: https://go-review.googlesource.com/25365
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
28ee179657
commit
f5758739a8
3 changed files with 32 additions and 4 deletions
|
|
@ -494,14 +494,19 @@ func trimUnexportedElems(spec *ast.TypeSpec) {
|
|||
}
|
||||
switch typ := spec.Type.(type) {
|
||||
case *ast.StructType:
|
||||
typ.Fields = trimUnexportedFields(typ.Fields, "fields")
|
||||
typ.Fields = trimUnexportedFields(typ.Fields, false)
|
||||
case *ast.InterfaceType:
|
||||
typ.Methods = trimUnexportedFields(typ.Methods, "methods")
|
||||
typ.Methods = trimUnexportedFields(typ.Methods, true)
|
||||
}
|
||||
}
|
||||
|
||||
// trimUnexportedFields returns the field list trimmed of unexported fields.
|
||||
func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
|
||||
func trimUnexportedFields(fields *ast.FieldList, isInterface bool) *ast.FieldList {
|
||||
what := "methods"
|
||||
if !isInterface {
|
||||
what = "fields"
|
||||
}
|
||||
|
||||
trimmed := false
|
||||
list := make([]*ast.Field, 0, len(fields.List))
|
||||
for _, field := range fields.List {
|
||||
|
|
@ -511,12 +516,23 @@ func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
|
|||
// Nothing else is allowed.
|
||||
switch ident := field.Type.(type) {
|
||||
case *ast.Ident:
|
||||
if isInterface && ident.Name == "error" && ident.Obj == nil {
|
||||
// For documentation purposes, we consider the builtin error
|
||||
// type special when embedded in an interface, such that it
|
||||
// always gets shown publicly.
|
||||
list = append(list, field)
|
||||
continue
|
||||
}
|
||||
names = []*ast.Ident{ident}
|
||||
case *ast.StarExpr:
|
||||
// Must have the form *identifier.
|
||||
if ident, ok := ident.X.(*ast.Ident); ok {
|
||||
// This is only valid on embedded types in structs.
|
||||
if ident, ok := ident.X.(*ast.Ident); ok && !isInterface {
|
||||
names = []*ast.Ident{ident}
|
||||
}
|
||||
case *ast.SelectorExpr:
|
||||
// An embedded type may refer to a type in another package.
|
||||
names = []*ast.Ident{ident.Sel}
|
||||
}
|
||||
if names == nil {
|
||||
// Can only happen if AST is incorrect. Safe to continue with a nil list.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue