mirror of
https://github.com/golang/go
synced 2024-11-02 11:50:30 +00:00
cmd/doc: perform type grouping for constants and variables
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>
This commit is contained in:
parent
c5f064ee49
commit
eca4e44611
3 changed files with 111 additions and 17 deletions
|
@ -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.
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
16
src/cmd/doc/testdata/pkg.go
vendored
16
src/cmd/doc/testdata/pkg.go
vendored
|
@ -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{}
|
||||
|
|
Loading…
Reference in a new issue