]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/doc: implement "go doc struct.field"
authorRob Pike <r@golang.org>
Wed, 22 Mar 2017 03:27:47 +0000 (20:27 -0700)
committerRob Pike <r@golang.org>
Wed, 22 Mar 2017 05:37:50 +0000 (05:37 +0000)
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 <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/doc/doc_test.go
src/cmd/doc/main.go
src/cmd/doc/pkg.go
src/cmd/go/alldocs.go
src/cmd/go/internal/doc/doc.go

index 454a0d6415d37ea514adc1a914877280614577f5..e534bfead30454f40545d137e329e3cf417f6d14 100644 (file)
@@ -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",
index df1890fe71465c8917db1b50244952c6034c4c88..76c7dba2d95f57a589ec708b50a463aa2683e2f7 100644 (file)
 //
 // One argument:
 //     go doc <pkg>
-//     go doc <sym>[.<method>]
-//     go doc [<pkg>.]<sym>[.<method>]
-//     go doc [<pkg>.][<sym>.]<method>
+//     go doc <sym>[.<methodOrField>]
+//     go doc [<pkg>.]<sym>[.<methodOrField>]
+//     go doc [<pkg>.][<sym>.]<methodOrField>
 // 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 <pkg> <sym>[.<method>]
+//     go doc <pkg> <sym>[.<methodOrField>]
 //
-// 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
index b59fcbbd035f720c1bde9c4d85d60bc46166ded4..7b0f9de775a0bd014457b7011c86c0c831bb67ed 100644 (file)
@@ -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.
index 5b768900b1cf608f9be8ed1d7168b5020bb44156..b650e3cce0142dc247555c5e0d1c15ab4ea73433 100644 (file)
 //
 // 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.
 //
 // which is schematically one of these:
 //
 //     go doc <pkg>
-//     go doc <sym>[.<method>]
-//     go doc [<pkg>.]<sym>[.<method>]
-//     go doc [<pkg>.][<sym>.]<method>
+//     go doc <sym>[.<methodOrField>]
+//     go doc [<pkg>.]<sym>[.<methodOrField>]
+//     go doc [<pkg>.][<sym>.]<methodOrField>
 //
 // 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
 // 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 <pkg> <sym>[.<method>]
+//     go doc <pkg> <sym>[.<methodOrField>]
 //
 // 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
 //             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
index 66ff07615ee45854485e1e037b067f57804816a2..e7e116af7ee999fd374d718becc2c3eca869bc60 100644 (file)
@@ -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 <pkg>
-       go doc <sym>[.<method>]
-       go doc [<pkg>.]<sym>[.<method>]
-       go doc [<pkg>.][<sym>.]<method>
+       go doc <sym>[.<methodOrField>]
+       go doc [<pkg>.]<sym>[.<methodOrField>]
+       go doc [<pkg>.][<sym>.]<methodOrField>
 
 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 <pkg> <sym>[.<method>]
+       go doc <pkg> <sym>[.<methodOrField>]
 
 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.
 `,
 }