parent
							
								
									8319caf63f
								
							
						
					
					
						commit
						2c69ef2eb0
					
				
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@ -14,7 +14,7 @@ require (
 | 
				
			|||||||
	github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a
 | 
						github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a
 | 
				
			||||||
	github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6
 | 
						github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6
 | 
				
			||||||
	github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613
 | 
						github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613
 | 
				
			||||||
	github.com/golangci/go-tools v0.0.0-20180109140146-35a9f45a5db0
 | 
						github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196
 | 
				
			||||||
	github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3
 | 
						github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3
 | 
				
			||||||
	github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee
 | 
						github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee
 | 
				
			||||||
	github.com/golangci/gofmt v0.0.0-20181105071733-0b8337e80d98
 | 
						github.com/golangci/gofmt v0.0.0-20181105071733-0b8337e80d98
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@ -48,8 +48,8 @@ github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6 h1:i2jIkQFb8RG45
 | 
				
			|||||||
github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
 | 
					github.com/golangci/errcheck v0.0.0-20181003203344-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
 | 
				
			||||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw=
 | 
					github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw=
 | 
				
			||||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
 | 
					github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
 | 
				
			||||||
github.com/golangci/go-tools v0.0.0-20180109140146-35a9f45a5db0 h1:tYc7NX0EeSyW9wFF0EXPB57lAiKRPwKZxVkaTsGuB9k=
 | 
					github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196 h1:9rtVlONXLF1rJZzvLt4tfOXtnAFUEhxCJ64Ibzj6ECo=
 | 
				
			||||||
github.com/golangci/go-tools v0.0.0-20180109140146-35a9f45a5db0/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM=
 | 
					github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM=
 | 
				
			||||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8=
 | 
					github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8=
 | 
				
			||||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
 | 
					github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
 | 
				
			||||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8=
 | 
					github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8=
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								test/testdata/gosimple.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								test/testdata/gosimple.go
									
									
									
									
										vendored
									
									
								
							@ -1,25 +1,30 @@
 | 
				
			|||||||
//args: -Egosimple
 | 
					//args: -Egosimple
 | 
				
			||||||
package testdata
 | 
					package testdata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "strings"
 | 
					import (
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Gosimple(id1, s1 string) string {
 | 
					func Gosimple(ss []string) {
 | 
				
			||||||
	if strings.HasPrefix(id1, s1) { // ERROR "should replace.*with.*strings.TrimPrefix"
 | 
						if ss != nil { // ERROR "S1031: unnecessary nil check around range"
 | 
				
			||||||
		id1 = strings.TrimPrefix(id1, s1)
 | 
							for _, s := range ss {
 | 
				
			||||||
 | 
								log.Printf(s)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return id1
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GosimpleNolintGosimple(id1, s1 string) string {
 | 
					func GosimpleNolintGosimple(ss []string) {
 | 
				
			||||||
	if strings.HasPrefix(id1, s1) { //nolint:gosimple
 | 
						if ss != nil { //nolint:gosimple
 | 
				
			||||||
		id1 = strings.TrimPrefix(id1, s1)
 | 
							for _, s := range ss {
 | 
				
			||||||
 | 
								log.Printf(s)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return id1
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GosimpleNolintMegacheck(id1, s1 string) string {
 | 
					func GosimpleNolintMegacheck(ss []string) {
 | 
				
			||||||
	if strings.HasPrefix(id1, s1) { //nolint:megacheck
 | 
						if ss != nil { //nolint:megacheck
 | 
				
			||||||
		id1 = strings.TrimPrefix(id1, s1)
 | 
							for _, s := range ss {
 | 
				
			||||||
 | 
								log.Printf(s)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return id1
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										27
									
								
								test/testdata/stylecheck.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								test/testdata/stylecheck.go
									
									
									
									
										vendored
									
									
								
							@ -2,19 +2,34 @@
 | 
				
			|||||||
package testdata
 | 
					package testdata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Stylecheck(x int) {
 | 
					func Stylecheck(x int) {
 | 
				
			||||||
	if 0 == x { // ERROR "don't use Yoda conditions"
 | 
						switch x {
 | 
				
			||||||
		panic(x)
 | 
						case 1:
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						default: // ERROR "ST1015: default case should be first or last in switch statement"
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						case 2:
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func StylecheckNolintStylecheck(x int) {
 | 
					func StylecheckNolintStylecheck(x int) {
 | 
				
			||||||
	if 0 == x { //nolint:stylecheck
 | 
						switch x {
 | 
				
			||||||
		panic(x)
 | 
						case 1:
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						default: //nolint:stylecheck
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						case 2:
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func StylecheckNolintMegacheck(x int) {
 | 
					func StylecheckNolintMegacheck(x int) {
 | 
				
			||||||
	if 0 == x { //nolint:megacheck // ERROR "don't use Yoda conditions"
 | 
						switch x {
 | 
				
			||||||
		panic(x)
 | 
						case 1:
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						default: //nolint:megacheck // ERROR "ST1015: default case should be first or last in switch statement"
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						case 2:
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								vendor/github.com/golangci/go-tools/arg/arg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/golangci/go-tools/arg/arg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -12,7 +12,6 @@ var args = map[string]int{
 | 
				
			|||||||
	"encoding/binary.Write.data":           2,
 | 
						"encoding/binary.Write.data":           2,
 | 
				
			||||||
	"errors.New.text":                      0,
 | 
						"errors.New.text":                      0,
 | 
				
			||||||
	"fmt.Printf.format":                    0,
 | 
						"fmt.Printf.format":                    0,
 | 
				
			||||||
	"fmt.Fprintf.format":                   1,
 | 
					 | 
				
			||||||
	"fmt.Sprintf.a[0]":                     1,
 | 
						"fmt.Sprintf.a[0]":                     1,
 | 
				
			||||||
	"fmt.Sprintf.format":                   0,
 | 
						"fmt.Sprintf.format":                   0,
 | 
				
			||||||
	"len.v":                                0,
 | 
						"len.v":                                0,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								vendor/github.com/golangci/go-tools/lint/generated.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/golangci/go-tools/lint/generated.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -7,6 +7,8 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
 | 
						// used by cgo before Go 1.11
 | 
				
			||||||
 | 
						oldCgo = []byte("// Created by cgo - DO NOT EDIT")
 | 
				
			||||||
	prefix = []byte("// Code generated ")
 | 
						prefix = []byte("// Code generated ")
 | 
				
			||||||
	suffix = []byte(" DO NOT EDIT.")
 | 
						suffix = []byte(" DO NOT EDIT.")
 | 
				
			||||||
	nl     = []byte("\n")
 | 
						nl     = []byte("\n")
 | 
				
			||||||
@ -25,6 +27,9 @@ func isGenerated(r io.Reader) bool {
 | 
				
			|||||||
		if bytes.HasPrefix(s, prefix) && bytes.HasSuffix(s, suffix) {
 | 
							if bytes.HasPrefix(s, prefix) && bytes.HasSuffix(s, suffix) {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if bytes.Equal(s, oldCgo) {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if err == io.EOF {
 | 
							if err == io.EOF {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										33
									
								
								vendor/github.com/golangci/go-tools/lint/lintdsl/lintdsl.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/golangci/go-tools/lint/lintdsl/lintdsl.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -233,26 +233,15 @@ func IsGoVersion(j *lint.Job, minor int) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func CallNameAST(j *lint.Job, call *ast.CallExpr) string {
 | 
					func CallNameAST(j *lint.Job, call *ast.CallExpr) string {
 | 
				
			||||||
	switch fun := call.Fun.(type) {
 | 
						sel, ok := call.Fun.(*ast.SelectorExpr)
 | 
				
			||||||
	case *ast.SelectorExpr:
 | 
						if !ok {
 | 
				
			||||||
		fn, ok := ObjectOf(j, fun.Sel).(*types.Func)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return ""
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return fn.FullName()
 | 
					 | 
				
			||||||
	case *ast.Ident:
 | 
					 | 
				
			||||||
		obj := ObjectOf(j, fun)
 | 
					 | 
				
			||||||
		switch obj := obj.(type) {
 | 
					 | 
				
			||||||
		case *types.Func:
 | 
					 | 
				
			||||||
			return obj.FullName()
 | 
					 | 
				
			||||||
		case *types.Builtin:
 | 
					 | 
				
			||||||
			return obj.Name()
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return ""
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						fn, ok := j.NodePackage(call).TypesInfo.ObjectOf(sel.Sel).(*types.Func)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return fn.FullName()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func IsCallToAST(j *lint.Job, node ast.Node, name string) bool {
 | 
					func IsCallToAST(j *lint.Job, node ast.Node, name string) bool {
 | 
				
			||||||
@ -332,11 +321,3 @@ func GroupSpecs(j *lint.Job, specs []ast.Spec) [][]ast.Spec {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return groups
 | 
						return groups
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func IsObject(obj types.Object, name string) bool {
 | 
					 | 
				
			||||||
	var path string
 | 
					 | 
				
			||||||
	if pkg := obj.Pkg(); pkg != nil {
 | 
					 | 
				
			||||||
		path = pkg.Path() + "."
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return path+obj.Name() == name
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/golangci/go-tools/lint/lintutil/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/golangci/go-tools/lint/lintutil/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -309,7 +309,7 @@ func Lint(cs []lint.Checker, paths []string, opt *Options) ([]lint.Problem, erro
 | 
				
			|||||||
	return problems, nil
 | 
						return problems, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var posRe = regexp.MustCompile(`^(.+?):(\d+):(\d+)?$`)
 | 
					var posRe = regexp.MustCompile(`^(.+?):(\d+)(?::(\d+)?)?$`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func parsePos(pos string) token.Position {
 | 
					func parsePos(pos string) token.Position {
 | 
				
			||||||
	if pos == "-" || pos == "" {
 | 
						if pos == "-" || pos == "" {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										412
									
								
								vendor/github.com/golangci/go-tools/simple/lint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										412
									
								
								vendor/github.com/golangci/go-tools/simple/lint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -62,8 +62,6 @@ func (c *Checker) Checks() []lint.Check {
 | 
				
			|||||||
		{ID: "S1030", FilterGenerated: true, Fn: c.LintBytesBufferConversions},
 | 
							{ID: "S1030", FilterGenerated: true, Fn: c.LintBytesBufferConversions},
 | 
				
			||||||
		{ID: "S1031", FilterGenerated: true, Fn: c.LintNilCheckAroundRange},
 | 
							{ID: "S1031", FilterGenerated: true, Fn: c.LintNilCheckAroundRange},
 | 
				
			||||||
		{ID: "S1032", FilterGenerated: true, Fn: c.LintSortHelpers},
 | 
							{ID: "S1032", FilterGenerated: true, Fn: c.LintSortHelpers},
 | 
				
			||||||
		{ID: "S1033", FilterGenerated: true, Fn: c.LintGuardedDelete},
 | 
					 | 
				
			||||||
		{ID: "S1034", FilterGenerated: true, Fn: c.LintSimplifyTypeSwitch},
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1087,26 +1085,22 @@ func (c *Checker) LintTrim(j *lint.Job) {
 | 
				
			|||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		switch {
 | 
							call, ok := condCall.Fun.(*ast.SelectorExpr)
 | 
				
			||||||
		case IsCallToAST(j, condCall, "strings.HasPrefix"):
 | 
							if !ok {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if IsIdent(call.X, "strings") {
 | 
				
			||||||
			pkg = "strings"
 | 
								pkg = "strings"
 | 
				
			||||||
 | 
							} else if IsIdent(call.X, "bytes") {
 | 
				
			||||||
 | 
								pkg = "bytes"
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if IsIdent(call.Sel, "HasPrefix") {
 | 
				
			||||||
			fun = "HasPrefix"
 | 
								fun = "HasPrefix"
 | 
				
			||||||
		case IsCallToAST(j, condCall, "strings.HasSuffix"):
 | 
							} else if IsIdent(call.Sel, "HasSuffix") {
 | 
				
			||||||
			pkg = "strings"
 | 
					 | 
				
			||||||
			fun = "HasSuffix"
 | 
								fun = "HasSuffix"
 | 
				
			||||||
		case IsCallToAST(j, condCall, "strings.Contains"):
 | 
							} else {
 | 
				
			||||||
			pkg = "strings"
 | 
					 | 
				
			||||||
			fun = "Contains"
 | 
					 | 
				
			||||||
		case IsCallToAST(j, condCall, "bytes.HasPrefix"):
 | 
					 | 
				
			||||||
			pkg = "bytes"
 | 
					 | 
				
			||||||
			fun = "HasPrefix"
 | 
					 | 
				
			||||||
		case IsCallToAST(j, condCall, "bytes.HasSuffix"):
 | 
					 | 
				
			||||||
			pkg = "bytes"
 | 
					 | 
				
			||||||
			fun = "HasSuffix"
 | 
					 | 
				
			||||||
		case IsCallToAST(j, condCall, "bytes.Contains"):
 | 
					 | 
				
			||||||
			pkg = "bytes"
 | 
					 | 
				
			||||||
			fun = "Contains"
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1123,121 +1117,102 @@ func (c *Checker) LintTrim(j *lint.Job) {
 | 
				
			|||||||
		if !sameNonDynamic(condCall.Args[0], assign.Lhs[0]) {
 | 
							if !sameNonDynamic(condCall.Args[0], assign.Lhs[0]) {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							slice, ok := assign.Rhs[0].(*ast.SliceExpr)
 | 
				
			||||||
		switch rhs := assign.Rhs[0].(type) {
 | 
							if !ok {
 | 
				
			||||||
		case *ast.CallExpr:
 | 
					 | 
				
			||||||
			if len(rhs.Args) < 2 || !sameNonDynamic(condCall.Args[0], rhs.Args[0]) || !sameNonDynamic(condCall.Args[1], rhs.Args[1]) {
 | 
					 | 
				
			||||||
				return true
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if IsCallToAST(j, condCall, "strings.HasPrefix") && IsCallToAST(j, rhs, "strings.TrimPrefix") ||
 | 
					 | 
				
			||||||
				IsCallToAST(j, condCall, "strings.HasSuffix") && IsCallToAST(j, rhs, "strings.TrimSuffix") ||
 | 
					 | 
				
			||||||
				IsCallToAST(j, condCall, "strings.Contains") && IsCallToAST(j, rhs, "strings.Replace") ||
 | 
					 | 
				
			||||||
				IsCallToAST(j, condCall, "bytes.HasPrefix") && IsCallToAST(j, rhs, "bytes.TrimPrefix") ||
 | 
					 | 
				
			||||||
				IsCallToAST(j, condCall, "bytes.HasSuffix") && IsCallToAST(j, rhs, "bytes.TrimSuffix") ||
 | 
					 | 
				
			||||||
				IsCallToAST(j, condCall, "bytes.Contains") && IsCallToAST(j, rhs, "bytes.Replace") {
 | 
					 | 
				
			||||||
				j.Errorf(ifstmt, "should replace this if statement with an unconditional %s", CallNameAST(j, rhs))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		case *ast.SliceExpr:
 | 
							}
 | 
				
			||||||
			slice := rhs
 | 
							if slice.Slice3 {
 | 
				
			||||||
			if !ok {
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !sameNonDynamic(slice.X, condCall.Args[0]) {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var index ast.Expr
 | 
				
			||||||
 | 
							switch fun {
 | 
				
			||||||
 | 
							case "HasPrefix":
 | 
				
			||||||
 | 
								// TODO(dh) We could detect a High that is len(s), but another
 | 
				
			||||||
 | 
								// rule will already flag that, anyway.
 | 
				
			||||||
 | 
								if slice.High != nil {
 | 
				
			||||||
				return true
 | 
									return true
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if slice.Slice3 {
 | 
								index = slice.Low
 | 
				
			||||||
				return true
 | 
							case "HasSuffix":
 | 
				
			||||||
			}
 | 
								if slice.Low != nil {
 | 
				
			||||||
			if !sameNonDynamic(slice.X, condCall.Args[0]) {
 | 
									n, ok := ExprToInt(j, slice.Low)
 | 
				
			||||||
				return true
 | 
									if !ok || n != 0 {
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			var index ast.Expr
 | 
					 | 
				
			||||||
			switch fun {
 | 
					 | 
				
			||||||
			case "HasPrefix":
 | 
					 | 
				
			||||||
				// TODO(dh) We could detect a High that is len(s), but another
 | 
					 | 
				
			||||||
				// rule will already flag that, anyway.
 | 
					 | 
				
			||||||
				if slice.High != nil {
 | 
					 | 
				
			||||||
					return true
 | 
										return true
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				index = slice.Low
 | 
					 | 
				
			||||||
			case "HasSuffix":
 | 
					 | 
				
			||||||
				if slice.Low != nil {
 | 
					 | 
				
			||||||
					n, ok := ExprToInt(j, slice.Low)
 | 
					 | 
				
			||||||
					if !ok || n != 0 {
 | 
					 | 
				
			||||||
						return true
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				index = slice.High
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								index = slice.High
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch index := index.(type) {
 | 
							switch index := index.(type) {
 | 
				
			||||||
			case *ast.CallExpr:
 | 
							case *ast.CallExpr:
 | 
				
			||||||
				if fun != "HasPrefix" {
 | 
								if fun != "HasPrefix" {
 | 
				
			||||||
					return true
 | 
									return true
 | 
				
			||||||
				}
 | 
								}
 | 
				
			||||||
				if fn, ok := index.Fun.(*ast.Ident); !ok || fn.Name != "len" {
 | 
								if fn, ok := index.Fun.(*ast.Ident); !ok || fn.Name != "len" {
 | 
				
			||||||
					return true
 | 
									return true
 | 
				
			||||||
				}
 | 
								}
 | 
				
			||||||
				if len(index.Args) != 1 {
 | 
								if len(index.Args) != 1 {
 | 
				
			||||||
					return true
 | 
									return true
 | 
				
			||||||
				}
 | 
								}
 | 
				
			||||||
				id3 := index.Args[Arg("len.v")]
 | 
								id3 := index.Args[Arg("len.v")]
 | 
				
			||||||
				switch oid3 := condCall.Args[1].(type) {
 | 
								switch oid3 := condCall.Args[1].(type) {
 | 
				
			||||||
				case *ast.BasicLit:
 | 
								case *ast.BasicLit:
 | 
				
			||||||
					if pkg != "strings" {
 | 
					 | 
				
			||||||
						return false
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					lit, ok := id3.(*ast.BasicLit)
 | 
					 | 
				
			||||||
					if !ok {
 | 
					 | 
				
			||||||
						return true
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					s1, ok1 := ExprToString(j, lit)
 | 
					 | 
				
			||||||
					s2, ok2 := ExprToString(j, condCall.Args[1])
 | 
					 | 
				
			||||||
					if !ok1 || !ok2 || s1 != s2 {
 | 
					 | 
				
			||||||
						return true
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				default:
 | 
					 | 
				
			||||||
					if !sameNonDynamic(id3, oid3) {
 | 
					 | 
				
			||||||
						return true
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case *ast.BasicLit, *ast.Ident:
 | 
					 | 
				
			||||||
				if fun != "HasPrefix" {
 | 
					 | 
				
			||||||
					return true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if pkg != "strings" {
 | 
									if pkg != "strings" {
 | 
				
			||||||
 | 
										return false
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									lit, ok := id3.(*ast.BasicLit)
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
					return true
 | 
										return true
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				string, ok1 := ExprToString(j, condCall.Args[1])
 | 
									s1, ok1 := ExprToString(j, lit)
 | 
				
			||||||
				int, ok2 := ExprToInt(j, slice.Low)
 | 
									s2, ok2 := ExprToString(j, condCall.Args[1])
 | 
				
			||||||
				if !ok1 || !ok2 || int != int64(len(string)) {
 | 
									if !ok1 || !ok2 || s1 != s2 {
 | 
				
			||||||
					return true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case *ast.BinaryExpr:
 | 
					 | 
				
			||||||
				if fun != "HasSuffix" {
 | 
					 | 
				
			||||||
					return true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if index.Op != token.SUB {
 | 
					 | 
				
			||||||
					return true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if !isLenOnIdent(index.X, condCall.Args[0]) ||
 | 
					 | 
				
			||||||
					!isLenOnIdent(index.Y, condCall.Args[1]) {
 | 
					 | 
				
			||||||
					return true
 | 
										return true
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
 | 
									if !sameNonDynamic(id3, oid3) {
 | 
				
			||||||
 | 
										return true
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case *ast.BasicLit, *ast.Ident:
 | 
				
			||||||
 | 
								if fun != "HasPrefix" {
 | 
				
			||||||
				return true
 | 
									return true
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if pkg != "strings" {
 | 
				
			||||||
			var replacement string
 | 
									return true
 | 
				
			||||||
			switch fun {
 | 
								}
 | 
				
			||||||
			case "HasPrefix":
 | 
								string, ok1 := ExprToString(j, condCall.Args[1])
 | 
				
			||||||
				replacement = "TrimPrefix"
 | 
								int, ok2 := ExprToInt(j, slice.Low)
 | 
				
			||||||
			case "HasSuffix":
 | 
								if !ok1 || !ok2 || int != int64(len(string)) {
 | 
				
			||||||
				replacement = "TrimSuffix"
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case *ast.BinaryExpr:
 | 
				
			||||||
 | 
								if fun != "HasSuffix" {
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if index.Op != token.SUB {
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if !isLenOnIdent(index.X, condCall.Args[0]) ||
 | 
				
			||||||
 | 
									!isLenOnIdent(index.Y, condCall.Args[1]) {
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			j.Errorf(ifstmt, "should replace this if statement with an unconditional %s.%s", pkg, replacement)
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var replacement string
 | 
				
			||||||
 | 
							switch fun {
 | 
				
			||||||
 | 
							case "HasPrefix":
 | 
				
			||||||
 | 
								replacement = "TrimPrefix"
 | 
				
			||||||
 | 
							case "HasSuffix":
 | 
				
			||||||
 | 
								replacement = "TrimSuffix"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							j.Errorf(ifstmt, "should replace this if statement with an unconditional %s.%s", pkg, replacement)
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
						for _, f := range j.Program.Files {
 | 
				
			||||||
		ast.Inspect(f, fn)
 | 
							ast.Inspect(f, fn)
 | 
				
			||||||
@ -1405,7 +1380,7 @@ func (c *Checker) LintAssertNotNil(j *lint.Job) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fn1 := func(node ast.Node) bool {
 | 
						fn := func(node ast.Node) bool {
 | 
				
			||||||
		ifstmt, ok := node.(*ast.IfStmt)
 | 
							ifstmt, ok := node.(*ast.IfStmt)
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
@ -1437,71 +1412,6 @@ func (c *Checker) LintAssertNotNil(j *lint.Job) {
 | 
				
			|||||||
		j.Errorf(ifstmt, "when %s is true, %s can't be nil", Render(j, assignIdent), Render(j, assertIdent))
 | 
							j.Errorf(ifstmt, "when %s is true, %s can't be nil", Render(j, assignIdent), Render(j, assertIdent))
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fn2 := func(node ast.Node) bool {
 | 
					 | 
				
			||||||
		// Check that outer ifstmt is an 'if x != nil {}'
 | 
					 | 
				
			||||||
		ifstmt, ok := node.(*ast.IfStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if ifstmt.Init != nil {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if ifstmt.Else != nil {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(ifstmt.Body.List) != 1 {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		binop, ok := ifstmt.Cond.(*ast.BinaryExpr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if binop.Op != token.NEQ {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		lhs, ok := binop.X.(*ast.Ident)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !IsNil(j, binop.Y) {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Check that inner ifstmt is an `if _, ok := x.(T); ok {}`
 | 
					 | 
				
			||||||
		ifstmt, ok = ifstmt.Body.List[0].(*ast.IfStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		assign, ok := ifstmt.Init.(*ast.AssignStmt)
 | 
					 | 
				
			||||||
		if !ok || len(assign.Lhs) != 2 || len(assign.Rhs) != 1 || !IsBlank(assign.Lhs[0]) {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		assert, ok := assign.Rhs[0].(*ast.TypeAssertExpr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		assertIdent, ok := assert.X.(*ast.Ident)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if lhs.Obj != assertIdent.Obj {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		assignIdent, ok := assign.Lhs[1].(*ast.Ident)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !isOKCheck(assignIdent, ifstmt.Cond) {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		j.Errorf(ifstmt, "when %s is true, %s can't be nil", Render(j, assignIdent), Render(j, assertIdent))
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fn := func(node ast.Node) bool {
 | 
					 | 
				
			||||||
		b1 := fn1(node)
 | 
					 | 
				
			||||||
		b2 := fn2(node)
 | 
					 | 
				
			||||||
		return b1 || b2
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
						for _, f := range j.Program.Files {
 | 
				
			||||||
		ast.Inspect(f, fn)
 | 
							ast.Inspect(f, fn)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -1822,143 +1732,3 @@ func (c *Checker) LintSortHelpers(j *lint.Job) {
 | 
				
			|||||||
		ast.Inspect(f, fnFuncs)
 | 
							ast.Inspect(f, fnFuncs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Checker) LintGuardedDelete(j *lint.Job) {
 | 
					 | 
				
			||||||
	isCommaOkMapIndex := func(stmt ast.Stmt) (b *ast.Ident, m ast.Expr, key ast.Expr, ok bool) {
 | 
					 | 
				
			||||||
		// Has to be of the form `_, <b:*ast.Ident> = <m:*types.Map>[<key>]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assign, ok := stmt.(*ast.AssignStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return nil, nil, nil, false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(assign.Lhs) != 2 || len(assign.Rhs) != 1 {
 | 
					 | 
				
			||||||
			return nil, nil, nil, false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !IsBlank(assign.Lhs[0]) {
 | 
					 | 
				
			||||||
			return nil, nil, nil, false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ident, ok := assign.Lhs[1].(*ast.Ident)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return nil, nil, nil, false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		index, ok := assign.Rhs[0].(*ast.IndexExpr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return nil, nil, nil, false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if _, ok := TypeOf(j, index.X).(*types.Map); !ok {
 | 
					 | 
				
			||||||
			return nil, nil, nil, false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		key = index.Index
 | 
					 | 
				
			||||||
		return ident, index.X, key, true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	fn := func(node ast.Node) bool {
 | 
					 | 
				
			||||||
		stmt, ok := node.(*ast.IfStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(stmt.Body.List) != 1 {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		expr, ok := stmt.Body.List[0].(*ast.ExprStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		call, ok := expr.X.(*ast.CallExpr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !IsCallToAST(j, call, "delete") {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		b, m, key, ok := isCommaOkMapIndex(stmt.Init)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if cond, ok := stmt.Cond.(*ast.Ident); !ok || ObjectOf(j, cond) != ObjectOf(j, b) {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if Render(j, call.Args[0]) != Render(j, m) || Render(j, call.Args[1]) != Render(j, key) {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		j.Errorf(stmt, "unnecessary guard around call to delete")
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
					 | 
				
			||||||
		ast.Inspect(f, fn)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Checker) LintSimplifyTypeSwitch(j *lint.Job) {
 | 
					 | 
				
			||||||
	fn := func(node ast.Node) bool {
 | 
					 | 
				
			||||||
		stmt, ok := node.(*ast.TypeSwitchStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if stmt.Init != nil {
 | 
					 | 
				
			||||||
			// bailing out for now, can't anticipate how type switches with initializers are being used
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		expr, ok := stmt.Assign.(*ast.ExprStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			// the user is in fact assigning the result
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		assert := expr.X.(*ast.TypeAssertExpr)
 | 
					 | 
				
			||||||
		ident, ok := assert.X.(*ast.Ident)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		x := ObjectOf(j, ident)
 | 
					 | 
				
			||||||
		var allOffenders []ast.Node
 | 
					 | 
				
			||||||
		for _, clause := range stmt.Body.List {
 | 
					 | 
				
			||||||
			clause := clause.(*ast.CaseClause)
 | 
					 | 
				
			||||||
			if len(clause.List) != 1 {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			hasUnrelatedAssertion := false
 | 
					 | 
				
			||||||
			var offenders []ast.Node
 | 
					 | 
				
			||||||
			ast.Inspect(clause, func(node ast.Node) bool {
 | 
					 | 
				
			||||||
				assert2, ok := node.(*ast.TypeAssertExpr)
 | 
					 | 
				
			||||||
				if !ok {
 | 
					 | 
				
			||||||
					return true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				ident, ok := assert2.X.(*ast.Ident)
 | 
					 | 
				
			||||||
				if !ok {
 | 
					 | 
				
			||||||
					hasUnrelatedAssertion = true
 | 
					 | 
				
			||||||
					return false
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if ObjectOf(j, ident) != x {
 | 
					 | 
				
			||||||
					hasUnrelatedAssertion = true
 | 
					 | 
				
			||||||
					return false
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if !types.Identical(TypeOf(j, clause.List[0]), TypeOf(j, assert2.Type)) {
 | 
					 | 
				
			||||||
					hasUnrelatedAssertion = true
 | 
					 | 
				
			||||||
					return false
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				offenders = append(offenders, assert2)
 | 
					 | 
				
			||||||
				return true
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
			if !hasUnrelatedAssertion {
 | 
					 | 
				
			||||||
				// don't flag cases that have other type assertions
 | 
					 | 
				
			||||||
				// unrelated to the one in the case clause. often
 | 
					 | 
				
			||||||
				// times, this is done for symmetry, when two
 | 
					 | 
				
			||||||
				// different values have to be asserted to the same
 | 
					 | 
				
			||||||
				// type.
 | 
					 | 
				
			||||||
				allOffenders = append(allOffenders, offenders...)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(allOffenders) != 0 {
 | 
					 | 
				
			||||||
			at := ""
 | 
					 | 
				
			||||||
			for _, offender := range allOffenders {
 | 
					 | 
				
			||||||
				pos := j.Program.DisplayPosition(offender.Pos())
 | 
					 | 
				
			||||||
				at += "\n\t" + pos.String()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			j.Errorf(expr, "assigning the result of this type assertion to a variable (switch %s := %s.(type)) could eliminate the following type assertions:%s", Render(j, ident), Render(j, ident), at)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
					 | 
				
			||||||
		ast.Inspect(f, fn)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										236
									
								
								vendor/github.com/golangci/go-tools/staticcheck/lint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										236
									
								
								vendor/github.com/golangci/go-tools/staticcheck/lint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -257,7 +257,7 @@ func (c *Checker) Checks() []lint.Check {
 | 
				
			|||||||
		{ID: "SA4000", FilterGenerated: false, Fn: c.CheckLhsRhsIdentical},
 | 
							{ID: "SA4000", FilterGenerated: false, Fn: c.CheckLhsRhsIdentical},
 | 
				
			||||||
		{ID: "SA4001", FilterGenerated: false, Fn: c.CheckIneffectiveCopy},
 | 
							{ID: "SA4001", FilterGenerated: false, Fn: c.CheckIneffectiveCopy},
 | 
				
			||||||
		{ID: "SA4002", FilterGenerated: false, Fn: c.CheckDiffSizeComparison},
 | 
							{ID: "SA4002", FilterGenerated: false, Fn: c.CheckDiffSizeComparison},
 | 
				
			||||||
		{ID: "SA4003", FilterGenerated: false, Fn: c.CheckExtremeComparison},
 | 
							{ID: "SA4003", FilterGenerated: false, Fn: c.CheckUnsignedComparison},
 | 
				
			||||||
		{ID: "SA4004", FilterGenerated: false, Fn: c.CheckIneffectiveLoop},
 | 
							{ID: "SA4004", FilterGenerated: false, Fn: c.CheckIneffectiveLoop},
 | 
				
			||||||
		{ID: "SA4006", FilterGenerated: false, Fn: c.CheckUnreadVariableValues},
 | 
							{ID: "SA4006", FilterGenerated: false, Fn: c.CheckUnreadVariableValues},
 | 
				
			||||||
		{ID: "SA4008", FilterGenerated: false, Fn: c.CheckLoopCondition},
 | 
							{ID: "SA4008", FilterGenerated: false, Fn: c.CheckLoopCondition},
 | 
				
			||||||
@ -272,7 +272,6 @@ func (c *Checker) Checks() []lint.Check {
 | 
				
			|||||||
		{ID: "SA4017", FilterGenerated: false, Fn: c.CheckPureFunctions},
 | 
							{ID: "SA4017", FilterGenerated: false, Fn: c.CheckPureFunctions},
 | 
				
			||||||
		{ID: "SA4018", FilterGenerated: true, Fn: c.CheckSelfAssignment},
 | 
							{ID: "SA4018", FilterGenerated: true, Fn: c.CheckSelfAssignment},
 | 
				
			||||||
		{ID: "SA4019", FilterGenerated: true, Fn: c.CheckDuplicateBuildConstraints},
 | 
							{ID: "SA4019", FilterGenerated: true, Fn: c.CheckDuplicateBuildConstraints},
 | 
				
			||||||
		{ID: "SA4020", FilterGenerated: false, Fn: c.CheckUnreachableTypeCases},
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{ID: "SA5000", FilterGenerated: false, Fn: c.CheckNilMaps},
 | 
							{ID: "SA5000", FilterGenerated: false, Fn: c.CheckNilMaps},
 | 
				
			||||||
		{ID: "SA5001", FilterGenerated: false, Fn: c.CheckEarlyDefer},
 | 
							{ID: "SA5001", FilterGenerated: false, Fn: c.CheckEarlyDefer},
 | 
				
			||||||
@ -287,7 +286,6 @@ func (c *Checker) Checks() []lint.Check {
 | 
				
			|||||||
		{ID: "SA6002", FilterGenerated: false, Fn: c.callChecker(checkSyncPoolValueRules)},
 | 
							{ID: "SA6002", FilterGenerated: false, Fn: c.callChecker(checkSyncPoolValueRules)},
 | 
				
			||||||
		{ID: "SA6003", FilterGenerated: false, Fn: c.CheckRangeStringRunes},
 | 
							{ID: "SA6003", FilterGenerated: false, Fn: c.CheckRangeStringRunes},
 | 
				
			||||||
		// {ID: "SA6004", FilterGenerated: false, Fn: c.CheckSillyRegexp},
 | 
							// {ID: "SA6004", FilterGenerated: false, Fn: c.CheckSillyRegexp},
 | 
				
			||||||
		{ID: "SA6005", FilterGenerated: false, Fn: c.CheckToLowerToUpperComparison},
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{ID: "SA9001", FilterGenerated: false, Fn: c.CheckDubiousDeferInChannelRangeLoop},
 | 
							{ID: "SA9001", FilterGenerated: false, Fn: c.CheckDubiousDeferInChannelRangeLoop},
 | 
				
			||||||
		{ID: "SA9002", FilterGenerated: false, Fn: c.CheckNonOctalFileMode},
 | 
							{ID: "SA9002", FilterGenerated: false, Fn: c.CheckNonOctalFileMode},
 | 
				
			||||||
@ -654,21 +652,14 @@ func (c *Checker) CheckInfiniteEmptyLoop(j *lint.Job) {
 | 
				
			|||||||
		// is dynamic and the loop might terminate. Similarly for
 | 
							// is dynamic and the loop might terminate. Similarly for
 | 
				
			||||||
		// channel receives.
 | 
							// channel receives.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if loop.Cond != nil && hasSideEffects(loop.Cond) {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							j.Errorf(loop, "this loop will spin, using 100%% CPU")
 | 
				
			||||||
		if loop.Cond != nil {
 | 
							if loop.Cond != nil {
 | 
				
			||||||
			if hasSideEffects(loop.Cond) {
 | 
					 | 
				
			||||||
				return true
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if ident, ok := loop.Cond.(*ast.Ident); ok {
 | 
					 | 
				
			||||||
				if k, ok := ObjectOf(j, ident).(*types.Const); ok {
 | 
					 | 
				
			||||||
					if !constant.BoolVal(k.Val()) {
 | 
					 | 
				
			||||||
						// don't flag `for false {}` loops. They're a debug aid.
 | 
					 | 
				
			||||||
						return true
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			j.Errorf(loop, "loop condition never changes or has a race condition")
 | 
								j.Errorf(loop, "loop condition never changes or has a race condition")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		j.Errorf(loop, "this loop will spin, using 100%% CPU")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -872,7 +863,7 @@ func (c *Checker) CheckLhsRhsIdentical(j *lint.Job) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		switch op.Op {
 | 
							switch op.Op {
 | 
				
			||||||
		case token.EQL, token.NEQ:
 | 
							case token.EQL, token.NEQ:
 | 
				
			||||||
			if basic, ok := TypeOf(j, op.X).Underlying().(*types.Basic); ok {
 | 
								if basic, ok := TypeOf(j, op.X).(*types.Basic); ok {
 | 
				
			||||||
				if kind := basic.Kind(); kind == types.Float32 || kind == types.Float64 {
 | 
									if kind := basic.Kind(); kind == types.Float32 || kind == types.Float64 {
 | 
				
			||||||
					// f == f and f != f might be used to check for NaN
 | 
										// f == f and f != f might be used to check for NaN
 | 
				
			||||||
					return true
 | 
										return true
 | 
				
			||||||
@ -964,24 +955,19 @@ func (c *Checker) CheckUnsafePrintf(j *lint.Job) {
 | 
				
			|||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		var arg int
 | 
							if !IsCallToAnyAST(j, call, "fmt.Printf", "fmt.Sprintf", "log.Printf") {
 | 
				
			||||||
		if IsCallToAnyAST(j, call, "fmt.Printf", "fmt.Sprintf", "log.Printf") {
 | 
					 | 
				
			||||||
			arg = Arg("fmt.Printf.format")
 | 
					 | 
				
			||||||
		} else if IsCallToAnyAST(j, call, "fmt.Fprintf") {
 | 
					 | 
				
			||||||
			arg = Arg("fmt.Fprintf.format")
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(call.Args) != arg+1 {
 | 
							if len(call.Args) != 1 {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		switch call.Args[arg].(type) {
 | 
							switch call.Args[Arg("fmt.Printf.format")].(type) {
 | 
				
			||||||
		case *ast.CallExpr, *ast.Ident:
 | 
							case *ast.CallExpr, *ast.Ident:
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		j.Errorf(call.Args[arg],
 | 
							j.Errorf(call.Args[Arg("fmt.Printf.format")],
 | 
				
			||||||
			"printf-style function with dynamic format string and no further arguments should use print-style function instead")
 | 
								"printf-style function with dynamic first argument and no further arguments should use print-style function instead")
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
						for _, f := range j.Program.Files {
 | 
				
			||||||
@ -1396,15 +1382,7 @@ func (c *Checker) CheckNilMaps(j *lint.Job) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Checker) CheckExtremeComparison(j *lint.Job) {
 | 
					func (c *Checker) CheckUnsignedComparison(j *lint.Job) {
 | 
				
			||||||
	isobj := func(expr ast.Expr, name string) bool {
 | 
					 | 
				
			||||||
		sel, ok := expr.(*ast.SelectorExpr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return IsObject(ObjectOf(j, sel.Sel), name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fn := func(node ast.Node) bool {
 | 
						fn := func(node ast.Node) bool {
 | 
				
			||||||
		expr, ok := node.(*ast.BinaryExpr)
 | 
							expr, ok := node.(*ast.BinaryExpr)
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
@ -1415,68 +1393,19 @@ func (c *Checker) CheckExtremeComparison(j *lint.Job) {
 | 
				
			|||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (basic.Info() & types.IsUnsigned) == 0 {
 | 
				
			||||||
		var max string
 | 
								return true
 | 
				
			||||||
		var min string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch basic.Kind() {
 | 
					 | 
				
			||||||
		case types.Uint8:
 | 
					 | 
				
			||||||
			max = "math.MaxUint8"
 | 
					 | 
				
			||||||
		case types.Uint16:
 | 
					 | 
				
			||||||
			max = "math.MaxUint16"
 | 
					 | 
				
			||||||
		case types.Uint32:
 | 
					 | 
				
			||||||
			max = "math.MaxUint32"
 | 
					 | 
				
			||||||
		case types.Uint64:
 | 
					 | 
				
			||||||
			max = "math.MaxUint64"
 | 
					 | 
				
			||||||
		case types.Uint:
 | 
					 | 
				
			||||||
			max = "math.MaxUint64"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case types.Int8:
 | 
					 | 
				
			||||||
			min = "math.MinInt8"
 | 
					 | 
				
			||||||
			max = "math.MaxInt8"
 | 
					 | 
				
			||||||
		case types.Int16:
 | 
					 | 
				
			||||||
			min = "math.MinInt16"
 | 
					 | 
				
			||||||
			max = "math.MaxInt16"
 | 
					 | 
				
			||||||
		case types.Int32:
 | 
					 | 
				
			||||||
			min = "math.MinInt32"
 | 
					 | 
				
			||||||
			max = "math.MaxInt32"
 | 
					 | 
				
			||||||
		case types.Int64:
 | 
					 | 
				
			||||||
			min = "math.MinInt64"
 | 
					 | 
				
			||||||
			max = "math.MaxInt64"
 | 
					 | 
				
			||||||
		case types.Int:
 | 
					 | 
				
			||||||
			min = "math.MinInt64"
 | 
					 | 
				
			||||||
			max = "math.MaxInt64"
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							lit, ok := expr.Y.(*ast.BasicLit)
 | 
				
			||||||
		if (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.Y, max) ||
 | 
							if !ok || lit.Value != "0" {
 | 
				
			||||||
			(expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.X, max) {
 | 
								return true
 | 
				
			||||||
			j.Errorf(expr, "no value of type %s is greater than %s", basic, max)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if expr.Op == token.LEQ && isobj(expr.Y, max) ||
 | 
							switch expr.Op {
 | 
				
			||||||
			expr.Op == token.GEQ && isobj(expr.X, max) {
 | 
							case token.GEQ:
 | 
				
			||||||
			j.Errorf(expr, "every value of type %s is <= %s", basic, max)
 | 
								j.Errorf(expr, "unsigned values are always >= 0")
 | 
				
			||||||
 | 
							case token.LSS:
 | 
				
			||||||
 | 
								j.Errorf(expr, "unsigned values are never < 0")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (basic.Info() & types.IsUnsigned) != 0 {
 | 
					 | 
				
			||||||
			if (expr.Op == token.LSS || expr.Op == token.LEQ) && IsIntLiteral(expr.Y, "0") ||
 | 
					 | 
				
			||||||
				(expr.Op == token.GTR || expr.Op == token.GEQ) && IsIntLiteral(expr.X, "0") {
 | 
					 | 
				
			||||||
				j.Errorf(expr, "no value of type %s is less than 0", basic)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if expr.Op == token.GEQ && IsIntLiteral(expr.Y, "0") ||
 | 
					 | 
				
			||||||
				expr.Op == token.LEQ && IsIntLiteral(expr.X, "0") {
 | 
					 | 
				
			||||||
				j.Errorf(expr, "every value of type %s is >= 0", basic)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if (expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.Y, min) ||
 | 
					 | 
				
			||||||
				(expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.X, min) {
 | 
					 | 
				
			||||||
				j.Errorf(expr, "no value of type %s is less than %s", basic, min)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if expr.Op == token.GEQ && isobj(expr.Y, min) ||
 | 
					 | 
				
			||||||
				expr.Op == token.LEQ && isobj(expr.X, min) {
 | 
					 | 
				
			||||||
				j.Errorf(expr, "every value of type %s is >= %s", basic, min)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
						for _, f := range j.Program.Files {
 | 
				
			||||||
@ -2887,122 +2816,3 @@ func (c *Checker) CheckTimerResetReturnValue(j *lint.Job) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Checker) CheckToLowerToUpperComparison(j *lint.Job) {
 | 
					 | 
				
			||||||
	fn := func(node ast.Node) bool {
 | 
					 | 
				
			||||||
		binExpr, ok := node.(*ast.BinaryExpr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var negative bool
 | 
					 | 
				
			||||||
		switch binExpr.Op {
 | 
					 | 
				
			||||||
		case token.EQL:
 | 
					 | 
				
			||||||
			negative = false
 | 
					 | 
				
			||||||
		case token.NEQ:
 | 
					 | 
				
			||||||
			negative = true
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const (
 | 
					 | 
				
			||||||
			lo = "strings.ToLower"
 | 
					 | 
				
			||||||
			up = "strings.ToUpper"
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var call string
 | 
					 | 
				
			||||||
		if IsCallToAST(j, binExpr.X, lo) && IsCallToAST(j, binExpr.Y, lo) {
 | 
					 | 
				
			||||||
			call = lo
 | 
					 | 
				
			||||||
		} else if IsCallToAST(j, binExpr.X, up) && IsCallToAST(j, binExpr.Y, up) {
 | 
					 | 
				
			||||||
			call = up
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bang := ""
 | 
					 | 
				
			||||||
		if negative {
 | 
					 | 
				
			||||||
			bang = "!"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		j.Errorf(binExpr, "should use %sstrings.EqualFold(a, b) instead of %s(a) %s %s(b)", bang, call, binExpr.Op, call)
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
					 | 
				
			||||||
		ast.Inspect(f, fn)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Checker) CheckUnreachableTypeCases(j *lint.Job) {
 | 
					 | 
				
			||||||
	// Check if T subsumes V in a type switch. T subsumes V if T is an interface and T's method set is a subset of V's method set.
 | 
					 | 
				
			||||||
	subsumes := func(T, V types.Type) bool {
 | 
					 | 
				
			||||||
		tIface, ok := T.Underlying().(*types.Interface)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return false
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return types.Implements(V, tIface)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	subsumesAny := func(Ts, Vs []types.Type) (types.Type, types.Type, bool) {
 | 
					 | 
				
			||||||
		for _, T := range Ts {
 | 
					 | 
				
			||||||
			for _, V := range Vs {
 | 
					 | 
				
			||||||
				if subsumes(T, V) {
 | 
					 | 
				
			||||||
					return T, V, true
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return nil, nil, false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fn := func(node ast.Node) bool {
 | 
					 | 
				
			||||||
		tsStmt, ok := node.(*ast.TypeSwitchStmt)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		type ccAndTypes struct {
 | 
					 | 
				
			||||||
			cc    *ast.CaseClause
 | 
					 | 
				
			||||||
			types []types.Type
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// All asserted types in the order of case clauses.
 | 
					 | 
				
			||||||
		ccs := make([]ccAndTypes, 0, len(tsStmt.Body.List))
 | 
					 | 
				
			||||||
		for _, stmt := range tsStmt.Body.List {
 | 
					 | 
				
			||||||
			cc, _ := stmt.(*ast.CaseClause)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Exclude the 'default' case.
 | 
					 | 
				
			||||||
			if len(cc.List) == 0 {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			Ts := make([]types.Type, len(cc.List))
 | 
					 | 
				
			||||||
			for i, expr := range cc.List {
 | 
					 | 
				
			||||||
				Ts[i] = TypeOf(j, expr)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			ccs = append(ccs, ccAndTypes{cc: cc, types: Ts})
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if len(ccs) <= 1 {
 | 
					 | 
				
			||||||
			// Zero or one case clauses, nothing to check.
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Check if case clauses following cc have types that are subsumed by cc.
 | 
					 | 
				
			||||||
		for i, cc := range ccs[:len(ccs)-1] {
 | 
					 | 
				
			||||||
			for _, next := range ccs[i+1:] {
 | 
					 | 
				
			||||||
				if T, V, yes := subsumesAny(cc.types, next.types); yes {
 | 
					 | 
				
			||||||
					j.Errorf(next.cc, "unreachable case clause: %s will always match before %s", T.String(), V.String())
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
					 | 
				
			||||||
		ast.Inspect(f, fn)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										25
									
								
								vendor/github.com/golangci/go-tools/stylecheck/lint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/golangci/go-tools/stylecheck/lint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -48,7 +48,6 @@ func (c *Checker) Checks() []lint.Check {
 | 
				
			|||||||
		{ID: "ST1013", FilterGenerated: true, Fn: c.CheckHTTPStatusCodes},
 | 
							{ID: "ST1013", FilterGenerated: true, Fn: c.CheckHTTPStatusCodes},
 | 
				
			||||||
		{ID: "ST1015", FilterGenerated: true, Fn: c.CheckDefaultCaseOrder},
 | 
							{ID: "ST1015", FilterGenerated: true, Fn: c.CheckDefaultCaseOrder},
 | 
				
			||||||
		{ID: "ST1016", FilterGenerated: false, Fn: c.CheckReceiverNamesIdentical},
 | 
							{ID: "ST1016", FilterGenerated: false, Fn: c.CheckReceiverNamesIdentical},
 | 
				
			||||||
		{ID: "ST1017", FilterGenerated: true, Fn: c.CheckYodaConditions},
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -624,27 +623,3 @@ func (c *Checker) CheckDefaultCaseOrder(j *lint.Job) {
 | 
				
			|||||||
		ast.Inspect(f, fn)
 | 
							ast.Inspect(f, fn)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Checker) CheckYodaConditions(j *lint.Job) {
 | 
					 | 
				
			||||||
	fn := func(node ast.Node) bool {
 | 
					 | 
				
			||||||
		cond, ok := node.(*ast.BinaryExpr)
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if cond.Op != token.EQL && cond.Op != token.NEQ {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if _, ok := cond.X.(*ast.BasicLit); !ok {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if _, ok := cond.Y.(*ast.BasicLit); ok {
 | 
					 | 
				
			||||||
			// Don't flag lit == lit conditions, just in case
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		j.Errorf(cond, "don't use Yoda conditions")
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, f := range j.Program.Files {
 | 
					 | 
				
			||||||
		ast.Inspect(f, fn)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										79
									
								
								vendor/github.com/golangci/go-tools/unused/implements.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/golangci/go-tools/unused/implements.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					package unused
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "go/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
 | 
				
			||||||
 | 
					func lookupMethod(T *types.Interface, pkg *types.Package, name string) (int, *types.Func) {
 | 
				
			||||||
 | 
						if name != "_" {
 | 
				
			||||||
 | 
							for i := 0; i < T.NumMethods(); i++ {
 | 
				
			||||||
 | 
								m := T.Method(i)
 | 
				
			||||||
 | 
								if sameId(m, pkg, name) {
 | 
				
			||||||
 | 
									return i, m
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return -1, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func sameId(obj types.Object, pkg *types.Package, name string) bool {
 | 
				
			||||||
 | 
						// spec:
 | 
				
			||||||
 | 
						// "Two identifiers are different if they are spelled differently,
 | 
				
			||||||
 | 
						// or if they appear in different packages and are not exported.
 | 
				
			||||||
 | 
						// Otherwise, they are the same."
 | 
				
			||||||
 | 
						if name != obj.Name() {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// obj.Name == name
 | 
				
			||||||
 | 
						if obj.Exported() {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// not exported, so packages must be the same (pkg == nil for
 | 
				
			||||||
 | 
						// fields in Universe scope; this can only happen for types
 | 
				
			||||||
 | 
						// introduced via Eval)
 | 
				
			||||||
 | 
						if pkg == nil || obj.Pkg() == nil {
 | 
				
			||||||
 | 
							return pkg == obj.Pkg()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// pkg != nil && obj.pkg != nil
 | 
				
			||||||
 | 
						return pkg.Path() == obj.Pkg().Path()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Checker) implements(V types.Type, T *types.Interface) bool {
 | 
				
			||||||
 | 
						// fast path for common case
 | 
				
			||||||
 | 
						if T.Empty() {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ityp, _ := V.Underlying().(*types.Interface); ityp != nil {
 | 
				
			||||||
 | 
							for i := 0; i < T.NumMethods(); i++ {
 | 
				
			||||||
 | 
								m := T.Method(i)
 | 
				
			||||||
 | 
								_, obj := lookupMethod(ityp, m.Pkg(), m.Name())
 | 
				
			||||||
 | 
								switch {
 | 
				
			||||||
 | 
								case obj == nil:
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								case !types.Identical(obj.Type(), m.Type()):
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A concrete type implements T if it implements all methods of T.
 | 
				
			||||||
 | 
						ms := c.msCache.MethodSet(V)
 | 
				
			||||||
 | 
						for i := 0; i < T.NumMethods(); i++ {
 | 
				
			||||||
 | 
							m := T.Method(i)
 | 
				
			||||||
 | 
							sel := ms.Lookup(m.Pkg(), m.Name())
 | 
				
			||||||
 | 
							if sel == nil {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							f, _ := sel.Obj().(*types.Func)
 | 
				
			||||||
 | 
							if f == nil {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if !types.Identical(f.Type(), m.Type()) {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								vendor/github.com/golangci/go-tools/unused/unused.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/golangci/go-tools/unused/unused.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -265,6 +265,7 @@ func (c *Checker) Check(prog *lint.Program) []Unused {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		unused = append(unused, Unused{Obj: obj, Position: pos})
 | 
							unused = append(unused, Unused{Obj: obj, Position: pos})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return unused
 | 
						return unused
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -552,10 +553,22 @@ func (c *Checker) processTypes(pkg *lint.Pkg) {
 | 
				
			|||||||
		for i := 0; i < iface.NumEmbeddeds(); i++ {
 | 
							for i := 0; i < iface.NumEmbeddeds(); i++ {
 | 
				
			||||||
			c.graph.markUsedBy(iface.Embedded(i), iface)
 | 
								c.graph.markUsedBy(iface.Embedded(i), iface)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						namedLoop:
 | 
				
			||||||
		for obj, objPtr := range named {
 | 
							for obj, objPtr := range named {
 | 
				
			||||||
			if !types.Implements(obj, iface) && !types.Implements(objPtr, iface) {
 | 
								switch obj.Underlying().(type) {
 | 
				
			||||||
				continue
 | 
								case *types.Interface:
 | 
				
			||||||
 | 
									// pointers to interfaces have no methods, only checking non-pointer
 | 
				
			||||||
 | 
									if !c.implements(obj, iface) {
 | 
				
			||||||
 | 
										continue namedLoop
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									// pointer receivers include the method set of non-pointer receivers,
 | 
				
			||||||
 | 
									// only checking pointer
 | 
				
			||||||
 | 
									if !c.implements(objPtr, iface) {
 | 
				
			||||||
 | 
										continue namedLoop
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ifaceMethods := make(map[string]struct{}, iface.NumMethods())
 | 
								ifaceMethods := make(map[string]struct{}, iface.NumMethods())
 | 
				
			||||||
			n := iface.NumMethods()
 | 
								n := iface.NumMethods()
 | 
				
			||||||
			for i := 0; i < n; i++ {
 | 
								for i := 0; i < n; i++ {
 | 
				
			||||||
@ -594,15 +607,15 @@ func (c *Checker) processTypes(pkg *lint.Pkg) {
 | 
				
			|||||||
func (c *Checker) processSelections(pkg *lint.Pkg) {
 | 
					func (c *Checker) processSelections(pkg *lint.Pkg) {
 | 
				
			||||||
	fn := func(expr *ast.SelectorExpr, sel *types.Selection, offset int) {
 | 
						fn := func(expr *ast.SelectorExpr, sel *types.Selection, offset int) {
 | 
				
			||||||
		scope := pkg.Types.Scope().Innermost(expr.Pos())
 | 
							scope := pkg.Types.Scope().Innermost(expr.Pos())
 | 
				
			||||||
		c.graph.markUsedBy(expr.X, c.topmostScope(scope, pkg.Types))
 | 
							c.graph.markUsedBy(sel, c.topmostScope(scope, pkg.Types))
 | 
				
			||||||
		c.graph.markUsedBy(sel.Obj(), expr.X)
 | 
							c.graph.markUsedBy(sel.Obj(), sel)
 | 
				
			||||||
		if len(sel.Index()) > 1 {
 | 
							if len(sel.Index()) > 1 {
 | 
				
			||||||
			typ := sel.Recv()
 | 
								typ := sel.Recv()
 | 
				
			||||||
			indices := sel.Index()
 | 
								indices := sel.Index()
 | 
				
			||||||
			for _, idx := range indices[:len(indices)-offset] {
 | 
								for _, idx := range indices[:len(indices)-offset] {
 | 
				
			||||||
				obj := getField(typ, idx)
 | 
									obj := getField(typ, idx)
 | 
				
			||||||
				typ = obj.Type()
 | 
									typ = obj.Type()
 | 
				
			||||||
				c.graph.markUsedBy(obj, expr.X)
 | 
									c.graph.markUsedBy(obj, sel)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/golangci/go-tools/version/version.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/golangci/go-tools/version/version.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -6,7 +6,7 @@ import (
 | 
				
			|||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Version = "devel"
 | 
					const Version = "2019.1.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Print() {
 | 
					func Print() {
 | 
				
			||||||
	if Version == "devel" {
 | 
						if Version == "devel" {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@ -61,7 +61,7 @@ github.com/golangci/errcheck/golangci
 | 
				
			|||||||
github.com/golangci/errcheck/internal/errcheck
 | 
					github.com/golangci/errcheck/internal/errcheck
 | 
				
			||||||
# github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613
 | 
					# github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613
 | 
				
			||||||
github.com/golangci/go-misc/deadcode
 | 
					github.com/golangci/go-misc/deadcode
 | 
				
			||||||
# github.com/golangci/go-tools v0.0.0-20180109140146-35a9f45a5db0
 | 
					# github.com/golangci/go-tools v0.0.0-20180109140146-af6baa5dc196
 | 
				
			||||||
github.com/golangci/go-tools/config
 | 
					github.com/golangci/go-tools/config
 | 
				
			||||||
github.com/golangci/go-tools/lint
 | 
					github.com/golangci/go-tools/lint
 | 
				
			||||||
github.com/golangci/go-tools/lint/lintutil
 | 
					github.com/golangci/go-tools/lint/lintutil
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user