diff --git a/bootstrap/bpdoc/bpdoc.go b/bootstrap/bpdoc/bpdoc.go index 49ed8bc..8ce7879 100644 --- a/bootstrap/bpdoc/bpdoc.go +++ b/bootstrap/bpdoc/bpdoc.go @@ -204,6 +204,10 @@ func nestedPropertyStructs(s reflect.Value) []nestedProperty { if proptools.HasTag(field, "blueprint", "mutated") { continue } + if proptools.IsConfigurable(field.Type) { + // Don't recurse into configurable properties, they're structs but not property structs + continue + } fieldValue := structValue.Field(i) diff --git a/bootstrap/bpdoc/bpdoc_test.go b/bootstrap/bpdoc/bpdoc_test.go index 67ad783..af993d3 100644 --- a/bootstrap/bpdoc/bpdoc_test.go +++ b/bootstrap/bpdoc/bpdoc_test.go @@ -112,6 +112,10 @@ func TestAllPackages(t *testing.T) { name: "list_of_nested", typ: "list of structToNest", }, + propInfo{ + name: "configurable_bool", + typ: "configurable bool", + }, propInfo{ name: "nested_in_other_embedded", typ: "otherStructToNest", diff --git a/bootstrap/bpdoc/properties.go b/bootstrap/bpdoc/properties.go index 29e6c56..404b8b9 100644 --- a/bootstrap/bpdoc/properties.go +++ b/bootstrap/bpdoc/properties.go @@ -272,6 +272,21 @@ func getType(expr ast.Expr) (typ string, innerProps []Property, err error) { if err != nil { return "", nil, err } + case *ast.IndexExpr: + // IndexExpr is used to represent generic type arguments + if !isConfigurableAst(a.X) { + var writer strings.Builder + if err := ast.Fprint(&writer, nil, expr, nil); err != nil { + return "", nil, err + } + return "", nil, fmt.Errorf("unknown type %s", writer.String()) + } + var innerType string + innerType, innerProps, err = getType(a.Index) + if err != nil { + return "", nil, err + } + typ = "configurable " + innerType default: typ = fmt.Sprintf("%T", expr) } @@ -279,6 +294,20 @@ func getType(expr ast.Expr) (typ string, innerProps []Property, err error) { return typ, innerProps, nil } +func isConfigurableAst(expr ast.Expr) bool { + switch e := expr.(type) { + case *ast.Ident: + return e.Name == "Configurable" + case *ast.SelectorExpr: + if l, ok := e.X.(*ast.Ident); ok && l.Name == "proptools" { + if e.Sel.Name == "Configurable" { + return true + } + } + } + return false +} + func (ps *PropertyStruct) ExcludeByTag(key, value string) { filterPropsByTag(&ps.Properties, key, value, true) } diff --git a/bootstrap/bpdoc/reader.go b/bootstrap/bpdoc/reader.go index 7aa655b..4b7f2b1 100644 --- a/bootstrap/bpdoc/reader.go +++ b/bootstrap/bpdoc/reader.go @@ -25,6 +25,8 @@ import ( "runtime" "strings" "sync" + + "github.com/google/blueprint/proptools" ) // Handles parsing and low-level processing of Blueprint module source files. Note that most getter @@ -119,7 +121,7 @@ func (r *Reader) PropertyStruct(pkgPath, name string, defaults reflect.Value) (* var props []Property // Base case: primitive type - if defaults.Kind() != reflect.Struct { + if defaults.Kind() != reflect.Struct || proptools.IsConfigurable(defaults.Type()) { props = append(props, Property{Name: name, Type: defaults.Type().String()}) return &PropertyStruct{Properties: props}, nil diff --git a/bootstrap/bpdoc/reader_test.go b/bootstrap/bpdoc/reader_test.go index bf324bf..46ab084 100644 --- a/bootstrap/bpdoc/reader_test.go +++ b/bootstrap/bpdoc/reader_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) type factoryFn func() (blueprint.Module, []interface{}) @@ -81,6 +82,8 @@ type complexProps struct { List_of_ints []int List_of_nested []structToNest + + Configurable_bool proptools.Configurable[bool] } // props docs. diff --git a/context.go b/context.go index 738e4c3..2d0205f 100644 --- a/context.go +++ b/context.go @@ -3883,7 +3883,7 @@ func (c *Context) OutDir() (string, error) { // ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to // property structs returned by the factory for that module type. func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} { - ret := make(map[string][]interface{}) + ret := make(map[string][]interface{}, len(c.moduleFactories)) for moduleType, factory := range c.moduleFactories { _, ret[moduleType] = factory() } diff --git a/proptools/proptools.go b/proptools/proptools.go index 270512a..409cd55 100644 --- a/proptools/proptools.go +++ b/proptools/proptools.go @@ -156,3 +156,7 @@ func isMapOfStruct(t reflect.Type) bool { func isConfigurable(t reflect.Type) bool { return isStruct(t) && t.NumField() > 0 && typeFields(t)[0].Type == configurableMarkerType } + +func IsConfigurable(t reflect.Type) bool { + return isConfigurable(t) +}