mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +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.
|
`type ExportedType struct { ... }`, // Exported type.
|
||||||
`const ExportedTypedConstant ExportedType = iota`, // Typed constant.
|
`const ExportedTypedConstant ExportedType = iota`, // Typed constant.
|
||||||
`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
|
`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{
|
[]string{
|
||||||
`const internalConstant = 2`, // No internal constants.
|
`const internalConstant = 2`, // No internal constants.
|
||||||
|
|
@ -144,6 +147,30 @@ var tests = []test{
|
||||||
},
|
},
|
||||||
nil,
|
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.
|
// Single variable.
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -211,27 +211,33 @@ func (pkg *Package) oneLineFunc(decl *ast.FuncDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// oneLineValueGenDecl prints a var or const declaration as a single line.
|
// 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
|
decl.Doc = nil
|
||||||
dotDotDot := ""
|
dotDotDot := ""
|
||||||
if len(decl.Specs) > 1 {
|
if len(decl.Specs) > 1 {
|
||||||
dotDotDot = " ..."
|
dotDotDot = " ..."
|
||||||
}
|
}
|
||||||
// Find the first relevant spec.
|
// Find the first relevant spec.
|
||||||
|
typ := ""
|
||||||
for i, spec := range decl.Specs {
|
for i, spec := range decl.Specs {
|
||||||
valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl.
|
valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl.
|
||||||
if !isExported(valueSpec.Names[0].Name) {
|
|
||||||
continue
|
// The type name may carry over from a previous specification in the
|
||||||
}
|
// case of constants and iota.
|
||||||
typ := ""
|
|
||||||
if valueSpec.Type != nil {
|
if valueSpec.Type != nil {
|
||||||
typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type))
|
typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type))
|
||||||
|
} else if len(valueSpec.Values) > 0 {
|
||||||
|
typ = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isExported(valueSpec.Names[0].Name) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
val := ""
|
val := ""
|
||||||
if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
|
if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
|
||||||
val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
|
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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -266,8 +272,8 @@ func (pkg *Package) packageDoc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg.newlines(2) // Guarantee blank line before the components.
|
pkg.newlines(2) // Guarantee blank line before the components.
|
||||||
pkg.valueSummary(pkg.doc.Consts)
|
pkg.valueSummary(pkg.doc.Consts, false)
|
||||||
pkg.valueSummary(pkg.doc.Vars)
|
pkg.valueSummary(pkg.doc.Vars, false)
|
||||||
pkg.funcSummary(pkg.doc.Funcs, false)
|
pkg.funcSummary(pkg.doc.Funcs, false)
|
||||||
pkg.typeSummary()
|
pkg.typeSummary()
|
||||||
pkg.bugs()
|
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.
|
// 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 {
|
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 {
|
if !showConstructors {
|
||||||
isConstructor = make(map[*doc.Func]bool)
|
isConstructor = make(map[*doc.Func]bool)
|
||||||
for _, typ := range pkg.doc.Types {
|
for _, typ := range pkg.doc.Types {
|
||||||
for _, constructor := range typ.Funcs {
|
if !isExported(typ.Name) {
|
||||||
if isExported(typ.Name) {
|
continue
|
||||||
isConstructor[constructor] = true
|
}
|
||||||
}
|
for _, f := range typ.Funcs {
|
||||||
|
isConstructor[f] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -341,7 +368,13 @@ func (pkg *Package) typeSummary() {
|
||||||
typeSpec := spec.(*ast.TypeSpec) // Must succeed.
|
typeSpec := spec.(*ast.TypeSpec) // Must succeed.
|
||||||
if isExported(typeSpec.Name.Name) {
|
if isExported(typeSpec.Name.Name) {
|
||||||
pkg.oneLineTypeDecl(typeSpec)
|
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 {
|
for _, constructor := range typ.Funcs {
|
||||||
if isExported(constructor.Name) {
|
if isExported(constructor.Name) {
|
||||||
pkg.Printf(indent)
|
pkg.Printf(indent)
|
||||||
|
|
@ -437,11 +470,29 @@ func (pkg *Package) symbolDoc(symbol string) bool {
|
||||||
// It's an unlikely scenario, probably not worth the trouble.
|
// It's an unlikely scenario, probably not worth the trouble.
|
||||||
// TODO: Would be nice if go/doc did this for us.
|
// TODO: Would be nice if go/doc did this for us.
|
||||||
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
|
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
|
||||||
|
var typ ast.Expr
|
||||||
for _, spec := range value.Decl.Specs {
|
for _, spec := range value.Decl.Specs {
|
||||||
vspec := spec.(*ast.ValueSpec)
|
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 {
|
for _, ident := range vspec.Names {
|
||||||
if isExported(ident.Name) {
|
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)
|
specs = append(specs, vspec)
|
||||||
|
typ = nil // Only inject type on first exported identifier
|
||||||
break
|
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 {
|
if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
|
||||||
pkg.Printf("\n")
|
pkg.Printf("\n")
|
||||||
}
|
}
|
||||||
pkg.valueSummary(typ.Consts)
|
pkg.valueSummary(typ.Consts, true)
|
||||||
pkg.valueSummary(typ.Vars)
|
pkg.valueSummary(typ.Vars, true)
|
||||||
pkg.funcSummary(typ.Funcs, true)
|
pkg.funcSummary(typ.Funcs, true)
|
||||||
pkg.funcSummary(typ.Methods, true)
|
pkg.funcSummary(typ.Methods, true)
|
||||||
found = 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 ReturnUnexported() unexportedType { return 0 }
|
||||||
func ReturnExported() ExportedType { return ExportedType{} }
|
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…
Add table
Add a link
Reference in a new issue