1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-12 20:27:30 +08:00

use consistent field access rules across read/write and argument conversion

This commit is contained in:
Conrad Pankoff 2018-12-16 11:52:39 +11:00
parent 15f95af6e7
commit 0f57984957
2 changed files with 52 additions and 40 deletions

View File

@ -285,6 +285,38 @@ func (self *_runtime) convertNumeric(v Value, t reflect.Type) reflect.Value {
panic(self.panicTypeError(fmt.Sprintf("unsupported type %v for numeric conversion", val.Type())))
}
func fieldIndexByName(t reflect.Type, name string) []int {
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if !validGoStructName(f.Name) {
continue
}
if f.Anonymous {
if a := fieldIndexByName(f.Type, name); a != nil {
return append([]int{i}, a...)
}
}
if a := strings.SplitN(f.Tag.Get("json"), ",", 2); a[0] != "" {
if a[0] == "-" {
continue
}
if a[0] == name {
return []int{i}
}
}
if f.Name == name {
return []int{i}
}
}
return nil
}
var typeOfValue = reflect.TypeOf(Value{})
// convertCallParameter converts request val to type t if possible.
@ -467,41 +499,15 @@ func (self *_runtime) convertCallParameter(v Value, t reflect.Type) reflect.Valu
s := reflect.New(t)
for _, k := range o.propertyOrder {
var f *reflect.StructField
idx := fieldIndexByName(t, k)
for i := 0; i < t.NumField(); i++ {
ff := t.Field(i)
if j := ff.Tag.Get("json"); j != "" {
if j == "-" {
continue
}
a := strings.Split(j, ",")
if a[0] == k {
f = &ff
break
}
}
if ff.Name == k {
f = &ff
break
}
if strings.EqualFold(ff.Name, k) {
f = &ff
}
}
if f == nil {
if idx == nil {
panic(self.panicTypeError("can't convert object; field %q was supplied but does not exist on target %v", k, t))
}
ss := s
for _, i := range f.Index {
for _, i := range idx {
if ss.Kind() == reflect.Ptr {
if ss.IsNil() {
if !ss.CanSet() {
@ -572,7 +578,7 @@ func (self *_runtime) convertCallParameter(v Value, t reflect.Type) reflect.Valu
s = v.Class()
}
panic(self.panicTypeError("can't convert from %q to %q", s, t.String()))
panic(self.panicTypeError("can't convert from %q to %q", s, t))
}
func (self *_runtime) toValue(value interface{}) Value {

View File

@ -36,6 +36,10 @@ func _newGoStructObject(value reflect.Value) *_goStructObject {
}
func (self _goStructObject) getValue(name string) reflect.Value {
if f, ok := self.field(name); ok {
return reflect.Indirect(self.value).FieldByIndex(f.Index)
}
if validGoStructName(name) {
// Do not reveal hidden or unexported fields
if field := reflect.Indirect(self.value).FieldByName(name); (field != reflect.Value{}) {
@ -51,24 +55,26 @@ func (self _goStructObject) getValue(name string) reflect.Value {
}
func (self _goStructObject) field(name string) (reflect.StructField, bool) {
return reflect.Indirect(self.value).Type().FieldByName(name)
t := reflect.Indirect(self.value).Type()
if idx := fieldIndexByName(t, name); len(idx) > 0 {
return t.FieldByIndex(idx), true
}
return reflect.StructField{}, false
}
func (self _goStructObject) method(name string) (reflect.Method, bool) {
return reflect.Indirect(self.value).Type().MethodByName(name)
}
func (self _goStructObject) setValue(name string, value Value) bool {
field, exists := self.field(name)
if !exists {
func (self _goStructObject) setValue(rt *_runtime, name string, value Value) bool {
if _, exists := self.field(name); !exists {
return false
}
fieldValue := self.getValue(name)
reflectValue, err := value.toReflectValue(field.Type.Kind())
if err != nil {
panic(err)
}
fieldValue.Set(reflectValue)
fieldValue.Set(rt.convertCallParameter(value, fieldValue.Type()))
return true
}
@ -128,7 +134,7 @@ func goStructCanPut(self *_object, name string) bool {
func goStructPut(self *_object, name string, value Value, throw bool) {
object := self.value.(*_goStructObject)
if object.setValue(name, value) {
if object.setValue(self.runtime, name, value) {
return
}