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 // This file contains the printf-checker. | 5 // This file contains the printf-checker. |
6 | 6 |
7 package main | 7 package main |
8 | 8 |
9 import ( | 9 import ( |
10 "flag" | 10 "flag" |
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 f.Badf(call.Pos(), "arg %s for printf verb %%%c of wrong type: %
s", f.gofmt(arg), state.verb, typeString) | 385 f.Badf(call.Pos(), "arg %s for printf verb %%%c of wrong type: %
s", f.gofmt(arg), state.verb, typeString) |
386 return false | 386 return false |
387 } | 387 } |
388 if v.typ&argString != 0 && f.recursiveStringer(arg) { | 388 if v.typ&argString != 0 && f.recursiveStringer(arg) { |
389 f.Badf(call.Pos(), "arg %s for printf causes recursive call to S
tring method", f.gofmt(arg)) | 389 f.Badf(call.Pos(), "arg %s for printf causes recursive call to S
tring method", f.gofmt(arg)) |
390 return false | 390 return false |
391 } | 391 } |
392 return true | 392 return true |
393 } | 393 } |
394 | 394 |
| 395 // recursiveStringer reports whether the provided argument is r, *r, or &r |
| 396 // for the fmt.Stringer receiver identifier r. |
395 func (f *File) recursiveStringer(arg ast.Expr) bool { | 397 func (f *File) recursiveStringer(arg ast.Expr) bool { |
396 if f.lastStringerReceiver == nil { | 398 if f.lastStringerReceiver == nil { |
397 return false | 399 return false |
398 } | 400 } |
399 var obj *ast.Object | 401 var obj *ast.Object |
400 switch e := arg.(type) { | 402 switch e := arg.(type) { |
401 case *ast.Ident: | 403 case *ast.Ident: |
402 obj = e.Obj | 404 obj = e.Obj |
403 case *ast.StarExpr: | 405 case *ast.StarExpr: |
404 if id, ok := e.X.(*ast.Ident); ok { | 406 if id, ok := e.X.(*ast.Ident); ok { |
405 obj = id.Obj | 407 obj = id.Obj |
406 } | 408 } |
407 case *ast.UnaryExpr: | 409 case *ast.UnaryExpr: |
408 if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND { | 410 if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND { |
409 obj = id.Obj | 411 obj = id.Obj |
410 } | 412 } |
411 } | 413 } |
| 414 // We compare the underlying Object, which checks that the identifier |
| 415 // is the one we declared as the receiver for the String method in |
| 416 // which this printf appears. |
412 return obj == f.lastStringerReceiver | 417 return obj == f.lastStringerReceiver |
413 } | 418 } |
414 | 419 |
415 // argCanBeChecked reports whether the specified argument is statically present; | 420 // argCanBeChecked reports whether the specified argument is statically present; |
416 // it may be beyond the list of arguments or in a terminal slice... argument, wh
ich | 421 // it may be beyond the list of arguments or in a terminal slice... argument, wh
ich |
417 // means we can't see it. | 422 // means we can't see it. |
418 func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, isStar bool, s
tate *formatState) bool { | 423 func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, isStar bool, s
tate *formatState) bool { |
419 argNum := state.argNums[formatArg] | 424 argNum := state.argNums[formatArg] |
420 if argNum < 0 { | 425 if argNum < 0 { |
421 // Shouldn't happen, so catch it with prejudice. | 426 // Shouldn't happen, so catch it with prejudice. |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 f.Badf(call.Pos(), "%s call ends with newline",
name) | 492 f.Badf(call.Pos(), "%s call ends with newline",
name) |
488 } | 493 } |
489 } | 494 } |
490 } | 495 } |
491 for _, arg := range args { | 496 for _, arg := range args { |
492 if f.recursiveStringer(arg) { | 497 if f.recursiveStringer(arg) { |
493 f.Badf(call.Pos(), "arg %s for print causes recursive ca
ll to String method", f.gofmt(arg)) | 498 f.Badf(call.Pos(), "arg %s for print causes recursive ca
ll to String method", f.gofmt(arg)) |
494 } | 499 } |
495 } | 500 } |
496 } | 501 } |
LEFT | RIGHT |