]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/doc: show documentation for interface methods when requested explicitly
authorRob Pike <r@golang.org>
Mon, 24 Oct 2016 19:38:06 +0000 (12:38 -0700)
committerRob Pike <r@golang.org>
Tue, 25 Oct 2016 20:09:49 +0000 (20:09 +0000)
For historical reasons, the go/doc package does not include
the methods within an interface as part of the documented
methods for that type. Thus,

go doc ast.Node.Pos

gives an incorrect and confusing error message:

doc: no method Node.Pos in package go/ast

This CL does some dirty work to dig down to the methods
so interface methods now present their documentation:

% go doc ast.node.pos
func Pos() token.Pos  // position of first character belonging to the node
%

It must largely sidestep the doc package to do this, which
is a shame. Perhaps things will improve there one day.

The change does not handle embeddings, and in principle the
same approach could be done for struct fields, but that is also
not here yet. But this CL fixes the thing that was bugging me.

Change-Id: Ic10a91936da96f54ee0b2f4a4fe4a8c9b93a5b4a
Reviewed-on: https://go-review.googlesource.com/31852
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/doc/doc_test.go
src/cmd/doc/pkg.go

index 3c668876d2e69fdbb368d7670fb78eba5fddc7ae..1c054fd566a0a3683ddbf86c56e833821a23580f 100644 (file)
@@ -304,7 +304,7 @@ var tests = []test{
 
        // Interface.
        {
-               "type",
+               "interface type",
                []string{p, `ExportedInterface`},
                []string{
                        `Comment about exported interface`, // Include comment.
@@ -324,7 +324,7 @@ var tests = []test{
        },
        // Interface -u with unexported methods.
        {
-               "type with unexported methods and -u",
+               "interface type with unexported methods and -u",
                []string{"-u", p, `ExportedInterface`},
                []string{
                        `Comment about exported interface`, // Include comment.
@@ -340,6 +340,19 @@ var tests = []test{
                },
        },
 
+       // Interface method.
+       {
+               "interface method",
+               []string{p, `ExportedInterface.ExportedMethod`},
+               []string{
+                       `Comment before exported method.*\n.*ExportedMethod\(\)` +
+                               `.*Comment on line with exported method`,
+               },
+               []string{
+                       `Comment about exported interface.`,
+               },
+       },
+
        // Method.
        {
                "method",
index 5ea1ebf599def181d908d765085a52b4274c02c7..daa6ed358cdce0e2234421532cc7eb9753e97c1c 100644 (file)
@@ -755,11 +755,48 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
        }
        found := false
        for _, typ := range types {
-               for _, meth := range typ.Methods {
-                       if match(method, meth.Name) {
-                               decl := meth.Decl
-                               decl.Body = nil
-                               pkg.emit(meth.Doc, decl)
+               if len(typ.Methods) > 0 {
+                       for _, meth := range typ.Methods {
+                               if match(method, meth.Name) {
+                                       decl := meth.Decl
+                                       decl.Body = nil
+                                       pkg.emit(meth.Doc, decl)
+                                       found = true
+                               }
+                       }
+                       continue
+               }
+               // Type may be an interface. The go/doc package does not attach
+               // an interface's methods to the doc.Type. We need to dig around.
+               spec := pkg.findTypeSpec(typ.Decl, typ.Name)
+               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 {
+                       // This is an interface, so there can be only one name.
+                       // TODO: Anonymous methods (embedding)
+                       if len(iMethod.Names) == 0 {
+                               continue
+                       }
+                       name := iMethod.Names[0].Name
+                       if match(method, name) {
+                               // pkg.oneLineField(iMethod, 0)
+                               if iMethod.Doc != nil {
+                                       for _, comment := range iMethod.Doc.List {
+                                               doc.ToText(&pkg.buf, comment.Text, "", indent, indentedWidth)
+                                       }
+                               }
+                               s := pkg.oneLineNode(iMethod.Type)
+                               // Hack: s starts "func" but there is no name present.
+                               // We could instead build a FuncDecl but it's not worthwhile.
+                               lineComment := ""
+                               if iMethod.Comment != nil {
+                                       lineComment = fmt.Sprintf("  %s", iMethod.Comment.List[0].Text)
+                               }
+                               pkg.Printf("func %s%s%s\n", name, s[4:], lineComment)
                                found = true
                        }
                }