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