mirror of
https://github.com/golang/go
synced 2024-11-18 20:04:52 -07:00
cmd/vet: verify potentially-recursive Stringers are actually Stringers
The printf recursiveStringer check was checking for a function called String(), but wasn't checking that it matched the actual function signature of Stringer. Fixes golang/go#30441 Change-Id: I09d5fba035bb717036f7edf57efc63e2e3fe51d5 Reviewed-on: https://go-review.googlesource.com/c/tools/+/164217 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
9e44c1c403
commit
36563e24a2
@ -856,20 +856,28 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Is it the receiver r, or &r?
|
||||
recv := stringMethod.Type().(*types.Signature).Recv()
|
||||
if recv == nil {
|
||||
sig := stringMethod.Type().(*types.Signature)
|
||||
if !isStringer(sig) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Is it the receiver r, or &r?
|
||||
if u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.AND {
|
||||
e = u.X // strip off & from &r
|
||||
}
|
||||
if id, ok := e.(*ast.Ident); ok {
|
||||
return pass.TypesInfo.Uses[id] == recv
|
||||
return pass.TypesInfo.Uses[id] == sig.Recv()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isStringer reports whether the method signature matches the String() definition in fmt.Stringer.
|
||||
func isStringer(sig *types.Signature) bool {
|
||||
return sig.Params().Len() == 0 &&
|
||||
sig.Results().Len() == 1 &&
|
||||
sig.Results().At(0).Type() == types.Typ[types.String]
|
||||
}
|
||||
|
||||
// isFunctionValue reports whether the expression is a function as opposed to a function call.
|
||||
// It is almost always a mistake to print a function value.
|
||||
func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
|
||||
|
14
go/analysis/passes/printf/testdata/src/a/a.go
vendored
14
go/analysis/passes/printf/testdata/src/a/a.go
vendored
@ -516,6 +516,20 @@ func (p *recursivePtrStringer) String() string {
|
||||
return fmt.Sprintln(p) // want "Sprintln arg p causes recursive call to String method"
|
||||
}
|
||||
|
||||
// implements a String() method but with non-matching return types
|
||||
type nonStringerWrongReturn int
|
||||
|
||||
func (s nonStringerWrongReturn) String() (string, error) {
|
||||
return "", fmt.Errorf("%v", s)
|
||||
}
|
||||
|
||||
// implements a String() method but with non-matching arguments
|
||||
type nonStringerWrongArgs int
|
||||
|
||||
func (s nonStringerWrongArgs) String(i int) string {
|
||||
return fmt.Sprintf("%d%v", i, s)
|
||||
}
|
||||
|
||||
type cons struct {
|
||||
car int
|
||||
cdr *cons
|
||||
|
Loading…
Reference in New Issue
Block a user