Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 ÿ// Copyright 2010 The Go Authors. All rights reserved.ÿ | 1 // Copyright 2010 The Go Authors. All rights reserved. |
2 ÿ// Use of this source code is governed by a BSD-styleÿ | 2 // Use of this source code is governed by a BSD-style |
3 ÿ// license that can be found in the LICENSE file.ÿ | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 ÿ// Govet is a simple checker for static errors in Go source code.ÿ | 5 // Govet is a simple checker for static errors in Go source code. |
6 ÿ// See doc.go for more information.ÿ | 6 // See doc.go for more information. |
7 package main | 7 package main |
8 | 8 |
9 import ( | 9 import ( |
10 "flag" | 10 "flag" |
11 "fmt" | 11 "fmt" |
12 "io" | 12 "io" |
13 "go/ast" | 13 "go/ast" |
14 "go/parser" | 14 "go/parser" |
15 "go/token" | 15 "go/token" |
16 "os" | 16 "os" |
17 "path/filepath" | 17 "path/filepath" |
18 "strconv" | 18 "strconv" |
19 "strings" | 19 "strings" |
20 "utf8" | 20 "utf8" |
21 ) | 21 ) |
22 | 22 |
23 var verbose = flag.Bool("v", false, "verbose") | 23 var verbose = flag.Bool("v", false, "verbose") |
24 var printfuncs = flag.String("printfuncs", "", "comma-separated list of print fu nction names to check") | 24 var printfuncs = flag.String("printfuncs", "", "comma-separated list of print fu nction names to check") |
25 var exitCode = 0 | 25 var exitCode = 0 |
26 | 26 |
27 ÿ// setExit sets the value for os.Exit when it is called, later. Itÿ | 27 // setExit sets the value for os.Exit when it is called, later. It |
28 ÿ// remembers the highest value.ÿ | 28 // remembers the highest value. |
29 func setExit(err int) { | 29 func setExit(err int) { |
30 if err > exitCode { | 30 if err > exitCode { |
31 exitCode = err | 31 exitCode = err |
32 } | 32 } |
33 } | 33 } |
34 | 34 |
35 ÿ// Usage is a replacement usage function for the flags package.ÿ | 35 // Usage is a replacement usage function for the flags package. |
36 func Usage() { | 36 func Usage() { |
37 fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) | 37 fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) |
38 flag.PrintDefaults() | 38 flag.PrintDefaults() |
39 os.Exit(2) | 39 os.Exit(2) |
40 } | 40 } |
41 | 41 |
42 ÿ// File is a wrapper for the state of a file used in the parser.ÿ | 42 // File is a wrapper for the state of a file used in the parser. |
43 ÿ// The parse tree walkers are all methods of this type.ÿ | 43 // The parse tree walkers are all methods of this type. |
44 type File struct { | 44 type File struct { |
45 file *token.File | 45 file *token.File |
46 } | 46 } |
47 | 47 |
48 func main() { | 48 func main() { |
49 flag.Usage = Usage | 49 flag.Usage = Usage |
50 flag.Parse() | 50 flag.Parse() |
51 | 51 |
52 if *printfuncs != "" { | 52 if *printfuncs != "" { |
53 for _, name := range strings.Split(*printfuncs, ",", -1) { | 53 for _, name := range strings.Split(*printfuncs, ",", -1) { |
(...skipping 14 matching lines...) Expand all Loading... | |
68 } else { | 68 } else { |
69 printList[name] = skip | 69 printList[name] = skip |
70 } | 70 } |
71 } | 71 } |
72 } | 72 } |
73 | 73 |
74 if flag.NArg() == 0 { | 74 if flag.NArg() == 0 { |
75 doFile("stdin", os.Stdin) | 75 doFile("stdin", os.Stdin) |
76 } else { | 76 } else { |
77 for _, name := range flag.Args() { | 77 for _, name := range flag.Args() { |
78 » » » ÿ// Is it a directory?ÿ | 78 » » » // Is it a directory? |
79 if fi, err := os.Stat(name); err == nil && fi.IsDirector y() { | 79 if fi, err := os.Stat(name); err == nil && fi.IsDirector y() { |
80 walkDir(name) | 80 walkDir(name) |
81 } else { | 81 } else { |
82 doFile(name, nil) | 82 doFile(name, nil) |
83 } | 83 } |
84 } | 84 } |
85 } | 85 } |
86 os.Exit(exitCode) | 86 os.Exit(exitCode) |
87 } | 87 } |
88 | 88 |
89 ÿ// doFile analyzes one file. If the reader is nil, the source code is read fro m theÿ | 89 // doFile analyzes one file. If the reader is nil, the source code is read from the |
90 ÿ// named file.ÿ | 90 // named file. |
91 func doFile(name string, reader io.Reader) { | 91 func doFile(name string, reader io.Reader) { |
92 fs := token.NewFileSet() | 92 fs := token.NewFileSet() |
93 parsedFile, err := parser.ParseFile(fs, name, reader, 0) | 93 parsedFile, err := parser.ParseFile(fs, name, reader, 0) |
94 if err != nil { | 94 if err != nil { |
95 error("%s: %s", name, err) | 95 error("%s: %s", name, err) |
96 return | 96 return |
97 } | 97 } |
98 file := &File{fs.File(parsedFile.Pos())} | 98 file := &File{fs.File(parsedFile.Pos())} |
99 file.checkFile(name, parsedFile) | 99 file.checkFile(name, parsedFile) |
100 } | 100 } |
101 | 101 |
102 ÿ// Visitor for filepath.Walk - trivial. Just calls doFile on each file.ÿ | 102 // Visitor for filepath.Walk - trivial. Just calls doFile on each file. |
103 ÿ// TODO: if govet becomes richer, might want to processÿ | 103 // TODO: if govet becomes richer, might want to process |
104 ÿ// a directory (package) at a time.ÿ | 104 // a directory (package) at a time. |
105 type V struct{} | 105 type V struct{} |
106 | 106 |
107 func (v V) VisitDir(path string, f *os.FileInfo) bool { | 107 func (v V) VisitDir(path string, f *os.FileInfo) bool { |
108 return true | 108 return true |
109 } | 109 } |
110 | 110 |
111 func (v V) VisitFile(path string, f *os.FileInfo) { | 111 func (v V) VisitFile(path string, f *os.FileInfo) { |
112 if strings.HasSuffix(path, ".go") { | 112 if strings.HasSuffix(path, ".go") { |
113 doFile(path, nil) | 113 doFile(path, nil) |
114 } | 114 } |
115 } | 115 } |
116 | 116 |
117 ÿ// walkDir recursively walks the tree looking for .go files.ÿ | 117 // walkDir recursively walks the tree looking for .go files. |
118 func walkDir(root string) { | 118 func walkDir(root string) { |
119 errors := make(chan os.Error) | 119 errors := make(chan os.Error) |
120 done := make(chan bool) | 120 done := make(chan bool) |
121 go func() { | 121 go func() { |
122 for e := range errors { | 122 for e := range errors { |
123 error("walk error: %s", e) | 123 error("walk error: %s", e) |
124 } | 124 } |
125 done <- true | 125 done <- true |
126 }() | 126 }() |
127 filepath.Walk(root, V{}, errors) | 127 filepath.Walk(root, V{}, errors) |
128 close(errors) | 128 close(errors) |
129 <-done | 129 <-done |
130 } | 130 } |
131 | 131 |
132 ÿ// error formats the error to standard error, adding programÿ | 132 // error formats the error to standard error, adding program |
133 ÿ// identification and a newlineÿ | 133 // identification and a newline |
134 func error(format string, args ...interface{}) { | 134 func error(format string, args ...interface{}) { |
135 fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...) | 135 fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...) |
136 setExit(2) | 136 setExit(2) |
137 } | 137 } |
138 | 138 |
139 ÿ// Println is fmt.Println guarded by -v.ÿ | 139 // Println is fmt.Println guarded by -v. |
140 func Println(args ...interface{}) { | 140 func Println(args ...interface{}) { |
141 if !*verbose { | 141 if !*verbose { |
142 return | 142 return |
143 } | 143 } |
144 fmt.Println(args...) | 144 fmt.Println(args...) |
145 } | 145 } |
146 | 146 |
147 ÿ// Printf is fmt.Printf guarded by -v.ÿ | 147 // Printf is fmt.Printf guarded by -v. |
148 func Printf(format string, args ...interface{}) { | 148 func Printf(format string, args ...interface{}) { |
149 if !*verbose { | 149 if !*verbose { |
150 return | 150 return |
151 } | 151 } |
152 fmt.Printf(format+"\n", args...) | 152 fmt.Printf(format+"\n", args...) |
153 } | 153 } |
154 | 154 |
155 ÿ// Bad reports an error and sets the exit code..ÿ | 155 // Bad reports an error and sets the exit code.. |
156 func (f *File) Bad(pos token.Pos, args ...interface{}) { | 156 func (f *File) Bad(pos token.Pos, args ...interface{}) { |
157 f.Warn(pos, args...) | 157 f.Warn(pos, args...) |
158 setExit(1) | 158 setExit(1) |
159 } | 159 } |
160 | 160 |
161 ÿ// Badf reports a formatted error and sets the exit code.ÿ | 161 // Badf reports a formatted error and sets the exit code. |
162 func (f *File) Badf(pos token.Pos, format string, args ...interface{}) { | 162 func (f *File) Badf(pos token.Pos, format string, args ...interface{}) { |
163 f.Warnf(pos, format, args...) | 163 f.Warnf(pos, format, args...) |
164 setExit(1) | 164 setExit(1) |
165 } | 165 } |
166 | 166 |
167 ÿ// Warn reports an error but does not set the exit code.ÿ | 167 // Warn reports an error but does not set the exit code. |
168 func (f *File) Warn(pos token.Pos, args ...interface{}) { | 168 func (f *File) Warn(pos token.Pos, args ...interface{}) { |
169 loc := f.file.Position(pos).String() + ": " | 169 loc := f.file.Position(pos).String() + ": " |
170 fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...)) | 170 fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...)) |
171 } | 171 } |
172 | 172 |
173 ÿ// Warnf reports a formatted error but does not set the exit code.ÿ | 173 // Warnf reports a formatted error but does not set the exit code. |
174 func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) { | 174 func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) { |
175 loc := f.file.Position(pos).String() + ": " | 175 loc := f.file.Position(pos).String() + ": " |
176 fmt.Fprintf(os.Stderr, loc+format+"\n", args...) | 176 fmt.Fprintf(os.Stderr, loc+format+"\n", args...) |
177 } | 177 } |
178 | 178 |
179 ÿ// checkFile checks all the top-level declarations in a file.ÿ | 179 // checkFile checks all the top-level declarations in a file. |
180 func (f *File) checkFile(name string, file *ast.File) { | 180 func (f *File) checkFile(name string, file *ast.File) { |
181 Println("Checking file", name) | 181 Println("Checking file", name) |
182 ast.Walk(f, file) | 182 ast.Walk(f, file) |
183 } | 183 } |
184 | 184 |
185 ÿ// Visit implements the ast.Visitor interface.ÿ | 185 // Visit implements the ast.Visitor interface. |
186 func (f *File) Visit(node ast.Node) ast.Visitor { | 186 func (f *File) Visit(node ast.Node) ast.Visitor { |
187 » ÿ// TODO: could return nil for nodes that cannot contain a CallExpr -ÿ | 187 » // TODO: could return nil for nodes that cannot contain a CallExpr - |
188 » ÿ// will shortcut traversal. Worthwhile?ÿ | 188 » // will shortcut traversal. Worthwhile? |
189 switch n := node.(type) { | 189 switch n := node.(type) { |
190 case *ast.CallExpr: | 190 case *ast.CallExpr: |
191 f.checkCallExpr(n) | 191 f.checkCallExpr(n) |
192 } | 192 } |
193 return f | 193 return f |
194 } | 194 } |
195 | 195 |
196 | 196 |
197 ÿ// checkCallExpr checks a call expression.ÿ | 197 // checkCallExpr checks a call expression. |
198 func (f *File) checkCallExpr(call *ast.CallExpr) { | 198 func (f *File) checkCallExpr(call *ast.CallExpr) { |
199 switch x := call.Fun.(type) { | 199 switch x := call.Fun.(type) { |
200 case *ast.Ident: | 200 case *ast.Ident: |
201 f.checkCall(call, x.Name) | 201 f.checkCall(call, x.Name) |
202 case *ast.SelectorExpr: | 202 case *ast.SelectorExpr: |
203 f.checkCall(call, x.Sel.Name) | 203 f.checkCall(call, x.Sel.Name) |
204 } | 204 } |
205 } | 205 } |
206 | 206 |
207 ÿ// printfList records the formatted-print functions. The value is the locationÿ | 207 // printfList records the formatted-print functions. The value is the location |
208 ÿ// of the format parameter.ÿ | 208 // of the format parameter. |
209 var printfList = map[string]int{ | 209 var printfList = map[string]int{ |
210 "Errorf": 0, | 210 "Errorf": 0, |
211 "Fatalf": 0, | 211 "Fatalf": 0, |
212 "Fprintf": 1, | 212 "Fprintf": 1, |
213 "Panicf": 0, | 213 "Panicf": 0, |
214 "Printf": 0, | 214 "Printf": 0, |
215 "Sprintf": 0, | 215 "Sprintf": 0, |
216 } | 216 } |
217 | 217 |
218 ÿ// printList records the unformatted-print functions. The value is the location ÿ | 218 // printList records the unformatted-print functions. The value is the location |
219 ÿ// of the first parameter to be printed.ÿ | 219 // of the first parameter to be printed. |
220 var printList = map[string]int{ | 220 var printList = map[string]int{ |
221 "Error": 0, | 221 "Error": 0, |
222 "Fatal": 0, | 222 "Fatal": 0, |
223 "Fprint": 1, "Fprintln": 1, | 223 "Fprint": 1, "Fprintln": 1, |
224 "Panic": 0, "Panicln": 0, | 224 "Panic": 0, "Panicln": 0, |
225 "Print": 0, "Println": 0, | 225 "Print": 0, "Println": 0, |
226 "Sprint": 0, "Sprintln": 0, | 226 "Sprint": 0, "Sprintln": 0, |
227 } | 227 } |
228 | 228 |
229 ÿ// checkCall triggers the print-specific checks if the call invokes a print fun ction.ÿ | 229 // checkCall triggers the print-specific checks if the call invokes a print func tion. |
230 func (f *File) checkCall(call *ast.CallExpr, name string) { | 230 func (f *File) checkCall(call *ast.CallExpr, name string) { |
231 if skip, ok := printfList[name]; ok { | 231 if skip, ok := printfList[name]; ok { |
232 f.checkPrintf(call, name, skip) | 232 f.checkPrintf(call, name, skip) |
233 return | 233 return |
234 } | 234 } |
235 if skip, ok := printList[name]; ok { | 235 if skip, ok := printList[name]; ok { |
236 f.checkPrint(call, name, skip) | 236 f.checkPrint(call, name, skip) |
237 return | 237 return |
238 } | 238 } |
239 } | 239 } |
240 | 240 |
241 ÿ// checkPrintf checks a call to a formatted print routine such as Printf.ÿ | 241 // checkPrintf checks a call to a formatted print routine such as Printf. |
242 ÿ// The skip argument records how many arguments to ignore; that is,ÿ | 242 // The skip argument records how many arguments to ignore; that is, |
243 ÿ// call.Args[skip] is (well, should be) the format argument.ÿ | 243 // call.Args[skip] is (well, should be) the format argument. |
244 func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) { | 244 func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) { |
245 if len(call.Args) <= skip { | 245 if len(call.Args) <= skip { |
246 return | 246 return |
247 } | 247 } |
248 » ÿ// Common case: literal is first argument.ÿ | 248 » // Common case: literal is first argument. |
249 arg := call.Args[skip] | 249 arg := call.Args[skip] |
250 lit, ok := arg.(*ast.BasicLit) | 250 lit, ok := arg.(*ast.BasicLit) |
251 if !ok { | 251 if !ok { |
252 » » ÿ// Too hard to check.ÿ | 252 » » // Too hard to check. |
253 if *verbose { | 253 if *verbose { |
254 f.Warn(call.Pos(), "can't check args for call to", name) | 254 f.Warn(call.Pos(), "can't check args for call to", name) |
255 } | 255 } |
256 return | 256 return |
257 } | 257 } |
258 if lit.Kind == token.STRING { | 258 if lit.Kind == token.STRING { |
259 if strings.Index(lit.Value, "%") < 0 { | 259 if strings.Index(lit.Value, "%") < 0 { |
rsc
2011/03/29 03:52:20
if strings.Contains(lit.Value, "%") {
since you'r
gri
2011/03/29 04:44:34
Done.
| |
260 if len(call.Args) > skip+1 { | 260 if len(call.Args) > skip+1 { |
261 f.Badf(call.Pos(), "no formatting directive in % s call", name) | 261 f.Badf(call.Pos(), "no formatting directive in % s call", name) |
262 } | 262 } |
263 return | 263 return |
264 } | 264 } |
265 } | 265 } |
266 » ÿ// Hard part: check formats against args.ÿ | 266 » // Hard part: check formats against args. |
267 » ÿ// Trivial but useful test: count.ÿ | 267 » // Trivial but useful test: count. |
268 numArgs := 0 | 268 numArgs := 0 |
269 for i, w := 0, 0; i < len(lit.Value); i += w { | 269 for i, w := 0, 0; i < len(lit.Value); i += w { |
270 w = 1 | 270 w = 1 |
271 if lit.Value[i] == '%' { | 271 if lit.Value[i] == '%' { |
272 nbytes, nargs := parsePrintfVerb(lit.Value[i:]) | 272 nbytes, nargs := parsePrintfVerb(lit.Value[i:]) |
273 w = nbytes | 273 w = nbytes |
274 numArgs += nargs | 274 numArgs += nargs |
275 } | 275 } |
276 } | 276 } |
277 expect := len(call.Args) - (skip + 1) | 277 expect := len(call.Args) - (skip + 1) |
278 if numArgs != expect { | 278 if numArgs != expect { |
279 f.Badf(call.Pos(), "wrong number of args in %s call: %d needed b ut %d args", name, numArgs, expect) | 279 f.Badf(call.Pos(), "wrong number of args in %s call: %d needed b ut %d args", name, numArgs, expect) |
280 } | 280 } |
281 } | 281 } |
282 | 282 |
283 ÿ// parsePrintfVerb returns the number of bytes and number of argumentsÿ | 283 // parsePrintfVerb returns the number of bytes and number of arguments |
284 ÿ// consumed by the Printf directive that begins s, including its percent signÿ | 284 // consumed by the Printf directive that begins s, including its percent sign |
285 ÿ// and verb.ÿ | 285 // and verb. |
286 func parsePrintfVerb(s string) (nbytes, nargs int) { | 286 func parsePrintfVerb(s string) (nbytes, nargs int) { |
287 » ÿ// There's guaranteed a percent sign.ÿ | 287 » // There's guaranteed a percent sign. |
288 nbytes = 1 | 288 nbytes = 1 |
289 end := len(s) | 289 end := len(s) |
290 » ÿ// There may be flags.ÿ | 290 » // There may be flags. |
291 FlagLoop: | 291 FlagLoop: |
292 for nbytes < end { | 292 for nbytes < end { |
293 switch s[nbytes] { | 293 switch s[nbytes] { |
294 case '#', '0', '+', '-', ' ': | 294 case '#', '0', '+', '-', ' ': |
295 nbytes++ | 295 nbytes++ |
296 default: | 296 default: |
297 break FlagLoop | 297 break FlagLoop |
298 } | 298 } |
299 } | 299 } |
300 getNum := func() { | 300 getNum := func() { |
301 if nbytes < end && s[nbytes] == '*' { | 301 if nbytes < end && s[nbytes] == '*' { |
302 nbytes++ | 302 nbytes++ |
303 nargs++ | 303 nargs++ |
304 } else { | 304 } else { |
305 for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' { | 305 for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' { |
306 nbytes++ | 306 nbytes++ |
307 } | 307 } |
308 } | 308 } |
309 } | 309 } |
310 » ÿ// There may be a width.ÿ | 310 » // There may be a width. |
311 getNum() | 311 getNum() |
312 » ÿ// If there's a period, there may be a precision.ÿ | 312 » // If there's a period, there may be a precision. |
313 if nbytes < end && s[nbytes] == '.' { | 313 if nbytes < end && s[nbytes] == '.' { |
314 nbytes++ | 314 nbytes++ |
315 getNum() | 315 getNum() |
316 } | 316 } |
317 » ÿ// Now a verb.ÿ | 317 » // Now a verb. |
318 c, w := utf8.DecodeRuneInString(s[nbytes:]) | 318 c, w := utf8.DecodeRuneInString(s[nbytes:]) |
319 nbytes += w | 319 nbytes += w |
320 if c != '%' { | 320 if c != '%' { |
321 nargs++ | 321 nargs++ |
322 } | 322 } |
323 return | 323 return |
324 } | 324 } |
325 | 325 |
326 | 326 |
327 ÿ// checkPrint checks a call to an unformatted print routine such as Println.ÿ | 327 // checkPrint checks a call to an unformatted print routine such as Println. |
328 ÿ// The skip argument records how many arguments to ignore; that is,ÿ | 328 // The skip argument records how many arguments to ignore; that is, |
329 ÿ// call.Args[skip] is the first argument to be printed.ÿ | 329 // call.Args[skip] is the first argument to be printed. |
330 func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) { | 330 func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) { |
331 isLn := strings.HasSuffix(name, "ln") | 331 isLn := strings.HasSuffix(name, "ln") |
332 args := call.Args | 332 args := call.Args |
333 if len(args) <= skip { | 333 if len(args) <= skip { |
334 if *verbose && !isLn { | 334 if *verbose && !isLn { |
335 f.Badf(call.Pos(), "no args in %s call", name) | 335 f.Badf(call.Pos(), "no args in %s call", name) |
336 } | 336 } |
337 return | 337 return |
338 } | 338 } |
339 arg := args[skip] | 339 arg := args[skip] |
340 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { | 340 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { |
341 if strings.Index(lit.Value, "%") >= 0 { | 341 if strings.Index(lit.Value, "%") >= 0 { |
rsc
2011/03/29 03:52:20
strings.Contains
gri
2011/03/29 04:44:34
Done.
| |
342 f.Badf(call.Pos(), "possible formatting directive in %s call", name) | 342 f.Badf(call.Pos(), "possible formatting directive in %s call", name) |
343 } | 343 } |
344 } | 344 } |
345 if isLn { | 345 if isLn { |
346 » » ÿ// The last item, if a string, should not have a newline.ÿ | 346 » » // The last item, if a string, should not have a newline. |
347 arg = args[len(call.Args)-1] | 347 arg = args[len(call.Args)-1] |
348 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRIN G { | 348 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRIN G { |
349 if strings.HasSuffix(lit.Value, `\n"`) { | 349 if strings.HasSuffix(lit.Value, `\n"`) { |
350 f.Badf(call.Pos(), "%s call ends with newline", name) | 350 f.Badf(call.Pos(), "%s call ends with newline", name) |
351 } | 351 } |
352 } | 352 } |
353 } | 353 } |
354 } | 354 } |
355 | 355 |
356 ÿ// This function never executes, but it serves as a simple test for the program .ÿ | 356 // This function never executes, but it serves as a simple test for the program. |
357 ÿ// Test with govet -printfuncs="Bad:1,Badf:1,Warn:1,Warnf:1" govet.goÿ | 357 // Test with govet -printfuncs="Bad:1,Badf:1,Warn:1,Warnf:1" govet.go |
358 func BadFunctionUsedInTests() { | 358 func BadFunctionUsedInTests() { |
359 » fmt.Println() ÿ// niladic callÿ | 359 » fmt.Println() // niladic call |
360 » fmt.Println("%s", "hi") ÿ// % in call to Printlnÿ | 360 » fmt.Println("%s", "hi") // % in call to Println |
361 » fmt.Printf("%s", "hi", 3) ÿ// wrong # percentsÿ | 361 » fmt.Printf("%s", "hi", 3) // wrong # percents |
362 » fmt.Printf("%s%%%d", "hi", 3) ÿ// right # percentsÿ | 362 » fmt.Printf("%s%%%d", "hi", 3) // right # percents |
363 » fmt.Printf("%.*d", 3, 3) ÿ// right # percents, with a *ÿ | 363 » fmt.Printf("%.*d", 3, 3) // right # percents, with a * |
364 » fmt.Printf("%.*d", 3, 3, 3) ÿ// wrong # percents, with a *ÿ | 364 » fmt.Printf("%.*d", 3, 3, 3) // wrong # percents, with a * |
365 » Printf("now is the time", "buddy") ÿ// no %sÿ | 365 » Printf("now is the time", "buddy") // no %s |
366 f := new(File) | 366 f := new(File) |
367 » f.Warn(0, "%s", "hello", 3) ÿ// % in call to added functionÿ | 367 » f.Warn(0, "%s", "hello", 3) // % in call to added function |
368 » f.Warnf(0, "%s", "hello", 3) ÿ// wrong # %s in call to added functionÿ | 368 » f.Warnf(0, "%s", "hello", 3) // wrong # %s in call to added function |
369 } | 369 } |
LEFT | RIGHT |