Merge remote-tracking branch 'aosp/upstream' into master

* aosp/upstream:
  Add proptools.FilterPropertyStruct
  Make CreateModule return the newly created module
  Add proptools.Int and proptools.IntDefault

Test: m checkbuild
Change-Id: I4bbd45be12794c1a8575799950772d4ecd272628
diff --git a/Blueprints b/Blueprints
index d58169e..c3c8975 100644
--- a/Blueprints
+++ b/Blueprints
@@ -79,6 +79,7 @@
         "proptools/clone.go",
         "proptools/escape.go",
         "proptools/extend.go",
+        "proptools/filter.go",
         "proptools/proptools.go",
         "proptools/tag.go",
         "proptools/typeequal.go",
@@ -87,6 +88,7 @@
         "proptools/clone_test.go",
         "proptools/escape_test.go",
         "proptools/extend_test.go",
+        "proptools/filter_test.go",
         "proptools/tag_test.go",
         "proptools/typeequal_test.go",
     ],
diff --git a/go.mod b/go.mod
index 933cd12..fe96d45 100644
--- a/go.mod
+++ b/go.mod
@@ -1 +1,3 @@
 module github.com/google/blueprint
+
+go 1.13
diff --git a/module_ctx.go b/module_ctx.go
index bc05787..be5d974 100644
--- a/module_ctx.go
+++ b/module_ctx.go
@@ -712,7 +712,7 @@
 
 	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
 	// the specified property structs to it as if the properties were set in a blueprint file.
-	CreateModule(ModuleFactory, ...interface{})
+	CreateModule(ModuleFactory, ...interface{}) Module
 }
 
 type BottomUpMutatorContext interface {
@@ -934,7 +934,7 @@
 	mctx.rename = append(mctx.rename, rename{mctx.module.group, name})
 }
 
-func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) {
+func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
 	module := mctx.context.newModule(factory)
 
 	module.relBlueprintsFile = mctx.module.relBlueprintsFile
@@ -950,6 +950,8 @@
 	}
 
 	mctx.newModules = append(mctx.newModules, module)
+
+	return module.logicModule
 }
 
 // SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
