From 108218453a2cd26920f9be899b4a5102e80007a8 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 19 Feb 2016 16:36:03 +1100 Subject: [PATCH] cmd/doc: handle embedded fields properly The structure of the code meant that an embedded field was never checked for export status. We need to check the name of the type, which is either of type T or type *T, and T might be unexported. Fixes #14356. Change-Id: I56f468e9b8ae67e9ed7509ed0b91d860507baed2 Reviewed-on: https://go-review.googlesource.com/19701 Reviewed-by: Robert Griesemer --- src/cmd/doc/doc_test.go | 9 +++++++-- src/cmd/doc/pkg.go | 20 +++++++++++++++++++- src/cmd/doc/testdata/pkg.go | 8 ++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go index ed1d0e7c79..20b61702b4 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/doc/doc_test.go @@ -221,6 +221,7 @@ var tests = []test{ `type ExportedType struct`, // Type definition. `Comment before exported field.*\n.*ExportedField +int` + `.*Comment on line with exported field.`, + `ExportedEmbeddedType.*Comment on line with exported embedded field.`, `Has unexported fields`, `func \(ExportedType\) ExportedMethod\(a int\) bool`, `const ExportedTypedConstant ExportedType = iota`, // Must include associated constant. @@ -228,6 +229,7 @@ var tests = []test{ }, []string{ `unexportedField`, // No unexported field. + `int.*embedded`, // No unexported embedded field. `Comment about exported method.`, // No comment about exported method. `unexportedMethod`, // No unexported method. `unexportedTypedConstant`, // No unexported constant. @@ -241,7 +243,11 @@ var tests = []test{ `Comment about exported type`, // Include comment. `type ExportedType struct`, // Type definition. `Comment before exported field.*\n.*ExportedField +int`, - `unexportedField int.*Comment on line with unexported field.`, + `unexportedField.*int.*Comment on line with unexported field.`, + `ExportedEmbeddedType.*Comment on line with exported embedded field.`, + `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field.`, + `unexportedType.*Comment on line with unexported embedded field.`, + `\*unexportedType.*Comment on line with unexported embedded \*field.`, `func \(ExportedType\) unexportedMethod\(a int\) bool`, `unexportedTypedConstant`, }, @@ -448,7 +454,6 @@ var trimTests = []trimTest{ {"", "", "", true}, {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, {"/usr/gopher/bar", "/usr/gopher", "bar", true}, - {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false}, {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false}, } diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 0b07f7cc7c..a14ccdb59b 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -487,9 +487,27 @@ func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList { trimmed := false list := make([]*ast.Field, 0, len(fields.List)) for _, field := range fields.List { + names := field.Names + if len(names) == 0 { + // Embedded type. Use the name of the type. It must be of type ident or *ident. + // Nothing else is allowed. + switch ident := field.Type.(type) { + case *ast.Ident: + names = []*ast.Ident{ident} + case *ast.StarExpr: + // Must have the form *identifier. + if ident, ok := ident.X.(*ast.Ident); ok { + names = []*ast.Ident{ident} + } + } + if names == nil { + // Can only happen if AST is incorrect. Safe to continue with a nil list. + log.Print("invalid program: unexpected type for embedded field") + } + } // Trims if any is unexported. Good enough in practice. ok := true - for _, name := range field.Names { + for _, name := range names { if !isExported(name.Name) { trimmed = true ok = false diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go index 3e7acee50b..1a673f78d4 100644 --- a/src/cmd/doc/testdata/pkg.go +++ b/src/cmd/doc/testdata/pkg.go @@ -60,8 +60,12 @@ func internalFunc(a int) bool // Comment about exported type. type ExportedType struct { // Comment before exported field. - ExportedField int // Comment on line with exported field. - unexportedField int // Comment on line with unexported field. + ExportedField int // Comment on line with exported field. + unexportedField int // Comment on line with unexported field. + ExportedEmbeddedType // Comment on line with exported embedded field. + *ExportedEmbeddedType // Comment on line with exported embedded *field. + unexportedType // Comment on line with unexported embedded field. + *unexportedType // Comment on line with unexported embedded *field. } // Comment about exported method. -- 2.48.1