From dda61d68c848e16feab2d2c910768df8503888e0 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sat, 22 Sep 2012 05:54:24 +1000 Subject: [PATCH] [release-branch.go1] go/ast: ast.Print must not crash with unexported fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ««« backport d134e30c4d29 go/ast: ast.Print must not crash with unexported fields Don't print unexported struct fields; their values are not accessible via reflection. Fixes #3898. Also: - added support for arrays - print empty maps, arrays, slices, structs on one line for a denser output - added respective test cases R=r CC=golang-dev https://golang.org/cl/6454089 »»» --- src/pkg/go/ast/print.go | 73 +++++++++++++++++++++++++----------- src/pkg/go/ast/print_test.go | 21 +++++++++++ 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go index 02cf9e0223..2de9af299e 100644 --- a/src/pkg/go/ast/print.go +++ b/src/pkg/go/ast/print.go @@ -34,7 +34,8 @@ func NotNilFilter(_ string, v reflect.Value) bool { // // A non-nil FieldFilter f may be provided to control the output: // struct fields for which f(fieldname, fieldvalue) is true are -// are printed; all others are filtered from the output. +// are printed; all others are filtered from the output. Unexported +// struct fields are never printed. // func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) { // setup printer @@ -145,15 +146,18 @@ func (p *printer) print(x reflect.Value) { p.print(x.Elem()) case reflect.Map: - p.printf("%s (len = %d) {\n", x.Type(), x.Len()) - p.indent++ - for _, key := range x.MapKeys() { - p.print(key) - p.printf(": ") - p.print(x.MapIndex(key)) + p.printf("%s (len = %d) {", x.Type(), x.Len()) + if x.Len() > 0 { + p.indent++ p.printf("\n") + for _, key := range x.MapKeys() { + p.print(key) + p.printf(": ") + p.print(x.MapIndex(key)) + p.printf("\n") + } + p.indent-- } - p.indent-- p.printf("}") case reflect.Ptr: @@ -169,32 +173,57 @@ func (p *printer) print(x reflect.Value) { p.print(x.Elem()) } + case reflect.Array: + p.printf("%s {", x.Type()) + if x.Len() > 0 { + p.indent++ + p.printf("\n") + for i, n := 0, x.Len(); i < n; i++ { + p.printf("%d: ", i) + p.print(x.Index(i)) + p.printf("\n") + } + p.indent-- + } + p.printf("}") + case reflect.Slice: if s, ok := x.Interface().([]byte); ok { p.printf("%#q", s) return } - p.printf("%s (len = %d) {\n", x.Type(), x.Len()) - p.indent++ - for i, n := 0, x.Len(); i < n; i++ { - p.printf("%d: ", i) - p.print(x.Index(i)) + p.printf("%s (len = %d) {", x.Type(), x.Len()) + if x.Len() > 0 { + p.indent++ p.printf("\n") + for i, n := 0, x.Len(); i < n; i++ { + p.printf("%d: ", i) + p.print(x.Index(i)) + p.printf("\n") + } + p.indent-- } - p.indent-- p.printf("}") case reflect.Struct: - p.printf("%s {\n", x.Type()) - p.indent++ t := x.Type() + p.printf("%s {", t) + p.indent++ + first := true for i, n := 0, t.NumField(); i < n; i++ { - name := t.Field(i).Name - value := x.Field(i) - if p.filter == nil || p.filter(name, value) { - p.printf("%s: ", name) - p.print(value) - p.printf("\n") + // exclude non-exported fields because their + // values cannot be accessed via reflection + if name := t.Field(i).Name; IsExported(name) { + value := x.Field(i) + if p.filter == nil || p.filter(name, value) { + if first { + p.printf("\n") + first = false + } + p.printf("%s: ", name) + p.print(value) + p.printf("\n") + } } } p.indent-- diff --git a/src/pkg/go/ast/print_test.go b/src/pkg/go/ast/print_test.go index 71c028e753..210f164301 100644 --- a/src/pkg/go/ast/print_test.go +++ b/src/pkg/go/ast/print_test.go @@ -23,6 +23,7 @@ var tests = []struct { {"foobar", "0 \"foobar\""}, // maps + {map[Expr]string{}, `0 map[ast.Expr]string (len = 0) {}`}, {map[string]int{"a": 1}, `0 map[string]int (len = 1) { 1 . "a": 1 @@ -31,7 +32,21 @@ var tests = []struct { // pointers {new(int), "0 *0"}, + // arrays + {[0]int{}, `0 [0]int {}`}, + {[3]int{1, 2, 3}, + `0 [3]int { + 1 . 0: 1 + 2 . 1: 2 + 3 . 2: 3 + 4 }`}, + {[...]int{42}, + `0 [1]int { + 1 . 0: 42 + 2 }`}, + // slices + {[]int{}, `0 []int (len = 0) {}`}, {[]int{1, 2, 3}, `0 []int (len = 3) { 1 . 0: 1 @@ -40,6 +55,12 @@ var tests = []struct { 4 }`}, // structs + {struct{}{}, `0 struct {} {}`}, + {struct{ x int }{007}, `0 struct { x int } {}`}, + {struct{ X, y int }{42, 991}, + `0 struct { X int; y int } { + 1 . X: 42 + 2 }`}, {struct{ X, Y int }{42, 991}, `0 struct { X int; Y int } { 1 . X: 42