Home | History | Annotate | Download | only in doc
      1 // Copyright 2015 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package main
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"go/ast"
     11 	"go/build"
     12 	"go/doc"
     13 	"go/format"
     14 	"go/parser"
     15 	"go/token"
     16 	"io"
     17 	"log"
     18 	"os"
     19 	"path/filepath"
     20 	"strings"
     21 	"unicode"
     22 	"unicode/utf8"
     23 )
     24 
     25 const (
     26 	punchedCardWidth = 80 // These things just won't leave us alone.
     27 	indentedWidth    = punchedCardWidth - len(indent)
     28 	indent           = "    "
     29 )
     30 
     31 type Package struct {
     32 	writer   io.Writer    // Destination for output.
     33 	name     string       // Package name, json for encoding/json.
     34 	userPath string       // String the user used to find this package.
     35 	pkg      *ast.Package // Parsed package.
     36 	file     *ast.File    // Merged from all files in the package
     37 	doc      *doc.Package
     38 	build    *build.Package
     39 	fs       *token.FileSet // Needed for printing.
     40 	buf      bytes.Buffer
     41 }
     42 
     43 type PackageError string // type returned by pkg.Fatalf.
     44 
     45 func (p PackageError) Error() string {
     46 	return string(p)
     47 }
     48 
     49 // prettyPath returns a version of the package path that is suitable for an
     50 // error message. It obeys the import comment if present. Also, since
     51 // pkg.build.ImportPath is sometimes the unhelpful "" or ".", it looks for a
     52 // directory name in GOROOT or GOPATH if that happens.
     53 func (pkg *Package) prettyPath() string {
     54 	path := pkg.build.ImportComment
     55 	if path == "" {
     56 		path = pkg.build.ImportPath
     57 	}
     58 	if path != "." && path != "" {
     59 		return path
     60 	}
     61 	// Convert the source directory into a more useful path.
     62 	// Also convert everything to slash-separated paths for uniform handling.
     63 	path = filepath.Clean(filepath.ToSlash(pkg.build.Dir))
     64 	// Can we find a decent prefix?
     65 	goroot := filepath.Join(build.Default.GOROOT, "src")
     66 	if p, ok := trim(path, filepath.ToSlash(goroot)); ok {
     67 		return p
     68 	}
     69 	for _, gopath := range splitGopath() {
     70 		if p, ok := trim(path, filepath.ToSlash(gopath)); ok {
     71 			return p
     72 		}
     73 	}
     74 	return path
     75 }
     76 
     77 // trim trims the directory prefix from the path, paying attention
     78 // to the path separator. If they are the same string or the prefix
     79 // is not present the original is returned. The boolean reports whether
     80 // the prefix is present. That path and prefix have slashes for separators.
     81 func trim(path, prefix string) (string, bool) {
     82 	if !strings.HasPrefix(path, prefix) {
     83 		return path, false
     84 	}
     85 	if path == prefix {
     86 		return path, true
     87 	}
     88 	if path[len(prefix)] == '/' {
     89 		return path[len(prefix)+1:], true
     90 	}
     91 	return path, false // Textual prefix but not a path prefix.
     92 }
     93 
     94 // pkg.Fatalf is like log.Fatalf, but panics so it can be recovered in the
     95 // main do function, so it doesn't cause an exit. Allows testing to work
     96 // without running a subprocess. The log prefix will be added when
     97 // logged in main; it is not added here.
     98 func (pkg *Package) Fatalf(format string, args ...interface{}) {
     99 	panic(PackageError(fmt.Sprintf(format, args...)))
    100 }
    101 
    102 // parsePackage turns the build package we found into a parsed package
    103 // we can then use to generate documentation.
    104 func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package {
    105 	fs := token.NewFileSet()
    106 	// include tells parser.ParseDir which files to include.
    107 	// That means the file must be in the build package's GoFiles or CgoFiles
    108 	// list only (no tag-ignored files, tests, swig or other non-Go files).
    109 	include := func(info os.FileInfo) bool {
    110 		for _, name := range pkg.GoFiles {
    111 			if name == info.Name() {
    112 				return true
    113 			}
    114 		}
    115 		for _, name := range pkg.CgoFiles {
    116 			if name == info.Name() {
    117 				return true
    118 			}
    119 		}
    120 		return false
    121 	}
    122 	pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments)
    123 	if err != nil {
    124 		log.Fatal(err)
    125 	}
    126 	// Make sure they are all in one package.
    127 	if len(pkgs) != 1 {
    128 		log.Fatalf("multiple packages in directory %s", pkg.Dir)
    129 	}
    130 	astPkg := pkgs[pkg.Name]
    131 
    132 	// TODO: go/doc does not include typed constants in the constants
    133 	// list, which is what we want. For instance, time.Sunday is of type
    134 	// time.Weekday, so it is defined in the type but not in the
    135 	// Consts list for the package. This prevents
    136 	//	go doc time.Sunday
    137 	// from finding the symbol. Work around this for now, but we
    138 	// should fix it in go/doc.
    139 	// A similar story applies to factory functions.
    140 	docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls)
    141 	for _, typ := range docPkg.Types {
    142 		docPkg.Consts = append(docPkg.Consts, typ.Consts...)
    143 		docPkg.Vars = append(docPkg.Vars, typ.Vars...)
    144 		docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
    145 	}
    146 
    147 	return &Package{
    148 		writer:   writer,
    149 		name:     pkg.Name,
    150 		userPath: userPath,
    151 		pkg:      astPkg,
    152 		file:     ast.MergePackageFiles(astPkg, 0),
    153 		doc:      docPkg,
    154 		build:    pkg,
    155 		fs:       fs,
    156 	}
    157 }
    158 
    159 func (pkg *Package) Printf(format string, args ...interface{}) {
    160 	fmt.Fprintf(&pkg.buf, format, args...)
    161 }
    162 
    163 func (pkg *Package) flush() {
    164 	_, err := pkg.writer.Write(pkg.buf.Bytes())
    165 	if err != nil {
    166 		log.Fatal(err)
    167 	}
    168 	pkg.buf.Reset() // Not needed, but it's a flush.
    169 }
    170 
    171 var newlineBytes = []byte("\n\n") // We never ask for more than 2.
    172 
    173 // newlines guarantees there are n newlines at the end of the buffer.
    174 func (pkg *Package) newlines(n int) {
    175 	for !bytes.HasSuffix(pkg.buf.Bytes(), newlineBytes[:n]) {
    176 		pkg.buf.WriteRune('\n')
    177 	}
    178 }
    179 
    180 // emit prints the node.
    181 func (pkg *Package) emit(comment string, node ast.Node) {
    182 	if node != nil {
    183 		err := format.Node(&pkg.buf, pkg.fs, node)
    184 		if err != nil {
    185 			log.Fatal(err)
    186 		}
    187 		if comment != "" {
    188 			pkg.newlines(1)
    189 			doc.ToText(&pkg.buf, comment, "    ", indent, indentedWidth)
    190 			pkg.newlines(2) // Blank line after comment to separate from next item.
    191 		} else {
    192 			pkg.newlines(1)
    193 		}
    194 	}
    195 }
    196 
    197 // oneLineNode returns a one-line summary of the given input node.
    198 func (pkg *Package) oneLineNode(node ast.Node) string {
    199 	const maxDepth = 10
    200 	return pkg.oneLineNodeDepth(node, maxDepth)
    201 }
    202 
    203 // oneLineNodeDepth returns a one-line summary of the given input node.
    204 // The depth specifies the maximum depth when traversing the AST.
    205 func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
    206 	const dotDotDot = "..."
    207 	if depth == 0 {
    208 		return dotDotDot
    209 	}
    210 	depth--
    211 
    212 	switch n := node.(type) {
    213 	case nil:
    214 		return ""
    215 
    216 	case *ast.GenDecl:
    217 		// Formats const and var declarations.
    218 		trailer := ""
    219 		if len(n.Specs) > 1 {
    220 			trailer = " " + dotDotDot
    221 		}
    222 
    223 		// Find the first relevant spec.
    224 		typ := ""
    225 		for i, spec := range n.Specs {
    226 			valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one GenDecl.
    227 
    228 			// The type name may carry over from a previous specification in the
    229 			// case of constants and iota.
    230 			if valueSpec.Type != nil {
    231 				typ = fmt.Sprintf(" %s", pkg.oneLineNodeDepth(valueSpec.Type, depth))
    232 			} else if len(valueSpec.Values) > 0 {
    233 				typ = ""
    234 			}
    235 
    236 			if !isExported(valueSpec.Names[0].Name) {
    237 				continue
    238 			}
    239 			val := ""
    240 			if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
    241 				val = fmt.Sprintf(" = %s", pkg.oneLineNodeDepth(valueSpec.Values[i], depth))
    242 			}
    243 			return fmt.Sprintf("%s %s%s%s%s", n.Tok, valueSpec.Names[0], typ, val, trailer)
    244 		}
    245 		return ""
    246 
    247 	case *ast.FuncDecl:
    248 		// Formats func declarations.
    249 		name := n.Name.Name
    250 		recv := pkg.oneLineNodeDepth(n.Recv, depth)
    251 		if len(recv) > 0 {
    252 			recv = "(" + recv + ") "
    253 		}
    254 		fnc := pkg.oneLineNodeDepth(n.Type, depth)
    255 		if strings.Index(fnc, "func") == 0 {
    256 			fnc = fnc[4:]
    257 		}
    258 		return fmt.Sprintf("func %s%s%s", recv, name, fnc)
    259 
    260 	case *ast.TypeSpec:
    261 		return fmt.Sprintf("type %s %s", n.Name.Name, pkg.oneLineNodeDepth(n.Type, depth))
    262 
    263 	case *ast.FuncType:
    264 		var params []string
    265 		if n.Params != nil {
    266 			for _, field := range n.Params.List {
    267 				params = append(params, pkg.oneLineField(field, depth))
    268 			}
    269 		}
    270 		needParens := false
    271 		var results []string
    272 		if n.Results != nil {
    273 			needParens = needParens || len(n.Results.List) > 1
    274 			for _, field := range n.Results.List {
    275 				needParens = needParens || len(field.Names) > 0
    276 				results = append(results, pkg.oneLineField(field, depth))
    277 			}
    278 		}
    279 
    280 		param := strings.Join(params, ", ")
    281 		if len(results) == 0 {
    282 			return fmt.Sprintf("func(%s)", param)
    283 		}
    284 		result := strings.Join(results, ", ")
    285 		if !needParens {
    286 			return fmt.Sprintf("func(%s) %s", param, result)
    287 		}
    288 		return fmt.Sprintf("func(%s) (%s)", param, result)
    289 
    290 	case *ast.StructType:
    291 		if n.Fields == nil || len(n.Fields.List) == 0 {
    292 			return "struct{}"
    293 		}
    294 		return "struct{ ... }"
    295 
    296 	case *ast.InterfaceType:
    297 		if n.Methods == nil || len(n.Methods.List) == 0 {
    298 			return "interface{}"
    299 		}
    300 		return "interface{ ... }"
    301 
    302 	case *ast.FieldList:
    303 		if n == nil || len(n.List) == 0 {
    304 			return ""
    305 		}
    306 		if len(n.List) == 1 {
    307 			return pkg.oneLineField(n.List[0], depth)
    308 		}
    309 		return dotDotDot
    310 
    311 	case *ast.FuncLit:
    312 		return pkg.oneLineNodeDepth(n.Type, depth) + " { ... }"
    313 
    314 	case *ast.CompositeLit:
    315 		typ := pkg.oneLineNodeDepth(n.Type, depth)
    316 		if len(n.Elts) == 0 {
    317 			return fmt.Sprintf("%s{}", typ)
    318 		}
    319 		return fmt.Sprintf("%s{ %s }", typ, dotDotDot)
    320 
    321 	case *ast.ArrayType:
    322 		length := pkg.oneLineNodeDepth(n.Len, depth)
    323 		element := pkg.oneLineNodeDepth(n.Elt, depth)
    324 		return fmt.Sprintf("[%s]%s", length, element)
    325 
    326 	case *ast.MapType:
    327 		key := pkg.oneLineNodeDepth(n.Key, depth)
    328 		value := pkg.oneLineNodeDepth(n.Value, depth)
    329 		return fmt.Sprintf("map[%s]%s", key, value)
    330 
    331 	case *ast.CallExpr:
    332 		fnc := pkg.oneLineNodeDepth(n.Fun, depth)
    333 		var args []string
    334 		for _, arg := range n.Args {
    335 			args = append(args, pkg.oneLineNodeDepth(arg, depth))
    336 		}
    337 		return fmt.Sprintf("%s(%s)", fnc, strings.Join(args, ", "))
    338 
    339 	case *ast.UnaryExpr:
    340 		return fmt.Sprintf("%s%s", n.Op, pkg.oneLineNodeDepth(n.X, depth))
    341 
    342 	case *ast.Ident:
    343 		return n.Name
    344 
    345 	default:
    346 		// As a fallback, use default formatter for all unknown node types.
    347 		buf := new(bytes.Buffer)
    348 		format.Node(buf, pkg.fs, node)
    349 		s := buf.String()
    350 		if strings.Contains(s, "\n") {
    351 			return dotDotDot
    352 		}
    353 		return s
    354 	}
    355 }
    356 
    357 // oneLineField returns a one-line summary of the field.
    358 func (pkg *Package) oneLineField(field *ast.Field, depth int) string {
    359 	var names []string
    360 	for _, name := range field.Names {
    361 		names = append(names, name.Name)
    362 	}
    363 	if len(names) == 0 {
    364 		return pkg.oneLineNodeDepth(field.Type, depth)
    365 	}
    366 	return strings.Join(names, ", ") + " " + pkg.oneLineNodeDepth(field.Type, depth)
    367 }
    368 
    369 // packageDoc prints the docs for the package (package doc plus one-liners of the rest).
    370 func (pkg *Package) packageDoc() {
    371 	defer pkg.flush()
    372 	if pkg.showInternals() {
    373 		pkg.packageClause(false)
    374 	}
    375 
    376 	doc.ToText(&pkg.buf, pkg.doc.Doc, "", indent, indentedWidth)
    377 	pkg.newlines(1)
    378 
    379 	if !pkg.showInternals() {
    380 		// Show only package docs for commands.
    381 		return
    382 	}
    383 
    384 	pkg.newlines(2) // Guarantee blank line before the components.
    385 	pkg.valueSummary(pkg.doc.Consts, false)
    386 	pkg.valueSummary(pkg.doc.Vars, false)
    387 	pkg.funcSummary(pkg.doc.Funcs, false)
    388 	pkg.typeSummary()
    389 	pkg.bugs()
    390 }
    391 
    392 // showInternals reports whether we should show the internals
    393 // of a package as opposed to just the package docs.
    394 // Used to decide whether to suppress internals for commands.
    395 // Called only by Package.packageDoc.
    396 func (pkg *Package) showInternals() bool {
    397 	return pkg.pkg.Name != "main" || showCmd
    398 }
    399 
    400 // packageClause prints the package clause.
    401 // The argument boolean, if true, suppresses the output if the
    402 // user's argument is identical to the actual package path or
    403 // is empty, meaning it's the current directory.
    404 func (pkg *Package) packageClause(checkUserPath bool) {
    405 	if checkUserPath {
    406 		if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
    407 			return
    408 		}
    409 	}
    410 	importPath := pkg.build.ImportComment
    411 	if importPath == "" {
    412 		importPath = pkg.build.ImportPath
    413 	}
    414 	pkg.Printf("package %s // import %q\n\n", pkg.name, importPath)
    415 	if importPath != pkg.build.ImportPath {
    416 		pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
    417 	}
    418 }
    419 
    420 // valueSummary prints a one-line summary for each set of values and constants.
    421 // If all the types in a constant or variable declaration belong to the same
    422 // type they can be printed by typeSummary, and so can be suppressed here.
    423 func (pkg *Package) valueSummary(values []*doc.Value, showGrouped bool) {
    424 	var isGrouped map[*doc.Value]bool
    425 	if !showGrouped {
    426 		isGrouped = make(map[*doc.Value]bool)
    427 		for _, typ := range pkg.doc.Types {
    428 			if !isExported(typ.Name) {
    429 				continue
    430 			}
    431 			for _, c := range typ.Consts {
    432 				isGrouped[c] = true
    433 			}
    434 			for _, v := range typ.Vars {
    435 				isGrouped[v] = true
    436 			}
    437 		}
    438 	}
    439 
    440 	for _, value := range values {
    441 		if !isGrouped[value] {
    442 			if decl := pkg.oneLineNode(value.Decl); decl != "" {
    443 				pkg.Printf("%s\n", decl)
    444 			}
    445 		}
    446 	}
    447 }
    448 
    449 // funcSummary prints a one-line summary for each function. Constructors
    450 // are printed by typeSummary, below, and so can be suppressed here.
    451 func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
    452 	// First, identify the constructors. Don't bother figuring out if they're exported.
    453 	var isConstructor map[*doc.Func]bool
    454 	if !showConstructors {
    455 		isConstructor = make(map[*doc.Func]bool)
    456 		for _, typ := range pkg.doc.Types {
    457 			if isExported(typ.Name) {
    458 				for _, f := range typ.Funcs {
    459 					isConstructor[f] = true
    460 				}
    461 			}
    462 		}
    463 	}
    464 	for _, fun := range funcs {
    465 		// Exported functions only. The go/doc package does not include methods here.
    466 		if isExported(fun.Name) {
    467 			if !isConstructor[fun] {
    468 				pkg.Printf("%s\n", pkg.oneLineNode(fun.Decl))
    469 			}
    470 		}
    471 	}
    472 }
    473 
    474 // typeSummary prints a one-line summary for each type, followed by its constructors.
    475 func (pkg *Package) typeSummary() {
    476 	for _, typ := range pkg.doc.Types {
    477 		for _, spec := range typ.Decl.Specs {
    478 			typeSpec := spec.(*ast.TypeSpec) // Must succeed.
    479 			if isExported(typeSpec.Name.Name) {
    480 				pkg.Printf("%s\n", pkg.oneLineNode(typeSpec))
    481 				// Now print the consts, vars, and constructors.
    482 				for _, c := range typ.Consts {
    483 					if decl := pkg.oneLineNode(c.Decl); decl != "" {
    484 						pkg.Printf(indent+"%s\n", decl)
    485 					}
    486 				}
    487 				for _, v := range typ.Vars {
    488 					if decl := pkg.oneLineNode(v.Decl); decl != "" {
    489 						pkg.Printf(indent+"%s\n", decl)
    490 					}
    491 				}
    492 				for _, constructor := range typ.Funcs {
    493 					if isExported(constructor.Name) {
    494 						pkg.Printf(indent+"%s\n", pkg.oneLineNode(constructor.Decl))
    495 					}
    496 				}
    497 			}
    498 		}
    499 	}
    500 }
    501 
    502 // bugs prints the BUGS information for the package.
    503 // TODO: Provide access to TODOs and NOTEs as well (very noisy so off by default)?
    504 func (pkg *Package) bugs() {
    505 	if pkg.doc.Notes["BUG"] == nil {
    506 		return
    507 	}
    508 	pkg.Printf("\n")
    509 	for _, note := range pkg.doc.Notes["BUG"] {
    510 		pkg.Printf("%s: %v\n", "BUG", note.Body)
    511 	}
    512 }
    513 
    514 // findValues finds the doc.Values that describe the symbol.
    515 func (pkg *Package) findValues(symbol string, docValues []*doc.Value) (values []*doc.Value) {
    516 	for _, value := range docValues {
    517 		for _, name := range value.Names {
    518 			if match(symbol, name) {
    519 				values = append(values, value)
    520 			}
    521 		}
    522 	}
    523 	return
    524 }
    525 
    526 // findFuncs finds the doc.Funcs that describes the symbol.
    527 func (pkg *Package) findFuncs(symbol string) (funcs []*doc.Func) {
    528 	for _, fun := range pkg.doc.Funcs {
    529 		if match(symbol, fun.Name) {
    530 			funcs = append(funcs, fun)
    531 		}
    532 	}
    533 	return
    534 }
    535 
    536 // findTypes finds the doc.Types that describes the symbol.
    537 // If symbol is empty, it finds all exported types.
    538 func (pkg *Package) findTypes(symbol string) (types []*doc.Type) {
    539 	for _, typ := range pkg.doc.Types {
    540 		if symbol == "" && isExported(typ.Name) || match(symbol, typ.Name) {
    541 			types = append(types, typ)
    542 		}
    543 	}
    544 	return
    545 }
    546 
    547 // findTypeSpec returns the ast.TypeSpec within the declaration that defines the symbol.
    548 // The name must match exactly.
    549 func (pkg *Package) findTypeSpec(decl *ast.GenDecl, symbol string) *ast.TypeSpec {
    550 	for _, spec := range decl.Specs {
    551 		typeSpec := spec.(*ast.TypeSpec) // Must succeed.
    552 		if symbol == typeSpec.Name.Name {
    553 			return typeSpec
    554 		}
    555 	}
    556 	return nil
    557 }
    558 
    559 // symbolDoc prints the docs for symbol. There may be multiple matches.
    560 // If symbol matches a type, output includes its methods factories and associated constants.
    561 // If there is no top-level symbol, symbolDoc looks for methods that match.
    562 func (pkg *Package) symbolDoc(symbol string) bool {
    563 	defer pkg.flush()
    564 	found := false
    565 	// Functions.
    566 	for _, fun := range pkg.findFuncs(symbol) {
    567 		if !found {
    568 			pkg.packageClause(true)
    569 		}
    570 		// Symbol is a function.
    571 		decl := fun.Decl
    572 		decl.Body = nil
    573 		pkg.emit(fun.Doc, decl)
    574 		found = true
    575 	}
    576 	// Constants and variables behave the same.
    577 	values := pkg.findValues(symbol, pkg.doc.Consts)
    578 	values = append(values, pkg.findValues(symbol, pkg.doc.Vars)...)
    579 	for _, value := range values {
    580 		// Print each spec only if there is at least one exported symbol in it.
    581 		// (See issue 11008.)
    582 		// TODO: Should we elide unexported symbols from a single spec?
    583 		// It's an unlikely scenario, probably not worth the trouble.
    584 		// TODO: Would be nice if go/doc did this for us.
    585 		specs := make([]ast.Spec, 0, len(value.Decl.Specs))
    586 		var typ ast.Expr
    587 		for _, spec := range value.Decl.Specs {
    588 			vspec := spec.(*ast.ValueSpec)
    589 
    590 			// The type name may carry over from a previous specification in the
    591 			// case of constants and iota.
    592 			if vspec.Type != nil {
    593 				typ = vspec.Type
    594 			}
    595 
    596 			for _, ident := range vspec.Names {
    597 				if isExported(ident.Name) {
    598 					if vspec.Type == nil && vspec.Values == nil && typ != nil {
    599 						// This a standalone identifier, as in the case of iota usage.
    600 						// Thus, assume the type comes from the previous type.
    601 						vspec.Type = &ast.Ident{
    602 							Name:    string(pkg.oneLineNode(typ)),
    603 							NamePos: vspec.End() - 1,
    604 						}
    605 					}
    606 
    607 					specs = append(specs, vspec)
    608 					typ = nil // Only inject type on first exported identifier
    609 					break
    610 				}
    611 			}
    612 		}
    613 		if len(specs) == 0 {
    614 			continue
    615 		}
    616 		value.Decl.Specs = specs
    617 		if !found {
    618 			pkg.packageClause(true)
    619 		}
    620 		pkg.emit(value.Doc, value.Decl)
    621 		found = true
    622 	}
    623 	// Types.
    624 	for _, typ := range pkg.findTypes(symbol) {
    625 		if !found {
    626 			pkg.packageClause(true)
    627 		}
    628 		decl := typ.Decl
    629 		spec := pkg.findTypeSpec(decl, typ.Name)
    630 		trimUnexportedElems(spec)
    631 		// If there are multiple types defined, reduce to just this one.
    632 		if len(decl.Specs) > 1 {
    633 			decl.Specs = []ast.Spec{spec}
    634 		}
    635 		pkg.emit(typ.Doc, decl)
    636 		// Show associated methods, constants, etc.
    637 		if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
    638 			pkg.Printf("\n")
    639 		}
    640 		pkg.valueSummary(typ.Consts, true)
    641 		pkg.valueSummary(typ.Vars, true)
    642 		pkg.funcSummary(typ.Funcs, true)
    643 		pkg.funcSummary(typ.Methods, true)
    644 		found = true
    645 	}
    646 	if !found {
    647 		// See if there are methods.
    648 		if !pkg.printMethodDoc("", symbol) {
    649 			return false
    650 		}
    651 	}
    652 	return true
    653 }
    654 
    655 // trimUnexportedElems modifies spec in place to elide unexported fields from
    656 // structs and methods from interfaces (unless the unexported flag is set).
    657 func trimUnexportedElems(spec *ast.TypeSpec) {
    658 	if unexported {
    659 		return
    660 	}
    661 	switch typ := spec.Type.(type) {
    662 	case *ast.StructType:
    663 		typ.Fields = trimUnexportedFields(typ.Fields, false)
    664 	case *ast.InterfaceType:
    665 		typ.Methods = trimUnexportedFields(typ.Methods, true)
    666 	}
    667 }
    668 
    669 // trimUnexportedFields returns the field list trimmed of unexported fields.
    670 func trimUnexportedFields(fields *ast.FieldList, isInterface bool) *ast.FieldList {
    671 	what := "methods"
    672 	if !isInterface {
    673 		what = "fields"
    674 	}
    675 
    676 	trimmed := false
    677 	list := make([]*ast.Field, 0, len(fields.List))
    678 	for _, field := range fields.List {
    679 		names := field.Names
    680 		if len(names) == 0 {
    681 			// Embedded type. Use the name of the type. It must be of type ident or *ident.
    682 			// Nothing else is allowed.
    683 			switch ident := field.Type.(type) {
    684 			case *ast.Ident:
    685 				if isInterface && ident.Name == "error" && ident.Obj == nil {
    686 					// For documentation purposes, we consider the builtin error
    687 					// type special when embedded in an interface, such that it
    688 					// always gets shown publicly.
    689 					list = append(list, field)
    690 					continue
    691 				}
    692 				names = []*ast.Ident{ident}
    693 			case *ast.StarExpr:
    694 				// Must have the form *identifier.
    695 				// This is only valid on embedded types in structs.
    696 				if ident, ok := ident.X.(*ast.Ident); ok && !isInterface {
    697 					names = []*ast.Ident{ident}
    698 				}
    699 			case *ast.SelectorExpr:
    700 				// An embedded type may refer to a type in another package.
    701 				names = []*ast.Ident{ident.Sel}
    702 			}
    703 			if names == nil {
    704 				// Can only happen if AST is incorrect. Safe to continue with a nil list.
    705 				log.Print("invalid program: unexpected type for embedded field")
    706 			}
    707 		}
    708 		// Trims if any is unexported. Good enough in practice.
    709 		ok := true
    710 		for _, name := range names {
    711 			if !isExported(name.Name) {
    712 				trimmed = true
    713 				ok = false
    714 				break
    715 			}
    716 		}
    717 		if ok {
    718 			list = append(list, field)
    719 		}
    720 	}
    721 	if !trimmed {
    722 		return fields
    723 	}
    724 	unexportedField := &ast.Field{
    725 		Type: &ast.Ident{
    726 			// Hack: printer will treat this as a field with a named type.
    727 			// Setting Name and NamePos to ("", fields.Closing-1) ensures that
    728 			// when Pos and End are called on this field, they return the
    729 			// position right before closing '}' character.
    730 			Name:    "",
    731 			NamePos: fields.Closing - 1,
    732 		},
    733 		Comment: &ast.CommentGroup{
    734 			List: []*ast.Comment{{Text: fmt.Sprintf("// Has unexported %s.\n", what)}},
    735 		},
    736 	}
    737 	return &ast.FieldList{
    738 		Opening: fields.Opening,
    739 		List:    append(list, unexportedField),
    740 		Closing: fields.Closing,
    741 	}
    742 }
    743 
    744 // printMethodDoc prints the docs for matches of symbol.method.
    745 // If symbol is empty, it prints all methods that match the name.
    746 // It reports whether it found any methods.
    747 func (pkg *Package) printMethodDoc(symbol, method string) bool {
    748 	defer pkg.flush()
    749 	types := pkg.findTypes(symbol)
    750 	if types == nil {
    751 		if symbol == "" {
    752 			return false
    753 		}
    754 		pkg.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
    755 	}
    756 	found := false
    757 	for _, typ := range types {
    758 		if len(typ.Methods) > 0 {
    759 			for _, meth := range typ.Methods {
    760 				if match(method, meth.Name) {
    761 					decl := meth.Decl
    762 					decl.Body = nil
    763 					pkg.emit(meth.Doc, decl)
    764 					found = true
    765 				}
    766 			}
    767 			continue
    768 		}
    769 		// Type may be an interface. The go/doc package does not attach
    770 		// an interface's methods to the doc.Type. We need to dig around.
    771 		spec := pkg.findTypeSpec(typ.Decl, typ.Name)
    772 		inter, ok := spec.Type.(*ast.InterfaceType)
    773 		if !ok {
    774 			// Not an interface type.
    775 			// TODO? Maybe handle struct fields here.
    776 			continue
    777 		}
    778 		for _, iMethod := range inter.Methods.List {
    779 			// This is an interface, so there can be only one name.
    780 			// TODO: Anonymous methods (embedding)
    781 			if len(iMethod.Names) == 0 {
    782 				continue
    783 			}
    784 			name := iMethod.Names[0].Name
    785 			if match(method, name) {
    786 				// pkg.oneLineField(iMethod, 0)
    787 				if iMethod.Doc != nil {
    788 					for _, comment := range iMethod.Doc.List {
    789 						doc.ToText(&pkg.buf, comment.Text, "", indent, indentedWidth)
    790 					}
    791 				}
    792 				s := pkg.oneLineNode(iMethod.Type)
    793 				// Hack: s starts "func" but there is no name present.
    794 				// We could instead build a FuncDecl but it's not worthwhile.
    795 				lineComment := ""
    796 				if iMethod.Comment != nil {
    797 					lineComment = fmt.Sprintf("  %s", iMethod.Comment.List[0].Text)
    798 				}
    799 				pkg.Printf("func %s%s%s\n", name, s[4:], lineComment)
    800 				found = true
    801 			}
    802 		}
    803 	}
    804 	return found
    805 }
    806 
    807 // methodDoc prints the docs for matches of symbol.method.
    808 func (pkg *Package) methodDoc(symbol, method string) bool {
    809 	defer pkg.flush()
    810 	return pkg.printMethodDoc(symbol, method)
    811 }
    812 
    813 // match reports whether the user's symbol matches the program's.
    814 // A lower-case character in the user's string matches either case in the program's.
    815 // The program string must be exported.
    816 func match(user, program string) bool {
    817 	if !isExported(program) {
    818 		return false
    819 	}
    820 	if matchCase {
    821 		return user == program
    822 	}
    823 	for _, u := range user {
    824 		p, w := utf8.DecodeRuneInString(program)
    825 		program = program[w:]
    826 		if u == p {
    827 			continue
    828 		}
    829 		if unicode.IsLower(u) && simpleFold(u) == simpleFold(p) {
    830 			continue
    831 		}
    832 		return false
    833 	}
    834 	return program == ""
    835 }
    836 
    837 // simpleFold returns the minimum rune equivalent to r
    838 // under Unicode-defined simple case folding.
    839 func simpleFold(r rune) rune {
    840 	for {
    841 		r1 := unicode.SimpleFold(r)
    842 		if r1 <= r {
    843 			return r1 // wrapped around, found min
    844 		}
    845 		r = r1
    846 	}
    847 }
    848