]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/doc: perform type grouping for constants and variables
authorJoe Tsai <joetsai@digital-static.net>
Wed, 3 Aug 2016 01:42:58 +0000 (18:42 -0700)
committerJoe Tsai <thebrokentoaster@gmail.com>
Fri, 30 Sep 2016 23:40:48 +0000 (23:40 +0000)
In golang.org/cl/22354, we added functionality to group functions under the
type that they construct to. In this CL, we extend the same concept to
constants and variables. This makes the doc tool more consistent with what
the godoc website does.

$ go doc reflect | egrep "ChanDir|Kind|SelectDir"
<<<
// Before:
const RecvDir ChanDir = 1 << iota ...
const Invalid Kind = iota ...
type ChanDir int
type Kind uint
type SelectDir int
    func ChanOf(dir ChanDir, t Type) Type

// After:
type ChanDir int
    const RecvDir ChanDir = 1 << iota ...
type Kind uint
    const Invalid Kind = iota ...
type SelectDir int
    const SelectSend SelectDir ...
    func ChanOf(dir ChanDir, t Type) Type
>>>

Furthermore, a fix was made to ensure that the type was printed in constant
blocks when the iota was applied on an unexported field.

$ go doc reflect SelectSend
<<<
// Before:
const (
SelectSend    // case Chan <- Send
SelectRecv    // case <-Chan:
SelectDefault // default
)

// After:
const (
SelectSend    SelectDir // case Chan <- Send
SelectRecv              // case <-Chan:
SelectDefault           // default
)
>>>

Fixes #16569

Change-Id: I26124c3d19e50caf9742bb936803a665e0fa6512
Reviewed-on: https://go-review.googlesource.com/25419
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/doc/doc_test.go
src/cmd/doc/pkg.go
src/cmd/doc/testdata/pkg.go

