Move arch properties to proptools.FilterPropertyStruct
Test: m checkbuild
Change-Id: I85c5e6c86aea4ccf5bcddc2e5d468d66e0b38671
diff --git a/android/arch.go b/android/arch.go
index 907c58b..b5b52a9 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -855,149 +855,11 @@
}
}
-func filterArchStructFields(fields []reflect.StructField) (filteredFields []reflect.StructField, filtered bool) {
- for _, field := range fields {
- if !proptools.HasTag(field, "android", "arch_variant") {
- filtered = true
- continue
- }
-
- // The arch_variant field isn't necessary past this point
- // Instead of wasting space, just remove it. Go also has a
- // 16-bit limit on structure name length. The name is constructed
- // based on the Go source representation of the structure, so
- // the tag names count towards that length.
- //
- // TODO: handle the uncommon case of other tags being involved
- if field.Tag == `android:"arch_variant"` {
- field.Tag = ""
- }
-
- // Recurse into structs
- switch field.Type.Kind() {
- case reflect.Struct:
- var subFiltered bool
- field.Type, subFiltered = filterArchStruct(field.Type)
- filtered = filtered || subFiltered
- if field.Type == nil {
- continue
- }
- case reflect.Ptr:
- if field.Type.Elem().Kind() == reflect.Struct {
- nestedType, subFiltered := filterArchStruct(field.Type.Elem())
- filtered = filtered || subFiltered
- if nestedType == nil {
- continue
- }
- field.Type = reflect.PtrTo(nestedType)
- }
- case reflect.Interface:
- panic("Interfaces are not supported in arch_variant properties")
- }
-
- filteredFields = append(filteredFields, field)
- }
-
- return filteredFields, filtered
-}
-
-// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a reflect.Type
-// that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, and a bool
-// that is true if the new struct type has fewer fields than the original type. If there are no fields in the
-// original type with the struct tag it returns nil and true.
-func filterArchStruct(prop reflect.Type) (filteredProp reflect.Type, filtered bool) {
- var fields []reflect.StructField
-
- ptr := prop.Kind() == reflect.Ptr
- if ptr {
- prop = prop.Elem()
- }
-
- for i := 0; i < prop.NumField(); i++ {
- fields = append(fields, prop.Field(i))
- }
-
- filteredFields, filtered := filterArchStructFields(fields)
-
- if len(filteredFields) == 0 {
- return nil, true
- }
-
- if !filtered {
- if ptr {
- return reflect.PtrTo(prop), false
- }
- return prop, false
- }
-
- ret := reflect.StructOf(filteredFields)
- if ptr {
- ret = reflect.PtrTo(ret)
- }
-
- return ret, true
-}
-
-// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a list of
-// reflect.Type that only contains the fields in the original type that have an `android:"arch_variant"` struct tag,
-// and a bool that is true if the new struct type has fewer fields than the original type. If there are no fields in
-// the original type with the struct tag it returns nil and true. Each returned struct type will have a maximum of
-// 10 top level fields in it to attempt to avoid hitting the reflect.StructOf name length limit, although the limit
-// can still be reached with a single struct field with many fields in it.
-func filterArchStructSharded(prop reflect.Type) (filteredProp []reflect.Type, filtered bool) {
- var fields []reflect.StructField
-
- ptr := prop.Kind() == reflect.Ptr
- if ptr {
- prop = prop.Elem()
- }
-
- for i := 0; i < prop.NumField(); i++ {
- fields = append(fields, prop.Field(i))
- }
-
- fields, filtered = filterArchStructFields(fields)
- if !filtered {
- if ptr {
- return []reflect.Type{reflect.PtrTo(prop)}, false
- }
- return []reflect.Type{prop}, false
- }
-
- if len(fields) == 0 {
- return nil, true
- }
-
- shards := shardFields(fields, 10)
-
- for _, shard := range shards {
- s := reflect.StructOf(shard)
- if ptr {
- s = reflect.PtrTo(s)
- }
- filteredProp = append(filteredProp, s)
- }
-
- return filteredProp, true
-}
-
-func shardFields(fields []reflect.StructField, shardSize int) [][]reflect.StructField {
- ret := make([][]reflect.StructField, 0, (len(fields)+shardSize-1)/shardSize)
- for len(fields) > shardSize {
- ret = append(ret, fields[0:shardSize])
- fields = fields[shardSize:]
- }
- if len(fields) > 0 {
- ret = append(ret, fields)
- }
- return ret
-}
-
// createArchType takes a reflect.Type that is either a struct or a pointer to a struct, and returns a list of
// reflect.Type that contains the arch-variant properties inside structs for each architecture, os, target, multilib,
// etc.
func createArchType(props reflect.Type) []reflect.Type {
- propShards, _ := filterArchStructSharded(props)
+ propShards, _ := proptools.FilterPropertyStructSharded(props, filterArchStruct)
if len(propShards) == 0 {
return nil
}
@@ -1096,6 +958,23 @@
return ret
}
+func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.StructField) {
+ if proptools.HasTag(field, "android", "arch_variant") {
+ // The arch_variant field isn't necessary past this point
+ // Instead of wasting space, just remove it. Go also has a
+ // 16-bit limit on structure name length. The name is constructed
+ // based on the Go source representation of the structure, so
+ // the tag names count towards that length.
+ //
+ // TODO: handle the uncommon case of other tags being involved
+ if field.Tag == `android:"arch_variant"` {
+ field.Tag = ""
+ }
+ return true, field
+ }
+ return false, field
+}
+
var archPropTypeMap OncePer
func InitArchModule(m Module) {
diff --git a/android/arch_test.go b/android/arch_test.go
index 0589e6c..11edb4f 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -17,6 +17,8 @@
import (
"reflect"
"testing"
+
+ "github.com/google/blueprint/proptools"
)
type Named struct {
@@ -219,7 +221,7 @@
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- out, filtered := filterArchStruct(reflect.TypeOf(test.in))
+ out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct)
if filtered != test.filtered {
t.Errorf("expected filtered %v, got %v", test.filtered, filtered)
}