Commit edb2d1cb authored by Daniel Martí's avatar Daniel Martí

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í <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarAlan Donovan <adonovan@google.com>
parent ef2c4865
......@@ -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"
}
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment