mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/doc: add -all flag to print all documentation for package
Unlike the one for the old godoc, you need the -u flag to see unexported symbols. This seems like the right behavior: it's consistent. For now at least, the argument must be a package, not a symbol. This is also different from old godoc. Required a little refactoring but also cleaned up a few things. Update #25595 Leaving the bug open for now until we tackle go doc -all symbol Change-Id: Ibc1975bfa592cb1e92513eb2e5e9e11e01a60095 Reviewed-on: https://go-review.googlesource.com/c/141977 Run-TryBot: Rob Pike <r@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
ee76992200
commit
101a677ebf
5 changed files with 327 additions and 92 deletions
|
|
@ -147,6 +147,69 @@ var tests = []test{
|
||||||
`type T1 T2`, // Type alias does not display as type declaration.
|
`type T1 T2`, // Type alias does not display as type declaration.
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Package dump -all
|
||||||
|
{
|
||||||
|
"full package",
|
||||||
|
[]string{"-all", p},
|
||||||
|
[]string{
|
||||||
|
`package pkg .*import`,
|
||||||
|
`Package comment`,
|
||||||
|
`CONSTANTS`,
|
||||||
|
`Comment before ConstOne`,
|
||||||
|
`ConstOne = 1`,
|
||||||
|
`ConstTwo = 2 // Comment on line with ConstTwo`,
|
||||||
|
`ConstFive`,
|
||||||
|
`ConstSix`,
|
||||||
|
`Const block where first entry is unexported`,
|
||||||
|
`ConstLeft2, constRight2 uint64`,
|
||||||
|
`constLeft3, ConstRight3`,
|
||||||
|
`ConstLeft4, ConstRight4`,
|
||||||
|
`Duplicate = iota`,
|
||||||
|
`const CaseMatch = 1`,
|
||||||
|
`const Casematch = 2`,
|
||||||
|
`const ExportedConstant = 1`,
|
||||||
|
`const MultiLineConst = `,
|
||||||
|
`MultiLineString1`,
|
||||||
|
`VARIABLES`,
|
||||||
|
`Comment before VarOne`,
|
||||||
|
`VarOne = 1`,
|
||||||
|
`Comment about block of variables`,
|
||||||
|
`VarFive = 5`,
|
||||||
|
`var ExportedVariable = 1`,
|
||||||
|
`var LongLine = newLongLine\(`,
|
||||||
|
`var MultiLineVar = map\[struct {`,
|
||||||
|
`FUNCTIONS`,
|
||||||
|
`func ExportedFunc\(a int\) bool`,
|
||||||
|
`Comment about exported function`,
|
||||||
|
`func MultiLineFunc\(x interface`,
|
||||||
|
`func ReturnUnexported\(\) unexportedType`,
|
||||||
|
`TYPES`,
|
||||||
|
`type ExportedInterface interface`,
|
||||||
|
`type ExportedStructOneField struct`,
|
||||||
|
`type ExportedType struct`,
|
||||||
|
`Comment about exported type`,
|
||||||
|
`const ConstGroup4 ExportedType = ExportedType`,
|
||||||
|
`ExportedTypedConstant ExportedType = iota`,
|
||||||
|
`Constants tied to ExportedType`,
|
||||||
|
`func ExportedTypeConstructor\(\) \*ExportedType`,
|
||||||
|
`Comment about constructor for exported type`,
|
||||||
|
`func ReturnExported\(\) ExportedType`,
|
||||||
|
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
||||||
|
`Comment about exported method`,
|
||||||
|
`type T1 = T2`,
|
||||||
|
`type T2 int`,
|
||||||
|
},
|
||||||
|
[]string{
|
||||||
|
`constThree`,
|
||||||
|
`_, _ uint64 = 2 \* iota, 1 << iota`,
|
||||||
|
`constLeft1, constRight1`,
|
||||||
|
`duplicate`,
|
||||||
|
`varFour`,
|
||||||
|
`func internalFunc`,
|
||||||
|
`unexportedField`,
|
||||||
|
`func \(unexportedType\)`,
|
||||||
|
},
|
||||||
|
},
|
||||||
// Package dump -u
|
// Package dump -u
|
||||||
{
|
{
|
||||||
"full package with u",
|
"full package with u",
|
||||||
|
|
@ -164,6 +227,58 @@ var tests = []test{
|
||||||
`MultiLine(String|Method|Field)`, // No data from multi line portions.
|
`MultiLine(String|Method|Field)`, // No data from multi line portions.
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Package dump -u -all
|
||||||
|
{
|
||||||
|
"full package",
|
||||||
|
[]string{"-u", "-all", p},
|
||||||
|
[]string{
|
||||||
|
`package pkg .*import`,
|
||||||
|
`Package comment`,
|
||||||
|
`CONSTANTS`,
|
||||||
|
`Comment before ConstOne`,
|
||||||
|
`ConstOne += 1`,
|
||||||
|
`ConstTwo += 2 // Comment on line with ConstTwo`,
|
||||||
|
`constThree = 3 // Comment on line with constThree`,
|
||||||
|
`ConstFive`,
|
||||||
|
`const internalConstant += 2`,
|
||||||
|
`Comment about internal constant`,
|
||||||
|
`VARIABLES`,
|
||||||
|
`Comment before VarOne`,
|
||||||
|
`VarOne += 1`,
|
||||||
|
`Comment about block of variables`,
|
||||||
|
`varFour += 4`,
|
||||||
|
`VarFive += 5`,
|
||||||
|
`varSix += 6`,
|
||||||
|
`var ExportedVariable = 1`,
|
||||||
|
`var LongLine = newLongLine\(`,
|
||||||
|
`var MultiLineVar = map\[struct {`,
|
||||||
|
`var internalVariable = 2`,
|
||||||
|
`Comment about internal variable`,
|
||||||
|
`FUNCTIONS`,
|
||||||
|
`func ExportedFunc\(a int\) bool`,
|
||||||
|
`Comment about exported function`,
|
||||||
|
`func MultiLineFunc\(x interface`,
|
||||||
|
`func internalFunc\(a int\) bool`,
|
||||||
|
`Comment about internal function`,
|
||||||
|
`func newLongLine\(ss .*string\)`,
|
||||||
|
`TYPES`,
|
||||||
|
`type ExportedType struct`,
|
||||||
|
`type T1 = T2`,
|
||||||
|
`type T2 int`,
|
||||||
|
`type unexportedType int`,
|
||||||
|
`Comment about unexported type`,
|
||||||
|
`ConstGroup1 unexportedType = iota`,
|
||||||
|
`ConstGroup2`,
|
||||||
|
`ConstGroup3`,
|
||||||
|
`ExportedTypedConstant_unexported unexportedType = iota`,
|
||||||
|
`Constants tied to unexportedType`,
|
||||||
|
`const unexportedTypedConstant unexportedType = 1`,
|
||||||
|
`func ReturnUnexported\(\) unexportedType`,
|
||||||
|
`func \(unexportedType\) ExportedMethod\(\) bool`,
|
||||||
|
`func \(unexportedType\) unexportedMethod\(\) bool`,
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
|
||||||
// Single constant.
|
// Single constant.
|
||||||
{
|
{
|
||||||
|
|
@ -361,7 +476,6 @@ var tests = []test{
|
||||||
`io.Reader.*Comment on line with embedded Reader`,
|
`io.Reader.*Comment on line with embedded Reader`,
|
||||||
},
|
},
|
||||||
[]string{
|
[]string{
|
||||||
`int.*embedded`, // No unexported embedded field.
|
|
||||||
`Comment about exported method`, // No comment about exported method.
|
`Comment about exported method`, // No comment about exported method.
|
||||||
`unexportedMethod`, // No unexported method.
|
`unexportedMethod`, // No unexported method.
|
||||||
`unexportedTypedConstant`, // No unexported constant.
|
`unexportedTypedConstant`, // No unexported constant.
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@
|
||||||
// The -src flag causes doc to print the full source code for the symbol, such
|
// The -src flag causes doc to print the full source code for the symbol, such
|
||||||
// as the body of a struct, function or method.
|
// as the body of a struct, function or method.
|
||||||
//
|
//
|
||||||
|
// The -all flag causes doc to print all documentation for the package and
|
||||||
|
// all its visible symbols. The argument must identify a package.
|
||||||
|
//
|
||||||
// For complete documentation, run "go help doc".
|
// For complete documentation, run "go help doc".
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
@ -52,6 +55,7 @@ import (
|
||||||
var (
|
var (
|
||||||
unexported bool // -u flag
|
unexported bool // -u flag
|
||||||
matchCase bool // -c flag
|
matchCase bool // -c flag
|
||||||
|
showAll bool // -all flag
|
||||||
showCmd bool // -cmd flag
|
showCmd bool // -cmd flag
|
||||||
showSrc bool // -src flag
|
showSrc bool // -src flag
|
||||||
)
|
)
|
||||||
|
|
@ -88,6 +92,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
|
||||||
matchCase = false
|
matchCase = false
|
||||||
flagSet.BoolVar(&unexported, "u", false, "show unexported symbols as well as exported")
|
flagSet.BoolVar(&unexported, "u", false, "show unexported symbols as well as exported")
|
||||||
flagSet.BoolVar(&matchCase, "c", false, "symbol matching honors case (paths not affected)")
|
flagSet.BoolVar(&matchCase, "c", false, "symbol matching honors case (paths not affected)")
|
||||||
|
flagSet.BoolVar(&showAll, "all", false, "show all documentation for package")
|
||||||
flagSet.BoolVar(&showCmd, "cmd", false, "show symbols with package docs even if package is a command")
|
flagSet.BoolVar(&showCmd, "cmd", false, "show symbols with package docs even if package is a command")
|
||||||
flagSet.BoolVar(&showSrc, "src", false, "show source code for symbol")
|
flagSet.BoolVar(&showSrc, "src", false, "show source code for symbol")
|
||||||
flagSet.Parse(args)
|
flagSet.Parse(args)
|
||||||
|
|
@ -127,6 +132,15 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
|
||||||
unexported = true
|
unexported = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have a package.
|
||||||
|
if showAll {
|
||||||
|
if symbol != "" {
|
||||||
|
return fmt.Errorf("-all valid only for package, not symbol: %s", symbol)
|
||||||
|
}
|
||||||
|
pkg.allDoc()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case symbol == "":
|
case symbol == "":
|
||||||
pkg.packageDoc() // The package exists, so we got some output.
|
pkg.packageDoc() // The package exists, so we got some output.
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,18 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
writer io.Writer // Destination for output.
|
writer io.Writer // Destination for output.
|
||||||
name string // Package name, json for encoding/json.
|
name string // Package name, json for encoding/json.
|
||||||
userPath string // String the user used to find this package.
|
userPath string // String the user used to find this package.
|
||||||
pkg *ast.Package // Parsed package.
|
pkg *ast.Package // Parsed package.
|
||||||
file *ast.File // Merged from all files in the package
|
file *ast.File // Merged from all files in the package
|
||||||
doc *doc.Package
|
doc *doc.Package
|
||||||
build *build.Package
|
build *build.Package
|
||||||
fs *token.FileSet // Needed for printing.
|
typedValue map[*doc.Value]bool // Consts and vars related to types.
|
||||||
buf bytes.Buffer
|
constructor map[*doc.Func]bool // Constructors.
|
||||||
|
packageClausePrinted bool // Prevent repeated package clauses.
|
||||||
|
fs *token.FileSet // Needed for printing.
|
||||||
|
buf bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
type PackageError string // type returned by pkg.Fatalf.
|
type PackageError string // type returned by pkg.Fatalf.
|
||||||
|
|
@ -142,21 +145,38 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
|
||||||
mode |= doc.PreserveAST // See comment for Package.emit.
|
mode |= doc.PreserveAST // See comment for Package.emit.
|
||||||
}
|
}
|
||||||
docPkg := doc.New(astPkg, pkg.ImportPath, mode)
|
docPkg := doc.New(astPkg, pkg.ImportPath, mode)
|
||||||
|
typedValue := make(map[*doc.Value]bool)
|
||||||
|
constructor := make(map[*doc.Func]bool)
|
||||||
for _, typ := range docPkg.Types {
|
for _, typ := range docPkg.Types {
|
||||||
docPkg.Consts = append(docPkg.Consts, typ.Consts...)
|
docPkg.Consts = append(docPkg.Consts, typ.Consts...)
|
||||||
|
for _, value := range typ.Consts {
|
||||||
|
typedValue[value] = true
|
||||||
|
}
|
||||||
docPkg.Vars = append(docPkg.Vars, typ.Vars...)
|
docPkg.Vars = append(docPkg.Vars, typ.Vars...)
|
||||||
|
for _, value := range typ.Vars {
|
||||||
|
typedValue[value] = true
|
||||||
|
}
|
||||||
docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
|
docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
|
||||||
|
for _, fun := range typ.Funcs {
|
||||||
|
// We don't count it as a constructor bound to the type
|
||||||
|
// if the type itself is not exported.
|
||||||
|
if isExported(typ.Name) {
|
||||||
|
constructor[fun] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Package{
|
return &Package{
|
||||||
writer: writer,
|
writer: writer,
|
||||||
name: pkg.Name,
|
name: pkg.Name,
|
||||||
userPath: userPath,
|
userPath: userPath,
|
||||||
pkg: astPkg,
|
pkg: astPkg,
|
||||||
file: ast.MergePackageFiles(astPkg, 0),
|
file: ast.MergePackageFiles(astPkg, 0),
|
||||||
doc: docPkg,
|
doc: docPkg,
|
||||||
build: pkg,
|
typedValue: typedValue,
|
||||||
fs: fs,
|
constructor: constructor,
|
||||||
|
build: pkg,
|
||||||
|
fs: fs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,6 +410,68 @@ func joinStrings(ss []string) string {
|
||||||
return strings.Join(ss, ", ")
|
return strings.Join(ss, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allDoc prints all the docs for the package.
|
||||||
|
func (pkg *Package) allDoc() {
|
||||||
|
defer pkg.flush()
|
||||||
|
if pkg.showInternals() {
|
||||||
|
pkg.packageClause(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.ToText(&pkg.buf, pkg.doc.Doc, "", indent, indentedWidth)
|
||||||
|
pkg.newlines(1)
|
||||||
|
|
||||||
|
printed := make(map[*ast.GenDecl]bool)
|
||||||
|
|
||||||
|
hdr := ""
|
||||||
|
printHdr := func(s string) {
|
||||||
|
if hdr != s {
|
||||||
|
pkg.Printf("\n%s\n\n", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants.
|
||||||
|
for _, value := range pkg.doc.Consts {
|
||||||
|
// Constants and variables come in groups, and valueDoc prints
|
||||||
|
// all the items in the group. We only need to find one exported symbol.
|
||||||
|
for _, name := range value.Names {
|
||||||
|
if isExported(name) && !pkg.typedValue[value] {
|
||||||
|
printHdr("CONSTANTS")
|
||||||
|
pkg.valueDoc(value, printed)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables.
|
||||||
|
for _, value := range pkg.doc.Vars {
|
||||||
|
// Constants and variables come in groups, and valueDoc prints
|
||||||
|
// all the items in the group. We only need to find one exported symbol.
|
||||||
|
for _, name := range value.Names {
|
||||||
|
if isExported(name) && !pkg.typedValue[value] {
|
||||||
|
printHdr("VARIABLES")
|
||||||
|
pkg.valueDoc(value, printed)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions.
|
||||||
|
for _, fun := range pkg.doc.Funcs {
|
||||||
|
if isExported(fun.Name) && !pkg.constructor[fun] {
|
||||||
|
printHdr("FUNCTIONS")
|
||||||
|
pkg.emit(fun.Doc, fun.Decl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Types.
|
||||||
|
for _, typ := range pkg.doc.Types {
|
||||||
|
if isExported(typ.Name) {
|
||||||
|
printHdr("TYPES")
|
||||||
|
pkg.typeDoc(typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
|
// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
|
||||||
func (pkg *Package) packageDoc() {
|
func (pkg *Package) packageDoc() {
|
||||||
defer pkg.flush()
|
defer pkg.flush()
|
||||||
|
|
@ -426,6 +508,10 @@ func (pkg *Package) showInternals() bool {
|
||||||
// user's argument is identical to the actual package path or
|
// user's argument is identical to the actual package path or
|
||||||
// is empty, meaning it's the current directory.
|
// is empty, meaning it's the current directory.
|
||||||
func (pkg *Package) packageClause(checkUserPath bool) {
|
func (pkg *Package) packageClause(checkUserPath bool) {
|
||||||
|
if pkg.packageClausePrinted {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if checkUserPath {
|
if checkUserPath {
|
||||||
if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
|
if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
|
||||||
return
|
return
|
||||||
|
|
@ -463,6 +549,7 @@ func (pkg *Package) packageClause(checkUserPath bool) {
|
||||||
if !usingModules && importPath != pkg.build.ImportPath {
|
if !usingModules && importPath != pkg.build.ImportPath {
|
||||||
pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
|
pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
|
||||||
}
|
}
|
||||||
|
pkg.packageClausePrinted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// valueSummary prints a one-line summary for each set of values and constants.
|
// valueSummary prints a one-line summary for each set of values and constants.
|
||||||
|
|
@ -497,22 +584,10 @@ func (pkg *Package) valueSummary(values []*doc.Value, showGrouped bool) {
|
||||||
// funcSummary prints a one-line summary for each function. Constructors
|
// funcSummary prints a one-line summary for each function. Constructors
|
||||||
// are printed by typeSummary, below, and so can be suppressed here.
|
// are printed by typeSummary, below, and so can be suppressed here.
|
||||||
func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
|
func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
|
||||||
// First, identify the constructors. Don't bother figuring out if they're exported.
|
|
||||||
var isConstructor map[*doc.Func]bool
|
|
||||||
if !showConstructors {
|
|
||||||
isConstructor = make(map[*doc.Func]bool)
|
|
||||||
for _, typ := range pkg.doc.Types {
|
|
||||||
if isExported(typ.Name) {
|
|
||||||
for _, f := range typ.Funcs {
|
|
||||||
isConstructor[f] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, fun := range funcs {
|
for _, fun := range funcs {
|
||||||
// Exported functions only. The go/doc package does not include methods here.
|
// Exported functions only. The go/doc package does not include methods here.
|
||||||
if isExported(fun.Name) {
|
if isExported(fun.Name) {
|
||||||
if !isConstructor[fun] {
|
if showConstructors || !pkg.constructor[fun] {
|
||||||
pkg.Printf("%s\n", pkg.oneLineNode(fun.Decl))
|
pkg.Printf("%s\n", pkg.oneLineNode(fun.Decl))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -629,71 +704,12 @@ func (pkg *Package) symbolDoc(symbol string) bool {
|
||||||
// So we remember which declarations we've printed to avoid duplication.
|
// So we remember which declarations we've printed to avoid duplication.
|
||||||
printed := make(map[*ast.GenDecl]bool)
|
printed := make(map[*ast.GenDecl]bool)
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
// Print each spec only if there is at least one exported symbol in it.
|
pkg.valueDoc(value, printed)
|
||||||
// (See issue 11008.)
|
|
||||||
// TODO: Should we elide unexported symbols from a single spec?
|
|
||||||
// It's an unlikely scenario, probably not worth the trouble.
|
|
||||||
// TODO: Would be nice if go/doc did this for us.
|
|
||||||
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
|
|
||||||
var typ ast.Expr
|
|
||||||
for _, spec := range value.Decl.Specs {
|
|
||||||
vspec := spec.(*ast.ValueSpec)
|
|
||||||
|
|
||||||
// The type name may carry over from a previous specification in the
|
|
||||||
// case of constants and iota.
|
|
||||||
if vspec.Type != nil {
|
|
||||||
typ = vspec.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ident := range vspec.Names {
|
|
||||||
if showSrc || isExported(ident.Name) {
|
|
||||||
if vspec.Type == nil && vspec.Values == nil && typ != nil {
|
|
||||||
// This a standalone identifier, as in the case of iota usage.
|
|
||||||
// Thus, assume the type comes from the previous type.
|
|
||||||
vspec.Type = &ast.Ident{
|
|
||||||
Name: pkg.oneLineNode(typ),
|
|
||||||
NamePos: vspec.End() - 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
specs = append(specs, vspec)
|
|
||||||
typ = nil // Only inject type on first exported identifier
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(specs) == 0 || printed[value.Decl] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
value.Decl.Specs = specs
|
|
||||||
if !found {
|
|
||||||
pkg.packageClause(true)
|
|
||||||
}
|
|
||||||
pkg.emit(value.Doc, value.Decl)
|
|
||||||
printed[value.Decl] = true
|
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
// Types.
|
// Types.
|
||||||
for _, typ := range pkg.findTypes(symbol) {
|
for _, typ := range pkg.findTypes(symbol) {
|
||||||
if !found {
|
pkg.typeDoc(typ)
|
||||||
pkg.packageClause(true)
|
|
||||||
}
|
|
||||||
decl := typ.Decl
|
|
||||||
spec := pkg.findTypeSpec(decl, typ.Name)
|
|
||||||
trimUnexportedElems(spec)
|
|
||||||
// If there are multiple types defined, reduce to just this one.
|
|
||||||
if len(decl.Specs) > 1 {
|
|
||||||
decl.Specs = []ast.Spec{spec}
|
|
||||||
}
|
|
||||||
pkg.emit(typ.Doc, decl)
|
|
||||||
// Show associated methods, constants, etc.
|
|
||||||
if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
|
|
||||||
pkg.Printf("\n")
|
|
||||||
}
|
|
||||||
pkg.valueSummary(typ.Consts, true)
|
|
||||||
pkg.valueSummary(typ.Vars, true)
|
|
||||||
pkg.funcSummary(typ.Funcs, true)
|
|
||||||
pkg.funcSummary(typ.Methods, true)
|
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
|
|
@ -705,6 +721,93 @@ func (pkg *Package) symbolDoc(symbol string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// valueDoc prints the docs for a constant or variable.
|
||||||
|
func (pkg *Package) valueDoc(value *doc.Value, printed map[*ast.GenDecl]bool) {
|
||||||
|
if printed[value.Decl] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Print each spec only if there is at least one exported symbol in it.
|
||||||
|
// (See issue 11008.)
|
||||||
|
// TODO: Should we elide unexported symbols from a single spec?
|
||||||
|
// It's an unlikely scenario, probably not worth the trouble.
|
||||||
|
// TODO: Would be nice if go/doc did this for us.
|
||||||
|
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
|
||||||
|
var typ ast.Expr
|
||||||
|
for _, spec := range value.Decl.Specs {
|
||||||
|
vspec := spec.(*ast.ValueSpec)
|
||||||
|
|
||||||
|
// The type name may carry over from a previous specification in the
|
||||||
|
// case of constants and iota.
|
||||||
|
if vspec.Type != nil {
|
||||||
|
typ = vspec.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ident := range vspec.Names {
|
||||||
|
if showSrc || isExported(ident.Name) {
|
||||||
|
if vspec.Type == nil && vspec.Values == nil && typ != nil {
|
||||||
|
// This a standalone identifier, as in the case of iota usage.
|
||||||
|
// Thus, assume the type comes from the previous type.
|
||||||
|
vspec.Type = &ast.Ident{
|
||||||
|
Name: pkg.oneLineNode(typ),
|
||||||
|
NamePos: vspec.End() - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
specs = append(specs, vspec)
|
||||||
|
typ = nil // Only inject type on first exported identifier
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(specs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value.Decl.Specs = specs
|
||||||
|
pkg.emit(value.Doc, value.Decl)
|
||||||
|
printed[value.Decl] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeDoc prints the docs for a type, including constructors and other items
|
||||||
|
// related to it.
|
||||||
|
func (pkg *Package) typeDoc(typ *doc.Type) {
|
||||||
|
decl := typ.Decl
|
||||||
|
spec := pkg.findTypeSpec(decl, typ.Name)
|
||||||
|
trimUnexportedElems(spec)
|
||||||
|
// If there are multiple types defined, reduce to just this one.
|
||||||
|
if len(decl.Specs) > 1 {
|
||||||
|
decl.Specs = []ast.Spec{spec}
|
||||||
|
}
|
||||||
|
pkg.emit(typ.Doc, decl)
|
||||||
|
pkg.newlines(2)
|
||||||
|
// Show associated methods, constants, etc.
|
||||||
|
if showAll {
|
||||||
|
printed := make(map[*ast.GenDecl]bool)
|
||||||
|
// We can use append here to print consts, then vars. Ditto for funcs and methods.
|
||||||
|
values := typ.Consts
|
||||||
|
values = append(values, typ.Vars...)
|
||||||
|
for _, value := range values {
|
||||||
|
for _, name := range value.Names {
|
||||||
|
if isExported(name) {
|
||||||
|
pkg.valueDoc(value, printed)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
funcs := typ.Funcs
|
||||||
|
funcs = append(funcs, typ.Methods...)
|
||||||
|
for _, fun := range funcs {
|
||||||
|
if isExported(fun.Name) {
|
||||||
|
pkg.emit(fun.Doc, fun.Decl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pkg.valueSummary(typ.Consts, true)
|
||||||
|
pkg.valueSummary(typ.Vars, true)
|
||||||
|
pkg.funcSummary(typ.Funcs, true)
|
||||||
|
pkg.funcSummary(typ.Methods, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// trimUnexportedElems modifies spec in place to elide unexported fields from
|
// trimUnexportedElems modifies spec in place to elide unexported fields from
|
||||||
// structs and methods from interfaces (unless the unexported flag is set or we
|
// structs and methods from interfaces (unless the unexported flag is set or we
|
||||||
// are asked to show the original source).
|
// are asked to show the original source).
|
||||||
|
|
|
||||||
|
|
@ -342,6 +342,8 @@
|
||||||
// cd go/src/encoding/json; go doc decode
|
// cd go/src/encoding/json; go doc decode
|
||||||
//
|
//
|
||||||
// Flags:
|
// Flags:
|
||||||
|
// -all
|
||||||
|
// Show all the documentation for the package.
|
||||||
// -c
|
// -c
|
||||||
// Respect case when matching symbols.
|
// Respect case when matching symbols.
|
||||||
// -cmd
|
// -cmd
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,8 @@ Examples:
|
||||||
cd go/src/encoding/json; go doc decode
|
cd go/src/encoding/json; go doc decode
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
|
-all
|
||||||
|
Show all the documentation for the package.
|
||||||
-c
|
-c
|
||||||
Respect case when matching symbols.
|
Respect case when matching symbols.
|
||||||
-cmd
|
-cmd
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue