]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/vet: extra args if any formats are indexed are ok
authorDaniel Martí <mvdan@mvdan.cc>
Mon, 29 Jan 2018 10:35:39 +0000 (10:35 +0000)
committerIan Lance Taylor <iant@golang.org>
Tue, 30 Jan 2018 14:36:35 +0000 (14:36 +0000)
For example, the following program is valid:

func main() {
fmt.Printf("%[1]d", 1, 2, 3)
}

If any of the formats are indexed, fmt will not complain about unused
extra arguments. See #22867 for more detail.

Make vet follow the same logic, to avoid erroring on programs that would
run without fmt complaining.

Fixes #23564.

Change-Id: Ic9dede5d4c37d1cd4fa24714216944897b5bb7cc
Reviewed-on: https://go-review.googlesource.com/90495
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
src/cmd/vet/print.go
src/cmd/vet/testdata/print.go

index 0cff951f6f173b4f120d56ff2ddafb517f108933..04c59551b2f88d31376c9455bfbb026502c61548 100644 (file)
@@ -295,6 +295,7 @@ type formatState struct {
        file         *File
        call         *ast.CallExpr
        argNum       int  // Which argument we're expecting to format now.
+       hasIndex     bool // Whether the argument is indexed.
        indexPending bool // Whether we have an indexed argument that has not resolved.
        nbytes       int  // number of bytes of the format string consumed.
 }
@@ -319,6 +320,7 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
        // Hard part: check formats against args.
        argNum := firstArg
        maxArgNum := firstArg
+       anyIndex := false
        for i, w := 0, 0; i < len(format); i += w {
                w = 1
                if format[i] != '%' {
@@ -332,6 +334,9 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
                if !f.okPrintfArg(call, state) { // One error per format is enough.
                        return
                }
+               if state.hasIndex {
+                       anyIndex = true
+               }
                if len(state.argNums) > 0 {
                        // Continue with the next sequential argument.
                        argNum = state.argNums[len(state.argNums)-1] + 1
@@ -346,6 +351,10 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
        if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
                return
        }
+       // If any formats are indexed, extra arguments are ignored.
+       if anyIndex {
+               return
+       }
        // There should be no leftover arguments.
        if maxArgNum != len(call.Args) {
                expect := maxArgNum - firstArg
@@ -404,6 +413,7 @@ func (s *formatState) parseIndex() bool {
        arg := int(arg32)
        arg += s.firstArg - 1 // We want to zero-index the actual arguments.
        s.argNum = arg
+       s.hasIndex = true
        s.indexPending = true
        return true
 }
index d7081a7303620a24ae07e2a1c1a857afd5d54c05..9a0a68dd98a3b60740c14f7c4f887b559ef98615 100644 (file)
@@ -270,8 +270,9 @@ func PrintfTests() {
        Printf("%d %[3]d %d %[-2]d x", 1, 2, 3, 4)            // ERROR "Printf format has invalid argument index \[-2\]"
        Printf("%d %[3]d %d %[2234234234234]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[2234234234234\]"
        Printf("%d %[3]d %-10d %[2]d x", 1, 2, 3)             // ERROR "Printf format %-10d reads arg #4, but call has only 3 args"
-       Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4, 5)          // ERROR "Printf call needs 4 args but has 5 args"
        Printf("%[1][3]d x", 1, 2)                            // ERROR "Printf format %\[1\]\[ has unknown verb \["
+       Printf("%[1]d x", 1, 2)                               // OK
+       Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4, 5)          // OK
 
        // wrote Println but meant Fprintln
        Printf("%p\n", os.Stdout)   // OK