Browse Source

Do not skip the entire anonymous field if its name is mapped to "". Fixes #84

Dmitry Panov 6 years ago
parent
commit
64be363d12
2 changed files with 130 additions and 28 deletions
  1. 24 21
      object_goreflect.go
  2. 106 7
      object_goreflect_test.go

+ 24 - 21
object_goreflect.go

@@ -425,34 +425,37 @@ func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectTypeI
 		}
 		if r.fieldNameMapper != nil {
 			name = r.fieldNameMapper.FieldName(t, field)
-			if name == "" {
-				continue
-			}
 		}
 
-		if inf, exists := info.Fields[name]; !exists {
-			info.FieldNames = append(info.FieldNames, name)
-		} else {
-			if len(inf.Index) <= len(index) {
-				continue
+		if name != "" {
+			if inf, exists := info.Fields[name]; !exists {
+				info.FieldNames = append(info.FieldNames, name)
+			} else {
+				if len(inf.Index) <= len(index) {
+					continue
+				}
 			}
 		}
 
-		idx := make([]int, len(index)+1)
-		copy(idx, index)
-		idx[len(idx)-1] = i
+		if name != "" || field.Anonymous {
+			idx := make([]int, len(index)+1)
+			copy(idx, index)
+			idx[len(idx)-1] = i
 
-		info.Fields[name] = reflectFieldInfo{
-			Index:     idx,
-			Anonymous: field.Anonymous,
-		}
-		if field.Anonymous {
-			typ := field.Type
-			for typ.Kind() == reflect.Ptr {
-				typ = typ.Elem()
+			if name != "" {
+				info.Fields[name] = reflectFieldInfo{
+					Index:     idx,
+					Anonymous: field.Anonymous,
+				}
 			}
-			if typ.Kind() == reflect.Struct {
-				r.buildFieldInfo(typ, idx, info)
+			if field.Anonymous {
+				typ := field.Type
+				for typ.Kind() == reflect.Ptr {
+					typ = typ.Elem()
+				}
+				if typ.Kind() == reflect.Struct {
+					r.buildFieldInfo(typ, idx, info)
+				}
 			}
 		}
 	}

+ 106 - 7
object_goreflect_test.go

@@ -59,13 +59,6 @@ func TestGoReflectSet(t *testing.T) {
 	}
 }
 
-type TestGoReflectMethod_Struct struct {
-}
-
-func (s *TestGoReflectMethod_Struct) M() int {
-	return 42
-}
-
 func TestGoReflectEnumerate(t *testing.T) {
 	const SCRIPT = `
 	var hasX = false;
@@ -630,6 +623,112 @@ func TestStructNonAddressable(t *testing.T) {
 	}
 }
 
+type testFieldMapper struct {
+}
+
+func (testFieldMapper) FieldName(t reflect.Type, f reflect.StructField) string {
+	if tag := f.Tag.Get("js"); tag != "" {
+		if tag == "-" {
+			return ""
+		}
+		return tag
+	}
+
+	return f.Name
+}
+
+func (testFieldMapper) MethodName(t reflect.Type, m reflect.Method) string {
+	return m.Name
+}
+
+func TestHidingAnonField(t *testing.T) {
+	type InnerType struct {
+		AnotherField string
+	}
+
+	type OuterType struct {
+		InnerType `js:"-"`
+		SomeField string
+	}
+
+	const SCRIPT = `
+	var a = Object.getOwnPropertyNames(o);
+	if (a.length !== 2) {
+		throw new Error("unexpected length: " + a.length);
+	}
+
+	if (a.indexOf("SomeField") === -1) {
+		throw new Error("no SomeField");
+	}
+
+	if (a.indexOf("AnotherField") === -1) {
+		throw new Error("no SomeField");
+	}
+	`
+
+	var o OuterType
+
+	vm := New()
+	vm.SetFieldNameMapper(testFieldMapper{})
+	vm.Set("o", &o)
+
+	_, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestFieldOverriding(t *testing.T) {
+	type InnerType struct {
+		AnotherField  string
+		AnotherField1 string
+	}
+
+	type OuterType struct {
+		InnerType     `js:"-"`
+		SomeField     string
+		AnotherField  string `js:"-"`
+		AnotherField1 string
+	}
+
+	const SCRIPT = `
+	if (o.SomeField !== "SomeField") {
+		throw new Error("SomeField");
+	}
+
+	if (o.AnotherField !== "AnotherField inner") {
+		throw new Error("AnotherField");
+	}
+
+	if (o.AnotherField1 !== "AnotherField1 outer") {
+		throw new Error("AnotherField1");
+	}
+
+	if (o.InnerType) {
+		throw new Error("InnerType is present");
+	}
+	`
+
+	o := OuterType{
+		InnerType: InnerType{
+			AnotherField:  "AnotherField inner",
+			AnotherField1: "AnotherField1 inner",
+		},
+		SomeField:     "SomeField",
+		AnotherField:  "AnotherField outer",
+		AnotherField1: "AnotherField1 outer",
+	}
+
+	vm := New()
+	vm.SetFieldNameMapper(testFieldMapper{})
+	vm.Set("o", &o)
+
+	_, err := vm.RunString(SCRIPT)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 func BenchmarkGoReflectGet(b *testing.B) {
 	type parent struct {
 		field, Test1, Test2, Test3, Test4, Test5, Test string