aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2019-03-07 11:27:58 -0800
committerandroid-build-merger <android-build-merger@google.com>2019-03-07 11:27:58 -0800
commit2cab480e587373be293104cb35ebff68d9ccea8b (patch)
treef3dc11476bb5e8fa9476c9bbed170ea900a970ab
parent8d7c363c122279d84ef179ddd31ce0a1cdf63525 (diff)
parentfe4eb94eb07216b6ce65d5495bfa04875d0e18b9 (diff)
downloadblueprint-2cab480e587373be293104cb35ebff68d9ccea8b.tar.gz
Merge remote-tracking branch 'aosp/upstream' into master am: ba03162726
am: fe4eb94eb0 Change-Id: I3d1be2ddb41257175482d8042750be8d43f93bfb
-rw-r--r--Blueprints2
-rw-r--r--proptools/proptools.go13
-rw-r--r--proptools/tag.go67
-rw-r--r--proptools/tag_test.go140
4 files changed, 209 insertions, 13 deletions
diff --git a/Blueprints b/Blueprints
index 56e28db..35e4190 100644
--- a/Blueprints
+++ b/Blueprints
@@ -80,12 +80,14 @@ bootstrap_go_package {
"proptools/escape.go",
"proptools/extend.go",
"proptools/proptools.go",
+ "proptools/tag.go",
"proptools/typeequal.go",
],
testSrcs: [
"proptools/clone_test.go",
"proptools/escape_test.go",
"proptools/extend_test.go",
+ "proptools/tag_test.go",
"proptools/typeequal_test.go",
],
}
diff --git a/proptools/proptools.go b/proptools/proptools.go
index f4da29e..e6e3ae7 100644
--- a/proptools/proptools.go
+++ b/proptools/proptools.go
@@ -15,8 +15,6 @@
package proptools
import (
- "reflect"
- "strings"
"unicode"
"unicode/utf8"
)
@@ -39,17 +37,6 @@ func FieldNameForProperty(propertyName string) string {
return fieldName
}
-func HasTag(field reflect.StructField, name, value string) bool {
- tag := field.Tag.Get(name)
- for _, entry := range strings.Split(tag, ",") {
- if entry == value {
- return true
- }
- }
-
- return false
-}
-
// BoolPtr returns a pointer to a new bool containing the given value.
func BoolPtr(b bool) *bool {
return &b
diff --git a/proptools/tag.go b/proptools/tag.go
new file mode 100644
index 0000000..af5b97e
--- /dev/null
+++ b/proptools/tag.go
@@ -0,0 +1,67 @@
+// 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 (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// HasTag returns true if a StructField has a tag in the form `name:"foo,value"`.
+func HasTag(field reflect.StructField, name, value string) bool {
+ tag := field.Tag.Get(name)
+ for _, entry := range strings.Split(tag, ",") {
+ if entry == value {
+ return true
+ }
+ }
+
+ return false
+}
+
+// PropertyIndexesWithTag returns the indexes of all properties (in the form used by reflect.Value.FieldByIndex) that
+// are tagged with the given key and value, including ones found in embedded structs or pointers to structs.
+func PropertyIndexesWithTag(ps interface{}, key, value string) [][]int {
+ t := reflect.TypeOf(ps)
+ if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
+ panic(fmt.Errorf("type %s is not a pointer to a struct", t))
+ }
+ t = t.Elem()
+
+ return propertyIndexesWithTag(t, key, value)
+}
+func propertyIndexesWithTag(t reflect.Type, key, value string) [][]int {
+ var indexes [][]int
+
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ ft := field.Type
+ if ft.Kind() == reflect.Struct || (ft.Kind() == reflect.Ptr && ft.Elem().Kind() == reflect.Struct) {
+ if ft.Kind() == reflect.Ptr {
+ ft = ft.Elem()
+ }
+ subIndexes := propertyIndexesWithTag(ft, key, value)
+ for _, sub := range subIndexes {
+ sub = append([]int{i}, sub...)
+ indexes = append(indexes, sub)
+ }
+ } else if HasTag(field, key, value) {
+ indexes = append(indexes, field.Index)
+ }
+ }
+
+ return indexes
+}
diff --git a/proptools/tag_test.go b/proptools/tag_test.go
new file mode 100644
index 0000000..0041c54
--- /dev/null
+++ b/proptools/tag_test.go
@@ -0,0 +1,140 @@
+// 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"
+)
+
+func TestHasTag(t *testing.T) {
+ type testType struct {
+ NoTag string
+ EmptyTag string ``
+ OtherTag string `foo:"bar"`
+ MatchingTag string `name:"value"`
+ ExtraValues string `name:"foo,value,bar"`
+ ExtraTags string `foo:"bar" name:"value"`
+ }
+
+ tests := []struct {
+ field string
+ want bool
+ }{
+ {
+ field: "NoTag",
+ want: false,
+ },
+ {
+ field: "EmptyTag",
+ want: false,
+ },
+ {
+ field: "OtherTag",
+ want: false,
+ },
+ {
+ field: "MatchingTag",
+ want: true,
+ },
+ {
+ field: "ExtraValues",
+ want: true,
+ },
+ {
+ field: "ExtraTags",
+ want: true,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.field, func(t *testing.T) {
+ field, _ := reflect.TypeOf(testType{}).FieldByName(test.field)
+ if got := HasTag(field, "name", "value"); got != test.want {
+ t.Errorf(`HasTag(%q, "name", "value") = %v, want %v`, field.Tag, got, test.want)
+ }
+ })
+ }
+}
+
+func TestPropertyIndexesWithTag(t *testing.T) {
+ tests := []struct {
+ name string
+ ps interface{}
+ want [][]int
+ }{
+ {
+ name: "none",
+ ps: &struct {
+ Foo string
+ }{},
+ want: nil,
+ },
+ {
+ name: "one",
+ ps: &struct {
+ Foo string `name:"value"`
+ }{},
+ want: [][]int{{0}},
+ },
+ {
+ name: "two",
+ ps: &struct {
+ Foo string `name:"value"`
+ Bar string `name:"value"`
+ }{},
+ want: [][]int{{0}, {1}},
+ },
+ {
+ name: "some",
+ ps: &struct {
+ Foo string `name:"other"`
+ Bar string `name:"value"`
+ }{},
+ want: [][]int{{1}},
+ },
+ {
+ name: "embedded",
+ ps: &struct {
+ Foo struct {
+ Bar string `name:"value"`
+ }
+ }{},
+ want: [][]int{{0, 0}},
+ },
+ {
+ name: "embedded ptr",
+ ps: &struct {
+ Foo *struct {
+ Bar string `name:"value"`
+ }
+ }{},
+ want: [][]int{{0, 0}},
+ },
+ {
+ name: "nil",
+ ps: (*struct {
+ Foo string `name:"value"`
+ })(nil),
+ want: [][]int{{0}},
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ if got := PropertyIndexesWithTag(test.ps, "name", "value"); !reflect.DeepEqual(got, test.want) {
+ t.Errorf("PropertyIndexesWithTag() = %v, want %v", got, test.want)
+ }
+ })
+ }
+}