Merge branch 'master' into lukeshu/reproduce

This commit is contained in:
Isaev Denis 2019-06-09 13:18:41 +03:00 committed by GitHub
commit 66d4a16c6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 552 additions and 9 deletions

View File

@ -61,6 +61,6 @@ issues:
# golangci.com configuration
# https://github.com/golangci/golangci/wiki/Configuration
service:
golangci-lint-version: 1.15.x # use the fixed version to not introduce new linters unexpectedly
golangci-lint-version: 1.16.x # use the fixed version to not introduce new linters unexpectedly
prepare:
- echo "here I can run custom commands, but no preparation needed for this repo"

View File

@ -204,6 +204,7 @@ and the following linters are disabled by default:
$ golangci-lint help linters
...
Disabled by default linters:
bodyclose: checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
depguard: Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
dupl: Tool for code clone detection [fast: true, auto-fix: false]
gochecknoglobals: Checks that no globals are present in Go code [fast: true, auto-fix: false]
@ -344,7 +345,7 @@ Read [this section](#internals) for details.
### Memory Usage of Golangci-lint
A trade-off between memory usage and execution time can be controlled by [`GOCC`](https://golang.org/pkg/runtime/#hdr-Environment_Variables) environment variable.
A trade-off between memory usage and execution time can be controlled by [`GOGC`](https://golang.org/pkg/runtime/#hdr-Environment_Variables) environment variable.
Less `GOGC` values trigger garbage collection more frequently and golangci-lint consumes less memory and more CPU. Below is the trade-off table for running on this repo:
|`GOGC`|Peak Memory, GB|Executon Time, s|
@ -416,6 +417,7 @@ golangci-lint help linters
### Disabled By Default Linters (`-E/--enable`)
- [bodyclose](https://github.com/timakin/bodyclose) - checks whether HTTP response body is closed successfully
- [golint](https://github.com/golang/lint) - Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
- [stylecheck](https://github.com/dominikh/go-tools/tree/master/stylecheck) - Stylecheck is a replacement for golint
- [gosec](https://github.com/securego/gosec) - Inspects source code for security problems
@ -871,7 +873,7 @@ issues:
# golangci.com configuration
# https://github.com/golangci/golangci/wiki/Configuration
service:
golangci-lint-version: 1.15.x # use the fixed version to not introduce new linters unexpectedly
golangci-lint-version: 1.16.x # use the fixed version to not introduce new linters unexpectedly
prepare:
- echo "here I can run custom commands, but no preparation needed for this repo"
```
@ -926,8 +928,8 @@ Short answer: go 1.11 and newer are oficially supported.
Long answer:
1. go < 1.9 isn't supported
2. go 1.9 is supported by golangci-lint <= v1.10.2
3. go 1.10 is oficially supported by golangci-lint <= 1.15.0.
4. go1.11 and go1.12 are oficially supported by the latest version of golangci-lint.
3. go 1.10 is officially supported by golangci-lint <= 1.15.0.
4. go1.11 and go1.12 are officially supported by the latest version of golangci-lint.
**`golangci-lint` doesn't work**
@ -946,6 +948,7 @@ Thanks to [alecthomas/gometalinter](https://github.com/alecthomas/gometalinter)
Thanks to [bradleyfalzon/revgrep](https://github.com/bradleyfalzon/revgrep) for cool diff tool.
Thanks to developers and authors of used linters:
- [timakin](https://github.com/timakin)
- [kisielk](https://github.com/kisielk)
- [golang](https://github.com/golang)
- [dominikh](https://github.com/dominikh)

View File

@ -313,7 +313,7 @@ Read [this section](#internals) for details.
### Memory Usage of Golangci-lint
A trade-off between memory usage and execution time can be controlled by [`GOCC`](https://golang.org/pkg/runtime/#hdr-Environment_Variables) environment variable.
A trade-off between memory usage and execution time can be controlled by [`GOGC`](https://golang.org/pkg/runtime/#hdr-Environment_Variables) environment variable.
Less `GOGC` values trigger garbage collection more frequently and golangci-lint consumes less memory and more CPU. Below is the trade-off table for running on this repo:
|`GOGC`|Peak Memory, GB|Executon Time, s|
@ -475,8 +475,8 @@ Short answer: go 1.11 and newer are oficially supported.
Long answer:
1. go < 1.9 isn't supported
2. go 1.9 is supported by golangci-lint <= v1.10.2
3. go 1.10 is oficially supported by golangci-lint <= 1.15.0.
4. go1.11 and go1.12 are oficially supported by the latest version of golangci-lint.
3. go 1.10 is officially supported by golangci-lint <= 1.15.0.
4. go1.11 and go1.12 are officially supported by the latest version of golangci-lint.
**`golangci-lint` doesn't work**

1
go.mod
View File

@ -50,6 +50,7 @@ require (
github.com/spf13/viper v1.0.2
github.com/stretchr/testify v1.2.2
github.com/valyala/quicktemplate v1.1.1
github.com/timakin/bodyclose v0.0.0-20190407043127-4a873e97b2bb
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a // indirect
golang.org/x/net v0.0.0-20190313220215-9f648a60d977 // indirect
golang.org/x/sys v0.0.0-20190312061237-fead79001313 // indirect

6
go.sum
View File

@ -77,6 +77,8 @@ github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno=
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@ -160,6 +162,8 @@ github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk
github.com/valyala/quicktemplate v1.1.1 h1:C58y/wN0FMTi2PR0n3onltemfFabany53j7M6SDDB8k=
github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/timakin/bodyclose v0.0.0-20190407043127-4a873e97b2bb h1:lI9ufgFfvuqRctP9Ny8lDDLbSWCMxBPletcSqrnyFYM=
github.com/timakin/bodyclose v0.0.0-20190407043127-4a873e97b2bb/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -188,6 +192,8 @@ golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20181205014116-22934f0fdb62/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420000508-685fecacd0a0 h1:pa1CyBALPFjblgkNQp7T7gEcFcG/GOG5Ck8IcnSVWGs=
golang.org/x/tools v0.0.0-20190420000508-685fecacd0a0/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=

View File

@ -172,7 +172,8 @@ log_crit() {
uname_os() {
os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$os" in
msys_nt) os="windows" ;;
msys_nt*) os="windows" ;;
mingw*) os="windows" ;;
esac
echo "$os"
}

View File

@ -0,0 +1,21 @@
package golinters
import (
"github.com/timakin/bodyclose/passes/bodyclose"
"golang.org/x/tools/go/analysis"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)
func NewBodyclose() *goanalysis.Linter {
analyzers := []*analysis.Analyzer{
bodyclose.Analyzer,
}
return goanalysis.NewLinter(
"bodyclose",
"checks whether HTTP response body is closed successfully",
analyzers,
nil,
)
}

View File

@ -89,6 +89,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithSpeed(4).
WithAlternativeNames("vet", "vetshadow").
WithURL("https://golang.org/cmd/vet/"),
linter.NewConfig(golinters.NewBodyclose()).
WithSSA().
WithPresets(linter.PresetPerformance, linter.PresetBugs).
WithSpeed(4).
WithURL("https://github.com/timakin/bodyclose"),
linter.NewConfig(golinters.Errcheck{}).
WithTypeInfo().
WithPresets(linter.PresetBugs).

12
test/testdata/bodyclose.go vendored Normal file
View File

@ -0,0 +1,12 @@
//args: -Ebodyclose
package testdata
import (
"io/ioutil"
"net/http"
)
func BodycloseNotClosed() {
resp, _ := http.Get("https://google.com") // ERROR "bodyclose: response body must be closed"
_, _ = ioutil.ReadAll(resp.Body)
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 GoStaticAnalysis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,10 @@
# analysisutil
[![godoc.org][godoc-badge]][godoc]
Utilities for x/tools/go/analysis package.
<!-- links -->
[godoc]: https://godoc.org/github.com/gostaticanalysis/analysisutil
[godoc-badge]: https://img.shields.io/badge/godoc-reference-4F73B3.svg?style=flat-square&label=%20godoc.org

View File

@ -0,0 +1,18 @@
package analysisutil
import (
"go/ast"
"go/token"
"golang.org/x/tools/go/analysis"
)
// File finds *ast.File in pass.Files by pos.
func File(pass *analysis.Pass, pos token.Pos) *ast.File {
for _, f := range pass.Files {
if f.Pos() <= pos && pos <= f.End() {
return f
}
}
return nil
}

View File

@ -0,0 +1,5 @@
module github.com/gostaticanalysis/analysisutil
go 1.12
require golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5

View File

@ -0,0 +1,6 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5 h1:ZcPpqKMdoZeNQ/4GHlyY4COf8n8SmpPv6mcqF1+VPSM=
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=

26
vendor/github.com/gostaticanalysis/analysisutil/pkg.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
package analysisutil
import (
"go/types"
"strings"
)
// RemoVendor removes vendoring infomation from import path.
func RemoveVendor(path string) string {
i := strings.Index(path, "vendor")
if i >= 0 {
return path[i+len("vendor")+1:]
}
return path
}
// LookupFromImports finds an object from import paths.
func LookupFromImports(imports []*types.Package, path, name string) types.Object {
path = RemoveVendor(path)
for i := range imports {
if path == RemoveVendor(imports[i].Path()) {
return imports[i].Scope().Lookup(name)
}
}
return nil
}

31
vendor/github.com/gostaticanalysis/analysisutil/ssa.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
package analysisutil
import "golang.org/x/tools/go/ssa"
// IfInstr returns *ssa.If which is contained in the block b.
// If the block b has not any if instruction, IfInstr returns nil.
func IfInstr(b *ssa.BasicBlock) *ssa.If {
if len(b.Instrs) == 0 {
return nil
}
ifinstr, ok := b.Instrs[len(b.Instrs)-1].(*ssa.If)
if !ok {
return nil
}
return ifinstr
}
// Phi returns phi values which are contained in the block b.
func Phi(b *ssa.BasicBlock) (phis []*ssa.Phi) {
for _, instr := range b.Instrs {
if phi, ok := instr.(*ssa.Phi); ok {
phis = append(phis, phi)
} else {
// no more phi
break
}
}
return
}

21
vendor/github.com/timakin/bodyclose/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Seiji Takahashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,352 @@
package bodyclose
import (
"fmt"
"go/ast"
"go/types"
"strconv"
"strings"
"github.com/gostaticanalysis/analysisutil"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa"
"golang.org/x/tools/go/ssa"
)
var Analyzer = &analysis.Analyzer{
Name: "bodyclose",
Doc: Doc,
Run: new(runner).run,
Requires: []*analysis.Analyzer{
buildssa.Analyzer,
},
}
const (
Doc = "bodyclose checks whether HTTP response body is closed successfully"
nethttpPath = "net/http"
closeMethod = "Close"
)
type runner struct {
pass *analysis.Pass
resObj types.Object
resTyp *types.Pointer
bodyObj types.Object
closeMthd *types.Func
skipFile map[*ast.File]bool
}
func (r *runner) run(pass *analysis.Pass) (interface{}, error) {
r.pass = pass
funcs := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA).SrcFuncs
r.resObj = analysisutil.LookupFromImports(pass.Pkg.Imports(), nethttpPath, "Response")
if r.resObj == nil {
// skip checking
return nil, nil
}
resNamed, ok := r.resObj.Type().(*types.Named)
if !ok {
return nil, fmt.Errorf("cannot find http.Response")
}
r.resTyp = types.NewPointer(resNamed)
resStruct, ok := r.resObj.Type().Underlying().(*types.Struct)
if !ok {
return nil, fmt.Errorf("cannot find http.Response")
}
for i := 0; i < resStruct.NumFields(); i++ {
field := resStruct.Field(i)
if field.Id() == "Body" {
r.bodyObj = field
}
}
if r.bodyObj == nil {
return nil, fmt.Errorf("cannot find the object http.Response.Body")
}
bodyNamed := r.bodyObj.Type().(*types.Named)
bodyItrf := bodyNamed.Underlying().(*types.Interface)
for i := 0; i < bodyItrf.NumMethods(); i++ {
bmthd := bodyItrf.Method(i)
if bmthd.Id() == closeMethod {
r.closeMthd = bmthd
}
}
r.skipFile = map[*ast.File]bool{}
for _, f := range funcs {
if r.noImportedNetHTTP(f) {
// skip this
continue
}
// skip if the function is just referenced
var isreffunc bool
for i := 0; i < f.Signature.Results().Len(); i++ {
if f.Signature.Results().At(i).Type().String() == r.resTyp.String() {
isreffunc = true
}
}
if isreffunc {
continue
}
for _, b := range f.Blocks {
for i := range b.Instrs {
pos := b.Instrs[i].Pos()
if r.isopen(b, i) {
pass.Reportf(pos, "response body must be closed")
}
}
}
}
return nil, nil
}
func (r *runner) isopen(b *ssa.BasicBlock, i int) bool {
call, ok := r.getReqCall(b.Instrs[i])
if !ok {
return false
}
if len(*call.Referrers()) == 0 {
return true
}
cRefs := *call.Referrers()
for _, cRef := range cRefs {
val, ok := r.getResVal(cRef)
if !ok {
continue
}
if len(*val.Referrers()) == 0 {
return true
}
resRefs := *val.Referrers()
for _, resRef := range resRefs {
switch resRef := resRef.(type) {
case *ssa.Store: // Call in Closure function
if len(*resRef.Addr.Referrers()) == 0 {
return true
}
for _, aref := range *resRef.Addr.Referrers() {
if c, ok := aref.(*ssa.MakeClosure); ok {
f := c.Fn.(*ssa.Function)
if r.noImportedNetHTTP(f) {
// skip this
return false
}
called := r.isClosureCalled(c)
return r.calledInFunc(f, called)
}
}
case *ssa.Call: // Indirect function call
if f, ok := resRef.Call.Value.(*ssa.Function); ok {
for _, b := range f.Blocks {
for i := range b.Instrs {
return r.isopen(b, i)
}
}
}
case *ssa.FieldAddr: // Normal reference to response entity
if resRef.Referrers() == nil {
return true
}
bRefs := *resRef.Referrers()
for _, bRef := range bRefs {
bOp, ok := r.getBodyOp(bRef)
if !ok {
continue
}
if len(*bOp.Referrers()) == 0 {
return true
}
ccalls := *bOp.Referrers()
for _, ccall := range ccalls {
if r.isCloseCall(ccall) {
return false
}
}
}
}
}
}
return true
}
func (r *runner) getReqCall(instr ssa.Instruction) (*ssa.Call, bool) {
call, ok := instr.(*ssa.Call)
if !ok {
return nil, false
}
if !strings.Contains(call.Type().String(), r.resTyp.String()) {
return nil, false
}
return call, true
}
func (r *runner) getResVal(instr ssa.Instruction) (ssa.Value, bool) {
switch instr := instr.(type) {
case *ssa.FieldAddr:
if instr.X.Type().String() == r.resTyp.String() {
return instr.X.(ssa.Value), true
}
case ssa.Value:
if instr.Type().String() == r.resTyp.String() {
return instr, true
}
}
return nil, false
}
func (r *runner) getBodyOp(instr ssa.Instruction) (*ssa.UnOp, bool) {
op, ok := instr.(*ssa.UnOp)
if !ok {
return nil, false
}
if op.Type() != r.bodyObj.Type() {
return nil, false
}
return op, true
}
func (r *runner) isCloseCall(ccall ssa.Instruction) bool {
switch ccall := ccall.(type) {
case *ssa.Defer:
if ccall.Call.Method.Name() == r.closeMthd.Name() {
return true
}
case *ssa.Call:
if ccall.Call.Method.Name() == r.closeMthd.Name() {
return true
}
case *ssa.ChangeInterface:
if ccall.Type().String() == "io.Closer" {
closeMtd := ccall.Type().Underlying().(*types.Interface).Method(0)
crs := *ccall.Referrers()
for _, cs := range crs {
if cs, ok := cs.(*ssa.Defer); ok {
if val, ok := cs.Common().Value.(*ssa.Function); ok {
for _, b := range val.Blocks {
for _, instr := range b.Instrs {
if c, ok := instr.(*ssa.Call); ok {
if c.Call.Method == closeMtd {
return true
}
}
}
}
}
}
}
}
}
return false
}
func (r *runner) isClosureCalled(c *ssa.MakeClosure) bool {
refs := *c.Referrers()
if len(refs) == 0 {
return false
}
for _, ref := range refs {
switch ref.(type) {
case *ssa.Call, *ssa.Defer:
return true
}
}
return false
}
func (r *runner) noImportedNetHTTP(f *ssa.Function) (ret bool) {
obj := f.Object()
if obj == nil {
return false
}
file := analysisutil.File(r.pass, obj.Pos())
if file == nil {
return false
}
if skip, has := r.skipFile[file]; has {
return skip
}
defer func() {
r.skipFile[file] = ret
}()
for _, impt := range file.Imports {
path, err := strconv.Unquote(impt.Path.Value)
if err != nil {
continue
}
path = analysisutil.RemoveVendor(path)
if path == nethttpPath {
return false
}
}
return true
}
func (r *runner) calledInFunc(f *ssa.Function, called bool) bool {
for _, b := range f.Blocks {
for i, instr := range b.Instrs {
switch instr := instr.(type) {
case *ssa.UnOp:
refs := *instr.Referrers()
if len(refs) == 0 {
return true
}
for _, r := range refs {
if v, ok := r.(ssa.Value); ok {
if ptr, ok := v.Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "io", "ReadCloser") {
return true
}
vrefs := *v.Referrers()
for _, vref := range vrefs {
if vref, ok := vref.(*ssa.UnOp); ok {
vrefs := *vref.Referrers()
if len(vrefs) == 0 {
return true
}
for _, vref := range vrefs {
if c, ok := vref.(*ssa.Call); ok {
if c.Call.Method.Name() == closeMethod {
return !called
}
}
}
}
}
}
}
default:
return r.isopen(b, i) || !called
}
}
}
return false
}
// isNamedType reports whether t is the named type path.name.
func isNamedType(t types.Type, path, name string) bool {
n, ok := t.(*types.Named)
if !ok {
return false
}
obj := n.Obj()
return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path
}

4
vendor/modules.txt vendored
View File

@ -106,6 +106,8 @@ github.com/golangci/prealloc
github.com/golangci/revgrep
# github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4
github.com/golangci/unconvert
# github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3
github.com/gostaticanalysis/analysisutil
# github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
github.com/hashicorp/hcl
github.com/hashicorp/hcl/hcl/printer
@ -183,6 +185,8 @@ github.com/stretchr/testify/require
github.com/valyala/bytebufferpool
# github.com/valyala/quicktemplate v1.1.1
github.com/valyala/quicktemplate
# github.com/timakin/bodyclose v0.0.0-20190407043127-4a873e97b2bb
github.com/timakin/bodyclose/passes/bodyclose
# golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a
golang.org/x/crypto/ssh/terminal
# golang.org/x/sys v0.0.0-20190312061237-fead79001313