}
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"
+}
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)