Merge remote-tracking branch 'aosp/upstream'
* aosp/upstream: Correct bug in generating anonymous nested props Add docs for nested and embedded structs Test: m soong_docs Change-Id: Ide95609b6c7d221037348768ade719992801e411
This commit is contained in:
commit
2aeb413fa1
4 changed files with 159 additions and 22 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/google/blueprint/proptools"
|
"github.com/google/blueprint/proptools"
|
||||||
)
|
)
|
||||||
|
@ -58,6 +59,7 @@ type Property struct {
|
||||||
OtherTexts []template.HTML
|
OtherTexts []template.HTML
|
||||||
Properties []Property
|
Properties []Property
|
||||||
Default string
|
Default string
|
||||||
|
Anonymous bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func AllPackages(pkgFiles map[string][]string, moduleTypeNameFactories map[string]reflect.Value,
|
func AllPackages(pkgFiles map[string][]string, moduleTypeNameFactories map[string]reflect.Value,
|
||||||
|
@ -75,6 +77,7 @@ func AllPackages(pkgFiles map[string][]string, moduleTypeNameFactories map[strin
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Some pruning work
|
// Some pruning work
|
||||||
|
removeAnonymousProperties(mtInfo)
|
||||||
removeEmptyPropertyStructs(mtInfo)
|
removeEmptyPropertyStructs(mtInfo)
|
||||||
collapseDuplicatePropertyStructs(mtInfo)
|
collapseDuplicatePropertyStructs(mtInfo)
|
||||||
collapseNestedPropertyStructs(mtInfo)
|
collapseNestedPropertyStructs(mtInfo)
|
||||||
|
@ -128,7 +131,9 @@ func assembleModuleTypeInfo(r *Reader, name string, factory reflect.Value,
|
||||||
}
|
}
|
||||||
ps.ExcludeByTag("blueprint", "mutated")
|
ps.ExcludeByTag("blueprint", "mutated")
|
||||||
|
|
||||||
for nestedName, nestedValue := range nestedPropertyStructs(v) {
|
for _, nestedProperty := range nestedPropertyStructs(v) {
|
||||||
|
nestedName := nestedProperty.nestPoint
|
||||||
|
nestedValue := nestedProperty.value
|
||||||
nestedType := nestedValue.Type()
|
nestedType := nestedValue.Type()
|
||||||
|
|
||||||
// Ignore property structs with unexported or unnamed types
|
// Ignore property structs with unexported or unnamed types
|
||||||
|
@ -140,12 +145,28 @@ func assembleModuleTypeInfo(r *Reader, name string, factory reflect.Value,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
nested.ExcludeByTag("blueprint", "mutated")
|
nested.ExcludeByTag("blueprint", "mutated")
|
||||||
nestPoint := ps.GetByName(nestedName)
|
if nestedName == "" {
|
||||||
if nestPoint == nil {
|
ps.Nest(nested)
|
||||||
return nil, fmt.Errorf("nesting point %q not found", nestedName)
|
} else {
|
||||||
|
nestPoint := ps.GetByName(nestedName)
|
||||||
|
if nestPoint == nil {
|
||||||
|
return nil, fmt.Errorf("nesting point %q not found", nestedName)
|
||||||
|
}
|
||||||
|
nestPoint.Nest(nested)
|
||||||
}
|
}
|
||||||
|
|
||||||
nestPoint.Nest(nested)
|
if nestedProperty.anonymous {
|
||||||
|
if nestedName != "" {
|
||||||
|
nestedName += "."
|
||||||
|
}
|
||||||
|
nestedName += proptools.PropertyNameForField(nested.Name)
|
||||||
|
nestedProp := ps.GetByName(nestedName)
|
||||||
|
// Anonymous properties may have already been omitted, no need to ensure they are filtered later
|
||||||
|
if nestedProp != nil {
|
||||||
|
// Set property to anonymous to allow future filtering
|
||||||
|
nestedProp.SetAnonymous()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mt.PropertyStructs = append(mt.PropertyStructs, ps)
|
mt.PropertyStructs = append(mt.PropertyStructs, ps)
|
||||||
}
|
}
|
||||||
|
@ -153,10 +174,31 @@ func assembleModuleTypeInfo(r *Reader, name string, factory reflect.Value,
|
||||||
return mt, nil
|
return mt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nestedPropertyStructs(s reflect.Value) map[string]reflect.Value {
|
type nestedProperty struct {
|
||||||
ret := make(map[string]reflect.Value)
|
nestPoint string
|
||||||
|
value reflect.Value
|
||||||
|
anonymous bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func nestedPropertyStructs(s reflect.Value) []nestedProperty {
|
||||||
|
ret := make([]nestedProperty, 0)
|
||||||
var walk func(structValue reflect.Value, prefix string)
|
var walk func(structValue reflect.Value, prefix string)
|
||||||
walk = func(structValue reflect.Value, prefix string) {
|
walk = func(structValue reflect.Value, prefix string) {
|
||||||
|
var nestStruct func(field reflect.StructField, value reflect.Value, fieldName string)
|
||||||
|
nestStruct = func(field reflect.StructField, value reflect.Value, fieldName string) {
|
||||||
|
nestPoint := prefix
|
||||||
|
if field.Anonymous {
|
||||||
|
nestPoint = strings.TrimSuffix(nestPoint, ".")
|
||||||
|
} else {
|
||||||
|
nestPoint = nestPoint + proptools.PropertyNameForField(fieldName)
|
||||||
|
}
|
||||||
|
ret = append(ret, nestedProperty{nestPoint: nestPoint, value: value, anonymous: field.Anonymous})
|
||||||
|
if nestPoint != "" {
|
||||||
|
nestPoint += "."
|
||||||
|
}
|
||||||
|
walk(value, nestPoint)
|
||||||
|
}
|
||||||
|
|
||||||
typ := structValue.Type()
|
typ := structValue.Type()
|
||||||
for i := 0; i < structValue.NumField(); i++ {
|
for i := 0; i < structValue.NumField(); i++ {
|
||||||
field := typ.Field(i)
|
field := typ.Field(i)
|
||||||
|
@ -174,8 +216,9 @@ func nestedPropertyStructs(s reflect.Value) map[string]reflect.Value {
|
||||||
case reflect.Bool, reflect.String, reflect.Slice, reflect.Int, reflect.Uint:
|
case reflect.Bool, reflect.String, reflect.Slice, reflect.Int, reflect.Uint:
|
||||||
// Nothing
|
// Nothing
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
walk(fieldValue, prefix+proptools.PropertyNameForField(field.Name)+".")
|
nestStruct(field, fieldValue, field.Name)
|
||||||
case reflect.Ptr, reflect.Interface:
|
case reflect.Ptr, reflect.Interface:
|
||||||
|
|
||||||
if !fieldValue.IsNil() {
|
if !fieldValue.IsNil() {
|
||||||
// We leave the pointer intact and zero out the struct that's
|
// We leave the pointer intact and zero out the struct that's
|
||||||
// pointed to.
|
// pointed to.
|
||||||
|
@ -188,9 +231,7 @@ func nestedPropertyStructs(s reflect.Value) map[string]reflect.Value {
|
||||||
elem = elem.Elem()
|
elem = elem.Elem()
|
||||||
}
|
}
|
||||||
if elem.Kind() == reflect.Struct {
|
if elem.Kind() == reflect.Struct {
|
||||||
nestPoint := prefix + proptools.PropertyNameForField(field.Name)
|
nestStruct(field, elem, field.Name)
|
||||||
ret[nestPoint] = elem
|
|
||||||
walk(elem, nestPoint+".")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -214,6 +255,27 @@ func removeEmptyPropertyStructs(mt *ModuleType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove any property structs that are anonymous
|
||||||
|
func removeAnonymousProperties(mt *ModuleType) {
|
||||||
|
var removeAnonymousProps func(props []Property) []Property
|
||||||
|
removeAnonymousProps = func(props []Property) []Property {
|
||||||
|
newProps := make([]Property, 0, len(props))
|
||||||
|
for _, p := range props {
|
||||||
|
if p.Anonymous {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(p.Properties) > 0 {
|
||||||
|
p.Properties = removeAnonymousProps(p.Properties)
|
||||||
|
}
|
||||||
|
newProps = append(newProps, p)
|
||||||
|
}
|
||||||
|
return newProps
|
||||||
|
}
|
||||||
|
for _, ps := range mt.PropertyStructs {
|
||||||
|
ps.Properties = removeAnonymousProps(ps.Properties)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Squashes duplicates of the same property struct into single entries
|
// Squashes duplicates of the same property struct into single entries
|
||||||
func collapseDuplicatePropertyStructs(mt *ModuleType) {
|
func collapseDuplicatePropertyStructs(mt *ModuleType) {
|
||||||
var collapsed []*PropertyStruct
|
var collapsed []*PropertyStruct
|
||||||
|
|
|
@ -36,20 +36,23 @@ func TestNestedPropertyStructs(t *testing.T) {
|
||||||
// mutated shouldn't be found because it's a mutated property.
|
// mutated shouldn't be found because it's a mutated property.
|
||||||
expected := []string{"child", "child.child"}
|
expected := []string{"child", "child.child"}
|
||||||
if len(allStructs) != len(expected) {
|
if len(allStructs) != len(expected) {
|
||||||
t.Errorf("expected %d structs, got %d, all entries: %q",
|
t.Fatalf("expected %d structs, got %d, all entries: %v",
|
||||||
len(expected), len(allStructs), allStructs)
|
len(expected), len(allStructs), allStructs)
|
||||||
}
|
}
|
||||||
for _, e := range expected {
|
got := []string{}
|
||||||
if _, ok := allStructs[e]; !ok {
|
for _, s := range allStructs {
|
||||||
t.Errorf("missing entry %q, all entries: %q", e, allStructs)
|
got = append(got, s.nestPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got, expected) {
|
||||||
|
t.Errorf("Expected nested properties:\n\t %q,\n but got\n\t %q", expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAllPackages(t *testing.T) {
|
func TestAllPackages(t *testing.T) {
|
||||||
packages, err := AllPackages(pkgFiles, moduleTypeNameFactories, moduleTypeNamePropertyStructs)
|
packages, err := AllPackages(pkgFiles, moduleTypeNameFactories, moduleTypeNamePropertyStructs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected nil error for AllPackages(%v, %v, %v), got %s", pkgFiles, moduleTypeNameFactories, moduleTypeNamePropertyStructs, err)
|
t.Fatalf("expected nil error for AllPackages(%v, %v, %v), got %s", pkgFiles, moduleTypeNameFactories, moduleTypeNamePropertyStructs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if numPackages := len(packages); numPackages != 1 {
|
if numPackages := len(packages); numPackages != 1 {
|
||||||
|
@ -58,24 +61,56 @@ func TestAllPackages(t *testing.T) {
|
||||||
|
|
||||||
pkg := packages[0]
|
pkg := packages[0]
|
||||||
|
|
||||||
|
expectedProps := map[string][]string{
|
||||||
|
"bar": []string{
|
||||||
|
"a",
|
||||||
|
"nested",
|
||||||
|
"nested.c",
|
||||||
|
"nested_struct",
|
||||||
|
"nested_struct.e",
|
||||||
|
"struct_has_embed",
|
||||||
|
"struct_has_embed.nested_in_embedded",
|
||||||
|
"struct_has_embed.nested_in_embedded.e",
|
||||||
|
"struct_has_embed.f",
|
||||||
|
"nested_in_other_embedded",
|
||||||
|
"nested_in_other_embedded.g",
|
||||||
|
"h",
|
||||||
|
},
|
||||||
|
"foo": []string{
|
||||||
|
"a",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range pkg.ModuleTypes {
|
for _, m := range pkg.ModuleTypes {
|
||||||
|
foundProps := []string{}
|
||||||
for _, p := range m.PropertyStructs {
|
for _, p := range m.PropertyStructs {
|
||||||
for _, err := range noMutatedProperties(p.Properties) {
|
nestedProps, errs := findAllProperties("", p.Properties)
|
||||||
|
foundProps = append(foundProps, nestedProps...)
|
||||||
|
for _, err := range errs {
|
||||||
t.Errorf("%s", err)
|
t.Errorf("%s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if wanted, ok := expectedProps[m.Name]; ok {
|
||||||
|
if !reflect.DeepEqual(foundProps, wanted) {
|
||||||
|
t.Errorf("For %s, expected\n\t %q,\nbut got\n\t %q", m.Name, wanted, foundProps)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func noMutatedProperties(properties []Property) []error {
|
func findAllProperties(prefix string, properties []Property) ([]string, []error) {
|
||||||
|
foundProps := []string{}
|
||||||
errs := []error{}
|
errs := []error{}
|
||||||
for _, p := range properties {
|
for _, p := range properties {
|
||||||
|
foundProps = append(foundProps, prefix+p.Name)
|
||||||
if hasTag(p.Tag, "blueprint", "mutated") {
|
if hasTag(p.Tag, "blueprint", "mutated") {
|
||||||
err := fmt.Errorf("Property %s has `blueprint:\"mutated\" tag but should have been excluded.", p)
|
err := fmt.Errorf("Property %s has `blueprint:\"mutated\" tag but should have been excluded.", p.Name)
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, noMutatedProperties(p.Properties)...)
|
nestedProps, nestedErrs := findAllProperties(prefix+p.Name+".", p.Properties)
|
||||||
|
foundProps = append(foundProps, nestedProps...)
|
||||||
|
errs = append(errs, nestedErrs...)
|
||||||
}
|
}
|
||||||
return errs
|
return foundProps, errs
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,10 @@ func (ps *PropertyStruct) GetByName(name string) *Property {
|
||||||
return getByName(name, "", &ps.Properties)
|
return getByName(name, "", &ps.Properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ps *PropertyStruct) Nest(nested *PropertyStruct) {
|
||||||
|
ps.Properties = append(ps.Properties, nested.Properties...)
|
||||||
|
}
|
||||||
|
|
||||||
func getByName(name string, prefix string, props *[]Property) *Property {
|
func getByName(name string, prefix string, props *[]Property) *Property {
|
||||||
for i := range *props {
|
for i := range *props {
|
||||||
if prefix+(*props)[i].Name == name {
|
if prefix+(*props)[i].Name == name {
|
||||||
|
@ -157,6 +161,10 @@ func (p *Property) Nest(nested *PropertyStruct) {
|
||||||
p.Properties = append(p.Properties, nested.Properties...)
|
p.Properties = append(p.Properties, nested.Properties...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Property) SetAnonymous() {
|
||||||
|
p.Anonymous = true
|
||||||
|
}
|
||||||
|
|
||||||
func newPropertyStruct(t *doc.Type) (*PropertyStruct, error) {
|
func newPropertyStruct(t *doc.Type) (*PropertyStruct, error) {
|
||||||
typeSpec := t.Decl.Specs[0].(*ast.TypeSpec)
|
typeSpec := t.Decl.Specs[0].(*ast.TypeSpec)
|
||||||
ps := PropertyStruct{
|
ps := PropertyStruct{
|
||||||
|
|
|
@ -36,6 +36,32 @@ func barFactory() (blueprint.Module, []interface{}) {
|
||||||
return nil, []interface{}{&complexProps{}}
|
return nil, []interface{}{&complexProps{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type structToNest struct {
|
||||||
|
E string
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructToEmbed struct {
|
||||||
|
Nested_in_embedded structToNest
|
||||||
|
|
||||||
|
// F string
|
||||||
|
F string
|
||||||
|
}
|
||||||
|
|
||||||
|
type otherStructToNest struct {
|
||||||
|
G string
|
||||||
|
}
|
||||||
|
|
||||||
|
type OtherStructToEmbed struct {
|
||||||
|
Nested_in_other_embedded otherStructToNest
|
||||||
|
|
||||||
|
// F string
|
||||||
|
H string
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructWithEmbedded struct {
|
||||||
|
StructToEmbed
|
||||||
|
}
|
||||||
|
|
||||||
// for bpdoc_test.go
|
// for bpdoc_test.go
|
||||||
type complexProps struct {
|
type complexProps struct {
|
||||||
A string
|
A string
|
||||||
|
@ -45,6 +71,12 @@ type complexProps struct {
|
||||||
C string
|
C string
|
||||||
D_mutated string `blueprint:"mutated"`
|
D_mutated string `blueprint:"mutated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Nested_struct structToNest
|
||||||
|
|
||||||
|
Struct_has_embed StructWithEmbedded
|
||||||
|
|
||||||
|
OtherStructToEmbed
|
||||||
}
|
}
|
||||||
|
|
||||||
// props docs.
|
// props docs.
|
||||||
|
|
Loading…
Reference in a new issue