mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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
This commit is contained in:
parent
3a2dec0246
commit
4a4c39e7d4
2 changed files with 42 additions and 35 deletions
|
|
@ -228,7 +228,9 @@ func (d *decodeState) value(v reflect.Value) {
|
||||||
// Feed in an empty string - the shortest, simplest value -
|
// Feed in an empty string - the shortest, simplest value -
|
||||||
// so that it knows we got to the end of the value.
|
// so that it knows we got to the end of the value.
|
||||||
if d.scan.redo {
|
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, '"')
|
||||||
d.scan.step(&d.scan, '"')
|
d.scan.step(&d.scan, '"')
|
||||||
|
|
@ -317,25 +319,22 @@ func (d *decodeState) array(v reflect.Value) {
|
||||||
}
|
}
|
||||||
v = pv
|
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.
|
// Check type of target.
|
||||||
av := v
|
switch v.Kind() {
|
||||||
if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
|
default:
|
||||||
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
||||||
d.off--
|
d.off--
|
||||||
d.next()
|
d.next()
|
||||||
return
|
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
|
i := 0
|
||||||
for {
|
for {
|
||||||
// Look ahead for ] - can only happen on first iteration.
|
// Look ahead for ] - can only happen on first iteration.
|
||||||
|
|
@ -349,23 +348,25 @@ func (d *decodeState) array(v reflect.Value) {
|
||||||
d.scan.undo(op)
|
d.scan.undo(op)
|
||||||
|
|
||||||
// Get element of array, growing if necessary.
|
// Get element of array, growing if necessary.
|
||||||
if i >= av.Cap() && sv.IsValid() {
|
if v.Kind() == reflect.Slice {
|
||||||
newcap := sv.Cap() + sv.Cap()/2
|
// Grow slice if necessary
|
||||||
|
if i >= v.Cap() {
|
||||||
|
newcap := v.Cap() + v.Cap()/2
|
||||||
if newcap < 4 {
|
if newcap < 4 {
|
||||||
newcap = 4
|
newcap = 4
|
||||||
}
|
}
|
||||||
newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
|
newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
|
||||||
reflect.Copy(newv, sv)
|
reflect.Copy(newv, v)
|
||||||
sv.Set(newv)
|
v.Set(newv)
|
||||||
|
}
|
||||||
|
if i >= v.Len() {
|
||||||
|
v.SetLen(i + 1)
|
||||||
}
|
}
|
||||||
if i >= av.Len() && sv.IsValid() {
|
|
||||||
// Must be slice; gave up on array during i >= av.Cap().
|
|
||||||
sv.SetLen(i + 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if i < v.Len() {
|
||||||
// Decode into element.
|
// Decode into element.
|
||||||
if i < av.Len() {
|
d.value(v.Index(i))
|
||||||
d.value(av.Index(i))
|
|
||||||
} else {
|
} else {
|
||||||
// Ran out of fixed array: skip.
|
// Ran out of fixed array: skip.
|
||||||
d.value(reflect.Value{})
|
d.value(reflect.Value{})
|
||||||
|
|
@ -382,19 +383,19 @@ func (d *decodeState) array(v reflect.Value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if i < av.Len() {
|
if i < v.Len() {
|
||||||
if !sv.IsValid() {
|
if v.Kind() == reflect.Array {
|
||||||
// Array. Zero the rest.
|
// Array. Zero the rest.
|
||||||
z := reflect.Zero(av.Type().Elem())
|
z := reflect.Zero(v.Type().Elem())
|
||||||
for ; i < av.Len(); i++ {
|
for ; i < v.Len(); i++ {
|
||||||
av.Index(i).Set(z)
|
v.Index(i).Set(z)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sv.SetLen(i)
|
v.SetLen(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if i == 0 && av.Kind() == reflect.Slice && sv.IsNil() {
|
if i == 0 && v.Kind() == reflect.Slice {
|
||||||
sv.Set(reflect.MakeSlice(sv.Type(), 0, 0))
|
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,12 @@ var unmarshalTests = []unmarshalTest{
|
||||||
|
|
||||||
// syntax errors
|
// syntax errors
|
||||||
{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
|
{`{"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
|
// composite tests
|
||||||
{allValueIndent, new(All), allValue, nil},
|
{allValueIndent, new(All), allValue, nil},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue