]> Cypherpunks repositories - gostls13.git/commitdiff
govet: handle '*' in print format strings.
authorRob Pike <r@golang.org>
Tue, 8 Mar 2011 22:36:56 +0000 (14:36 -0800)
committerRob Pike <r@golang.org>
Tue, 8 Mar 2011 22:36:56 +0000 (14:36 -0800)
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

src/cmd/govet/govet.go
src/pkg/fmt/scan_test.go

index ff6421de898a93f668cd3b1594928493b168e4c6..72e80a2fbd9eb5d872922285cefeac30a8f12886 100644 (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
index cab86dd9869700531e474f9d21dff0bfc25236b7..be16fe847ae708cc739120169fa5603cc65721e8 100644 (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)
        }
 }