Commit 294d16c9 authored by Rob Pike's avatar Rob Pike

cmd/doc: add a -src flag to show original source

It's long-desired but was blocked by #26835. That is now fixed, so
it's easy. When -src is off, we behave as before. But with -src
set, initialize the go/doc package to preserve the original AST and
things flow very easily.

With -src, since you're seeing inside the package source anyway it
shows unexported fields and constants: you see the original source.
But you still need -u to ask about them.

Fixes #18807

Change-Id: I473e90323b4eff0735360274dc0d2d9dba16ff8b
Reviewed-on: https://go-review.googlesource.com/c/140959Reviewed-by: 's avatarAndrew Gerrand <adg@golang.org>
Run-TryBot: Andrew Gerrand <adg@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent d5e72203
This diff is collapsed.
......@@ -28,6 +28,9 @@
// For commands, unless the -cmd flag is present "go doc command"
// shows only the package-level docs for the package.
//
// The -src flag causes doc to print the full source code for the symbol, such
// as the body of a struct, function or method.
//
// For complete documentation, run "go help doc".
package main
......@@ -50,6 +53,7 @@ var (
unexported bool // -u flag
matchCase bool // -c flag
showCmd bool // -cmd flag
showSrc bool // -src flag
)
// usage is a replacement usage function for the flags package.
......@@ -85,6 +89,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
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(&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.Parse(args)
var paths []string
var symbol, method string
......
......@@ -137,7 +137,11 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
// from finding the symbol. Work around this for now, but we
// should fix it in go/doc.
// A similar story applies to factory functions.
docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls)
mode := doc.AllDecls
if showSrc {
mode |= doc.PreserveAST // See comment for Package.emit.
}
docPkg := doc.New(astPkg, pkg.ImportPath, mode)
for _, typ := range docPkg.Types {
docPkg.Consts = append(docPkg.Consts, typ.Consts...)
docPkg.Vars = append(docPkg.Vars, typ.Vars...)
......@@ -177,14 +181,16 @@ func (pkg *Package) newlines(n int) {
}
}
// emit prints the node.
// emit prints the node. If showSrc is true, it ignores the provided comment,
// assuming the comment is in the node itself. Otherwise, the go/doc package
// clears the stuff we don't want to print anyway. It's a bit of a magic trick.
func (pkg *Package) emit(comment string, node ast.Node) {
if node != nil {
err := format.Node(&pkg.buf, pkg.fs, node)
if err != nil {
log.Fatal(err)
}
if comment != "" {
if comment != "" && !showSrc {
pkg.newlines(1)
doc.ToText(&pkg.buf, comment, " ", indent, indentedWidth)
pkg.newlines(2) // Blank line after comment to separate from next item.
......@@ -611,7 +617,6 @@ func (pkg *Package) symbolDoc(symbol string) bool {
}
// Symbol is a function.
decl := fun.Decl
decl.Body = nil
pkg.emit(fun.Doc, decl)
found = true
}
......@@ -641,7 +646,7 @@ func (pkg *Package) symbolDoc(symbol string) bool {
}
for _, ident := range vspec.Names {
if isExported(ident.Name) {
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.
......@@ -701,9 +706,10 @@ func (pkg *Package) symbolDoc(symbol string) bool {
}
// trimUnexportedElems modifies spec in place to elide unexported fields from
// structs and methods from interfaces (unless the unexported flag is set).
// structs and methods from interfaces (unless the unexported flag is set or we
// are asked to show the original source).
func trimUnexportedElems(spec *ast.TypeSpec) {
if unexported {
if unexported || showSrc {
return
}
switch typ := spec.Type.(type) {
......@@ -808,7 +814,6 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
for _, meth := range typ.Methods {
if match(method, meth.Name) {
decl := meth.Decl
decl.Body = nil
pkg.emit(meth.Doc, decl)
found = true
}
......
......@@ -5,6 +5,8 @@
// Package comment.
package pkg
import "io"
// Constants
// Comment about exported constant.
......@@ -52,7 +54,9 @@ var (
)
// Comment about exported function.
func ExportedFunc(a int) bool
func ExportedFunc(a int) bool {
return true != false
}
// Comment about internal function.
func internalFunc(a int) bool
......@@ -73,7 +77,7 @@ type ExportedType struct {
// Comment about exported method.
func (ExportedType) ExportedMethod(a int) bool {
return true
return true != true
}
// Comment about unexported method.
......
......@@ -348,6 +348,13 @@
// Treat a command (package main) like a regular package.
// Otherwise package main's exported symbols are hidden
// when showing the package's top-level documentation.
// -src
// Show the full source code for the symbol. This will
// display the full Go source of its declaration and
// definition, such as a function definition (including
// the body), type declaration or enclosing const
// block. The output may therefore include unexported
// details.
// -u
// Show documentation for unexported as well as exported
// symbols, methods, and fields.
......
......@@ -112,6 +112,13 @@ Flags:
Treat a command (package main) like a regular package.
Otherwise package main's exported symbols are hidden
when showing the package's top-level documentation.
-src
Show the full source code for the symbol. This will
display the full Go source of its declaration and
definition, such as a function definition (including
the body), type declaration or enclosing const
block. The output may therefore include unexported
details.
-u
Show documentation for unexported as well as exported
symbols, methods, and fields.
......
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