Commit d3bd6b6a authored by Rob Pike's avatar Rob Pike Committed by Gerrit Code Review

cmd/doc: print documentation for all matches in a package, not just the first

Change-Id: Id0d4ac7169f741dfeec7b1e67bdc21e49ae37b9e
Reviewed-on: https://go-review.googlesource.com/9430Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent a88994c1
...@@ -218,89 +218,89 @@ func (pkg *Package) typeSummary() { ...@@ -218,89 +218,89 @@ func (pkg *Package) typeSummary() {
} }
} }
// findValue finds the doc.Value that describes the symbol. // findValues finds the doc.Values that describe the symbol.
func (pkg *Package) findValue(symbol string, values []*doc.Value) *doc.Value { func (pkg *Package) findValues(symbol string, docValues []*doc.Value) (values []*doc.Value) {
for _, value := range values { for _, value := range docValues {
for _, name := range value.Names { for _, name := range value.Names {
if match(symbol, name) { if match(symbol, name) {
return value values = append(values, value)
} }
} }
} }
return nil return
} }
// findType finds the doc.Func that describes the symbol. // findFuncs finds the doc.Funcs that describes the symbol.
func (pkg *Package) findFunc(symbol string) *doc.Func { func (pkg *Package) findFuncs(symbol string) (funcs []*doc.Func) {
for _, fun := range pkg.doc.Funcs { for _, fun := range pkg.doc.Funcs {
if match(symbol, fun.Name) { if match(symbol, fun.Name) {
return fun funcs = append(funcs, fun)
} }
} }
return nil return
} }
// findType finds the doc.Type that describes the symbol. // findTypes finds the doc.Types that describes the symbol.
func (pkg *Package) findType(symbol string) *doc.Type { func (pkg *Package) findTypes(symbol string) (types []*doc.Type) {
for _, typ := range pkg.doc.Types { for _, typ := range pkg.doc.Types {
if match(symbol, typ.Name) { if match(symbol, typ.Name) {
return typ types = append(types, typ)
} }
} }
return nil return
} }
// findTypeSpec returns the ast.TypeSpec within the declaration that defines the symbol. // findTypeSpec returns the ast.TypeSpec within the declaration that defines the symbol.
// The name must match exactly.
func (pkg *Package) findTypeSpec(decl *ast.GenDecl, symbol string) *ast.TypeSpec { func (pkg *Package) findTypeSpec(decl *ast.GenDecl, symbol string) *ast.TypeSpec {
for _, spec := range decl.Specs { for _, spec := range decl.Specs {
typeSpec := spec.(*ast.TypeSpec) // Must succeed. typeSpec := spec.(*ast.TypeSpec) // Must succeed.
if match(symbol, typeSpec.Name.Name) { if symbol == typeSpec.Name.Name {
return typeSpec return typeSpec
} }
} }
return nil return nil
} }
// symbolDoc prints the doc for symbol. If it is a type, this includes its methods, // symbolDoc prints the docs for symbol. There may be multiple matches.
// factories (TODO) and associated constants. // If symbol matches a type, output includes its methods factories and associated constants.
func (pkg *Package) symbolDoc(symbol string) { func (pkg *Package) symbolDoc(symbol string) {
// TODO: resolve ambiguity in doc foo vs. doc Foo. found := false
// Functions. // Functions.
if fun := pkg.findFunc(symbol); fun != nil { for _, fun := range pkg.findFuncs(symbol) {
// Symbol is a function. // Symbol is a function.
decl := fun.Decl decl := fun.Decl
decl.Body = nil decl.Body = nil
pkg.emit(fun.Doc, decl) pkg.emit(fun.Doc, decl)
return found = true
} }
// Constants and variables behave the same. // Constants and variables behave the same.
value := pkg.findValue(symbol, pkg.doc.Consts) values := pkg.findValues(symbol, pkg.doc.Consts)
if value == nil { values = append(values, pkg.findValues(symbol, pkg.doc.Vars)...)
value = pkg.findValue(symbol, pkg.doc.Vars) for _, value := range values {
}
if value != nil {
pkg.emit(value.Doc, value.Decl) pkg.emit(value.Doc, value.Decl)
return found = true
} }
// Types. // Types.
typ := pkg.findType(symbol) for _, typ := range pkg.findTypes(symbol) {
if typ == nil {
log.Fatalf("symbol %s not present in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
}
decl := typ.Decl decl := typ.Decl
spec := pkg.findTypeSpec(decl, symbol) spec := pkg.findTypeSpec(decl, typ.Name)
trimUnexportedFields(spec) trimUnexportedFields(spec)
// If there are multiple types defined, reduce to just this one. // If there are multiple types defined, reduce to just this one.
if len(decl.Specs) > 1 { if len(decl.Specs) > 1 {
decl.Specs = []ast.Spec{spec} decl.Specs = []ast.Spec{spec}
} }
pkg.emit(typ.Doc, decl) pkg.emit(typ.Doc, decl)
// TODO: Show factory functions.
// Show associated methods, constants, etc. // Show associated methods, constants, etc.
pkg.valueSummary(typ.Consts) pkg.valueSummary(typ.Consts)
pkg.valueSummary(typ.Vars) pkg.valueSummary(typ.Vars)
pkg.funcSummary(typ.Funcs) pkg.funcSummary(typ.Funcs)
pkg.funcSummary(typ.Methods) pkg.funcSummary(typ.Methods)
found = true
}
if !found {
log.Fatalf("symbol %s not present in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
}
} }
// trimUnexportedFields modifies spec in place to elide unexported fields (unless // trimUnexportedFields modifies spec in place to elide unexported fields (unless
...@@ -347,21 +347,26 @@ func trimUnexportedFields(spec *ast.TypeSpec) { ...@@ -347,21 +347,26 @@ func trimUnexportedFields(spec *ast.TypeSpec) {
} }
} }
// methodDoc prints the doc for symbol.method. // methodDoc prints the docs for matches of symbol.method.
func (pkg *Package) methodDoc(symbol, method string) { func (pkg *Package) methodDoc(symbol, method string) {
typ := pkg.findType(symbol) types := pkg.findTypes(symbol)
if typ == nil { if types == nil {
log.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath) log.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
} }
found := false
for _, typ := range types {
for _, meth := range typ.Methods { for _, meth := range typ.Methods {
if match(method, meth.Name) { if match(method, meth.Name) {
decl := meth.Decl decl := meth.Decl
decl.Body = nil decl.Body = nil
pkg.emit(meth.Doc, decl) pkg.emit(meth.Doc, decl)
return found = true
} }
} }
}
if !found {
log.Fatalf("no method %s.%s in package %s installed in %q", symbol, method, pkg.name, pkg.build.ImportPath) log.Fatalf("no method %s.%s in package %s installed in %q", symbol, method, pkg.name, pkg.build.ImportPath)
}
} }
// match reports whether the user's symbol matches the program's. // match reports whether the user's symbol matches the program's.
......
...@@ -220,7 +220,9 @@ The package paths must be either a qualified path or a proper suffix of a path ...@@ -220,7 +220,9 @@ The package paths must be either a qualified path or a proper suffix of a path
path elements like . and ... are not implemented by go doc. path elements like . and ... are not implemented by go doc.
When matching symbols, lower-case letters match either case but upper-case letters When matching symbols, lower-case letters match either case but upper-case letters
match exactly. match exactly. This means that there may be multiple matches in a package if
different symbols have different cases. If this occurs, documentation for all
matches is printed.
Examples: Examples:
go doc go doc
......
...@@ -40,7 +40,9 @@ The package paths must be either a qualified path or a proper suffix of a path ...@@ -40,7 +40,9 @@ The package paths must be either a qualified path or a proper suffix of a path
path elements like . and ... are not implemented by go doc. path elements like . and ... are not implemented by go doc.
When matching symbols, lower-case letters match either case but upper-case letters When matching symbols, lower-case letters match either case but upper-case letters
match exactly. match exactly. This means that there may be multiple matches in a package if
different symbols have different cases. If this occurs, documentation for all
matches is printed.
Examples: Examples:
go doc go doc
......
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