github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/simple/lint.go (about)

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