if typ != nil {
if sig, ok := typ.(*types.Signature); ok {
if !sig.Variadic() {
- // Skip checking non-variadic functions
+ // Skip checking non-variadic functions.
return "", -1
}
idx := sig.Params().Len() - 2
// fixed arguments.
return "", -1
}
- s, ok := stringLiteralArg(f, call, idx)
+ s, ok := stringConstantArg(f, call, idx)
if !ok {
- // The last argument before variadic args isn't a string
+ // The last argument before variadic args isn't a string.
return "", -1
}
return s, idx
}
}
- // Cannot determine call's signature. Fallback to scanning for the first
- // string argument in the call
+ // Cannot determine call's signature. Fall back to scanning for the first
+ // string constant in the call.
for idx := range call.Args {
- if s, ok := stringLiteralArg(f, call, idx); ok {
+ if s, ok := stringConstantArg(f, call, idx); ok {
return s, idx
}
+ if f.pkg.types[call.Args[idx]].Type == types.Typ[types.String] {
+ // Skip checking a call with a non-constant format
+ // string argument, since its contents are unavailable
+ // for validation.
+ return "", -1
+ }
}
return "", -1
}
-// stringLiteralArg returns call's string constant argument at the index idx.
+// stringConstantArg returns call's string constant argument at the index idx.
//
// ("", false) is returned if call's argument at the index idx isn't a string
-// literal.
-func stringLiteralArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
+// constant.
+func stringConstantArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
if idx >= len(call.Args) {
return "", false
}
externalprintf.Logf(level, "%d", 42) // OK
externalprintf.Errorf(level, level, "foo %q bar", "foobar") // OK
externalprintf.Logf(level, "%d") // ERROR "format reads arg 1, have only 0 args"
+ var formatStr = "%s %s"
+ externalprintf.Sprintf(formatStr, "a", "b") // OK
+ externalprintf.Logf(level, formatStr, "a", "b") // OK
// user-defined Println-like functions
ss := &someStruct{}