1
0
mirror of https://github.com/golang/go synced 2024-10-04 08:21:22 -06:00

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
This commit is contained in:
Robert Griesemer 2012-08-02 17:05:51 -07:00
parent 2f39a33b6a
commit 593c51cff1
2 changed files with 72 additions and 22 deletions

View File

@ -34,7 +34,8 @@ func NotNilFilter(_ string, v reflect.Value) bool {
// //
// A non-nil FieldFilter f may be provided to control the output: // A non-nil FieldFilter f may be provided to control the output:
// struct fields for which f(fieldname, fieldvalue) is true are // 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) { func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
// setup printer // setup printer
@ -145,8 +146,10 @@ func (p *printer) print(x reflect.Value) {
p.print(x.Elem()) p.print(x.Elem())
case reflect.Map: case reflect.Map:
p.printf("%s (len = %d) {\n", x.Type(), x.Len()) p.printf("%s (len = %d) {", x.Type(), x.Len())
if x.Len() > 0 {
p.indent++ p.indent++
p.printf("\n")
for _, key := range x.MapKeys() { for _, key := range x.MapKeys() {
p.print(key) p.print(key)
p.printf(": ") p.printf(": ")
@ -154,6 +157,7 @@ func (p *printer) print(x reflect.Value) {
p.printf("\n") p.printf("\n")
} }
p.indent-- p.indent--
}
p.printf("}") p.printf("}")
case reflect.Ptr: case reflect.Ptr:
@ -169,34 +173,59 @@ func (p *printer) print(x reflect.Value) {
p.print(x.Elem()) p.print(x.Elem())
} }
case reflect.Slice: case reflect.Array:
if s, ok := x.Interface().([]byte); ok { p.printf("%s {", x.Type())
p.printf("%#q", s) if x.Len() > 0 {
return
}
p.printf("%s (len = %d) {\n", x.Type(), x.Len())
p.indent++ p.indent++
p.printf("\n")
for i, n := 0, x.Len(); i < n; i++ { for i, n := 0, x.Len(); i < n; i++ {
p.printf("%d: ", i) p.printf("%d: ", i)
p.print(x.Index(i)) p.print(x.Index(i))
p.printf("\n") p.printf("\n")
} }
p.indent-- p.indent--
}
p.printf("}")
case reflect.Slice:
if s, ok := x.Interface().([]byte); ok {
p.printf("%#q", s)
return
}
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.printf("}") p.printf("}")
case reflect.Struct: case reflect.Struct:
p.printf("%s {\n", x.Type())
p.indent++
t := x.Type() t := x.Type()
p.printf("%s {", t)
p.indent++
first := true
for i, n := 0, t.NumField(); i < n; i++ { for i, n := 0, t.NumField(); i < n; i++ {
name := t.Field(i).Name // exclude non-exported fields because their
// values cannot be accessed via reflection
if name := t.Field(i).Name; IsExported(name) {
value := x.Field(i) value := x.Field(i)
if p.filter == nil || p.filter(name, value) { if p.filter == nil || p.filter(name, value) {
if first {
p.printf("\n")
first = false
}
p.printf("%s: ", name) p.printf("%s: ", name)
p.print(value) p.print(value)
p.printf("\n") p.printf("\n")
} }
} }
}
p.indent-- p.indent--
p.printf("}") p.printf("}")

View File

@ -23,6 +23,7 @@ var tests = []struct {
{"foobar", "0 \"foobar\""}, {"foobar", "0 \"foobar\""},
// maps // maps
{map[Expr]string{}, `0 map[ast.Expr]string (len = 0) {}`},
{map[string]int{"a": 1}, {map[string]int{"a": 1},
`0 map[string]int (len = 1) { `0 map[string]int (len = 1) {
1 . "a": 1 1 . "a": 1
@ -31,7 +32,21 @@ var tests = []struct {
// pointers // pointers
{new(int), "0 *0"}, {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 // slices
{[]int{}, `0 []int (len = 0) {}`},
{[]int{1, 2, 3}, {[]int{1, 2, 3},
`0 []int (len = 3) { `0 []int (len = 3) {
1 . 0: 1 1 . 0: 1
@ -40,6 +55,12 @@ var tests = []struct {
4 }`}, 4 }`},
// structs // 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}, {struct{ X, Y int }{42, 991},
`0 struct { X int; Y int } { `0 struct { X int; Y int } {
1 . X: 42 1 . X: 42