Commit b3a5f9e5 authored by Robert Griesemer's avatar Robert Griesemer

go/doc: don't show methods of exported anonymous fields

Added flag AllMethods: if not set (future default), embedded
methods of exported (and thus visible) embedded fields are not
shown in the final package documentation

The actual change for AllMethods is just in sortedFuncs. All
other changes are simplifications of the existing logic (mostly
deletion of code): Because method conflicts due to embedding
must always be detected, remove any premature elimination of
types and methods. Instead collect all named types and all
methods and do the filtering at the end.

Miscellaneous:
- renamed baseType -> namedType
- streamline logic for recording embedded types
- record embedded types via a map (simpler data structures)

AllMethods is set by default; so the output is unchanged and
the tests pass. The next CL will enable the AllMethods flag
and have adjusted tests (and fix issue 2791).

R=rsc
CC=golang-dev
https://golang.org/cl/5572076
parent a0d0ed20
......@@ -68,12 +68,17 @@ const (
// extract documentation for all package-level declarations,
// not just exported ones
AllDecls Mode = 1 << iota
// show all embedded methods, not just the ones of
// invisible (unexported) anonymous fields
AllMethods
)
// New computes the package documentation for the given package AST.
// New takes ownership of the AST pkg and may edit or overwrite it.
//
func New(pkg *ast.Package, importPath string, mode Mode) *Package {
mode |= AllMethods // TODO(gri) remove this to enable flag
var r reader
r.readPackage(pkg, mode)
r.computeMethodSets()
......@@ -86,8 +91,8 @@ func New(pkg *ast.Package, importPath string, mode Mode) *Package {
Filenames: r.filenames,
Bugs: r.bugs,
Consts: sortedValues(r.values, token.CONST),
Types: sortedTypes(r.types),
Types: sortedTypes(r.types, mode&AllMethods != 0),
Vars: sortedValues(r.values, token.VAR),
Funcs: sortedFuncs(r.funcs),
Funcs: sortedFuncs(r.funcs, true),
}
}
......@@ -23,11 +23,11 @@ func filterIdentList(list []*ast.Ident) []*ast.Ident {
}
// filterFieldList removes unexported fields (field names) from the field list
// in place and returns true if fields were removed. Removed fields that are
// anonymous (embedded) fields are added as embedded types to base. filterType
// is called with the types of all remaining fields.
// in place and returns true if fields were removed. Anonymous fields are
// recorded with the parent type. filterType is called with the types of
// all remaining fields.
//
func (r *reader) filterFieldList(base *baseType, fields *ast.FieldList) (removedFields bool) {
func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList) (removedFields bool) {
if fields == nil {
return
}
......@@ -37,18 +37,9 @@ func (r *reader) filterFieldList(base *baseType, fields *ast.FieldList) (removed
keepField := false
if n := len(field.Names); n == 0 {
// anonymous field
name, imp := baseTypeName(field.Type)
name := r.recordAnonymousField(parent, field.Type)
if ast.IsExported(name) {
// we keep the field - in this case r.readDecl
// will take care of adding the embedded type
keepField = true
} else if base != nil && !imp {
// we don't keep the field - add it as an embedded
// type so we won't loose its methods, if any
if embedded := r.lookupType(name); embedded != nil {
_, ptr := field.Type.(*ast.StarExpr)
base.addEmbeddedType(embedded, ptr)
}
}
} else {
field.Names = filterIdentList(field.Names)
......@@ -86,7 +77,7 @@ func (r *reader) filterParamList(fields *ast.FieldList) {
// in place. If fields (or methods) have been removed, the corresponding
// struct or interface type has the Incomplete field set to true.
//
func (r *reader) filterType(base *baseType, typ ast.Expr) {
func (r *reader) filterType(parent *namedType, typ ast.Expr) {
switch t := typ.(type) {
case *ast.Ident:
// nothing to do
......@@ -95,14 +86,14 @@ func (r *reader) filterType(base *baseType, typ ast.Expr) {
case *ast.ArrayType:
r.filterType(nil, t.Elt)
case *ast.StructType:
if r.filterFieldList(base, t.Fields) {
if r.filterFieldList(parent, t.Fields) {
t.Incomplete = true
}
case *ast.FuncType:
r.filterParamList(t.Params)
r.filterParamList(t.Results)
case *ast.InterfaceType:
if r.filterFieldList(base, t.Methods) {
if r.filterFieldList(parent, t.Methods) {
t.Incomplete = true
}
case *ast.MapType:
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment