go/analysis/passes/printf: check for nil scope of instance methods

Fixes golang/go#55350

Change-Id: I28784b42de72e9d489e40d546e171af23b9e5c13
Reviewed-on: https://go-review.googlesource.com/c/tools/+/433755
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Tim King <taking@google.com>
Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Zvonimir Pavlinovic 2022-09-23 15:41:06 -07:00
parent 3db607bf98
commit 199742a5a6
2 changed files with 29 additions and 2 deletions

View File

@ -945,11 +945,16 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) {
return "", false
}
// inScope returns true if e is in the scope of f.
inScope := func(e ast.Expr, f *types.Func) bool {
return f.Scope() != nil && f.Scope().Contains(e.Pos())
}
// Is the expression e within the body of that String or Error method?
var method *types.Func
if strOk && strMethod.Pkg() == pass.Pkg && strMethod.Scope().Contains(e.Pos()) {
if strOk && strMethod.Pkg() == pass.Pkg && inScope(e, strMethod) {
method = strMethod
} else if errOk && errMethod.Pkg() == pass.Pkg && errMethod.Scope().Contains(e.Pos()) {
} else if errOk && errMethod.Pkg() == pass.Pkg && inScope(e, errMethod) {
method = errMethod
} else {
return "", false

View File

@ -121,3 +121,25 @@ func TestTermReduction[T1 interface{ ~int | string }, T2 interface {
fmt.Printf("%d", t2)
fmt.Printf("%s", t2) // want "wrong type.*contains typeparams.myInt"
}
type U[T any] struct{}
func (u U[T]) String() string {
fmt.Println(u) // want `fmt.Println arg u causes recursive call to \(typeparams.U\[T\]\).String method`
return ""
}
type S[T comparable] struct {
t T
}
func (s S[T]) String() T {
fmt.Println(s) // Not flagged. We currently do not consider String() T to implement fmt.Stringer (see #55928).
return s.t
}
func TestInstanceStringer() {
// Tests String method with nil Scope (#55350)
fmt.Println(&S[string]{})
fmt.Println(&U[string]{})
}