]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/vet: fix some pointer false positives in printf
authorDaniel Martí <mvdan@mvdan.cc>
Tue, 6 Nov 2018 15:14:56 +0000 (15:14 +0000)
committerDaniel Martí <mvdan@mvdan.cc>
Fri, 9 Nov 2018 14:57:28 +0000 (14:57 +0000)
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: Alan Donovan <adonovan@google.com>
src/cmd/vet/testdata/print.go
src/cmd/vet/types.go

index 88163b59d949bbbf406f3ef1e487cc641228bdd2..b2289bc2acce32af7ecf27cde35b5dce570a3551 100644 (file)
@@ -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"
+}
index 3ff4b5966de2174b51a95717d5f256df93e5804d..78823aed979bcee23d988e14092af305a02d529b 100644 (file)
@@ -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)