Skip to content

Commit eca4e44

Browse files
committed
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 <[email protected]> Run-TryBot: Joe Tsai <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent c5f064e commit eca4e44

File tree

3 files changed

+111
-17
lines changed

3 files changed

+111
-17
lines changed

src/cmd/doc/doc_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ var tests = []test{
6565
`type ExportedType struct { ... }`, // Exported type.
6666
`const ExportedTypedConstant ExportedType = iota`, // Typed constant.
6767
`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
68+
`const ConstLeft2 uint64 ...`, // Typed constant using unexported iota.
69+
`const ConstGroup1 unexportedType = iota ...`, // Typed constant using unexported type.
70+
`const ConstGroup4 ExportedType = ExportedType{}`, // Typed constant using exported type.
6871
},
6972
[]string{
7073
`const internalConstant = 2`, // No internal constants.
@@ -144,6 +147,30 @@ var tests = []test{
144147
},
145148
nil,
146149
},
150+
// Block of constants with carryover type from unexported field.
151+
{
152+
"block of constants with carryover type",
153+
[]string{p, `ConstLeft2`},
154+
[]string{
155+
`ConstLeft2, constRight2 uint64`,
156+
`constLeft3, ConstRight3`,
157+
`ConstLeft4, ConstRight4`,
158+
},
159+
nil,
160+
},
161+
// Block of constants -u with carryover type from unexported field.
162+
{
163+
"block of constants with carryover type",
164+
[]string{"-u", p, `ConstLeft2`},
165+
[]string{
166+
`_, _ uint64 = 2 \* iota, 1 << iota`,
167+
`constLeft1, constRight1`,
168+
`ConstLeft2, constRight2`,
169+
`constLeft3, ConstRight3`,
170+
`ConstLeft4, ConstRight4`,
171+
},
172+
nil,
173+
},
147174

148175
// Single variable.
149176
{

src/cmd/doc/pkg.go

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -211,27 +211,33 @@ func (pkg *Package) oneLineFunc(decl *ast.FuncDecl) {
211211
}
212212

213213
// oneLineValueGenDecl prints a var or const declaration as a single line.
214-
func (pkg *Package) oneLineValueGenDecl(decl *ast.GenDecl) {
214+
func (pkg *Package) oneLineValueGenDecl(prefix string, decl *ast.GenDecl) {
215215
decl.Doc = nil
216216
dotDotDot := ""
217217
if len(decl.Specs) > 1 {
218218
dotDotDot = " ..."
219219
}
220220
// Find the first relevant spec.
221+
typ := ""
221222
for i, spec := range decl.Specs {
222223
valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl.
223-
if !isExported(valueSpec.Names[0].Name) {
224-
continue
225-
}
226-
typ := ""
224+
225+
// The type name may carry over from a previous specification in the
226+
// case of constants and iota.
227227
if valueSpec.Type != nil {
228228
typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type))
229+
} else if len(valueSpec.Values) > 0 {
230+
typ = ""
231+
}
232+
233+
if !isExported(valueSpec.Names[0].Name) {
234+
continue
229235
}
230236
val := ""
231237
if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
232238
val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
233239
}
234-
pkg.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
240+
pkg.Printf("%s%s %s%s%s%s\n", prefix, decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
235241
break
236242
}
237243
}
@@ -266,8 +272,8 @@ func (pkg *Package) packageDoc() {
266272
}
267273

268274
pkg.newlines(2) // Guarantee blank line before the components.
269-
pkg.valueSummary(pkg.doc.Consts)
270-
pkg.valueSummary(pkg.doc.Vars)
275+
pkg.valueSummary(pkg.doc.Consts, false)
276+
pkg.valueSummary(pkg.doc.Vars, false)
271277
pkg.funcSummary(pkg.doc.Funcs, false)
272278
pkg.typeSummary()
273279
pkg.bugs()
@@ -302,9 +308,29 @@ func (pkg *Package) packageClause(checkUserPath bool) {
302308
}
303309

304310
// valueSummary prints a one-line summary for each set of values and constants.
305-
func (pkg *Package) valueSummary(values []*doc.Value) {
311+
// If all the types in a constant or variable declaration belong to the same
312+
// type they can be printed by typeSummary, and so can be suppressed here.
313+
func (pkg *Package) valueSummary(values []*doc.Value, showGrouped bool) {
314+
var isGrouped map[*doc.Value]bool
315+
if !showGrouped {
316+
isGrouped = make(map[*doc.Value]bool)
317+
for _, typ := range pkg.doc.Types {
318+
if !isExported(typ.Name) {
319+
continue
320+
}
321+
for _, c := range typ.Consts {
322+
isGrouped[c] = true
323+
}
324+
for _, v := range typ.Vars {
325+
isGrouped[v] = true
326+
}
327+
}
328+
}
329+
306330
for _, value := range values {
307-
pkg.oneLineValueGenDecl(value.Decl)
331+
if !isGrouped[value] {
332+
pkg.oneLineValueGenDecl("", value.Decl)
333+
}
308334
}
309335
}
310336

@@ -316,10 +342,11 @@ func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
316342
if !showConstructors {
317343
isConstructor = make(map[*doc.Func]bool)
318344
for _, typ := range pkg.doc.Types {
319-
for _, constructor := range typ.Funcs {
320-
if isExported(typ.Name) {
321-
isConstructor[constructor] = true
322-
}
345+
if !isExported(typ.Name) {
346+
continue
347+
}
348+
for _, f := range typ.Funcs {
349+
isConstructor[f] = true
323350
}
324351
}
325352
}
@@ -341,7 +368,13 @@ func (pkg *Package) typeSummary() {
341368
typeSpec := spec.(*ast.TypeSpec) // Must succeed.
342369
if isExported(typeSpec.Name.Name) {
343370
pkg.oneLineTypeDecl(typeSpec)
344-
// Now print the constructors.
371+
// Now print the consts, vars, and constructors.
372+
for _, c := range typ.Consts {
373+
pkg.oneLineValueGenDecl(indent, c.Decl)
374+
}
375+
for _, v := range typ.Vars {
376+
pkg.oneLineValueGenDecl(indent, v.Decl)
377+
}
345378
for _, constructor := range typ.Funcs {
346379
if isExported(constructor.Name) {
347380
pkg.Printf(indent)
@@ -437,11 +470,29 @@ func (pkg *Package) symbolDoc(symbol string) bool {
437470
// It's an unlikely scenario, probably not worth the trouble.
438471
// TODO: Would be nice if go/doc did this for us.
439472
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
473+
var typ ast.Expr
440474
for _, spec := range value.Decl.Specs {
441475
vspec := spec.(*ast.ValueSpec)
476+
477+
// The type name may carry over from a previous specification in the
478+
// case of constants and iota.
479+
if vspec.Type != nil {
480+
typ = vspec.Type
481+
}
482+
442483
for _, ident := range vspec.Names {
443484
if isExported(ident.Name) {
485+
if vspec.Type == nil && vspec.Values == nil && typ != nil {
486+
// This a standalone identifier, as in the case of iota usage.
487+
// Thus, assume the type comes from the previous type.
488+
vspec.Type = &ast.Ident{
489+
Name: string(pkg.formatNode(typ)),
490+
NamePos: vspec.End() - 1,
491+
}
492+
}
493+
444494
specs = append(specs, vspec)
495+
typ = nil // Only inject type on first exported identifier
445496
break
446497
}
447498
}
@@ -473,8 +524,8 @@ func (pkg *Package) symbolDoc(symbol string) bool {
473524
if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
474525
pkg.Printf("\n")
475526
}
476-
pkg.valueSummary(typ.Consts)
477-
pkg.valueSummary(typ.Vars)
527+
pkg.valueSummary(typ.Consts, true)
528+
pkg.valueSummary(typ.Vars, true)
478529
pkg.funcSummary(typ.Funcs, true)
479530
pkg.funcSummary(typ.Methods, true)
480531
found = true

src/cmd/doc/testdata/pkg.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,19 @@ const Casematch = 2
126126

127127
func ReturnUnexported() unexportedType { return 0 }
128128
func ReturnExported() ExportedType { return ExportedType{} }
129+
130+
const (
131+
_, _ uint64 = 2 * iota, 1 << iota
132+
constLeft1, constRight1
133+
ConstLeft2, constRight2
134+
constLeft3, ConstRight3
135+
ConstLeft4, ConstRight4
136+
)
137+
138+
const (
139+
ConstGroup1 unexportedType = iota
140+
ConstGroup2
141+
ConstGroup3
142+
)
143+
144+
const ConstGroup4 ExportedType = ExportedType{}

0 commit comments

Comments
 (0)