From: Daniel Martí Date: Tue, 6 Nov 2018 15:14:56 +0000 (+0000) Subject: cmd/vet: fix some pointer false positives in printf X-Git-Tag: go1.12beta1~437 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=edb2d1cbf23c1a638837f21bc7dd51a0807ab236;p=gostls13.git cmd/vet: fix some pointer false positives in printf fmt's godoc reads: For compound objects, the elements are printed using these rules, recursively, laid out like this: struct: {field0 field1 ...} array, slice: [elem0 elem1 ...] maps: map[key1:value1 key2:value2 ...] pointer to above: &{}, &[], &map[] That is, a pointer to a struct, array, slice, or map, can be correctly printed by fmt if the type pointed to can be printed without issues. vet was only following this rule for pointers to structs, omitting arrays, slices, and maps. Fix that, and add tests for all the combinations. Updates #27672. Change-Id: Ie61ebe1fffc594184f7b24d7dbf72d7d5de78309 Reviewed-on: https://go-review.googlesource.com/c/147758 Run-TryBot: Daniel Martí TryBot-Result: Gobot Gobot Reviewed-by: Alan Donovan --- diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index 88163b59d9..b2289bc2ac 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -645,3 +645,29 @@ func dbg(format string, args ...interface{}) { } fmt.Printf(format, args...) } + +func PointersToCompoundTypes() { + stringSlice := []string{"a", "b"} + fmt.Printf("%s", &stringSlice) // not an error + + intSlice := []int{3, 4} + fmt.Printf("%s", &intSlice) // ERROR "Printf format %s has arg &intSlice of wrong type \*\[\]int" + + stringArray := [2]string{"a", "b"} + fmt.Printf("%s", &stringArray) // not an error + + intArray := [2]int{3, 4} + fmt.Printf("%s", &intArray) // ERROR "Printf format %s has arg &intArray of wrong type \*\[2\]int" + + stringStruct := struct{ F string }{"foo"} + fmt.Printf("%s", &stringStruct) // not an error + + intStruct := struct{ F int }{3} + fmt.Printf("%s", &intStruct) // ERROR "Printf format %s has arg &intStruct of wrong type \*struct{F int}" + + stringMap := map[string]string{"foo": "bar"} + fmt.Printf("%s", &stringMap) // not an error + + intMap := map[int]int{3: 4} + fmt.Printf("%s", &intMap) // ERROR "Printf format %s has arg &intMap of wrong type \*map\[int\]int" +} diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go index 3ff4b5966d..78823aed97 100644 --- a/src/cmd/vet/types.go +++ b/src/cmd/vet/types.go @@ -217,12 +217,20 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp if t == argPointer { return true } - // If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct. - if str, ok := typ.Elem().Underlying().(*types.Struct); ok { - return f.matchStructArgType(t, str, arg, inProgress) + under := typ.Elem().Underlying() + switch under.(type) { + case *types.Struct: // see below + case *types.Array: // see below + case *types.Slice: // see below + case *types.Map: // see below + default: + // Check whether the rest can print pointers. + return t&argPointer != 0 } - // Check whether the rest can print pointers. - return t&argPointer != 0 + // If it's a pointer to a struct, array, slice, or map, that's + // equivalent in our analysis to whether we can print the type + // being pointed to. + return f.matchArgTypeInternal(t, under, arg, inProgress) case *types.Struct: return f.matchStructArgType(t, typ, arg, inProgress)