Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions passes/bodyclose/bodyclose.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ func (r *runner) isopen(b *ssa.BasicBlock, i int) bool {
return false
}

if r.isHeadCall(call) {
return false
}

if r.responseHandledByDirective(call) {
return false
}
Expand Down Expand Up @@ -335,9 +339,38 @@ func (r *runner) getReqCall(instr ssa.Instruction) (*ssa.Call, bool) {
return nil, false
}

if r.isHeadCall(call) {
return nil, false
}

return call, true
}

func (r *runner) isHeadCall(call *ssa.Call) bool {
if call == nil {
return false
}
callee := call.Call.StaticCallee()
if callee == nil {
return false
}
if callee.Pkg == nil || callee.Pkg.Pkg.Path() != nethttpPath {
return false
}
if callee.Name() != "Head" {
return false
}
recv := callee.Signature.Recv()
if recv == nil {
return true
}
recvType := recv.Type()
if ptr, ok := recvType.(*types.Pointer); ok {
recvType = ptr.Elem()
}
return isNamedType(recvType, nethttpPath, "Client")
}

func (r *runner) getResVal(instr ssa.Instruction) (ssa.Value, bool) {
switch instr := instr.(type) {
case *ssa.FieldAddr:
Expand Down
122 changes: 122 additions & 0 deletions passes/bodyclose/testdata/src/a/issue78.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package a

import (
"net/http"
)

type CustomClient struct {
*http.Client
}

func issue78HeadPackage() {
resp, err := http.Head("http://example.com/") // OK
if err != nil {
return
}
_ = resp.Header
}

func issue78HeadPackageUnassigned() {
http.Head("http://example.com/") // OK
}

func issue78HeadPackageDiscard() {
_, err := http.Head("http://example.com/") // OK
if err != nil {
return
}
}

func issue78HeadClientPointer() {
client := &http.Client{}
resp, err := client.Head("http://example.com/") // OK
if err != nil {
return
}
_ = resp.Header
}

func issue78HeadClientValue() {
var client http.Client
resp, err := client.Head("http://example.com/") // OK
if err != nil {
return
}
_ = resp.Header
}

func issue78HeadDefaultClient() {
resp, err := http.DefaultClient.Head("http://example.com/") // OK
if err != nil {
return
}
_ = resp.Header
}

func issue78HeadClientUnassigned() {
client := &http.Client{}
client.Head("http://example.com/") // OK
}

func issue78HeadWithClose() {
resp, err := http.Head("http://example.com/") // OK
if err != nil {
return
}
defer resp.Body.Close()
}

func issue78HeadCustomClient() {
cc := &CustomClient{Client: &http.Client{}}
resp, err := cc.Head("http://example.com/") // OK
if err != nil {
return
}
_ = resp.Header
}

func issue78HeadReadBody() {
resp, err := http.Head("http://example.com/") // OK
if err != nil {
return
}
buf := make([]byte, 10)
resp.Body.Read(buf)
}

func issue78HeadInClosure() {
go func() {
resp, err := http.Head("http://example.com/") // OK
if err != nil {
return
}
_ = resp.StatusCode
}()
}

func issue78HeadLoop() {
for i := 0; i < 3; i++ {
resp, err := http.Head("http://example.com/") // OK
if err != nil {
continue
}
_ = resp.StatusCode
}
}

func issue78GetStillReported() {
resp, err := http.Get("http://example.com/") // want "response body must be closed"
if err != nil {
return
}
_ = resp.Header
}

func issue78ClientGetStillReported() {
client := &http.Client{}
resp, err := client.Get("http://example.com/") // want "response body must be closed"
if err != nil {
return
}
_ = resp.Header
}