mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/vet: simplify format checker
Simplify the code a bit, get it working after recent go/types changes, and handle "%*%" just in case. Preparation for handling argument indexing. R=gri CC=golang-dev https://golang.org/cl/9747045
This commit is contained in:
parent
20029fe5f7
commit
c7f7fa1381
@ -139,9 +139,6 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string, formatIndex int) {
|
|||||||
if format[i] == '%' {
|
if format[i] == '%' {
|
||||||
verb, flags, nbytes, nargs := f.parsePrintfVerb(call, format[i:])
|
verb, flags, nbytes, nargs := f.parsePrintfVerb(call, format[i:])
|
||||||
w = nbytes
|
w = nbytes
|
||||||
if verb == '%' { // "%%" does nothing interesting.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// If we've run out of args, print after loop will pick that up.
|
// If we've run out of args, print after loop will pick that up.
|
||||||
if argNum+nargs <= len(call.Args) {
|
if argNum+nargs <= len(call.Args) {
|
||||||
f.checkPrintfArg(call, verb, flags, argNum, nargs)
|
f.checkPrintfArg(call, verb, flags, argNum, nargs)
|
||||||
@ -228,6 +225,7 @@ type printVerb struct {
|
|||||||
|
|
||||||
// Common flag sets for printf verbs.
|
// Common flag sets for printf verbs.
|
||||||
const (
|
const (
|
||||||
|
noFlag = ""
|
||||||
numFlag = " -+.0"
|
numFlag = " -+.0"
|
||||||
sharpNumFlag = " -+.0#"
|
sharpNumFlag = " -+.0#"
|
||||||
allFlags = " -+.0#"
|
allFlags = " -+.0#"
|
||||||
@ -242,6 +240,7 @@ var printVerbs = []printVerb{
|
|||||||
// '+' is required sign for numbers, Go format for %v.
|
// '+' is required sign for numbers, Go format for %v.
|
||||||
// '#' is alternate format for several verbs.
|
// '#' is alternate format for several verbs.
|
||||||
// ' ' is spacer for numbers
|
// ' ' is spacer for numbers
|
||||||
|
{'%', noFlag, 0},
|
||||||
{'b', numFlag, argInt | argFloat},
|
{'b', numFlag, argInt | argFloat},
|
||||||
{'c', "-", argRune | argInt},
|
{'c', "-", argRune | argInt},
|
||||||
{'d', numFlag, argInt},
|
{'d', numFlag, argInt},
|
||||||
@ -263,42 +262,48 @@ var printVerbs = []printVerb{
|
|||||||
{'X', sharpNumFlag, argRune | argInt | argString},
|
{'X', sharpNumFlag, argRune | argInt | argString},
|
||||||
}
|
}
|
||||||
|
|
||||||
const printfVerbs = "bcdeEfFgGopqstTvxUX"
|
|
||||||
|
|
||||||
func (f *File) checkPrintfArg(call *ast.CallExpr, verb rune, flags []byte, argNum, nargs int) {
|
func (f *File) checkPrintfArg(call *ast.CallExpr, verb rune, flags []byte, argNum, nargs int) {
|
||||||
|
var v printVerb
|
||||||
|
found := false
|
||||||
// Linear scan is fast enough for a small list.
|
// Linear scan is fast enough for a small list.
|
||||||
for _, v := range printVerbs {
|
for _, v = range printVerbs {
|
||||||
if v.verb == verb {
|
if v.verb == verb {
|
||||||
for _, flag := range flags {
|
found = true
|
||||||
if !strings.ContainsRune(v.flags, rune(flag)) {
|
break
|
||||||
f.Badf(call.Pos(), "unrecognized printf flag for verb %q: %q", verb, flag)
|
}
|
||||||
return
|
}
|
||||||
}
|
if !found {
|
||||||
}
|
f.Badf(call.Pos(), "unrecognized printf verb %q", verb)
|
||||||
// Verb is good. If nargs>1, we have something like %.*s and all but the final
|
return
|
||||||
// arg must be integer.
|
}
|
||||||
for i := 0; i < nargs-1; i++ {
|
for _, flag := range flags {
|
||||||
if !f.matchArgType(argInt, call.Args[argNum+i]) {
|
if !strings.ContainsRune(v.flags, rune(flag)) {
|
||||||
f.Badf(call.Pos(), "arg %s for * in printf format not of type int", f.gofmt(call.Args[argNum+i]))
|
f.Badf(call.Pos(), "unrecognized printf flag for verb %q: %q", verb, flag)
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, v := range printVerbs {
|
|
||||||
if v.verb == verb {
|
|
||||||
arg := call.Args[argNum+nargs-1]
|
|
||||||
if !f.matchArgType(v.typ, arg) {
|
|
||||||
typeString := ""
|
|
||||||
if typ := f.pkg.types[arg]; typ != nil {
|
|
||||||
typeString = typ.String()
|
|
||||||
}
|
|
||||||
f.Badf(call.Pos(), "arg %s for printf verb %%%c of wrong type: %s", f.gofmt(arg), verb, typeString)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.Badf(call.Pos(), "unrecognized printf verb %q", verb)
|
// Verb is good. If nargs>trueArgs, we have something like %.*s and all but the final
|
||||||
|
// arg must be integer.
|
||||||
|
trueArgs := 1
|
||||||
|
if verb == '%' {
|
||||||
|
trueArgs = 0
|
||||||
|
}
|
||||||
|
for i := 0; i < nargs-trueArgs; i++ {
|
||||||
|
if !f.matchArgType(argInt, call.Args[argNum+i]) {
|
||||||
|
f.Badf(call.Pos(), "arg %s for * in printf format not of type int", f.gofmt(call.Args[argNum+i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if verb == '%' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
arg := call.Args[argNum+nargs-trueArgs]
|
||||||
|
if !f.matchArgType(v.typ, arg) {
|
||||||
|
typeString := ""
|
||||||
|
if typ := f.pkg.types[arg]; typ != nil {
|
||||||
|
typeString = typ.String()
|
||||||
|
}
|
||||||
|
f.Badf(call.Pos(), "arg %s for printf verb %%%c of wrong type: %s", f.gofmt(arg), verb, typeString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPrint checks a call to an unformatted print routine such as Println.
|
// checkPrint checks a call to an unformatted print routine such as Println.
|
||||||
|
37
cmd/vet/testdata/print.go
vendored
37
cmd/vet/testdata/print.go
vendored
@ -74,6 +74,7 @@ func PrintfTests() {
|
|||||||
fmt.Printf("%x %x %x %x", 3, i, "hi", s)
|
fmt.Printf("%x %x %x %x", 3, i, "hi", s)
|
||||||
fmt.Printf("%X %X %X %X", 3, i, "hi", s)
|
fmt.Printf("%X %X %X %X", 3, i, "hi", s)
|
||||||
fmt.Printf("%.*s %d %g", 3, "hi", 23, 2.3)
|
fmt.Printf("%.*s %d %g", 3, "hi", 23, 2.3)
|
||||||
|
fmt.Printf("%*%", 2) // Ridiculous but allowed.
|
||||||
// Some bad format/argTypes
|
// Some bad format/argTypes
|
||||||
fmt.Printf("%b", "hi") // ERROR "arg .hi. for printf verb %b of wrong type"
|
fmt.Printf("%b", "hi") // ERROR "arg .hi. for printf verb %b of wrong type"
|
||||||
fmt.Printf("%c", 2.3) // ERROR "arg 2.3 for printf verb %c of wrong type"
|
fmt.Printf("%c", 2.3) // ERROR "arg 2.3 for printf verb %c of wrong type"
|
||||||
@ -93,24 +94,24 @@ func PrintfTests() {
|
|||||||
fmt.Printf("%x", nil) // ERROR "arg nil for printf verb %x of wrong type"
|
fmt.Printf("%x", nil) // ERROR "arg nil for printf verb %x of wrong type"
|
||||||
fmt.Printf("%X", 2.3) // ERROR "arg 2.3 for printf verb %X of wrong type"
|
fmt.Printf("%X", 2.3) // ERROR "arg 2.3 for printf verb %X of wrong type"
|
||||||
fmt.Printf("%.*s %d %g", 3, "hi", 23, 'x') // ERROR "arg 'x' for printf verb %g of wrong type"
|
fmt.Printf("%.*s %d %g", 3, "hi", 23, 'x') // ERROR "arg 'x' for printf verb %g of wrong type"
|
||||||
// TODO
|
fmt.Println() // not an error
|
||||||
fmt.Println() // not an error
|
fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
|
||||||
fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
|
fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args for format in Printf call"
|
||||||
fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args for format in Printf call"
|
fmt.Printf("%"+("s"), "hi", 3) // ERROR "wrong number of args for format in Printf call"
|
||||||
fmt.Printf("%"+("s"), "hi", 3) // ERROR "wrong number of args for format in Printf call"
|
fmt.Printf("%s%%%d", "hi", 3) // correct
|
||||||
fmt.Printf("%s%%%d", "hi", 3) // correct
|
fmt.Printf("%08s", "woo") // correct
|
||||||
fmt.Printf("%08s", "woo") // correct
|
fmt.Printf("% 8s", "woo") // correct
|
||||||
fmt.Printf("% 8s", "woo") // correct
|
fmt.Printf("%.*d", 3, 3) // correct
|
||||||
fmt.Printf("%.*d", 3, 3) // correct
|
fmt.Printf("%.*d", 3, 3, 3) // ERROR "wrong number of args for format in Printf call"
|
||||||
fmt.Printf("%.*d", 3, 3, 3) // ERROR "wrong number of args for format in Printf call"
|
fmt.Printf("%.*d", "hi", 3) // ERROR "arg .hi. for \* in printf format not of type int"
|
||||||
fmt.Printf("%.*d", "hi", 3) // ERROR "arg .hi. for \* in printf format not of type int"
|
fmt.Printf("%.*d", i, 3) // correct
|
||||||
fmt.Printf("%.*d", i, 3) // correct
|
fmt.Printf("%.*d", s, 3) // ERROR "arg s for \* in printf format not of type int"
|
||||||
fmt.Printf("%.*d", s, 3) // ERROR "arg s for \* in printf format not of type int"
|
fmt.Printf("%*%", 0.22) // ERROR "arg 0.22 for \* in printf format not of type int"
|
||||||
fmt.Printf("%q %q", multi()...) // ok
|
fmt.Printf("%q %q", multi()...) // ok
|
||||||
fmt.Printf("%#q", `blah`) // ok
|
fmt.Printf("%#q", `blah`) // ok
|
||||||
printf("now is the time", "buddy") // ERROR "no formatting directive"
|
printf("now is the time", "buddy") // ERROR "no formatting directive"
|
||||||
Printf("now is the time", "buddy") // ERROR "no formatting directive"
|
Printf("now is the time", "buddy") // ERROR "no formatting directive"
|
||||||
Printf("hi") // ok
|
Printf("hi") // ok
|
||||||
const format = "%s %s\n"
|
const format = "%s %s\n"
|
||||||
Printf(format, "hi", "there")
|
Printf(format, "hi", "there")
|
||||||
Printf(format, "hi") // ERROR "wrong number of args for format in Printf call"
|
Printf(format, "hi") // ERROR "wrong number of args for format in Printf call"
|
||||||
|
@ -62,7 +62,7 @@ func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
|
|||||||
if typ == nil {
|
if typ == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
basic, ok := typ.(*types.Basic)
|
basic, ok := typ.Underlying().(*types.Basic)
|
||||||
if !ok {
|
if !ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user