diff --git a/android/module.go b/android/module.go index eb9d3d7c1..e190e8be4 100644 --- a/android/module.go +++ b/android/module.go @@ -1470,8 +1470,10 @@ func (m *ModuleBase) AddJSONData(d *map[string]interface{}) { } type propInfo struct { - Name string - Type string + Name string + Type string + Value string + Values []string } func (m *ModuleBase) propertiesWithValues() []propInfo { @@ -1511,18 +1513,60 @@ func (m *ModuleBase) propertiesWithValues() []propInfo { return } elKind := v.Type().Elem().Kind() - info = append(info, propInfo{name, elKind.String() + " " + kind.String()}) + info = append(info, propInfo{Name: name, Type: elKind.String() + " " + kind.String(), Values: sliceReflectionValue(v)}) default: - info = append(info, propInfo{name, kind.String()}) + info = append(info, propInfo{Name: name, Type: kind.String(), Value: reflectionValue(v)}) } } for _, p := range props { propsWithValues("", reflect.ValueOf(p).Elem()) } + sort.Slice(info, func(i, j int) bool { + return info[i].Name < info[j].Name + }) return info } +func reflectionValue(value reflect.Value) string { + switch value.Kind() { + case reflect.Bool: + return fmt.Sprintf("%t", value.Bool()) + case reflect.Int64: + return fmt.Sprintf("%d", value.Int()) + case reflect.String: + return fmt.Sprintf("%s", value.String()) + case reflect.Struct: + if value.IsZero() { + return "{}" + } + length := value.NumField() + vals := make([]string, length, length) + for i := 0; i < length; i++ { + sTyp := value.Type().Field(i) + if proptools.ShouldSkipProperty(sTyp) { + continue + } + name := sTyp.Name + vals[i] = fmt.Sprintf("%s: %s", name, reflectionValue(value.Field(i))) + } + return fmt.Sprintf("%s{%s}", value.Type(), strings.Join(vals, ", ")) + case reflect.Array, reflect.Slice: + vals := sliceReflectionValue(value) + return fmt.Sprintf("[%s]", strings.Join(vals, ", ")) + } + return "" +} + +func sliceReflectionValue(value reflect.Value) []string { + length := value.Len() + vals := make([]string, length, length) + for i := 0; i < length; i++ { + vals[i] = reflectionValue(value.Index(i)) + } + return vals +} + func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {} func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {} diff --git a/android/module_test.go b/android/module_test.go index 1dcddf71b..77ef14673 100644 --- a/android/module_test.go +++ b/android/module_test.go @@ -563,6 +563,12 @@ type PropsTestModuleEmbedded struct { Embedded_prop *string } +type StructInSlice struct { + G string + H bool + I []string +} + type propsTestModule struct { ModuleBase DefaultableModuleBase @@ -579,6 +585,8 @@ type propsTestModule struct { E *string } F *string `blueprint:"mutated"` + + Slice_of_struct []StructInSlice } } @@ -621,7 +629,7 @@ func TestUsedProperties(t *testing.T) { } `, expectedProps: []propInfo{ - propInfo{"Name", "string"}, + propInfo{Name: "Name", Type: "string", Value: "foo"}, }, }, { @@ -634,10 +642,10 @@ func TestUsedProperties(t *testing.T) { } `, expectedProps: []propInfo{ - propInfo{"A", "string"}, - propInfo{"B", "bool"}, - propInfo{"D", "int64"}, - propInfo{"Name", "string"}, + propInfo{Name: "A", Type: "string", Value: "abc"}, + propInfo{Name: "B", Type: "bool", Value: "true"}, + propInfo{Name: "D", Type: "int64", Value: "123"}, + propInfo{Name: "Name", Type: "string", Value: "foo"}, }, }, { @@ -650,10 +658,10 @@ func TestUsedProperties(t *testing.T) { `, expectedProps: []propInfo{ // for non-pointer cannot distinguish between unused and intentionally set to empty - propInfo{"A", "string"}, - propInfo{"B", "bool"}, - propInfo{"D", "int64"}, - propInfo{"Name", "string"}, + propInfo{Name: "A", Type: "string", Value: ""}, + propInfo{Name: "B", Type: "bool", Value: "true"}, + propInfo{Name: "D", Type: "int64", Value: "123"}, + propInfo{Name: "Name", Type: "string", Value: "foo"}, }, }, { @@ -666,8 +674,8 @@ func TestUsedProperties(t *testing.T) { } `, expectedProps: []propInfo{ - propInfo{"Nested.E", "string"}, - propInfo{"Name", "string"}, + propInfo{Name: "Name", Type: "string", Value: "foo"}, + propInfo{Name: "Nested.E", Type: "string", Value: "abc"}, }, }, { @@ -682,8 +690,8 @@ func TestUsedProperties(t *testing.T) { } `, expectedProps: []propInfo{ - propInfo{"Name", "string"}, - propInfo{"Arch.X86_64.A", "string"}, + propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "abc"}, + propInfo{Name: "Name", Type: "string", Value: "foo"}, }, }, { @@ -694,8 +702,34 @@ func TestUsedProperties(t *testing.T) { } `, expectedProps: []propInfo{ - propInfo{"Embedded_prop", "string"}, - propInfo{"Name", "string"}, + propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, + propInfo{Name: "Name", Type: "string", Value: "foo"}, + }, + }, + { + desc: "struct slice", + bp: `test { + name: "foo", + slice_of_struct: [ + { + g: "abc", + h: false, + i: ["baz"], + }, + { + g: "def", + h: true, + i: [], + }, + ] + } + `, + expectedProps: []propInfo{ + propInfo{Name: "Name", Type: "string", Value: "foo"}, + propInfo{Name: "Slice_of_struct", Type: "struct slice", Values: []string{ + `android.StructInSlice{G: abc, H: false, I: [baz]}`, + `android.StructInSlice{G: def, H: true, I: []}`, + }}, }, }, { @@ -705,19 +739,20 @@ test_defaults { name: "foo_defaults", a: "a", b: true, + c: ["default_c"], embedded_prop:"a", arch: { x86_64: { - a: "a", + a: "x86_64 a", }, }, } test { name: "foo", defaults: ["foo_defaults"], - c: ["a"], + c: ["c"], nested: { - e: "d", + e: "nested e", }, target: { linux: { @@ -727,15 +762,15 @@ test { } `, expectedProps: []propInfo{ - propInfo{"A", "string"}, - propInfo{"B", "bool"}, - propInfo{"C", "string slice"}, - propInfo{"Embedded_prop", "string"}, - propInfo{"Nested.E", "string"}, - propInfo{"Name", "string"}, - propInfo{"Arch.X86_64.A", "string"}, - propInfo{"Target.Linux.A", "string"}, - propInfo{"Defaults", "string slice"}, + propInfo{Name: "A", Type: "string", Value: "a"}, + propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"}, + propInfo{Name: "B", Type: "bool", Value: "true"}, + propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}}, + propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}}, + propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, + propInfo{Name: "Name", Type: "string", Value: "foo"}, + propInfo{Name: "Nested.E", Type: "string", Value: "nested e"}, + propInfo{Name: "Target.Linux.A", Type: "string", Value: "a"}, }, }, }