github.com/wgliang/gometalinter@v2.0.6-0.20180523041418-a75adcf7cb0e+incompatible/_linters/src/honnef.co/go/tools/simple/lint.go (about)

     1  // Package simple contains a linter for Go source code.
     2  package simple // import "honnef.co/go/tools/simple"
     3  
     4  import (
     5  	"go/ast"
     6  	"go/constant"
     7  	"go/token"
     8  	"go/types"
     9  	"reflect"
    10  	"strings"
    11  
    12  	"honnef.co/go/tools/internal/sharedcheck"
    13  	"honnef.co/go/tools/lint"
    14  	"honnef.co/go/tools/ssa"
    15  
    16  	"golang.org/x/tools/go/types/typeutil"
    17  )
    18  
    19  type Checker struct {
    20  	CheckGenerated bool
    21  	MS             *typeutil.MethodSetCache
    22  
    23  	nodeFns map[ast.Node]*ssa.Function
    24  }
    25  
    26  func NewChecker() *Checker {
    27  	return &Checker{
    28  		MS: &typeutil.MethodSetCache{},
    29  	}
    30  }
    31  
    32  func (*Checker) Name() string   { return "gosimple" }
    33  func (*Checker) Prefix() string { return "S" }
    34  
    35  func (c *Checker) Init(prog *lint.Program) {
    36  	c.nodeFns = lint.NodeFns(prog.Packages)
    37  }
    38  
    39  func (c *Checker) Funcs() map[string]lint.Func {
    40  	return map[string]lint.Func{
    41  		"S1000": c.LintSingleCaseSelect,
    42  		"S1001": c.LintLoopCopy,
    43  		"S1002": c.LintIfBoolCmp,
    44  		"S1003": c.LintStringsContains,
    45  		"S1004": c.LintBytesCompare,
    46  		"S1005": c.LintUnnecessaryBlank,
    47  		"S1006": c.LintForTrue,
    48  		"S1007": c.LintRegexpRaw,
    49  		"S1008": c.LintIfReturn,
    50  		"S1009": c.LintRedundantNilCheckWithLen,
    51  		"S1010": c.LintSlicing,
    52  		"S1011": c.LintLoopAppend,
    53  		"S1012": c.LintTimeSince,
    54  		"S1013": c.LintSimplerReturn,
    55  		"S1014": nil,
    56  		"S1015": nil,
    57  		"S1016": c.LintSimplerStructConversion,
    58  		"S1017": c.LintTrim,
    59  		"S1018": c.LintLoopSlide,
    60  		"S1019": c.LintMakeLenCap,
    61  		"S1020": c.LintAssertNotNil,
    62  		"S1021": c.LintDeclareAssign,
    63  		"S1022": nil,
    64  		"S1023": c.LintRedundantBreak,
    65  		"S1024": c.LintTimeUntil,
    66  		"S1025": c.LintRedundantSprintf,
    67  		"S1026": nil,
    68  		"S1027": nil,
    69  		"S1028": c.LintErrorsNewSprintf,
    70  		"S1029": c.LintRangeStringRunes,
    71  		"S1030": c.LintBytesBufferConversions,
    72  		"S1031": c.LintNilCheckAroundRange,
    73  	}
    74  }
    75  
    76  func (c *Checker) filterGenerated(files []*ast.File) []*ast.File {
    77  	if c.CheckGenerated {
    78  		return files
    79  	}
    80  	var out []*ast.File
    81  	for _, f := range files {
    82  		if !lint.IsGenerated(f) {
    83  			out = append(out, f)
    84  		}
    85  	}
    86  	return out
    87  }
    88  
    89  func (c *Checker) LintSingleCaseSelect(j *lint.Job) {
    90  	isSingleSelect := func(node ast.Node) bool {
    91  		v, ok := node.(*ast.SelectStmt)
    92  		if !ok {
    93  			return false
    94  		}
    95  		return len(v.Body.List) == 1
    96  	}
    97  
    98  	seen := map[ast.Node]struct{}{}
    99  	fn := func(node ast.Node) bool {
   100  		switch v := node.(type) {
   101  		case *ast.ForStmt:
   102  			if len(v.Body.List) != 1 {
   103  				return true
   104  			}
   105  			if !isSingleSelect(v.Body.List[0]) {
   106  				return true
   107  			}
   108  			if _, ok := v.Body.List[0].(*ast.SelectStmt).Body.List[0].(*ast.CommClause).Comm.(*ast.SendStmt); ok {
   109  				// Don't suggest using range for channel sends
   110  				return true
   111  			}
   112  			seen[v.Body.List[0]] = struct{}{}
   113  			j.Errorf(node, "should use for range instead of for { select {} }")
   114  		case *ast.SelectStmt:
   115  			if _, ok := seen[v]; ok {
   116  				return true
   117  			}
   118  			if !isSingleSelect(v) {
   119  				return true
   120  			}
   121  			j.Errorf(node, "should use a simple channel send/receive instead of select with a single case")
   122  			return true
   123  		}
   124  		return true
   125  	}
   126  	for _, f := range c.filterGenerated(j.Program.Files) {
   127  		ast.Inspect(f, fn)
   128  	}
   129  }
   130  
   131  func (c *Checker) LintLoopCopy(j *lint.Job) {
   132  	fn := func(node ast.Node) bool {
   133  		loop, ok := node.(*ast.RangeStmt)
   134  		if !ok {
   135  			return true
   136  		}
   137  
   138  		if loop.Key == nil {
   139  			return true
   140  		}
   141  		if len(loop.Body.List) != 1 {
   142  			return true
   143  		}
   144  		stmt, ok := loop.Body.List[0].(*ast.AssignStmt)
   145  		if !ok {
   146  			return true
   147  		}
   148  		if stmt.Tok != token.ASSIGN || len(stmt.Lhs) != 1 || len(stmt.Rhs) != 1 {
   149  			return true
   150  		}
   151  		lhs, ok := stmt.Lhs[0].(*ast.IndexExpr)
   152  		if !ok {
   153  			return true
   154  		}
   155  		if _, ok := j.Program.Info.TypeOf(lhs.X).(*types.Slice); !ok {
   156  			return true
   157  		}
   158  		lidx, ok := lhs.Index.(*ast.Ident)
   159  		if !ok {
   160  			return true
   161  		}
   162  		key, ok := loop.Key.(*ast.Ident)
   163  		if !ok {
   164  			return true
   165  		}
   166  		if j.Program.Info.TypeOf(lhs) == nil || j.Program.Info.TypeOf(stmt.Rhs[0]) == nil {
   167  			return true
   168  		}
   169  		if j.Program.Info.ObjectOf(lidx) != j.Program.Info.ObjectOf(key) {
   170  			return true
   171  		}
   172  		if !types.Identical(j.Program.Info.TypeOf(lhs), j.Program.Info.TypeOf(stmt.Rhs[0])) {
   173  			return true
   174  		}
   175  		if _, ok := j.Program.Info.TypeOf(loop.X).(*types.Slice); !ok {
   176  			return true
   177  		}
   178  
   179  		if rhs, ok := stmt.Rhs[0].(*ast.IndexExpr); ok {
   180  			rx, ok := rhs.X.(*ast.Ident)
   181  			_ = rx
   182  			if !ok {
   183  				return true
   184  			}
   185  			ridx, ok := rhs.Index.(*ast.Ident)
   186  			if !ok {
   187  				return true
   188  			}
   189  			if j.Program.Info.ObjectOf(ridx) != j.Program.Info.ObjectOf(key) {
   190  				return true
   191  			}
   192  		} else if rhs, ok := stmt.Rhs[0].(*ast.Ident); ok {
   193  			value, ok := loop.Value.(*ast.Ident)
   194  			if !ok {
   195  				return true
   196  			}
   197  			if j.Program.Info.ObjectOf(rhs) != j.Program.Info.ObjectOf(value) {
   198  				return true
   199  			}
   200  		} else {
   201  			return true
   202  		}
   203  		j.Errorf(loop, "should use copy() instead of a loop")
   204  		return true
   205  	}
   206  	for _, f := range c.filterGenerated(j.Program.Files) {
   207  		ast.Inspect(f, fn)
   208  	}
   209  }
   210  
   211  func (c *Checker) LintIfBoolCmp(j *lint.Job) {
   212  	fn := func(node ast.Node) bool {
   213  		expr, ok := node.(*ast.BinaryExpr)
   214  		if !ok || (expr.Op != token.EQL && expr.Op != token.NEQ) {
   215  			return true
   216  		}
   217  		x := j.IsBoolConst(expr.X)
   218  		y := j.IsBoolConst(expr.Y)
   219  		if !x && !y {
   220  			return true
   221  		}
   222  		var other ast.Expr
   223  		var val bool
   224  		if x {
   225  			val = j.BoolConst(expr.X)
   226  			other = expr.Y
   227  		} else {
   228  			val = j.BoolConst(expr.Y)
   229  			other = expr.X
   230  		}
   231  		basic, ok := j.Program.Info.TypeOf(other).Underlying().(*types.Basic)
   232  		if !ok || basic.Kind() != types.Bool {
   233  			return true
   234  		}
   235  		op := ""
   236  		if (expr.Op == token.EQL && !val) || (expr.Op == token.NEQ && val) {
   237  			op = "!"
   238  		}
   239  		r := op + j.Render(other)
   240  		l1 := len(r)
   241  		r = strings.TrimLeft(r, "!")
   242  		if (l1-len(r))%2 == 1 {
   243  			r = "!" + r
   244  		}
   245  		j.Errorf(expr, "should omit comparison to bool constant, can be simplified to %s", r)
   246  		return true
   247  	}
   248  	for _, f := range c.filterGenerated(j.Program.Files) {
   249  		ast.Inspect(f, fn)
   250  	}
   251  }
   252  
   253  func (c *Checker) LintBytesBufferConversions(j *lint.Job) {
   254  	fn := func(node ast.Node) bool {
   255  		call, ok := node.(*ast.CallExpr)
   256  		if !ok || len(call.Args) != 1 {
   257  			return true
   258  		}
   259  
   260  		argCall, ok := call.Args[0].(*ast.CallExpr)
   261  		if !ok {
   262  			return true
   263  		}
   264  		sel, ok := argCall.Fun.(*ast.SelectorExpr)
   265  		if !ok {
   266  			return true
   267  		}
   268  
   269  		typ := j.Program.Info.TypeOf(call.Fun)
   270  		if typ == types.Universe.Lookup("string").Type() && j.IsCallToAST(call.Args[0], "(*bytes.Buffer).Bytes") {
   271  			j.Errorf(call, "should use %v.String() instead of %v", j.Render(sel.X), j.Render(call))
   272  		} else if typ, ok := typ.(*types.Slice); ok && typ.Elem() == types.Universe.Lookup("byte").Type() && j.IsCallToAST(call.Args[0], "(*bytes.Buffer).String") {
   273  			j.Errorf(call, "should use %v.Bytes() instead of %v", j.Render(sel.X), j.Render(call))
   274  		}
   275  
   276  		return true
   277  	}
   278  	for _, f := range c.filterGenerated(j.Program.Files) {
   279  		ast.Inspect(f, fn)
   280  	}
   281  }
   282  
   283  func (c *Checker) LintStringsContains(j *lint.Job) {
   284  	// map of value to token to bool value
   285  	allowed := map[int64]map[token.Token]bool{
   286  		-1: {token.GTR: true, token.NEQ: true, token.EQL: false},
   287  		0:  {token.GEQ: true, token.LSS: false},
   288  	}
   289  	fn := func(node ast.Node) bool {
   290  		expr, ok := node.(*ast.BinaryExpr)
   291  		if !ok {
   292  			return true
   293  		}
   294  		switch expr.Op {
   295  		case token.GEQ, token.GTR, token.NEQ, token.LSS, token.EQL:
   296  		default:
   297  			return true
   298  		}
   299  
   300  		value, ok := j.ExprToInt(expr.Y)
   301  		if !ok {
   302  			return true
   303  		}
   304  
   305  		allowedOps, ok := allowed[value]
   306  		if !ok {
   307  			return true
   308  		}
   309  		b, ok := allowedOps[expr.Op]
   310  		if !ok {
   311  			return true
   312  		}
   313  
   314  		call, ok := expr.X.(*ast.CallExpr)
   315  		if !ok {
   316  			return true
   317  		}
   318  		sel, ok := call.Fun.(*ast.SelectorExpr)
   319  		if !ok {
   320  			return true
   321  		}
   322  		pkgIdent, ok := sel.X.(*ast.Ident)
   323  		if !ok {
   324  			return true
   325  		}
   326  		funIdent := sel.Sel
   327  		if pkgIdent.Name != "strings" && pkgIdent.Name != "bytes" {
   328  			return true
   329  		}
   330  		newFunc := ""
   331  		switch funIdent.Name {
   332  		case "IndexRune":
   333  			newFunc = "ContainsRune"
   334  		case "IndexAny":
   335  			newFunc = "ContainsAny"
   336  		case "Index":
   337  			newFunc = "Contains"
   338  		default:
   339  			return true
   340  		}
   341  
   342  		prefix := ""
   343  		if !b {
   344  			prefix = "!"
   345  		}
   346  		j.Errorf(node, "should use %s%s.%s(%s) instead", prefix, pkgIdent.Name, newFunc, j.RenderArgs(call.Args))
   347  
   348  		return true
   349  	}
   350  	for _, f := range c.filterGenerated(j.Program.Files) {
   351  		ast.Inspect(f, fn)
   352  	}
   353  }
   354  
   355  func (c *Checker) LintBytesCompare(j *lint.Job) {
   356  	fn := func(node ast.Node) bool {
   357  		expr, ok := node.(*ast.BinaryExpr)
   358  		if !ok {
   359  			return true
   360  		}
   361  		if expr.Op != token.NEQ && expr.Op != token.EQL {
   362  			return true
   363  		}
   364  		call, ok := expr.X.(*ast.CallExpr)
   365  		if !ok {
   366  			return true
   367  		}
   368  		if !j.IsCallToAST(call, "bytes.Compare") {
   369  			return true
   370  		}
   371  		value, ok := j.ExprToInt(expr.Y)
   372  		if !ok || value != 0 {
   373  			return true
   374  		}
   375  		args := j.RenderArgs(call.Args)
   376  		prefix := ""
   377  		if expr.Op == token.NEQ {
   378  			prefix = "!"
   379  		}
   380  		j.Errorf(node, "should use %sbytes.Equal(%s) instead", prefix, args)
   381  		return true
   382  	}
   383  	for _, f := range c.filterGenerated(j.Program.Files) {
   384  		ast.Inspect(f, fn)
   385  	}
   386  }
   387  
   388  func (c *Checker) LintForTrue(j *lint.Job) {
   389  	fn := func(node ast.Node) bool {
   390  		loop, ok := node.(*ast.ForStmt)
   391  		if !ok {
   392  			return true
   393  		}
   394  		if loop.Init != nil || loop.Post != nil {
   395  			return true
   396  		}
   397  		if !j.IsBoolConst(loop.Cond) || !j.BoolConst(loop.Cond) {
   398  			return true
   399  		}
   400  		j.Errorf(loop, "should use for {} instead of for true {}")
   401  		return true
   402  	}
   403  	for _, f := range c.filterGenerated(j.Program.Files) {
   404  		ast.Inspect(f, fn)
   405  	}
   406  }
   407  
   408  func (c *Checker) LintRegexpRaw(j *lint.Job) {
   409  	fn := func(node ast.Node) bool {
   410  		call, ok := node.(*ast.CallExpr)
   411  		if !ok {
   412  			return true
   413  		}
   414  		if !j.IsCallToAST(call, "regexp.MustCompile") &&
   415  			!j.IsCallToAST(call, "regexp.Compile") {
   416  			return true
   417  		}
   418  		sel, ok := call.Fun.(*ast.SelectorExpr)
   419  		if !ok {
   420  			return true
   421  		}
   422  		if len(call.Args) != 1 {
   423  			// invalid function call
   424  			return true
   425  		}
   426  		lit, ok := call.Args[0].(*ast.BasicLit)
   427  		if !ok {
   428  			// TODO(dominikh): support string concat, maybe support constants
   429  			return true
   430  		}
   431  		if lit.Kind != token.STRING {
   432  			// invalid function call
   433  			return true
   434  		}
   435  		if lit.Value[0] != '"' {
   436  			// already a raw string
   437  			return true
   438  		}
   439  		val := lit.Value
   440  		if !strings.Contains(val, `\\`) {
   441  			return true
   442  		}
   443  
   444  		bs := false
   445  		for _, c := range val {
   446  			if !bs && c == '\\' {
   447  				bs = true
   448  				continue
   449  			}
   450  			if bs && c == '\\' {
   451  				bs = false
   452  				continue
   453  			}
   454  			if bs {
   455  				// backslash followed by non-backslash -> escape sequence
   456  				return true
   457  			}
   458  		}
   459  
   460  		j.Errorf(call, "should use raw string (`...`) with regexp.%s to avoid having to escape twice", sel.Sel.Name)
   461  		return true
   462  	}
   463  	for _, f := range c.filterGenerated(j.Program.Files) {
   464  		ast.Inspect(f, fn)
   465  	}
   466  }
   467  
   468  func (c *Checker) LintIfReturn(j *lint.Job) {
   469  	fn := func(node ast.Node) bool {
   470  		block, ok := node.(*ast.BlockStmt)
   471  		if !ok {
   472  			return true
   473  		}
   474  		l := len(block.List)
   475  		if l < 2 {
   476  			return true
   477  		}
   478  		n1, n2 := block.List[l-2], block.List[l-1]
   479  
   480  		if len(block.List) >= 3 {
   481  			if _, ok := block.List[l-3].(*ast.IfStmt); ok {
   482  				// Do not flag a series of if statements
   483  				return true
   484  			}
   485  		}
   486  		// if statement with no init, no else, a single condition
   487  		// checking an identifier or function call and just a return
   488  		// statement in the body, that returns a boolean constant
   489  		ifs, ok := n1.(*ast.IfStmt)
   490  		if !ok {
   491  			return true
   492  		}
   493  		if ifs.Else != nil || ifs.Init != nil {
   494  			return true
   495  		}
   496  		if len(ifs.Body.List) != 1 {
   497  			return true
   498  		}
   499  		if op, ok := ifs.Cond.(*ast.BinaryExpr); ok {
   500  			switch op.Op {
   501  			case token.EQL, token.LSS, token.GTR, token.NEQ, token.LEQ, token.GEQ:
   502  			default:
   503  				return true
   504  			}
   505  		}
   506  		ret1, ok := ifs.Body.List[0].(*ast.ReturnStmt)
   507  		if !ok {
   508  			return true
   509  		}
   510  		if len(ret1.Results) != 1 {
   511  			return true
   512  		}
   513  		if !j.IsBoolConst(ret1.Results[0]) {
   514  			return true
   515  		}
   516  
   517  		ret2, ok := n2.(*ast.ReturnStmt)
   518  		if !ok {
   519  			return true
   520  		}
   521  		if len(ret2.Results) != 1 {
   522  			return true
   523  		}
   524  		if !j.IsBoolConst(ret2.Results[0]) {
   525  			return true
   526  		}
   527  		j.Errorf(n1, "should use 'return <expr>' instead of 'if <expr> { return <bool> }; return <bool>'")
   528  		return true
   529  	}
   530  	for _, f := range c.filterGenerated(j.Program.Files) {
   531  		ast.Inspect(f, fn)
   532  	}
   533  }
   534  
   535  // LintRedundantNilCheckWithLen checks for the following reduntant nil-checks:
   536  //
   537  //   if x == nil || len(x) == 0 {}
   538  //   if x != nil && len(x) != 0 {}
   539  //   if x != nil && len(x) == N {} (where N != 0)
   540  //   if x != nil && len(x) > N {}
   541  //   if x != nil && len(x) >= N {} (where N != 0)
   542  //
   543  func (c *Checker) LintRedundantNilCheckWithLen(j *lint.Job) {
   544  	isConstZero := func(expr ast.Expr) (isConst bool, isZero bool) {
   545  		_, ok := expr.(*ast.BasicLit)
   546  		if ok {
   547  			return true, lint.IsZero(expr)
   548  		}
   549  		id, ok := expr.(*ast.Ident)
   550  		if !ok {
   551  			return false, false
   552  		}
   553  		c, ok := j.Program.Info.ObjectOf(id).(*types.Const)
   554  		if !ok {
   555  			return false, false
   556  		}
   557  		return true, c.Val().Kind() == constant.Int && c.Val().String() == "0"
   558  	}
   559  
   560  	fn := func(node ast.Node) bool {
   561  		// check that expr is "x || y" or "x && y"
   562  		expr, ok := node.(*ast.BinaryExpr)
   563  		if !ok {
   564  			return true
   565  		}
   566  		if expr.Op != token.LOR && expr.Op != token.LAND {
   567  			return true
   568  		}
   569  		eqNil := expr.Op == token.LOR
   570  
   571  		// check that x is "xx == nil" or "xx != nil"
   572  		x, ok := expr.X.(*ast.BinaryExpr)
   573  		if !ok {
   574  			return true
   575  		}
   576  		if eqNil && x.Op != token.EQL {
   577  			return true
   578  		}
   579  		if !eqNil && x.Op != token.NEQ {
   580  			return true
   581  		}
   582  		xx, ok := x.X.(*ast.Ident)
   583  		if !ok {
   584  			return true
   585  		}
   586  		if !j.IsNil(x.Y) {
   587  			return true
   588  		}
   589  
   590  		// check that y is "len(xx) == 0" or "len(xx) ... "
   591  		y, ok := expr.Y.(*ast.BinaryExpr)
   592  		if !ok {
   593  			return true
   594  		}
   595  		if eqNil && y.Op != token.EQL { // must be len(xx) *==* 0
   596  			return false
   597  		}
   598  		yx, ok := y.X.(*ast.CallExpr)
   599  		if !ok {
   600  			return true
   601  		}
   602  		yxFun, ok := yx.Fun.(*ast.Ident)
   603  		if !ok || yxFun.Name != "len" || len(yx.Args) != 1 {
   604  			return true
   605  		}
   606  		yxArg, ok := yx.Args[0].(*ast.Ident)
   607  		if !ok {
   608  			return true
   609  		}
   610  		if yxArg.Name != xx.Name {
   611  			return true
   612  		}
   613  
   614  		if eqNil && !lint.IsZero(y.Y) { // must be len(x) == *0*
   615  			return true
   616  		}
   617  
   618  		if !eqNil {
   619  			isConst, isZero := isConstZero(y.Y)
   620  			if !isConst {
   621  				return true
   622  			}
   623  			switch y.Op {
   624  			case token.EQL:
   625  				// avoid false positive for "xx != nil && len(xx) == 0"
   626  				if isZero {
   627  					return true
   628  				}
   629  			case token.GEQ:
   630  				// avoid false positive for "xx != nil && len(xx) >= 0"
   631  				if isZero {
   632  					return true
   633  				}
   634  			case token.NEQ:
   635  				// avoid false positive for "xx != nil && len(xx) != <non-zero>"
   636  				if !isZero {
   637  					return true
   638  				}
   639  			case token.GTR:
   640  				// ok
   641  			default:
   642  				return true
   643  			}
   644  		}
   645  
   646  		// finally check that xx type is one of array, slice, map or chan
   647  		// this is to prevent false positive in case if xx is a pointer to an array
   648  		var nilType string
   649  		switch j.Program.Info.TypeOf(xx).(type) {
   650  		case *types.Slice:
   651  			nilType = "nil slices"
   652  		case *types.Map:
   653  			nilType = "nil maps"
   654  		case *types.Chan:
   655  			nilType = "nil channels"
   656  		default:
   657  			return true
   658  		}
   659  		j.Errorf(expr, "should omit nil check; len() for %s is defined as zero", nilType)
   660  		return true
   661  	}
   662  	for _, f := range c.filterGenerated(j.Program.Files) {
   663  		ast.Inspect(f, fn)
   664  	}
   665  }
   666  
   667  func (c *Checker) LintSlicing(j *lint.Job) {
   668  	fn := func(node ast.Node) bool {
   669  		n, ok := node.(*ast.SliceExpr)
   670  		if !ok {
   671  			return true
   672  		}
   673  		if n.Max != nil {
   674  			return true
   675  		}
   676  		s, ok := n.X.(*ast.Ident)
   677  		if !ok || s.Obj == nil {
   678  			return true
   679  		}
   680  		call, ok := n.High.(*ast.CallExpr)
   681  		if !ok || len(call.Args) != 1 || call.Ellipsis.IsValid() {
   682  			return true
   683  		}
   684  		fun, ok := call.Fun.(*ast.Ident)
   685  		if !ok || fun.Name != "len" {
   686  			return true
   687  		}
   688  		if _, ok := j.Program.Info.ObjectOf(fun).(*types.Builtin); !ok {
   689  			return true
   690  		}
   691  		arg, ok := call.Args[0].(*ast.Ident)
   692  		if !ok || arg.Obj != s.Obj {
   693  			return true
   694  		}
   695  		j.Errorf(n, "should omit second index in slice, s[a:len(s)] is identical to s[a:]")
   696  		return true
   697  	}
   698  	for _, f := range c.filterGenerated(j.Program.Files) {
   699  		ast.Inspect(f, fn)
   700  	}
   701  }
   702  
   703  func refersTo(info *types.Info, expr ast.Expr, ident *ast.Ident) bool {
   704  	found := false
   705  	fn := func(node ast.Node) bool {
   706  		ident2, ok := node.(*ast.Ident)
   707  		if !ok {
   708  			return true
   709  		}
   710  		if info.ObjectOf(ident) == info.ObjectOf(ident2) {
   711  			found = true
   712  			return false
   713  		}
   714  		return true
   715  	}
   716  	ast.Inspect(expr, fn)
   717  	return found
   718  }
   719  
   720  func (c *Checker) LintLoopAppend(j *lint.Job) {
   721  	fn := func(node ast.Node) bool {
   722  		loop, ok := node.(*ast.RangeStmt)
   723  		if !ok {
   724  			return true
   725  		}
   726  		if !lint.IsBlank(loop.Key) {
   727  			return true
   728  		}
   729  		val, ok := loop.Value.(*ast.Ident)
   730  		if !ok {
   731  			return true
   732  		}
   733  		if len(loop.Body.List) != 1 {
   734  			return true
   735  		}
   736  		stmt, ok := loop.Body.List[0].(*ast.AssignStmt)
   737  		if !ok {
   738  			return true
   739  		}
   740  		if stmt.Tok != token.ASSIGN || len(stmt.Lhs) != 1 || len(stmt.Rhs) != 1 {
   741  			return true
   742  		}
   743  		if refersTo(j.Program.Info, stmt.Lhs[0], val) {
   744  			return true
   745  		}
   746  		call, ok := stmt.Rhs[0].(*ast.CallExpr)
   747  		if !ok {
   748  			return true
   749  		}
   750  		if len(call.Args) != 2 || call.Ellipsis.IsValid() {
   751  			return true
   752  		}
   753  		fun, ok := call.Fun.(*ast.Ident)
   754  		if !ok {
   755  			return true
   756  		}
   757  		obj := j.Program.Info.ObjectOf(fun)
   758  		fn, ok := obj.(*types.Builtin)
   759  		if !ok || fn.Name() != "append" {
   760  			return true
   761  		}
   762  
   763  		src := j.Program.Info.TypeOf(loop.X)
   764  		dst := j.Program.Info.TypeOf(call.Args[0])
   765  		// TODO(dominikh) remove nil check once Go issue #15173 has
   766  		// been fixed
   767  		if src == nil {
   768  			return true
   769  		}
   770  		if !types.Identical(src, dst) {
   771  			return true
   772  		}
   773  
   774  		if j.Render(stmt.Lhs[0]) != j.Render(call.Args[0]) {
   775  			return true
   776  		}
   777  
   778  		el, ok := call.Args[1].(*ast.Ident)
   779  		if !ok {
   780  			return true
   781  		}
   782  		if j.Program.Info.ObjectOf(val) != j.Program.Info.ObjectOf(el) {
   783  			return true
   784  		}
   785  		j.Errorf(loop, "should replace loop with %s = append(%s, %s...)",
   786  			j.Render(stmt.Lhs[0]), j.Render(call.Args[0]), j.Render(loop.X))
   787  		return true
   788  	}
   789  	for _, f := range c.filterGenerated(j.Program.Files) {
   790  		ast.Inspect(f, fn)
   791  	}
   792  }
   793  
   794  func (c *Checker) LintTimeSince(j *lint.Job) {
   795  	fn := func(node ast.Node) bool {
   796  		call, ok := node.(*ast.CallExpr)
   797  		if !ok {
   798  			return true
   799  		}
   800  		sel, ok := call.Fun.(*ast.SelectorExpr)
   801  		if !ok {
   802  			return true
   803  		}
   804  		if !j.IsCallToAST(sel.X, "time.Now") {
   805  			return true
   806  		}
   807  		if sel.Sel.Name != "Sub" {
   808  			return true
   809  		}
   810  		j.Errorf(call, "should use time.Since instead of time.Now().Sub")
   811  		return true
   812  	}
   813  	for _, f := range c.filterGenerated(j.Program.Files) {
   814  		ast.Inspect(f, fn)
   815  	}
   816  }
   817  
   818  func (c *Checker) LintTimeUntil(j *lint.Job) {
   819  	if !j.IsGoVersion(8) {
   820  		return
   821  	}
   822  	fn := func(node ast.Node) bool {
   823  		call, ok := node.(*ast.CallExpr)
   824  		if !ok {
   825  			return true
   826  		}
   827  		if !j.IsCallToAST(call, "(time.Time).Sub") {
   828  			return true
   829  		}
   830  		if !j.IsCallToAST(call.Args[0], "time.Now") {
   831  			return true
   832  		}
   833  		j.Errorf(call, "should use time.Until instead of t.Sub(time.Now())")
   834  		return true
   835  	}
   836  	for _, f := range c.filterGenerated(j.Program.Files) {
   837  		ast.Inspect(f, fn)
   838  	}
   839  }
   840  
   841  func (c *Checker) LintSimplerReturn(j *lint.Job) {
   842  	fn1 := func(node ast.Node) bool {
   843  		var ret *ast.FieldList
   844  		switch x := node.(type) {
   845  		case *ast.FuncDecl:
   846  			ret = x.Type.Results
   847  		case *ast.FuncLit:
   848  			ret = x.Type.Results
   849  		default:
   850  			return true
   851  		}
   852  		if ret == nil {
   853  			return true
   854  		}
   855  
   856  		fn2 := func(node ast.Node) bool {
   857  			block, ok := node.(*ast.BlockStmt)
   858  			if !ok {
   859  				return true
   860  			}
   861  			if len(block.List) < 2 {
   862  				return true
   863  			}
   864  
   865  		outer:
   866  			for i, stmt := range block.List {
   867  				if i == len(block.List)-1 {
   868  					break
   869  				}
   870  				if i > 0 {
   871  					// don't flag an if in a series of ifs
   872  					if _, ok := block.List[i-1].(*ast.IfStmt); ok {
   873  						continue
   874  					}
   875  				}
   876  
   877  				// if <id1> != nil
   878  				ifs, ok := stmt.(*ast.IfStmt)
   879  				if !ok || len(ifs.Body.List) != 1 || ifs.Else != nil {
   880  					continue
   881  				}
   882  				expr, ok := ifs.Cond.(*ast.BinaryExpr)
   883  				if !ok || expr.Op != token.NEQ || !j.IsNil(expr.Y) {
   884  					continue
   885  				}
   886  				id1, ok := expr.X.(*ast.Ident)
   887  				if !ok {
   888  					continue
   889  				}
   890  
   891  				// return ..., <id1>
   892  				ret1, ok := ifs.Body.List[0].(*ast.ReturnStmt)
   893  				if !ok || len(ret1.Results) == 0 {
   894  					continue
   895  				}
   896  				var results1 []types.Object
   897  				for _, res := range ret1.Results {
   898  					ident, ok := res.(*ast.Ident)
   899  					if !ok {
   900  						continue outer
   901  					}
   902  					results1 = append(results1, j.Program.Info.ObjectOf(ident))
   903  				}
   904  				if results1[len(results1)-1] != j.Program.Info.ObjectOf(id1) {
   905  					continue
   906  				}
   907  
   908  				// return ..., [<id1> | nil]
   909  				ret2, ok := block.List[i+1].(*ast.ReturnStmt)
   910  				if !ok || len(ret2.Results) == 0 {
   911  					continue
   912  				}
   913  				var results2 []types.Object
   914  				for _, res := range ret2.Results {
   915  					ident, ok := res.(*ast.Ident)
   916  					if !ok {
   917  						continue outer
   918  					}
   919  					results2 = append(results2, j.Program.Info.ObjectOf(ident))
   920  				}
   921  				_, isNil := results2[len(results2)-1].(*types.Nil)
   922  				if results2[len(results2)-1] != j.Program.Info.ObjectOf(id1) &&
   923  					!isNil {
   924  					continue
   925  				}
   926  				for i, v := range results1[:len(results1)-1] {
   927  					if v != results2[i] {
   928  						continue outer
   929  					}
   930  				}
   931  
   932  				id1Obj := j.Program.Info.ObjectOf(id1)
   933  				if id1Obj == nil {
   934  					continue
   935  				}
   936  				_, idIface := id1Obj.Type().Underlying().(*types.Interface)
   937  				_, retIface := j.Program.Info.TypeOf(ret.List[len(ret.List)-1].Type).Underlying().(*types.Interface)
   938  
   939  				if retIface && !idIface {
   940  					// When the return value is an interface, but the
   941  					// identifier is not, an explicit check for nil is
   942  					// required to return an untyped nil.
   943  					continue
   944  				}
   945  
   946  				j.Errorf(ifs, "'if %s != nil { return %s }; return %s' can be simplified to 'return %s'",
   947  					j.Render(expr.X), j.RenderArgs(ret1.Results),
   948  					j.RenderArgs(ret2.Results), j.RenderArgs(ret1.Results))
   949  			}
   950  			return true
   951  		}
   952  		ast.Inspect(node, fn2)
   953  		return true
   954  	}
   955  	for _, f := range c.filterGenerated(j.Program.Files) {
   956  		ast.Inspect(f, fn1)
   957  	}
   958  }
   959  
   960  func (c *Checker) LintUnnecessaryBlank(j *lint.Job) {
   961  	fn1 := func(node ast.Node) {
   962  		assign, ok := node.(*ast.AssignStmt)
   963  		if !ok {
   964  			return
   965  		}
   966  		if len(assign.Lhs) != 2 || len(assign.Rhs) != 1 {
   967  			return
   968  		}
   969  		if !lint.IsBlank(assign.Lhs[1]) {
   970  			return
   971  		}
   972  		switch rhs := assign.Rhs[0].(type) {
   973  		case *ast.IndexExpr:
   974  			// The type-checker should make sure that it's a map, but
   975  			// let's be safe.
   976  			if _, ok := j.Program.Info.TypeOf(rhs.X).Underlying().(*types.Map); !ok {
   977  				return
   978  			}
   979  		case *ast.UnaryExpr:
   980  			if rhs.Op != token.ARROW {
   981  				return
   982  			}
   983  		default:
   984  			return
   985  		}
   986  		cp := *assign
   987  		cp.Lhs = cp.Lhs[0:1]
   988  		j.Errorf(assign, "should write %s instead of %s", j.Render(&cp), j.Render(assign))
   989  	}
   990  
   991  	fn2 := func(node ast.Node) {
   992  		stmt, ok := node.(*ast.AssignStmt)
   993  		if !ok {
   994  			return
   995  		}
   996  		if len(stmt.Lhs) != len(stmt.Rhs) {
   997  			return
   998  		}
   999  		for i, lh := range stmt.Lhs {
  1000  			rh := stmt.Rhs[i]
  1001  			if !lint.IsBlank(lh) {
  1002  				continue
  1003  			}
  1004  			expr, ok := rh.(*ast.UnaryExpr)
  1005  			if !ok {
  1006  				continue
  1007  			}
  1008  			if expr.Op != token.ARROW {
  1009  				continue
  1010  			}
  1011  			j.Errorf(lh, "'_ = <-ch' can be simplified to '<-ch'")
  1012  		}
  1013  	}
  1014  
  1015  	fn3 := func(node ast.Node) {
  1016  		rs, ok := node.(*ast.RangeStmt)
  1017  		if !ok {
  1018  			return
  1019  		}
  1020  		if lint.IsBlank(rs.Key) && (rs.Value == nil || lint.IsBlank(rs.Value)) {
  1021  			j.Errorf(rs.Key, "should omit values from range; this loop is equivalent to `for range ...`")
  1022  		}
  1023  	}
  1024  
  1025  	fn := func(node ast.Node) bool {
  1026  		fn1(node)
  1027  		fn2(node)
  1028  		if j.IsGoVersion(4) {
  1029  			fn3(node)
  1030  		}
  1031  		return true
  1032  	}
  1033  	for _, f := range c.filterGenerated(j.Program.Files) {
  1034  		ast.Inspect(f, fn)
  1035  	}
  1036  }
  1037  
  1038  func (c *Checker) LintSimplerStructConversion(j *lint.Job) {
  1039  	var skip ast.Node
  1040  	fn := func(node ast.Node) bool {
  1041  		// Do not suggest type conversion between pointers
  1042  		if unary, ok := node.(*ast.UnaryExpr); ok && unary.Op == token.AND {
  1043  			if lit, ok := unary.X.(*ast.CompositeLit); ok {
  1044  				skip = lit
  1045  			}
  1046  			return true
  1047  		}
  1048  
  1049  		if node == skip {
  1050  			return true
  1051  		}
  1052  
  1053  		lit, ok := node.(*ast.CompositeLit)
  1054  		if !ok {
  1055  			return true
  1056  		}
  1057  		typ1, _ := j.Program.Info.TypeOf(lit.Type).(*types.Named)
  1058  		if typ1 == nil {
  1059  			return true
  1060  		}
  1061  		s1, ok := typ1.Underlying().(*types.Struct)
  1062  		if !ok {
  1063  			return true
  1064  		}
  1065  
  1066  		var typ2 *types.Named
  1067  		var ident *ast.Ident
  1068  		getSelType := func(expr ast.Expr) (types.Type, *ast.Ident, bool) {
  1069  			sel, ok := expr.(*ast.SelectorExpr)
  1070  			if !ok {
  1071  				return nil, nil, false
  1072  			}
  1073  			ident, ok := sel.X.(*ast.Ident)
  1074  			if !ok {
  1075  				return nil, nil, false
  1076  			}
  1077  			typ := j.Program.Info.TypeOf(sel.X)
  1078  			return typ, ident, typ != nil
  1079  		}
  1080  		if len(lit.Elts) == 0 {
  1081  			return true
  1082  		}
  1083  		if s1.NumFields() != len(lit.Elts) {
  1084  			return true
  1085  		}
  1086  		for i, elt := range lit.Elts {
  1087  			var t types.Type
  1088  			var id *ast.Ident
  1089  			var ok bool
  1090  			switch elt := elt.(type) {
  1091  			case *ast.SelectorExpr:
  1092  				t, id, ok = getSelType(elt)
  1093  				if !ok {
  1094  					return true
  1095  				}
  1096  				if i >= s1.NumFields() || s1.Field(i).Name() != elt.Sel.Name {
  1097  					return true
  1098  				}
  1099  			case *ast.KeyValueExpr:
  1100  				var sel *ast.SelectorExpr
  1101  				sel, ok = elt.Value.(*ast.SelectorExpr)
  1102  				if !ok {
  1103  					return true
  1104  				}
  1105  
  1106  				if elt.Key.(*ast.Ident).Name != sel.Sel.Name {
  1107  					return true
  1108  				}
  1109  				t, id, ok = getSelType(elt.Value)
  1110  			}
  1111  			if !ok {
  1112  				return true
  1113  			}
  1114  			// All fields must be initialized from the same object
  1115  			if ident != nil && ident.Obj != id.Obj {
  1116  				return true
  1117  			}
  1118  			typ2, _ = t.(*types.Named)
  1119  			if typ2 == nil {
  1120  				return true
  1121  			}
  1122  			ident = id
  1123  		}
  1124  
  1125  		if typ2 == nil {
  1126  			return true
  1127  		}
  1128  
  1129  		if typ1.Obj().Pkg() != typ2.Obj().Pkg() {
  1130  			// Do not suggest type conversions between different
  1131  			// packages. Types in different packages might only match
  1132  			// by coincidence. Furthermore, if the dependency ever
  1133  			// adds more fields to its type, it could break the code
  1134  			// that relies on the type conversion to work.
  1135  			return true
  1136  		}
  1137  
  1138  		s2, ok := typ2.Underlying().(*types.Struct)
  1139  		if !ok {
  1140  			return true
  1141  		}
  1142  		if typ1 == typ2 {
  1143  			return true
  1144  		}
  1145  		if !structsIdentical(s1, s2) {
  1146  			return true
  1147  		}
  1148  		j.Errorf(node, "should convert %s (type %s) to %s instead of using struct literal",
  1149  			ident.Name, typ2.Obj().Name(), typ1.Obj().Name())
  1150  		return true
  1151  	}
  1152  	for _, f := range c.filterGenerated(j.Program.Files) {
  1153  		ast.Inspect(f, fn)
  1154  	}
  1155  }
  1156  
  1157  func (c *Checker) LintTrim(j *lint.Job) {
  1158  	sameNonDynamic := func(node1, node2 ast.Node) bool {
  1159  		if reflect.TypeOf(node1) != reflect.TypeOf(node2) {
  1160  			return false
  1161  		}
  1162  
  1163  		switch node1 := node1.(type) {
  1164  		case *ast.Ident:
  1165  			return node1.Obj == node2.(*ast.Ident).Obj
  1166  		case *ast.SelectorExpr:
  1167  			return j.Render(node1) == j.Render(node2)
  1168  		case *ast.IndexExpr:
  1169  			return j.Render(node1) == j.Render(node2)
  1170  		}
  1171  		return false
  1172  	}
  1173  
  1174  	isLenOnIdent := func(fn ast.Expr, ident ast.Expr) bool {
  1175  		call, ok := fn.(*ast.CallExpr)
  1176  		if !ok {
  1177  			return false
  1178  		}
  1179  		if fn, ok := call.Fun.(*ast.Ident); !ok || fn.Name != "len" {
  1180  			return false
  1181  		}
  1182  		if len(call.Args) != 1 {
  1183  			return false
  1184  		}
  1185  		return sameNonDynamic(call.Args[0], ident)
  1186  	}
  1187  
  1188  	fn := func(node ast.Node) bool {
  1189  		var pkg string
  1190  		var fun string
  1191  
  1192  		ifstmt, ok := node.(*ast.IfStmt)
  1193  		if !ok {
  1194  			return true
  1195  		}
  1196  		if ifstmt.Init != nil {
  1197  			return true
  1198  		}
  1199  		if ifstmt.Else != nil {
  1200  			return true
  1201  		}
  1202  		if len(ifstmt.Body.List) != 1 {
  1203  			return true
  1204  		}
  1205  		condCall, ok := ifstmt.Cond.(*ast.CallExpr)
  1206  		if !ok {
  1207  			return true
  1208  		}
  1209  		call, ok := condCall.Fun.(*ast.SelectorExpr)
  1210  		if !ok {
  1211  			return true
  1212  		}
  1213  		if lint.IsIdent(call.X, "strings") {
  1214  			pkg = "strings"
  1215  		} else if lint.IsIdent(call.X, "bytes") {
  1216  			pkg = "bytes"
  1217  		} else {
  1218  			return true
  1219  		}
  1220  		if lint.IsIdent(call.Sel, "HasPrefix") {
  1221  			fun = "HasPrefix"
  1222  		} else if lint.IsIdent(call.Sel, "HasSuffix") {
  1223  			fun = "HasSuffix"
  1224  		} else {
  1225  			return true
  1226  		}
  1227  
  1228  		assign, ok := ifstmt.Body.List[0].(*ast.AssignStmt)
  1229  		if !ok {
  1230  			return true
  1231  		}
  1232  		if assign.Tok != token.ASSIGN {
  1233  			return true
  1234  		}
  1235  		if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
  1236  			return true
  1237  		}
  1238  		if !sameNonDynamic(condCall.Args[0], assign.Lhs[0]) {
  1239  			return true
  1240  		}
  1241  		slice, ok := assign.Rhs[0].(*ast.SliceExpr)
  1242  		if !ok {
  1243  			return true
  1244  		}
  1245  		if slice.Slice3 {
  1246  			return true
  1247  		}
  1248  		if !sameNonDynamic(slice.X, condCall.Args[0]) {
  1249  			return true
  1250  		}
  1251  		var index ast.Expr
  1252  		switch fun {
  1253  		case "HasPrefix":
  1254  			// TODO(dh) We could detect a High that is len(s), but another
  1255  			// rule will already flag that, anyway.
  1256  			if slice.High != nil {
  1257  				return true
  1258  			}
  1259  			index = slice.Low
  1260  		case "HasSuffix":
  1261  			if slice.Low != nil {
  1262  				n, ok := j.ExprToInt(slice.Low)
  1263  				if !ok || n != 0 {
  1264  					return true
  1265  				}
  1266  			}
  1267  			index = slice.High
  1268  		}
  1269  
  1270  		switch index := index.(type) {
  1271  		case *ast.CallExpr:
  1272  			if fun != "HasPrefix" {
  1273  				return true
  1274  			}
  1275  			if fn, ok := index.Fun.(*ast.Ident); !ok || fn.Name != "len" {
  1276  				return true
  1277  			}
  1278  			if len(index.Args) != 1 {
  1279  				return true
  1280  			}
  1281  			id3 := index.Args[0]
  1282  			switch oid3 := condCall.Args[1].(type) {
  1283  			case *ast.BasicLit:
  1284  				if pkg != "strings" {
  1285  					return false
  1286  				}
  1287  				lit, ok := id3.(*ast.BasicLit)
  1288  				if !ok {
  1289  					return true
  1290  				}
  1291  				s1, ok1 := j.ExprToString(lit)
  1292  				s2, ok2 := j.ExprToString(condCall.Args[1])
  1293  				if !ok1 || !ok2 || s1 != s2 {
  1294  					return true
  1295  				}
  1296  			default:
  1297  				if !sameNonDynamic(id3, oid3) {
  1298  					return true
  1299  				}
  1300  			}
  1301  		case *ast.BasicLit, *ast.Ident:
  1302  			if fun != "HasPrefix" {
  1303  				return true
  1304  			}
  1305  			if pkg != "strings" {
  1306  				return true
  1307  			}
  1308  			string, ok1 := j.ExprToString(condCall.Args[1])
  1309  			int, ok2 := j.ExprToInt(slice.Low)
  1310  			if !ok1 || !ok2 || int != int64(len(string)) {
  1311  				return true
  1312  			}
  1313  		case *ast.BinaryExpr:
  1314  			if fun != "HasSuffix" {
  1315  				return true
  1316  			}
  1317  			if index.Op != token.SUB {
  1318  				return true
  1319  			}
  1320  			if !isLenOnIdent(index.X, condCall.Args[0]) ||
  1321  				!isLenOnIdent(index.Y, condCall.Args[1]) {
  1322  				return true
  1323  			}
  1324  		default:
  1325  			return true
  1326  		}
  1327  
  1328  		var replacement string
  1329  		switch fun {
  1330  		case "HasPrefix":
  1331  			replacement = "TrimPrefix"
  1332  		case "HasSuffix":
  1333  			replacement = "TrimSuffix"
  1334  		}
  1335  		j.Errorf(ifstmt, "should replace this if statement with an unconditional %s.%s", pkg, replacement)
  1336  		return true
  1337  	}
  1338  	for _, f := range c.filterGenerated(j.Program.Files) {
  1339  		ast.Inspect(f, fn)
  1340  	}
  1341  }
  1342  
  1343  func (c *Checker) LintLoopSlide(j *lint.Job) {
  1344  	// TODO(dh): detect bs[i+offset] in addition to bs[offset+i]
  1345  	// TODO(dh): consider merging this function with LintLoopCopy
  1346  	// TODO(dh): detect length that is an expression, not a variable name
  1347  	// TODO(dh): support sliding to a different offset than the beginning of the slice
  1348  
  1349  	fn := func(node ast.Node) bool {
  1350  		/*
  1351  			for i := 0; i < n; i++ {
  1352  				bs[i] = bs[offset+i]
  1353  			}
  1354  
  1355  						↓
  1356  
  1357  			copy(bs[:n], bs[offset:offset+n])
  1358  		*/
  1359  
  1360  		loop, ok := node.(*ast.ForStmt)
  1361  		if !ok || len(loop.Body.List) != 1 || loop.Init == nil || loop.Cond == nil || loop.Post == nil {
  1362  			return true
  1363  		}
  1364  		assign, ok := loop.Init.(*ast.AssignStmt)
  1365  		if !ok || len(assign.Lhs) != 1 || len(assign.Rhs) != 1 || !lint.IsZero(assign.Rhs[0]) {
  1366  			return true
  1367  		}
  1368  		initvar, ok := assign.Lhs[0].(*ast.Ident)
  1369  		if !ok {
  1370  			return true
  1371  		}
  1372  		post, ok := loop.Post.(*ast.IncDecStmt)
  1373  		if !ok || post.Tok != token.INC {
  1374  			return true
  1375  		}
  1376  		postvar, ok := post.X.(*ast.Ident)
  1377  		if !ok || j.Program.Info.ObjectOf(postvar) != j.Program.Info.ObjectOf(initvar) {
  1378  			return true
  1379  		}
  1380  		bin, ok := loop.Cond.(*ast.BinaryExpr)
  1381  		if !ok || bin.Op != token.LSS {
  1382  			return true
  1383  		}
  1384  		binx, ok := bin.X.(*ast.Ident)
  1385  		if !ok || j.Program.Info.ObjectOf(binx) != j.Program.Info.ObjectOf(initvar) {
  1386  			return true
  1387  		}
  1388  		biny, ok := bin.Y.(*ast.Ident)
  1389  		if !ok {
  1390  			return true
  1391  		}
  1392  
  1393  		assign, ok = loop.Body.List[0].(*ast.AssignStmt)
  1394  		if !ok || len(assign.Lhs) != 1 || len(assign.Rhs) != 1 || assign.Tok != token.ASSIGN {
  1395  			return true
  1396  		}
  1397  		lhs, ok := assign.Lhs[0].(*ast.IndexExpr)
  1398  		if !ok {
  1399  			return true
  1400  		}
  1401  		rhs, ok := assign.Rhs[0].(*ast.IndexExpr)
  1402  		if !ok {
  1403  			return true
  1404  		}
  1405  
  1406  		bs1, ok := lhs.X.(*ast.Ident)
  1407  		if !ok {
  1408  			return true
  1409  		}
  1410  		bs2, ok := rhs.X.(*ast.Ident)
  1411  		if !ok {
  1412  			return true
  1413  		}
  1414  		obj1 := j.Program.Info.ObjectOf(bs1)
  1415  		obj2 := j.Program.Info.ObjectOf(bs2)
  1416  		if obj1 != obj2 {
  1417  			return true
  1418  		}
  1419  		if _, ok := obj1.Type().Underlying().(*types.Slice); !ok {
  1420  			return true
  1421  		}
  1422  
  1423  		index1, ok := lhs.Index.(*ast.Ident)
  1424  		if !ok || j.Program.Info.ObjectOf(index1) != j.Program.Info.ObjectOf(initvar) {
  1425  			return true
  1426  		}
  1427  		index2, ok := rhs.Index.(*ast.BinaryExpr)
  1428  		if !ok || index2.Op != token.ADD {
  1429  			return true
  1430  		}
  1431  		add1, ok := index2.X.(*ast.Ident)
  1432  		if !ok {
  1433  			return true
  1434  		}
  1435  		add2, ok := index2.Y.(*ast.Ident)
  1436  		if !ok || j.Program.Info.ObjectOf(add2) != j.Program.Info.ObjectOf(initvar) {
  1437  			return true
  1438  		}
  1439  
  1440  		j.Errorf(loop, "should use copy(%s[:%s], %s[%s:]) instead", j.Render(bs1), j.Render(biny), j.Render(bs1), j.Render(add1))
  1441  		return true
  1442  	}
  1443  	for _, f := range c.filterGenerated(j.Program.Files) {
  1444  		ast.Inspect(f, fn)
  1445  	}
  1446  }
  1447  
  1448  func (c *Checker) LintMakeLenCap(j *lint.Job) {
  1449  	fn := func(node ast.Node) bool {
  1450  		call, ok := node.(*ast.CallExpr)
  1451  		if !ok {
  1452  			return true
  1453  		}
  1454  		if fn, ok := call.Fun.(*ast.Ident); !ok || fn.Name != "make" {
  1455  			// FIXME check whether make is indeed the built-in function
  1456  			return true
  1457  		}
  1458  		switch len(call.Args) {
  1459  		case 2:
  1460  			// make(T, len)
  1461  			if _, ok := j.Program.Info.TypeOf(call.Args[0]).Underlying().(*types.Slice); ok {
  1462  				break
  1463  			}
  1464  			if lint.IsZero(call.Args[1]) {
  1465  				j.Errorf(call.Args[1], "should use make(%s) instead", j.Render(call.Args[0]))
  1466  			}
  1467  		case 3:
  1468  			// make(T, len, cap)
  1469  			if j.Render(call.Args[1]) == j.Render(call.Args[2]) {
  1470  				j.Errorf(call.Args[1], "should use make(%s, %s) instead", j.Render(call.Args[0]), j.Render(call.Args[1]))
  1471  			}
  1472  		}
  1473  		return false
  1474  	}
  1475  	for _, f := range c.filterGenerated(j.Program.Files) {
  1476  		ast.Inspect(f, fn)
  1477  	}
  1478  }
  1479  
  1480  func (c *Checker) LintAssertNotNil(j *lint.Job) {
  1481  	isNilCheck := func(ident *ast.Ident, expr ast.Expr) bool {
  1482  		xbinop, ok := expr.(*ast.BinaryExpr)
  1483  		if !ok || xbinop.Op != token.NEQ {
  1484  			return false
  1485  		}
  1486  		xident, ok := xbinop.X.(*ast.Ident)
  1487  		if !ok || xident.Obj != ident.Obj {
  1488  			return false
  1489  		}
  1490  		if !j.IsNil(xbinop.Y) {
  1491  			return false
  1492  		}
  1493  		return true
  1494  	}
  1495  	isOKCheck := func(ident *ast.Ident, expr ast.Expr) bool {
  1496  		yident, ok := expr.(*ast.Ident)
  1497  		if !ok || yident.Obj != ident.Obj {
  1498  			return false
  1499  		}
  1500  		return true
  1501  	}
  1502  	fn := func(node ast.Node) bool {
  1503  		ifstmt, ok := node.(*ast.IfStmt)
  1504  		if !ok {
  1505  			return true
  1506  		}
  1507  		assign, ok := ifstmt.Init.(*ast.AssignStmt)
  1508  		if !ok || len(assign.Lhs) != 2 || len(assign.Rhs) != 1 || !lint.IsBlank(assign.Lhs[0]) {
  1509  			return true
  1510  		}
  1511  		assert, ok := assign.Rhs[0].(*ast.TypeAssertExpr)
  1512  		if !ok {
  1513  			return true
  1514  		}
  1515  		binop, ok := ifstmt.Cond.(*ast.BinaryExpr)
  1516  		if !ok || binop.Op != token.LAND {
  1517  			return true
  1518  		}
  1519  		assertIdent, ok := assert.X.(*ast.Ident)
  1520  		if !ok {
  1521  			return true
  1522  		}
  1523  		assignIdent, ok := assign.Lhs[1].(*ast.Ident)
  1524  		if !ok {
  1525  			return true
  1526  		}
  1527  		if !(isNilCheck(assertIdent, binop.X) && isOKCheck(assignIdent, binop.Y)) &&
  1528  			!(isNilCheck(assertIdent, binop.Y) && isOKCheck(assignIdent, binop.X)) {
  1529  			return true
  1530  		}
  1531  		j.Errorf(ifstmt, "when %s is true, %s can't be nil", j.Render(assignIdent), j.Render(assertIdent))
  1532  		return true
  1533  	}
  1534  	for _, f := range c.filterGenerated(j.Program.Files) {
  1535  		ast.Inspect(f, fn)
  1536  	}
  1537  }
  1538  
  1539  func (c *Checker) LintDeclareAssign(j *lint.Job) {
  1540  	fn := func(node ast.Node) bool {
  1541  		block, ok := node.(*ast.BlockStmt)
  1542  		if !ok {
  1543  			return true
  1544  		}
  1545  		if len(block.List) < 2 {
  1546  			return true
  1547  		}
  1548  		for i, stmt := range block.List[:len(block.List)-1] {
  1549  			_ = i
  1550  			decl, ok := stmt.(*ast.DeclStmt)
  1551  			if !ok {
  1552  				continue
  1553  			}
  1554  			gdecl, ok := decl.Decl.(*ast.GenDecl)
  1555  			if !ok || gdecl.Tok != token.VAR || len(gdecl.Specs) != 1 {
  1556  				continue
  1557  			}
  1558  			vspec, ok := gdecl.Specs[0].(*ast.ValueSpec)
  1559  			if !ok || len(vspec.Names) != 1 || len(vspec.Values) != 0 {
  1560  				continue
  1561  			}
  1562  
  1563  			assign, ok := block.List[i+1].(*ast.AssignStmt)
  1564  			if !ok || assign.Tok != token.ASSIGN {
  1565  				continue
  1566  			}
  1567  			if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
  1568  				continue
  1569  			}
  1570  			ident, ok := assign.Lhs[0].(*ast.Ident)
  1571  			if !ok {
  1572  				continue
  1573  			}
  1574  			if vspec.Names[0].Obj != ident.Obj {
  1575  				continue
  1576  			}
  1577  
  1578  			if refersTo(j.Program.Info, assign.Rhs[0], ident) {
  1579  				continue
  1580  			}
  1581  			j.Errorf(decl, "should merge variable declaration with assignment on next line")
  1582  		}
  1583  		return true
  1584  	}
  1585  	for _, f := range c.filterGenerated(j.Program.Files) {
  1586  		ast.Inspect(f, fn)
  1587  	}
  1588  }
  1589  
  1590  func (c *Checker) LintRedundantBreak(j *lint.Job) {
  1591  	fn1 := func(node ast.Node) {
  1592  		clause, ok := node.(*ast.CaseClause)
  1593  		if !ok {
  1594  			return
  1595  		}
  1596  		if len(clause.Body) < 2 {
  1597  			return
  1598  		}
  1599  		branch, ok := clause.Body[len(clause.Body)-1].(*ast.BranchStmt)
  1600  		if !ok || branch.Tok != token.BREAK || branch.Label != nil {
  1601  			return
  1602  		}
  1603  		j.Errorf(branch, "redundant break statement")
  1604  		return
  1605  	}
  1606  	fn2 := func(node ast.Node) {
  1607  		var ret *ast.FieldList
  1608  		var body *ast.BlockStmt
  1609  		switch x := node.(type) {
  1610  		case *ast.FuncDecl:
  1611  			ret = x.Type.Results
  1612  			body = x.Body
  1613  		case *ast.FuncLit:
  1614  			ret = x.Type.Results
  1615  			body = x.Body
  1616  		default:
  1617  			return
  1618  		}
  1619  		// if the func has results, a return can't be redundant.
  1620  		// similarly, if there are no statements, there can be
  1621  		// no return.
  1622  		if ret != nil || body == nil || len(body.List) < 1 {
  1623  			return
  1624  		}
  1625  		rst, ok := body.List[len(body.List)-1].(*ast.ReturnStmt)
  1626  		if !ok {
  1627  			return
  1628  		}
  1629  		// we don't need to check rst.Results as we already
  1630  		// checked x.Type.Results to be nil.
  1631  		j.Errorf(rst, "redundant return statement")
  1632  	}
  1633  	fn := func(node ast.Node) bool {
  1634  		fn1(node)
  1635  		fn2(node)
  1636  		return true
  1637  	}
  1638  	for _, f := range c.filterGenerated(j.Program.Files) {
  1639  		ast.Inspect(f, fn)
  1640  	}
  1641  }
  1642  
  1643  func (c *Checker) Implements(j *lint.Job, typ types.Type, iface string) bool {
  1644  	// OPT(dh): we can cache the type lookup
  1645  	idx := strings.IndexRune(iface, '.')
  1646  	var scope *types.Scope
  1647  	var ifaceName string
  1648  	if idx == -1 {
  1649  		scope = types.Universe
  1650  		ifaceName = iface
  1651  	} else {
  1652  		pkgName := iface[:idx]
  1653  		pkg := j.Program.Prog.Package(pkgName)
  1654  		if pkg == nil {
  1655  			return false
  1656  		}
  1657  		scope = pkg.Pkg.Scope()
  1658  		ifaceName = iface[idx+1:]
  1659  	}
  1660  
  1661  	obj := scope.Lookup(ifaceName)
  1662  	if obj == nil {
  1663  		return false
  1664  	}
  1665  	i, ok := obj.Type().Underlying().(*types.Interface)
  1666  	if !ok {
  1667  		return false
  1668  	}
  1669  	return types.Implements(typ, i)
  1670  }
  1671  
  1672  func (c *Checker) LintRedundantSprintf(j *lint.Job) {
  1673  	fn := func(node ast.Node) bool {
  1674  		call, ok := node.(*ast.CallExpr)
  1675  		if !ok {
  1676  			return true
  1677  		}
  1678  		if !j.IsCallToAST(call, "fmt.Sprintf") {
  1679  			return true
  1680  		}
  1681  		if len(call.Args) != 2 {
  1682  			return true
  1683  		}
  1684  		if s, ok := j.ExprToString(call.Args[0]); !ok || s != "%s" {
  1685  			return true
  1686  		}
  1687  		pkg := j.NodePackage(call)
  1688  		arg := call.Args[1]
  1689  		typ := pkg.Info.TypeOf(arg)
  1690  
  1691  		if c.Implements(j, typ, "fmt.Stringer") {
  1692  			j.Errorf(call, "should use String() instead of fmt.Sprintf")
  1693  			return true
  1694  		}
  1695  
  1696  		if typ.Underlying() == types.Universe.Lookup("string").Type() {
  1697  			if typ == types.Universe.Lookup("string").Type() {
  1698  				j.Errorf(call, "the argument is already a string, there's no need to use fmt.Sprintf")
  1699  			} else {
  1700  				j.Errorf(call, "the argument's underlying type is a string, should use a simple conversion instead of fmt.Sprintf")
  1701  			}
  1702  		}
  1703  		return true
  1704  	}
  1705  	for _, f := range c.filterGenerated(j.Program.Files) {
  1706  		ast.Inspect(f, fn)
  1707  	}
  1708  }
  1709  
  1710  func (c *Checker) LintErrorsNewSprintf(j *lint.Job) {
  1711  	fn := func(node ast.Node) bool {
  1712  		if !j.IsCallToAST(node, "errors.New") {
  1713  			return true
  1714  		}
  1715  		call := node.(*ast.CallExpr)
  1716  		if !j.IsCallToAST(call.Args[0], "fmt.Sprintf") {
  1717  			return true
  1718  		}
  1719  		j.Errorf(node, "should use fmt.Errorf(...) instead of errors.New(fmt.Sprintf(...))")
  1720  		return true
  1721  	}
  1722  	for _, f := range c.filterGenerated(j.Program.Files) {
  1723  		ast.Inspect(f, fn)
  1724  	}
  1725  }
  1726  
  1727  func (c *Checker) LintRangeStringRunes(j *lint.Job) {
  1728  	sharedcheck.CheckRangeStringRunes(c.nodeFns, j)
  1729  }
  1730  
  1731  func (c *Checker) LintNilCheckAroundRange(j *lint.Job) {
  1732  	fn := func(node ast.Node) bool {
  1733  		ifstmt, ok := node.(*ast.IfStmt)
  1734  		if !ok {
  1735  			return true
  1736  		}
  1737  
  1738  		cond, ok := ifstmt.Cond.(*ast.BinaryExpr)
  1739  		if !ok {
  1740  			return true
  1741  		}
  1742  
  1743  		if cond.Op != token.NEQ || !j.IsNil(cond.Y) || len(ifstmt.Body.List) != 1 {
  1744  			return true
  1745  		}
  1746  
  1747  		loop, ok := ifstmt.Body.List[0].(*ast.RangeStmt)
  1748  		if !ok {
  1749  			return true
  1750  		}
  1751  		ifXIdent, ok := cond.X.(*ast.Ident)
  1752  		if !ok {
  1753  			return true
  1754  		}
  1755  		rangeXIdent, ok := loop.X.(*ast.Ident)
  1756  		if !ok {
  1757  			return true
  1758  		}
  1759  		if ifXIdent.Obj != rangeXIdent.Obj {
  1760  			return true
  1761  		}
  1762  		switch j.Program.Info.TypeOf(rangeXIdent).(type) {
  1763  		case *types.Slice, *types.Map:
  1764  			j.Errorf(node, "unnecessary nil check around range")
  1765  		}
  1766  		return true
  1767  	}
  1768  	for _, f := range c.filterGenerated(j.Program.Files) {
  1769  		ast.Inspect(f, fn)
  1770  	}
  1771  }