Only instantiate nil struct pointers that are used

unpackProperties was instantiating all nil struct pointers in any struct
that had a property set.  Check if the property is set first, and only
instantiate the struct if it was set.

This has a slight behavioral change, as now structures that only exist
through nil pointers and are never set into will not be type-checked.
This should be fixed in a later patch set that moves the type checking
to be done across all property structs once per factory before blueprint
files are loaded.

Change-Id: I0dea34d7fff76bb4fc907516a2d996e4ea2408d6
This commit is contained in:
Colin Cross 2016-08-08 17:24:03 -07:00
parent fd1ef9ec7a
commit a437135876

View file

@ -139,10 +139,15 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
panic(fmt.Errorf("field %s is not settable", propertyName))
}
// Get the property value if it was specified.
packedProperty, propertyIsSet := propertyMap[propertyName]
origFieldValue := fieldValue
// To make testing easier we validate the struct field's type regardless
// of whether or not the property was specified in the parsed string.
// TODO(ccross): we don't validate types inside nil struct pointers
// Move type validation to a function that runs on each factory once
switch kind := fieldValue.Kind(); kind {
case reflect.Bool, reflect.String, reflect.Struct:
// Do nothing
@ -164,7 +169,10 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
case reflect.Ptr:
switch ptrKind := fieldValue.Type().Elem().Kind(); ptrKind {
case reflect.Struct:
if fieldValue.IsNil() {
if fieldValue.IsNil() && (propertyIsSet || field.Anonymous) {
// Instantiate nil struct pointers
// Set into origFieldValue in case it was an interface, in which case
// fieldValue points to the unsettable pointer inside the interface
fieldValue = reflect.New(fieldValue.Type().Elem())
origFieldValue.Set(fieldValue)
}
@ -190,9 +198,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
continue
}
// Get the property value if it was specified.
packedProperty, ok := propertyMap[propertyName]
if !ok {
if !propertyIsSet {
// This property wasn't specified.
continue
}