diff --git a/passes/bodyclose/bodyclose.go b/passes/bodyclose/bodyclose.go index 27042a1..38142be 100644 --- a/passes/bodyclose/bodyclose.go +++ b/passes/bodyclose/bodyclose.go @@ -149,6 +149,22 @@ func (r *runner) isopen(b *ssa.BasicBlock, i int) bool { return r.calledInFunc(f, called) } + // Case when calling Close() from struct field or method + if s, ok := aref.(*ssa.Store); ok { + if f, ok := s.Addr.(*ssa.FieldAddr); ok { + for _, bRef := range f.Block().Instrs { + bOp, ok := r.getBodyOp(bRef) + if !ok { + continue + } + for _, ccall := range *bOp.Referrers() { + if r.isCloseCall(ccall) { + return false + } + } + } + } + } } case *ssa.Call, *ssa.Defer: // Indirect function call // Hacky way to extract CommonCall diff --git a/passes/bodyclose/testdata/src/a/issue42.go b/passes/bodyclose/testdata/src/a/issue42.go new file mode 100644 index 0000000..49ac4f0 --- /dev/null +++ b/passes/bodyclose/testdata/src/a/issue42.go @@ -0,0 +1,27 @@ +package a + +import ( + "net/http" +) + +type MyResponse struct { + Original *http.Response +} + +func (r *MyResponse) Response() *http.Response { + return r.Original +} + +// issue42_1 is case when http.Response from struct field +func issue42_1() { + r := &MyResponse{} + r.Original, _ = http.Get("http://example.com/") // OK + _ = r.Original.Body.Close() +} + +// issue42_2 is case when http.Response from a function +func issue42_2() { + r := &MyResponse{} + r.Original, _ = http.Get("http://example.com/") // OK + _ = r.Response().Body.Close() +}