]> Cypherpunks repositories - gostls13.git/commitdiff
go/ast: ast.Print must not crash with unexported fields
authorRobert Griesemer <gri@golang.org>
Fri, 3 Aug 2012 00:05:51 +0000 (17:05 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 3 Aug 2012 00:05:51 +0000 (17:05 -0700)
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
src/pkg/go/ast/print_test.go

index 02cf9e022343765edad62d4608e486715320c3b9..2de9af299e5cd811a60354dc99a8244b4bda94a4 100644 (file)
@@ -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--
index 71c028e753787e4b322c8ab629cb04b115677623..210f1643010c716bae62b262a9797baaf94045a0 100644 (file)
@@ -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