Merge "android:path attribute is respected for fields in a slice of struct"

This commit is contained in:
Treehugger Robot 2021-02-24 00:54:56 +00:00 committed by Gerrit Code Review
commit 4dc0702ce2
2 changed files with 89 additions and 35 deletions

View file

@ -76,52 +76,73 @@ func pathPropertiesForPropertyStruct(ps interface{}) []string {
var ret []string var ret []string
for _, i := range pathPropertyIndexes { for _, i := range pathPropertyIndexes {
// Turn an index into a field. var values []reflect.Value
sv := fieldByIndex(v, i) fieldsByIndex(v, i, &values)
if !sv.IsValid() { for _, sv := range values {
// Skip properties inside a nil pointer. if !sv.IsValid() {
continue // Skip properties inside a nil pointer.
}
// If the field is a non-nil pointer step into it.
if sv.Kind() == reflect.Ptr {
if sv.IsNil() {
continue continue
} }
sv = sv.Elem()
}
// Collect paths from all strings and slices of strings. // If the field is a non-nil pointer step into it.
switch sv.Kind() { if sv.Kind() == reflect.Ptr {
case reflect.String: if sv.IsNil() {
ret = append(ret, sv.String()) continue
case reflect.Slice: }
ret = append(ret, sv.Interface().([]string)...) sv = sv.Elem()
default: }
panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
v.Type().FieldByIndex(i).Name, v.Type(), sv.Type())) // Collect paths from all strings and slices of strings.
switch sv.Kind() {
case reflect.String:
ret = append(ret, sv.String())
case reflect.Slice:
ret = append(ret, sv.Interface().([]string)...)
default:
panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
}
} }
} }
return ret return ret
} }
// fieldByIndex is like reflect.Value.FieldByIndex, but returns an invalid reflect.Value when // fieldsByIndex is similar to reflect.Value.FieldByIndex, but is more robust: it doesn't track
// traversing a nil pointer to a struct. // nil pointers and it returns multiple values when there's slice of struct.
func fieldByIndex(v reflect.Value, index []int) reflect.Value { func fieldsByIndex(v reflect.Value, index []int, values *[]reflect.Value) {
// leaf case
if len(index) == 1 { if len(index) == 1 {
return v.Field(index[0]) if isSliceOfStruct(v) {
} for i := 0; i < v.Len(); i++ {
for _, x := range index { *values = append(*values, v.Index(i).Field(index[0]))
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return reflect.Value{}
} }
v = v.Elem() } else {
*values = append(*values, v.Field(index[0]))
} }
v = v.Field(x) return
} }
return v
// recursion
if v.Kind() == reflect.Ptr {
// don't track nil pointer
if v.IsNil() {
return
}
v = v.Elem()
} else if isSliceOfStruct(v) {
// do the recursion for all elements
for i := 0; i < v.Len(); i++ {
fieldsByIndex(v.Index(i).Field(index[0]), index[1:], values)
}
return
}
fieldsByIndex(v.Field(index[0]), index[1:], values)
return
}
func isSliceOfStruct(v reflect.Value) bool {
return v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Struct
} }
var pathPropertyIndexesCache OncePer var pathPropertyIndexesCache OncePer

View file

@ -33,12 +33,21 @@ type pathDepsMutatorTestModule struct {
Foo string `android:"path"` Foo string `android:"path"`
} }
// nested slices of struct
props3 struct {
X []struct {
Y []struct {
Z []string `android:"path"`
}
}
}
sourceDeps []string sourceDeps []string
} }
func pathDepsMutatorTestModuleFactory() Module { func pathDepsMutatorTestModuleFactory() Module {
module := &pathDepsMutatorTestModule{} module := &pathDepsMutatorTestModule{}
module.AddProperties(&module.props, &module.props2) module.AddProperties(&module.props, &module.props2, &module.props3)
InitAndroidArchModule(module, DeviceSupported, MultilibBoth) InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
return module return module
} }
@ -73,8 +82,20 @@ func TestPathDepsMutator(t *testing.T) {
bar: [":b"], bar: [":b"],
baz: ":c{.bar}", baz: ":c{.bar}",
qux: ":d", qux: ":d",
x: [
{
y: [
{
z: [":x", ":y"],
},
{
z: [":z"],
},
],
},
],
}`, }`,
deps: []string{"a", "b", "c"}, deps: []string{"a", "b", "c", "x", "y", "z"},
}, },
{ {
name: "arch variant", name: "arch variant",
@ -113,6 +134,18 @@ func TestPathDepsMutator(t *testing.T) {
filegroup { filegroup {
name: "d", name: "d",
} }
filegroup {
name: "x",
}
filegroup {
name: "y",
}
filegroup {
name: "z",
}
` `
config := TestArchConfig(buildDir, nil, bp, nil) config := TestArchConfig(buildDir, nil, bp, nil)