From: Rob Pike Date: Wed, 22 Mar 2017 03:27:47 +0000 (-0700) Subject: cmd/doc: implement "go doc struct.field" X-Git-Tag: go1.9beta1~1050 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2c47c3e22e0d4f238a844da6904ce4e98bb4efd1;p=gostls13.git cmd/doc: implement "go doc struct.field" By analogy with the handling of methods on types, show the documentation for a single field of a struct. % go doc ast.structtype.fields struct StructType { Fields *FieldList // list of field declarations } % Fixes #19169. Change-Id: I002f992e4aa64bee667e2e4bccc7082486149842 Reviewed-on: https://go-review.googlesource.com/38438 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go index 454a0d6415..e534bfead3 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/doc/doc_test.go @@ -390,6 +390,29 @@ var tests = []test{ nil, }, + // Field. + { + "field", + []string{p, `ExportedType.ExportedField`}, + []string{ + `ExportedField int`, + `Comment before exported field.`, + `Comment on line with exported field.`, + }, + nil, + }, + + // Field with -u. + { + "method with -u", + []string{"-u", p, `ExportedType.unexportedField`}, + []string{ + `unexportedField int`, + `Comment on line with unexported field.`, + }, + nil, + }, + // Case matching off. { "case matching off", diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go index df1890fe71..76c7dba2d9 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/doc/main.go @@ -10,18 +10,18 @@ // // One argument: // go doc -// go doc [.] -// go doc [.][.] -// go doc [.][.] +// go doc [.] +// go doc [.][.] +// go doc [.][.] // The first item in this list that succeeds is the one whose documentation // is printed. If there is a symbol but no package, the package in the current // directory is chosen. However, if the argument begins with a capital // letter it is always assumed to be a symbol in the current directory. // // Two arguments: -// go doc [.] +// go doc [.] // -// Show the documentation for the package, symbol, and method. The +// Show the documentation for the package, symbol, and method or field. The // first argument must be a full package path. This is similar to the // command-line usage for the godoc command. // @@ -129,6 +129,9 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { if pkg.methodDoc(symbol, method) { return } + if pkg.fieldDoc(symbol, method) { + return + } } } } @@ -149,7 +152,7 @@ func failMessage(paths []string, symbol, method string) error { if method == "" { return fmt.Errorf("no symbol %s in package%s", symbol, &b) } - return fmt.Errorf("no method %s.%s in package%s", symbol, method, &b) + return fmt.Errorf("no method or field %s.%s in package%s", symbol, method, &b) } // parseArgs analyzes the arguments (if any) and returns the package diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index b59fcbbd03..7b0f9de775 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -790,7 +790,6 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool { inter, ok := spec.Type.(*ast.InterfaceType) if !ok { // Not an interface type. - // TODO? Maybe handle struct fields here. continue } for _, iMethod := range inter.Methods.List { @@ -821,12 +820,68 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool { return found } +// printFieldDoc prints the docs for matches of symbol.fieldName. +// It reports whether it found any field. +// Both symbol and fieldName must be non-empty or it returns false. +func (pkg *Package) printFieldDoc(symbol, fieldName string) bool { + if symbol == "" || fieldName == "" { + return false + } + defer pkg.flush() + types := pkg.findTypes(symbol) + if types == nil { + pkg.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 { + // Type must be a struct. + spec := pkg.findTypeSpec(typ.Decl, typ.Name) + structType, ok := spec.Type.(*ast.StructType) + if !ok { + // Not a struct type. + continue + } + for _, field := range structType.Fields.List { + // TODO: Anonymous fields. + for _, name := range field.Names { + if match(fieldName, name.Name) { + if !found { + pkg.Printf("struct %s {\n", typ.Name) + } + if field.Doc != nil { + for _, comment := range field.Doc.List { + doc.ToText(&pkg.buf, comment.Text, indent, indent, indentedWidth) + } + } + s := pkg.oneLineNode(field.Type) + lineComment := "" + if field.Comment != nil { + lineComment = fmt.Sprintf(" %s", field.Comment.List[0].Text) + } + pkg.Printf("%s%s %s%s\n", indent, name, s, lineComment) + found = true + } + } + } + } + if found { + pkg.Printf("}\n") + } + return found +} + // methodDoc prints the docs for matches of symbol.method. func (pkg *Package) methodDoc(symbol, method string) bool { defer pkg.flush() return pkg.printMethodDoc(symbol, method) } +// fieldDoc prints the docs for matches of symbol.field. +func (pkg *Package) fieldDoc(symbol, field string) bool { + defer pkg.flush() + return pkg.printFieldDoc(symbol, field) +} + // match reports whether the user's symbol matches the program's. // A lower-case character in the user's string matches either case in the program's. // The program string must be exported. diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 5b768900b1..b650e3cce0 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -209,12 +209,13 @@ // // Usage: // -// go doc [-u] [-c] [package|[package.]symbol[.method]] +// go doc [-u] [-c] [package|[package.]symbol[.methodOrField]] // // Doc prints the documentation comments associated with the item identified by its -// arguments (a package, const, func, type, var, or method) followed by a one-line -// summary of each of the first-level items "under" that item (package-level -// declarations for a package, methods for a type, etc.). +// arguments (a package, const, func, type, var, method, or struct field) +// followed by a one-line summary of each of the first-level items "under" +// that item (package-level declarations for a package, methods for a type, +// etc.). // // Doc accepts zero, one, or two arguments. // @@ -232,9 +233,9 @@ // which is schematically one of these: // // go doc -// go doc [.] -// go doc [.][.] -// go doc [.][.] +// go doc [.] +// go doc [.][.] +// go doc [.][.] // // The first item in this list matched by the argument is the one whose documentation // is printed. (See the examples below.) However, if the argument starts with a capital @@ -254,10 +255,10 @@ // elements like . and ... are not implemented by go doc. // // When run with two arguments, the first must be a full package path (not just a -// suffix), and the second is a symbol or symbol and method; this is similar to the -// syntax accepted by godoc: +// suffix), and the second is a symbol, or symbol with method or struct field. +// This is similar to the syntax accepted by godoc: // -// go doc [.] +// go doc [.] // // In all forms, when matching symbols, lower-case letters in the argument match // either case but upper-case letters match exactly. This means that there may be @@ -308,7 +309,7 @@ // when showing the package's top-level documentation. // -u // Show documentation for unexported as well as exported -// symbols and methods. +// symbols, methods, and fields. // // // Print Go environment information diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go index 66ff07615e..e7e116af7e 100644 --- a/src/cmd/go/internal/doc/doc.go +++ b/src/cmd/go/internal/doc/doc.go @@ -12,14 +12,15 @@ import ( var CmdDoc = &base.Command{ Run: runDoc, - UsageLine: "doc [-u] [-c] [package|[package.]symbol[.method]]", + UsageLine: "doc [-u] [-c] [package|[package.]symbol[.methodOrField]]", CustomFlags: true, Short: "show documentation for package or symbol", Long: ` Doc prints the documentation comments associated with the item identified by its -arguments (a package, const, func, type, var, or method) followed by a one-line -summary of each of the first-level items "under" that item (package-level -declarations for a package, methods for a type, etc.). +arguments (a package, const, func, type, var, method, or struct field) +followed by a one-line summary of each of the first-level items "under" +that item (package-level declarations for a package, methods for a type, +etc.). Doc accepts zero, one, or two arguments. @@ -37,9 +38,9 @@ on what is installed in GOROOT and GOPATH, as well as the form of the argument, which is schematically one of these: go doc - go doc [.] - go doc [.][.] - go doc [.][.] + go doc [.] + go doc [.][.] + go doc [.][.] The first item in this list matched by the argument is the one whose documentation is printed. (See the examples below.) However, if the argument starts with a capital @@ -59,10 +60,10 @@ path. The go tool's usual package mechanism does not apply: package path elements like . and ... are not implemented by go doc. When run with two arguments, the first must be a full package path (not just a -suffix), and the second is a symbol or symbol and method; this is similar to the -syntax accepted by godoc: +suffix), and the second is a symbol, or symbol with method or struct field. +This is similar to the syntax accepted by godoc: - go doc [.] + go doc [.] In all forms, when matching symbols, lower-case letters in the argument match either case but upper-case letters match exactly. This means that there may be @@ -113,7 +114,7 @@ Flags: when showing the package's top-level documentation. -u Show documentation for unexported as well as exported - symbols and methods. + symbols, methods, and fields. `, }