`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
{
"full package with u",
`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.
{
`io.Reader.*Comment on line with embedded Reader`,
},
[]string{
- `int.*embedded`, // No unexported embedded field.
`Comment about exported method`, // No comment about exported method.
`unexportedMethod`, // No unexported method.
`unexportedTypedConstant`, // No unexported constant.
)
type Package struct {
- writer io.Writer // Destination for output.
- name string // Package name, json for encoding/json.
- userPath string // String the user used to find this package.
- pkg *ast.Package // Parsed package.
- file *ast.File // Merged from all files in the package
- doc *doc.Package
- build *build.Package
- fs *token.FileSet // Needed for printing.
- buf bytes.Buffer
+ writer io.Writer // Destination for output.
+ name string // Package name, json for encoding/json.
+ userPath string // String the user used to find this package.
+ pkg *ast.Package // Parsed package.
+ file *ast.File // Merged from all files in the package
+ doc *doc.Package
+ build *build.Package
+ typedValue map[*doc.Value]bool // Consts and vars related to types.
+ 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.
mode |= doc.PreserveAST // See comment for Package.emit.
}
docPkg := doc.New(astPkg, pkg.ImportPath, mode)
+ typedValue := make(map[*doc.Value]bool)
+ constructor := make(map[*doc.Func]bool)
for _, typ := range docPkg.Types {
docPkg.Consts = append(docPkg.Consts, typ.Consts...)
+ for _, value := range typ.Consts {
+ typedValue[value] = true
+ }
docPkg.Vars = append(docPkg.Vars, typ.Vars...)
+ for _, value := range typ.Vars {
+ typedValue[value] = true
+ }
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{
- writer: writer,
- name: pkg.Name,
- userPath: userPath,
- pkg: astPkg,
- file: ast.MergePackageFiles(astPkg, 0),
- doc: docPkg,
- build: pkg,
- fs: fs,
+ writer: writer,
+ name: pkg.Name,
+ userPath: userPath,
+ pkg: astPkg,
+ file: ast.MergePackageFiles(astPkg, 0),
+ doc: docPkg,
+ typedValue: typedValue,
+ constructor: constructor,
+ build: pkg,
+ fs: fs,
}
}
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).
func (pkg *Package) packageDoc() {
defer pkg.flush()
// user's argument is identical to the actual package path or
// is empty, meaning it's the current directory.
func (pkg *Package) packageClause(checkUserPath bool) {
+ if pkg.packageClausePrinted {
+ return
+ }
+
if checkUserPath {
if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
return
if !usingModules && importPath != 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.
// funcSummary prints a one-line summary for each function. Constructors
// are printed by typeSummary, below, and so can be suppressed here.
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 {
// Exported functions only. The go/doc package does not include methods here.
if isExported(fun.Name) {
- if !isConstructor[fun] {
+ if showConstructors || !pkg.constructor[fun] {
pkg.Printf("%s\n", pkg.oneLineNode(fun.Decl))
}
}
// So we remember which declarations we've printed to avoid duplication.
printed := make(map[*ast.GenDecl]bool)
for _, value := range values {
- // 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)
+ pkg.valueDoc(value, printed)
+ found = true
+ }
+ // Types.
+ for _, typ := range pkg.findTypes(symbol) {
+ pkg.typeDoc(typ)
+ found = true
+ }
+ if !found {
+ // See if there are methods.
+ if !pkg.printMethodDoc("", symbol) {
+ return false
+ }
+ }
+ return true
+}
- // The type name may carry over from a previous specification in the
- // case of constants and iota.
- if vspec.Type != nil {
- typ = vspec.Type
- }
+// 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,
- }
+ 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
}
+
+ 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
}
- // Types.
- for _, typ := range pkg.findTypes(symbol) {
- if !found {
- 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}
+ 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
+ }
+ }
}
- 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")
+ 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)
- found = true
- }
- if !found {
- // See if there are methods.
- if !pkg.printMethodDoc("", symbol) {
- return false
- }
}
- return true
}
// trimUnexportedElems modifies spec in place to elide unexported fields from