diff --git a/proptools/unpack.go b/proptools/unpack.go
index e1d733c..e6b688e 100644
--- a/proptools/unpack.go
+++ b/proptools/unpack.go
@@ -108,6 +108,7 @@ func UnpackProperties(properties []*parser.Property, objects ...interface{}) (ma
func (ctx *unpackContext) reportUnusedNames(unusedNames []string) []error {
sort.Strings(unusedNames)
+ unusedNames = removeUnnecessaryUnusedNames(unusedNames)
var lastReported string
for _, name := range unusedNames {
// if 'foo' has been reported, ignore 'foo\..*' and 'foo\[.*'
@@ -125,6 +126,23 @@ func (ctx *unpackContext) reportUnusedNames(unusedNames []string) []error {
return ctx.errs
}
+// When property a.b.c is not used, (also there is no a.* or a.b.* used)
+// "a", "a.b" and "a.b.c" are all in unusedNames.
+// removeUnnecessaryUnusedNames only keeps the last "a.b.c" as the real unused
+// name.
+func removeUnnecessaryUnusedNames(names []string) []string {
+ if len(names) == 0 {
+ return names
+ }
+ var simplifiedNames []string
+ for index, name := range names {
+ if index == len(names)-1 || !strings.HasPrefix(names[index+1], name) {
+ simplifiedNames = append(simplifiedNames, name)
+ }
+ }
+ return simplifiedNames
+}
+
func (ctx *unpackContext) buildPropertyMap(prefix string, properties []*parser.Property) bool {
nOldErrors := len(ctx.errs)
for _, property := range properties {
diff --git a/proptools/unpack_test.go b/proptools/unpack_test.go
index 7e2751d..35aabf9 100644
--- a/proptools/unpack_test.go
+++ b/proptools/unpack_test.go
@@ -17,7 +17,6 @@ package proptools
import (
"bytes"
"reflect"
-
"testing"
"github.com/google/blueprint/parser"
@@ -962,6 +961,37 @@ func TestUnpackErrors(t *testing.T) {
`:3:16: can't assign string value to list property "map_list"`,
},
},
+ {
+ name: "non-existent property",
+ input: `
+ m {
+ foo: {
+ foo_prop1: true,
+ foo_prop2: false,
+ foo_prop3: true,
+ },
+ bar: {
+ bar_prop: false,
+ },
+ baz: true,
+ exist: false,
+ }
+ `,
+ output: []interface{}{
+ &struct {
+ Foo struct {
+ Foo_prop1 bool
+ }
+ Exist bool
+ }{},
+ },
+ errors: []string{
+ `:5:16: unrecognized property "foo.foo_prop2"`,
+ `:6:16: unrecognized property "foo.foo_prop3"`,
+ `:9:15: unrecognized property "bar.bar_prop"`,
+ `:11:9: unrecognized property "baz"`,
+ },
+ },
}
for _, testCase := range testCases {
@@ -1196,3 +1226,58 @@ func BenchmarkUnpackProperties(b *testing.B) {
run(b, props, bp)
})
}
+
+func TestRemoveUnnecessaryUnusedNames(t *testing.T) {
+ testCases := []struct {
+ name string
+ input []string
+ output []string
+ }{
+ {
+ name: "no unused names",
+ input: []string{},
+ output: []string{},
+ },
+ {
+ name: "only one unused name",
+ input: []string{"a.b.c"},
+ output: []string{"a.b.c"},
+ },
+ {
+ name: "unused names in a chain",
+ input: []string{"a", "a.b", "a.b.c"},
+ output: []string{"a.b.c"},
+ },
+ {
+ name: "unused names unrelated",
+ input: []string{"a.b.c", "s.t", "x.y"},
+ output: []string{"a.b.c", "s.t", "x.y"},
+ },
+ {
+ name: "unused names partially related one",
+ input: []string{"a.b", "a.b.c", "a.b.d"},
+ output: []string{"a.b.c", "a.b.d"},
+ },
+ {
+ name: "unused names partially related two",
+ input: []string{"a", "a.b.c", "a.c"},
+ output: []string{"a.b.c", "a.c"},
+ },
+ {
+ name: "unused names partially related three",
+ input: []string{"a.b.c", "b.c", "c"},
+ output: []string{"a.b.c", "b.c", "c"},
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ simplifiedNames := removeUnnecessaryUnusedNames(testCase.input)
+ if !reflect.DeepEqual(simplifiedNames, testCase.output) {
+ t.Errorf("test case: %s", testCase.name)
+ t.Errorf(" input: %s", testCase.input)
+ t.Errorf(" expect: %s", testCase.output)
+ t.Errorf(" got: %s", simplifiedNames)
+ }
+ })
+ }
+}