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/errcheck v0.0.0-20181003203344-ef45e06d44b6
 | 
			
		||||
	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/gocyclo v0.0.0-20180528134321-2becd97e67ee
 | 
			
		||||
	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/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-tools v0.0.0-20180109140146-35a9f45a5db0 h1:tYc7NX0EeSyW9wFF0EXPB57lAiKRPwKZxVkaTsGuB9k=
 | 
			
		||||
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 h1:9rtVlONXLF1rJZzvLt4tfOXtnAFUEhxCJ64Ibzj6ECo=
 | 
			
		||||
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/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
 | 
			
		||||
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
 | 
			
		||||
package testdata
 | 
			
		||||
 | 
			
		||||
import "strings"
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Gosimple(id1, s1 string) string {
 | 
			
		||||
	if strings.HasPrefix(id1, s1) { // ERROR "should replace.*with.*strings.TrimPrefix"
 | 
			
		||||
		id1 = strings.TrimPrefix(id1, s1)
 | 
			
		||||
func Gosimple(ss []string) {
 | 
			
		||||
	if ss != nil { // ERROR "S1031: unnecessary nil check around range"
 | 
			
		||||
		for _, s := range ss {
 | 
			
		||||
			log.Printf(s)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return id1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GosimpleNolintGosimple(id1, s1 string) string {
 | 
			
		||||
	if strings.HasPrefix(id1, s1) { //nolint:gosimple
 | 
			
		||||
		id1 = strings.TrimPrefix(id1, s1)
 | 
			
		||||
func GosimpleNolintGosimple(ss []string) {
 | 
			
		||||
	if ss != nil { //nolint:gosimple
 | 
			
		||||
		for _, s := range ss {
 | 
			
		||||
			log.Printf(s)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return id1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GosimpleNolintMegacheck(id1, s1 string) string {
 | 
			
		||||
	if strings.HasPrefix(id1, s1) { //nolint:megacheck
 | 
			
		||||
		id1 = strings.TrimPrefix(id1, s1)
 | 
			
		||||
func GosimpleNolintMegacheck(ss []string) {
 | 
			
		||||
	if ss != nil { //nolint:megacheck
 | 
			
		||||
		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
 | 
			
		||||
 | 
			
		||||
func Stylecheck(x int) {
 | 
			
		||||
	if 0 == x { // ERROR "don't use Yoda conditions"
 | 
			
		||||
		panic(x)
 | 
			
		||||
	switch 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) {
 | 
			
		||||
	if 0 == x { //nolint:stylecheck
 | 
			
		||||
		panic(x)
 | 
			
		||||
	switch x {
 | 
			
		||||
	case 1:
 | 
			
		||||
		return
 | 
			
		||||
	default: //nolint:stylecheck
 | 
			
		||||
		return
 | 
			
		||||
	case 2:
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StylecheckNolintMegacheck(x int) {
 | 
			
		||||
	if 0 == x { //nolint:megacheck // ERROR "don't use Yoda conditions"
 | 
			
		||||
		panic(x)
 | 
			
		||||
	switch 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,
 | 
			
		||||
	"errors.New.text":                      0,
 | 
			
		||||
	"fmt.Printf.format":                    0,
 | 
			
		||||
	"fmt.Fprintf.format":                   1,
 | 
			
		||||
	"fmt.Sprintf.a[0]":                     1,
 | 
			
		||||
	"fmt.Sprintf.format":                   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 (
 | 
			
		||||
	// used by cgo before Go 1.11
 | 
			
		||||
	oldCgo = []byte("// Created by cgo - DO NOT EDIT")
 | 
			
		||||
	prefix = []byte("// Code generated ")
 | 
			
		||||
	suffix = []byte(" DO NOT EDIT.")
 | 
			
		||||
	nl     = []byte("\n")
 | 
			
		||||
@ -25,6 +27,9 @@ func isGenerated(r io.Reader) bool {
 | 
			
		||||
		if bytes.HasPrefix(s, prefix) && bytes.HasSuffix(s, suffix) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if bytes.Equal(s, oldCgo) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/golangci/go-tools/lint/lintdsl/lintdsl.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								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 {
 | 
			
		||||
	switch fun := call.Fun.(type) {
 | 
			
		||||
	case *ast.SelectorExpr:
 | 
			
		||||
		fn, ok := ObjectOf(j, fun.Sel).(*types.Func)
 | 
			
		||||
	sel, ok := call.Fun.(*ast.SelectorExpr)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	fn, ok := j.NodePackage(call).TypesInfo.ObjectOf(sel.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 ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var posRe = regexp.MustCompile(`^(.+?):(\d+):(\d+)?$`)
 | 
			
		||||
var posRe = regexp.MustCompile(`^(.+?):(\d+)(?::(\d+)?)?$`)
 | 
			
		||||
 | 
			
		||||
func parsePos(pos string) token.Position {
 | 
			
		||||
	if pos == "-" || pos == "" {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										260
									
								
								vendor/github.com/golangci/go-tools/simple/lint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										260
									
								
								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: "S1031", FilterGenerated: true, Fn: c.LintNilCheckAroundRange},
 | 
			
		||||
		{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 {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		switch {
 | 
			
		||||
		case IsCallToAST(j, condCall, "strings.HasPrefix"):
 | 
			
		||||
		call, ok := condCall.Fun.(*ast.SelectorExpr)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if IsIdent(call.X, "strings") {
 | 
			
		||||
			pkg = "strings"
 | 
			
		||||
		} else if IsIdent(call.X, "bytes") {
 | 
			
		||||
			pkg = "bytes"
 | 
			
		||||
		} else {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if IsIdent(call.Sel, "HasPrefix") {
 | 
			
		||||
			fun = "HasPrefix"
 | 
			
		||||
		case IsCallToAST(j, condCall, "strings.HasSuffix"):
 | 
			
		||||
			pkg = "strings"
 | 
			
		||||
		} else if IsIdent(call.Sel, "HasSuffix") {
 | 
			
		||||
			fun = "HasSuffix"
 | 
			
		||||
		case IsCallToAST(j, condCall, "strings.Contains"):
 | 
			
		||||
			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:
 | 
			
		||||
		} else {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -1123,23 +1117,7 @@ func (c *Checker) LintTrim(j *lint.Job) {
 | 
			
		||||
		if !sameNonDynamic(condCall.Args[0], assign.Lhs[0]) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch rhs := assign.Rhs[0].(type) {
 | 
			
		||||
		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
 | 
			
		||||
		case *ast.SliceExpr:
 | 
			
		||||
			slice := rhs
 | 
			
		||||
		slice, ok := assign.Rhs[0].(*ast.SliceExpr)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
@ -1235,9 +1213,6 @@ func (c *Checker) LintTrim(j *lint.Job) {
 | 
			
		||||
		}
 | 
			
		||||
		j.Errorf(ifstmt, "should replace this if statement with an unconditional %s.%s", pkg, replacement)
 | 
			
		||||
		return true
 | 
			
		||||
		default:
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, f := range j.Program.Files {
 | 
			
		||||
		ast.Inspect(f, fn)
 | 
			
		||||
@ -1405,7 +1380,7 @@ func (c *Checker) LintAssertNotNil(j *lint.Job) {
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	fn1 := func(node ast.Node) bool {
 | 
			
		||||
	fn := func(node ast.Node) bool {
 | 
			
		||||
		ifstmt, ok := node.(*ast.IfStmt)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			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))
 | 
			
		||||
		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 {
 | 
			
		||||
		ast.Inspect(f, fn)
 | 
			
		||||
	}
 | 
			
		||||
@ -1822,143 +1732,3 @@ func (c *Checker) LintSortHelpers(j *lint.Job) {
 | 
			
		||||
		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: "SA4001", FilterGenerated: false, Fn: c.CheckIneffectiveCopy},
 | 
			
		||||
		{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: "SA4006", FilterGenerated: false, Fn: c.CheckUnreadVariableValues},
 | 
			
		||||
		{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: "SA4018", FilterGenerated: true, Fn: c.CheckSelfAssignment},
 | 
			
		||||
		{ID: "SA4019", FilterGenerated: true, Fn: c.CheckDuplicateBuildConstraints},
 | 
			
		||||
		{ID: "SA4020", FilterGenerated: false, Fn: c.CheckUnreachableTypeCases},
 | 
			
		||||
 | 
			
		||||
		{ID: "SA5000", FilterGenerated: false, Fn: c.CheckNilMaps},
 | 
			
		||||
		{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: "SA6003", FilterGenerated: false, Fn: c.CheckRangeStringRunes},
 | 
			
		||||
		// {ID: "SA6004", FilterGenerated: false, Fn: c.CheckSillyRegexp},
 | 
			
		||||
		{ID: "SA6005", FilterGenerated: false, Fn: c.CheckToLowerToUpperComparison},
 | 
			
		||||
 | 
			
		||||
		{ID: "SA9001", FilterGenerated: false, Fn: c.CheckDubiousDeferInChannelRangeLoop},
 | 
			
		||||
		{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
 | 
			
		||||
		// 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 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, "this loop will spin, using 100%% CPU")
 | 
			
		||||
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
@ -872,7 +863,7 @@ func (c *Checker) CheckLhsRhsIdentical(j *lint.Job) {
 | 
			
		||||
		}
 | 
			
		||||
		switch op.Op {
 | 
			
		||||
		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 {
 | 
			
		||||
					// f == f and f != f might be used to check for NaN
 | 
			
		||||
					return true
 | 
			
		||||
@ -964,24 +955,19 @@ func (c *Checker) CheckUnsafePrintf(j *lint.Job) {
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		var arg int
 | 
			
		||||
		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 {
 | 
			
		||||
		if !IsCallToAnyAST(j, call, "fmt.Printf", "fmt.Sprintf", "log.Printf") {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if len(call.Args) != arg+1 {
 | 
			
		||||
		if len(call.Args) != 1 {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		switch call.Args[arg].(type) {
 | 
			
		||||
		switch call.Args[Arg("fmt.Printf.format")].(type) {
 | 
			
		||||
		case *ast.CallExpr, *ast.Ident:
 | 
			
		||||
		default:
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		j.Errorf(call.Args[arg],
 | 
			
		||||
			"printf-style function with dynamic format string and no further arguments should use print-style function instead")
 | 
			
		||||
		j.Errorf(call.Args[Arg("fmt.Printf.format")],
 | 
			
		||||
			"printf-style function with dynamic first argument and no further arguments should use print-style function instead")
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	for _, f := range j.Program.Files {
 | 
			
		||||
@ -1396,15 +1382,7 @@ func (c *Checker) CheckNilMaps(j *lint.Job) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Checker) CheckExtremeComparison(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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
func (c *Checker) CheckUnsignedComparison(j *lint.Job) {
 | 
			
		||||
	fn := func(node ast.Node) bool {
 | 
			
		||||
		expr, ok := node.(*ast.BinaryExpr)
 | 
			
		||||
		if !ok {
 | 
			
		||||
@ -1415,68 +1393,19 @@ func (c *Checker) CheckExtremeComparison(j *lint.Job) {
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var max string
 | 
			
		||||
		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"
 | 
			
		||||
		if (basic.Info() & types.IsUnsigned) == 0 {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.Y, max) ||
 | 
			
		||||
			(expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.X, max) {
 | 
			
		||||
			j.Errorf(expr, "no value of type %s is greater than %s", basic, max)
 | 
			
		||||
		lit, ok := expr.Y.(*ast.BasicLit)
 | 
			
		||||
		if !ok || lit.Value != "0" {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if expr.Op == token.LEQ && isobj(expr.Y, max) ||
 | 
			
		||||
			expr.Op == token.GEQ && isobj(expr.X, max) {
 | 
			
		||||
			j.Errorf(expr, "every value of type %s is <= %s", basic, max)
 | 
			
		||||
		switch expr.Op {
 | 
			
		||||
		case token.GEQ:
 | 
			
		||||
			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
 | 
			
		||||
	}
 | 
			
		||||
	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: "ST1015", FilterGenerated: true, Fn: c.CheckDefaultCaseOrder},
 | 
			
		||||
		{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)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return unused
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -552,10 +553,22 @@ func (c *Checker) processTypes(pkg *lint.Pkg) {
 | 
			
		||||
		for i := 0; i < iface.NumEmbeddeds(); i++ {
 | 
			
		||||
			c.graph.markUsedBy(iface.Embedded(i), iface)
 | 
			
		||||
		}
 | 
			
		||||
	namedLoop:
 | 
			
		||||
		for obj, objPtr := range named {
 | 
			
		||||
			if !types.Implements(obj, iface) && !types.Implements(objPtr, iface) {
 | 
			
		||||
				continue
 | 
			
		||||
			switch obj.Underlying().(type) {
 | 
			
		||||
			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())
 | 
			
		||||
			n := iface.NumMethods()
 | 
			
		||||
			for i := 0; i < n; i++ {
 | 
			
		||||
@ -594,15 +607,15 @@ func (c *Checker) processTypes(pkg *lint.Pkg) {
 | 
			
		||||
func (c *Checker) processSelections(pkg *lint.Pkg) {
 | 
			
		||||
	fn := func(expr *ast.SelectorExpr, sel *types.Selection, offset int) {
 | 
			
		||||
		scope := pkg.Types.Scope().Innermost(expr.Pos())
 | 
			
		||||
		c.graph.markUsedBy(expr.X, c.topmostScope(scope, pkg.Types))
 | 
			
		||||
		c.graph.markUsedBy(sel.Obj(), expr.X)
 | 
			
		||||
		c.graph.markUsedBy(sel, c.topmostScope(scope, pkg.Types))
 | 
			
		||||
		c.graph.markUsedBy(sel.Obj(), sel)
 | 
			
		||||
		if len(sel.Index()) > 1 {
 | 
			
		||||
			typ := sel.Recv()
 | 
			
		||||
			indices := sel.Index()
 | 
			
		||||
			for _, idx := range indices[:len(indices)-offset] {
 | 
			
		||||
				obj := getField(typ, idx)
 | 
			
		||||
				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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const Version = "devel"
 | 
			
		||||
const Version = "2019.1.1"
 | 
			
		||||
 | 
			
		||||
func Print() {
 | 
			
		||||
	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/go-misc v0.0.0-20180628070357-927a3d87b613
 | 
			
		||||
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/lint
 | 
			
		||||
github.com/golangci/go-tools/lint/lintutil
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user