1
0
mirror of https://github.com/golang/go synced 2024-11-19 23:34:40 -07:00

govet: handle '*' in print format strings.

While we're on govet, fix a couple of mistakes in a test.

Fixes #1592.

R=rsc
CC=golang-dev
https://golang.org/cl/4239071
This commit is contained in:
Rob Pike 2011-03-08 14:36:56 -08:00
parent f3ed1ad50c
commit 8138654aa8
2 changed files with 57 additions and 12 deletions

View File

@ -18,6 +18,7 @@ import (
"path/filepath"
"strconv"
"strings"
"utf8"
)
var verbose = flag.Bool("v", false, "verbose")
@ -265,23 +266,65 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
}
// Hard part: check formats against args.
// Trivial but useful test: count.
numPercent := 0
for i := 0; i < len(lit.Value); i++ {
numArgs := 0
for i, w := 0, 0; i < len(lit.Value); i += w {
w = 1
if lit.Value[i] == '%' {
if i+1 < len(lit.Value) && lit.Value[i+1] == '%' {
// %% doesn't count.
i++
} else {
numPercent++
}
nbytes, nargs := parsePrintfVerb(lit.Value[i:])
w = nbytes
numArgs += nargs
}
}
expect := len(call.Args) - (skip + 1)
if numPercent != expect {
f.Badf(call.Pos(), "wrong number of formatting directives in %s call: %d percent(s) for %d args", name, numPercent, expect)
if numArgs != expect {
f.Badf(call.Pos(), "wrong number of args in %s call: %d needed but %d args", name, numArgs, expect)
}
}
// parsePrintfVerb returns the number of bytes and number of arguments
// consumed by the Printf directive that begins s, including its percent sign
// and verb.
func parsePrintfVerb(s []byte) (nbytes, nargs int) {
// There's guaranteed a percent sign.
nbytes = 1
end := len(s)
// There may be flags
FlagLoop:
for nbytes < end {
switch s[nbytes] {
case '#', '0', '+', '-', ' ':
nbytes++
default:
break FlagLoop
}
}
getNum := func() {
if nbytes < end && s[nbytes] == '*' {
nbytes++
nargs++
} else {
for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' {
nbytes++
}
}
}
// There may be a width
getNum()
// If there's a period, there may be a precision.
if nbytes < end && s[nbytes] == '.' {
nbytes++
getNum()
}
// Now a verb.
c, w := utf8.DecodeRune(s[nbytes:])
nbytes += w
if c != '%' {
nargs++
}
return
}
var terminalNewline = []byte(`\n"`) // \n at end of interpreted string
// checkPrint checks a call to an unformatted print routine such as Println.
@ -320,6 +363,8 @@ func BadFunctionUsedInTests() {
fmt.Println("%s", "hi") // % in call to Println
fmt.Printf("%s", "hi", 3) // wrong # percents
fmt.Printf("%s%%%d", "hi", 3) // right # percents
fmt.Printf("%.*d", 3, 3) // right # percents, with a *
fmt.Printf("%.*d", 3, 3, 3) // wrong # percents, with a *
Printf("now is the time", "buddy") // no %s
f := new(File)
f.Warn(0, "%s", "hello", 3) // % in call to added function

View File

@ -820,12 +820,12 @@ func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error
i := 1
for ; r != nil; r = r.next {
if r.i != i {
t.Fatal("bad scan: expected %d got %d", i, r.i)
t.Fatalf("bad scan: expected %d got %d", i, r.i)
}
i++
}
if i-1 != intCount {
t.Fatal("bad scan count: expected %d got %d", intCount, i-1)
t.Fatalf("bad scan count: expected %d got %d", intCount, i-1)
}
}