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,8 +76,9 @@ 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)
for _, sv := range values {
if !sv.IsValid() { if !sv.IsValid() {
// Skip properties inside a nil pointer. // Skip properties inside a nil pointer.
continue continue
@ -102,26 +103,46 @@ func pathPropertiesForPropertyStruct(ps interface{}) []string {
v.Type().FieldByIndex(i).Name, v.Type(), sv.Type())) 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++ {
*values = append(*values, v.Index(i).Field(index[0]))
} }
for _, x := range index { } else {
*values = append(*values, v.Field(index[0]))
}
return
}
// recursion
if v.Kind() == reflect.Ptr { if v.Kind() == reflect.Ptr {
// don't track nil pointer
if v.IsNil() { if v.IsNil() {
return reflect.Value{} return
} }
v = v.Elem() 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)
} }
v = v.Field(x) return
} }
return v 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)