index 453a3d53aa5481c4596f3829b42d5a2df8ed5425..3b8fd317fe95d383b530e270cd62cd6d168eff1b 100644 (file)
@@ -65,6 +65,9 @@ var tests = []test{
                        `type ExportedType struct { ... }`,                      // Exported type.
                        `const ExportedTypedConstant ExportedType = iota`,       // Typed constant.
                        `const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
+                       `const ConstLeft2 uint64 ...`,                           // Typed constant using unexported iota.
+                       `const ConstGroup1 unexportedType = iota ...`,           // Typed constant using unexported type.
+                       `const ConstGroup4 ExportedType = ExportedType{}`,       // Typed constant using exported type.
                },
                []string{
                        `const internalConstant = 2`,        // No internal constants.
@@ -144,6 +147,30 @@ var tests = []test{
                },
                nil,
        },
+       // Block of constants with carryover type from unexported field.
+       {
+               "block of constants with carryover type",
+               []string{p, `ConstLeft2`},
+               []string{
+                       `ConstLeft2, constRight2 uint64`,
+                       `constLeft3, ConstRight3`,
+                       `ConstLeft4, ConstRight4`,
+               },
+               nil,
+       },
+       // Block of constants -u with carryover type from unexported field.
+       {
+               "block of constants with carryover type",
+               []string{"-u", p, `ConstLeft2`},
+               []string{
+                       `_, _ uint64 = 2 \* iota, 1 << iota`,
+                       `constLeft1, constRight1`,
+                       `ConstLeft2, constRight2`,
+                       `constLeft3, ConstRight3`,
+                       `ConstLeft4, ConstRight4`,
+               },
+               nil,
+       },
 
        // Single variable.
        {
index defddfd74a6b9ccd2c2b34ce8e401afe33ca503b..ccc568fdef71474377fcfa32c43983515f16a19e 100644 (file)
@@ -211,27 +211,33 @@ func (pkg *Package) oneLineFunc(decl *ast.FuncDecl) {
 }
 
 // oneLineValueGenDecl prints a var or const declaration as a single line.
-func (pkg *Package) oneLineValueGenDecl(decl *ast.GenDecl) {
+func (pkg *Package) oneLineValueGenDecl(prefix string, decl *ast.GenDecl) {
        decl.Doc = nil
        dotDotDot := ""
        if len(decl.Specs) > 1 {
                dotDotDot = " ..."
        }
        // Find the first relevant spec.
+       typ := ""
        for i, spec := range decl.Specs {
                valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl.
-               if !isExported(valueSpec.Names[0].Name) {
-                       continue
-               }
-               typ := ""
+
+               // The type name may carry over from a previous specification in the
+               // case of constants and iota.
                if valueSpec.Type != nil {
                        typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type))
+               } else if len(valueSpec.Values) > 0 {
+                       typ = ""
+               }
+
+               if !isExported(valueSpec.Names[0].Name) {
+                       continue
                }
                val := ""
                if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
                        val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
                }
-               pkg.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
+               pkg.Printf("%s%s %s%s%s%s\n", prefix, decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
                break
        }
 }
@@ -266,8 +272,8 @@ func (pkg *Package) packageDoc() {
        }
 
        pkg.newlines(2) // Guarantee blank line before the components.
-       pkg.valueSummary(pkg.doc.Consts)
-       pkg.valueSummary(pkg.doc.Vars)
+       pkg.valueSummary(pkg.doc.Consts, false)
+       pkg.valueSummary(pkg.doc.Vars, false)
        pkg.funcSummary(pkg.doc.Funcs, false)
        pkg.typeSummary()
        pkg.bugs()
@@ -302,9 +308,29 @@ func (pkg *Package) packageClause(checkUserPath bool) {
 }
 
 // valueSummary prints a one-line summary for each set of values and constants.
-func (pkg *Package) valueSummary(values []*doc.Value) {
+// If all the types in a constant or variable declaration belong to the same
+// type they can be printed by typeSummary, and so can be suppressed here.
+func (pkg *Package) valueSummary(values []*doc.Value, showGrouped bool) {
+       var isGrouped map[*doc.Value]bool
+       if !showGrouped {
+               isGrouped = make(map[*doc.Value]bool)
+               for _, typ := range pkg.doc.Types {
+                       if !isExported(typ.Name) {
+                               continue
+                       }
+                       for _, c := range typ.Consts {
+                               isGrouped[c] = true
+                       }
+                       for _, v := range typ.Vars {
+                               isGrouped[v] = true
+                       }
+               }
+       }
+
        for _, value := range values {
-               pkg.oneLineValueGenDecl(value.Decl)
+               if !isGrouped[value] {
+                       pkg.oneLineValueGenDecl("", value.Decl)
+               }
        }
 }
 
@@ -316,10 +342,11 @@ func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
        if !showConstructors {
                isConstructor = make(map[*doc.Func]bool)
                for _, typ := range pkg.doc.Types {
-                       for _, constructor := range typ.Funcs {
-                               if isExported(typ.Name) {
-                                       isConstructor[constructor] = true
-                               }
+                       if !isExported(typ.Name) {
+                               continue
+                       }
+                       for _, f := range typ.Funcs {
+                               isConstructor[f] = true
                        }
                }
        }
@@ -341,7 +368,13 @@ func (pkg *Package) typeSummary() {
                        typeSpec := spec.(*ast.TypeSpec) // Must succeed.
                        if isExported(typeSpec.Name.Name) {
                                pkg.oneLineTypeDecl(typeSpec)
-                               // Now print the constructors.
+                               // Now print the consts, vars, and constructors.
+                               for _, c := range typ.Consts {
+                                       pkg.oneLineValueGenDecl(indent, c.Decl)
+                               }
+                               for _, v := range typ.Vars {
+                                       pkg.oneLineValueGenDecl(indent, v.Decl)
+                               }
                                for _, constructor := range typ.Funcs {
                                        if isExported(constructor.Name) {
                                                pkg.Printf(indent)
@@ -437,11 +470,29 @@ func (pkg *Package) symbolDoc(symbol string) bool {
                // It's an unlikely scenario, probably not worth the trouble.
                // TODO: Would be nice if go/doc did this for us.
                specs := make([]ast.Spec, 0, len(value.Decl.Specs))
+               var typ ast.Expr
                for _, spec := range value.Decl.Specs {
                        vspec := spec.(*ast.ValueSpec)
+
+                       // The type name may carry over from a previous specification in the
+                       // case of constants and iota.
+                       if vspec.Type != nil {
+                               typ = vspec.Type
+                       }
+
                        for _, ident := range vspec.Names {
                                if 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.
+                                               vspec.Type = &ast.Ident{
+                                                       Name:    string(pkg.formatNode(typ)),
+                                                       NamePos: vspec.End() - 1,
+                                               }
+                                       }
+
                                        specs = append(specs, vspec)
+                                       typ = nil // Only inject type on first exported identifier
                                        break
                                }
                        }
@@ -473,8 +524,8 @@ func (pkg *Package) symbolDoc(symbol string) bool {
                if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
                        pkg.Printf("\n")
                }
-               pkg.valueSummary(typ.Consts)
-               pkg.valueSummary(typ.Vars)
+               pkg.valueSummary(typ.Consts, true)
+               pkg.valueSummary(typ.Vars, true)
                pkg.funcSummary(typ.Funcs, true)
                pkg.funcSummary(typ.Methods, true)
                found = true
index 6a52ac2f6540f11156e58114d811aa9b01641ec4..fb941cde7a256406cccec149f7080180d03e3957 100644 (file)
@@ -126,3 +126,19 @@ const Casematch = 2
 
 func ReturnUnexported() unexportedType { return 0 }
 func ReturnExported() ExportedType     { return ExportedType{} }
+
+const (
+       _, _ uint64 = 2 * iota, 1 << iota
+       constLeft1, constRight1
+       ConstLeft2, constRight2
+       constLeft3, ConstRight3
+       ConstLeft4, ConstRight4
+)
+
+const (
+       ConstGroup1 unexportedType = iota
+       ConstGroup2
+       ConstGroup3
+)
+
+const ConstGroup4 ExportedType = ExportedType{}