diff --git a/proptools/filter.go b/proptools/filter.go
new file mode 100644
index 0000000..7a61b02
--- /dev/null
+++ b/proptools/filter.go
@@ -0,0 +1,159 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package proptools
+
+import (
+	"reflect"
+)
+
+type FilterFieldPredicate func(field reflect.StructField, string string) (bool, reflect.StructField)
+
+func filterPropertyStructFields(fields []reflect.StructField, prefix string, predicate FilterFieldPredicate) (filteredFields []reflect.StructField, filtered bool) {
+	for _, field := range fields {
+		var keep bool
+		if keep, field = predicate(field, prefix); !keep {
+			filtered = true
+			continue
+		}
+
+		subPrefix := field.Name
+		if prefix != "" {
+			subPrefix = prefix + "." + subPrefix
+		}
+
+		// Recurse into structs
+		switch field.Type.Kind() {
+		case reflect.Struct:
+			var subFiltered bool
+			field.Type, subFiltered = filterPropertyStruct(field.Type, subPrefix, predicate)
+			filtered = filtered || subFiltered
+			if field.Type == nil {
+				continue
+			}
+		case reflect.Ptr:
+			if field.Type.Elem().Kind() == reflect.Struct {
+				nestedType, subFiltered := filterPropertyStruct(field.Type.Elem(), subPrefix, predicate)
+				filtered = filtered || subFiltered
+				if nestedType == nil {
+					continue
+				}
+				field.Type = reflect.PtrTo(nestedType)
+			}
+		case reflect.Interface:
+			panic("Interfaces are not supported in filtered property structs")
+		}
+
+		filteredFields = append(filteredFields, field)
+	}
+
+	return filteredFields, filtered
+}
+
+// FilterPropertyStruct takes a reflect.Type that is either a struct or a pointer to a struct, and returns a
+// reflect.Type that only contains the fields in the original type for which predicate returns true, 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 for which predicate returns true it returns nil and true.
+func FilterPropertyStruct(prop reflect.Type, predicate FilterFieldPredicate) (filteredProp reflect.Type, filtered bool) {
+	return filterPropertyStruct(prop, "", predicate)
+}
+
+func filterPropertyStruct(prop reflect.Type, prefix string, predicate FilterFieldPredicate) (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 := filterPropertyStructFields(fields, prefix, predicate)
+
+	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
+}
+
+// FilterPropertyStructSharded 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 for which predicate returns true, 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
+// for which predicate returns true 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 65535 byte type name length limit in reflect.StructOf
+// (reflect.nameFrom: name too long), although the limit can still be reached with a single struct field with many
+// fields in it.
+func FilterPropertyStructSharded(prop reflect.Type, predicate FilterFieldPredicate) (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 = filterPropertyStructFields(fields, "", predicate)
+	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
+}
diff --git a/proptools/filter_test.go b/proptools/filter_test.go
new file mode 100644
index 0000000..695549a
--- /dev/null
+++ b/proptools/filter_test.go
@@ -0,0 +1,239 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package proptools
+
+import (
+	"reflect"
+	"testing"
+)
+
+type Named struct {
+	A *string `keep:"true"`
+	B *string
+}
+
+type NamedAllFiltered struct {
+	A *string
+}
+
+type NamedNoneFiltered struct {
+	A *string `keep:"true"`
+}
+
+func TestFilterPropertyStruct(t *testing.T) {
+	tests := []struct {
+		name     string
+		in       interface{}
+		out      interface{}
+		filtered bool
+	}{
+		// Property tests
+		{
+			name: "basic",
+			in: &struct {
+				A *string `keep:"true"`
+				B *string
+			}{},
+			out: &struct {
+				A *string
+			}{},
+			filtered: true,
+		},
+		{
+			name: "all filtered",
+			in: &struct {
+				A *string
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "none filtered",
+			in: &struct {
+				A *string `keep:"true"`
+			}{},
+			out: &struct {
+				A *string `keep:"true"`
+			}{},
+			filtered: false,
+		},
+
+		// Sub-struct tests
+		{
+			name: "substruct",
+			in: &struct {
+				A struct {
+					A *string `keep:"true"`
+					B *string
+				} `keep:"true"`
+			}{},
+			out: &struct {
+				A struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "substruct all filtered",
+			in: &struct {
+				A struct {
+					A *string
+				} `keep:"true"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "substruct none filtered",
+			in: &struct {
+				A struct {
+					A *string `keep:"true"`
+				} `keep:"true"`
+			}{},
+			out: &struct {
+				A struct {
+					A *string `keep:"true"`
+				} `keep:"true"`
+			}{},
+			filtered: false,
+		},
+
+		// Named sub-struct tests
+		{
+			name: "named substruct",
+			in: &struct {
+				A Named `keep:"true"`
+			}{},
+			out: &struct {
+				A struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "substruct all filtered",
+			in: &struct {
+				A NamedAllFiltered `keep:"true"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "substruct none filtered",
+			in: &struct {
+				A NamedNoneFiltered `keep:"true"`
+			}{},
+			out: &struct {
+				A NamedNoneFiltered `keep:"true"`
+			}{},
+			filtered: false,
+		},
+
+		// Pointer to sub-struct tests
+		{
+			name: "pointer substruct",
+			in: &struct {
+				A *struct {
+					A *string `keep:"true"`
+					B *string
+				} `keep:"true"`
+			}{},
+			out: &struct {
+				A *struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "pointer substruct all filtered",
+			in: &struct {
+				A *struct {
+					A *string
+				} `keep:"true"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "pointer substruct none filtered",
+			in: &struct {
+				A *struct {
+					A *string `keep:"true"`
+				} `keep:"true"`
+			}{},
+			out: &struct {
+				A *struct {
+					A *string `keep:"true"`
+				} `keep:"true"`
+			}{},
+			filtered: false,
+		},
+
+		// Pointer to named sub-struct tests
+		{
+			name: "pointer named substruct",
+			in: &struct {
+				A *Named `keep:"true"`
+			}{},
+			out: &struct {
+				A *struct {
+					A *string
+				}
+			}{},
+			filtered: true,
+		},
+		{
+			name: "pointer substruct all filtered",
+			in: &struct {
+				A *NamedAllFiltered `keep:"true"`
+			}{},
+			out:      nil,
+			filtered: true,
+		},
+		{
+			name: "pointer substruct none filtered",
+			in: &struct {
+				A *NamedNoneFiltered `keep:"true"`
+			}{},
+			out: &struct {
+				A *NamedNoneFiltered `keep:"true"`
+			}{},
+			filtered: false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			out, filtered := FilterPropertyStruct(reflect.TypeOf(test.in),
+				func(field reflect.StructField, prefix string) (bool, reflect.StructField) {
+					if HasTag(field, "keep", "true") {
+						field.Tag = ""
+						return true, field
+					}
+					return false, field
+				})
+			if filtered != test.filtered {
+				t.Errorf("expected filtered %v, got %v", test.filtered, filtered)
+			}
+			expected := reflect.TypeOf(test.out)
+			if out != expected {
+				t.Errorf("expected type %v, got %v", expected, out)
+			}
+		})
+	}
+}
diff --git a/proptools/proptools.go b/proptools/proptools.go
index e6e3ae7..6881828 100644
--- a/proptools/proptools.go
+++ b/proptools/proptools.go
@@ -82,3 +82,18 @@
 func String(s *string) string {
 	return StringDefault(s, "")
 }
+
+// IntDefault takes a pointer to an int64 and returns the value pointed to by the pointer cast to int
+// if it is non-nil, or def if the pointer is nil.
+func IntDefault(i *int64, def int) int {
+	if i != nil {
+		return int(*i)
+	}
+	return def
+}
+
+// Int takes a pointer to an int64 and returns the value pointed to by the pointer cast to int
+// if it is non-nil, or 0 if the pointer is nil.
+func Int(i *int64) int {
+	return IntDefault(i, 0)
+}