From 4a4c39e7d4f95ffcaa6971c35c4adeb740dcc515 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9my=20Oudompheng?= Date: Mon, 19 Dec 2011 15:32:06 -0500 Subject: [PATCH] encoding/json: cleanup leftover variables in array decoding. An old update for API changes in reflect package left several helper variables that do not have a meaning anymore, and the type checking of arrays vs slices was broken. Fixes #2513. R=ultrotter, rsc CC=golang-dev, remy https://golang.org/cl/5488094 --- src/pkg/encoding/json/decode.go | 71 ++++++++++++++-------------- src/pkg/encoding/json/decode_test.go | 6 +++ 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/pkg/encoding/json/decode.go b/src/pkg/encoding/json/decode.go index 0a70092629..8287b33003 100644 --- a/src/pkg/encoding/json/decode.go +++ b/src/pkg/encoding/json/decode.go @@ -228,7 +228,9 @@ func (d *decodeState) value(v reflect.Value) { // Feed in an empty string - the shortest, simplest value - // so that it knows we got to the end of the value. if d.scan.redo { - panic("redo") + // rewind. + d.scan.redo = false + d.scan.step = stateBeginValue } d.scan.step(&d.scan, '"') d.scan.step(&d.scan, '"') @@ -317,25 +319,22 @@ func (d *decodeState) array(v reflect.Value) { } v = pv - // Decoding into nil interface? Switch to non-reflect code. - iv := v - ok := iv.Kind() == reflect.Interface - if ok { - iv.Set(reflect.ValueOf(d.arrayInterface())) - return - } - // Check type of target. - av := v - if av.Kind() != reflect.Array && av.Kind() != reflect.Slice { + switch v.Kind() { + default: d.saveError(&UnmarshalTypeError{"array", v.Type()}) d.off-- d.next() return + case reflect.Interface: + // Decoding into nil interface? Switch to non-reflect code. + v.Set(reflect.ValueOf(d.arrayInterface())) + return + case reflect.Array: + case reflect.Slice: + break } - sv := v - i := 0 for { // Look ahead for ] - can only happen on first iteration. @@ -349,23 +348,25 @@ func (d *decodeState) array(v reflect.Value) { d.scan.undo(op) // Get element of array, growing if necessary. - if i >= av.Cap() && sv.IsValid() { - newcap := sv.Cap() + sv.Cap()/2 - if newcap < 4 { - newcap = 4 + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) } - newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap) - reflect.Copy(newv, sv) - sv.Set(newv) - } - if i >= av.Len() && sv.IsValid() { - // Must be slice; gave up on array during i >= av.Cap(). - sv.SetLen(i + 1) } - // Decode into element. - if i < av.Len() { - d.value(av.Index(i)) + if i < v.Len() { + // Decode into element. + d.value(v.Index(i)) } else { // Ran out of fixed array: skip. d.value(reflect.Value{}) @@ -382,19 +383,19 @@ func (d *decodeState) array(v reflect.Value) { } } - if i < av.Len() { - if !sv.IsValid() { + if i < v.Len() { + if v.Kind() == reflect.Array { // Array. Zero the rest. - z := reflect.Zero(av.Type().Elem()) - for ; i < av.Len(); i++ { - av.Index(i).Set(z) + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) } } else { - sv.SetLen(i) + v.SetLen(i) } } - if i == 0 && av.Kind() == reflect.Slice && sv.IsNil() { - sv.Set(reflect.MakeSlice(sv.Type(), 0, 0)) + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) } } diff --git a/src/pkg/encoding/json/decode_test.go b/src/pkg/encoding/json/decode_test.go index e569fa2f70..05c8a064a4 100644 --- a/src/pkg/encoding/json/decode_test.go +++ b/src/pkg/encoding/json/decode_test.go @@ -74,6 +74,12 @@ var unmarshalTests = []unmarshalTest{ // syntax errors {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}}, + {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}}, + + // array tests + {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil}, + {`[1, 2, 3]`, new([1]int), [1]int{1}, nil}, + {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil}, // composite tests {allValueIndent, new(All), allValue, nil}, -- 2.50.0