Commit 8138654a authored by Rob Pike's avatar Rob Pike

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
parent f3ed1ad5
...@@ -18,6 +18,7 @@ import ( ...@@ -18,6 +18,7 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"utf8"
) )
var verbose = flag.Bool("v", false, "verbose") var verbose = flag.Bool("v", false, "verbose")
...@@ -265,23 +266,65 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) { ...@@ -265,23 +266,65 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
} }
// Hard part: check formats against args. // Hard part: check formats against args.
// Trivial but useful test: count. // Trivial but useful test: count.
numPercent := 0 numArgs := 0
for i := 0; i < len(lit.Value); i++ { for i, w := 0, 0; i < len(lit.Value); i += w {
w = 1
if lit.Value[i] == '%' { if lit.Value[i] == '%' {
if i+1 < len(lit.Value) && lit.Value[i+1] == '%' { nbytes, nargs := parsePrintfVerb(lit.Value[i:])
// %% doesn't count. w = nbytes
i++ numArgs += nargs
}
}
expect := len(call.Args) - (skip + 1)
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 { } else {
numPercent++ for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' {
nbytes++
} }
} }
} }
expect := len(call.Args) - (skip + 1) // There may be a width
if numPercent != expect { getNum()
f.Badf(call.Pos(), "wrong number of formatting directives in %s call: %d percent(s) for %d args", name, numPercent, expect) // 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 var terminalNewline = []byte(`\n"`) // \n at end of interpreted string
// checkPrint checks a call to an unformatted print routine such as Println. // checkPrint checks a call to an unformatted print routine such as Println.
...@@ -320,6 +363,8 @@ func BadFunctionUsedInTests() { ...@@ -320,6 +363,8 @@ func BadFunctionUsedInTests() {
fmt.Println("%s", "hi") // % in call to Println fmt.Println("%s", "hi") // % in call to Println
fmt.Printf("%s", "hi", 3) // wrong # percents fmt.Printf("%s", "hi", 3) // wrong # percents
fmt.Printf("%s%%%d", "hi", 3) // right # 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 Printf("now is the time", "buddy") // no %s
f := new(File) f := new(File)
f.Warn(0, "%s", "hello", 3) // % in call to added function f.Warn(0, "%s", "hello", 3) // % in call to added function
......
...@@ -820,12 +820,12 @@ func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error ...@@ -820,12 +820,12 @@ func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error
i := 1 i := 1
for ; r != nil; r = r.next { for ; r != nil; r = r.next {
if r.i != i { 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++ i++
} }
if i-1 != intCount { 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)
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment