From 14f8027a10040b99773bcd5cb452579926cf2758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Mon, 29 Jan 2018 10:35:39 +0000 Subject: [PATCH] cmd/vet: extra args if any formats are indexed are ok MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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í TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor Reviewed-by: Rob Pike --- src/cmd/vet/print.go | 10 ++++++++++ src/cmd/vet/testdata/print.go | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go index 0cff951f6f..04c59551b2 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -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 } diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index d7081a7303..9a0a68dd98 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -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