github.com/gwaycc/gometalinter@v3.0.0+incompatible/_linters/src/honnef.co/go/tools/staticcheck/lint.go (about)

     1  // Package staticcheck contains a linter for Go source code.
     2  package staticcheck // import "honnef.co/go/tools/staticcheck"
     3  
     4  import (
     5  	"fmt"
     6  	"go/ast"
     7  	"go/constant"
     8  	"go/token"
     9  	"go/types"
    10  	htmltemplate "html/template"
    11  	"net/http"
    12  	"regexp"
    13  	"regexp/syntax"
    14  	"sort"
    15  	"strconv"
    16  	"strings"
    17  	"sync"
    18  	texttemplate "text/template"
    19  
    20  	. "honnef.co/go/tools/arg"
    21  	"honnef.co/go/tools/deprecated"
    22  	"honnef.co/go/tools/functions"
    23  	"honnef.co/go/tools/internal/sharedcheck"
    24  	"honnef.co/go/tools/lint"
    25  	. "honnef.co/go/tools/lint/lintdsl"
    26  	"honnef.co/go/tools/ssa"
    27  	"honnef.co/go/tools/ssautil"
    28  	"honnef.co/go/tools/staticcheck/vrp"
    29  
    30  	"golang.org/x/tools/go/ast/astutil"
    31  	"golang.org/x/tools/go/packages"
    32  )
    33  
    34  func validRegexp(call *Call) {
    35  	arg := call.Args[0]
    36  	err := ValidateRegexp(arg.Value)
    37  	if err != nil {
    38  		arg.Invalid(err.Error())
    39  	}
    40  }
    41  
    42  type runeSlice []rune
    43  
    44  func (rs runeSlice) Len() int               { return len(rs) }
    45  func (rs runeSlice) Less(i int, j int) bool { return rs[i] < rs[j] }
    46  func (rs runeSlice) Swap(i int, j int)      { rs[i], rs[j] = rs[j], rs[i] }
    47  
    48  func utf8Cutset(call *Call) {
    49  	arg := call.Args[1]
    50  	if InvalidUTF8(arg.Value) {
    51  		arg.Invalid(MsgInvalidUTF8)
    52  	}
    53  }
    54  
    55  func uniqueCutset(call *Call) {
    56  	arg := call.Args[1]
    57  	if !UniqueStringCutset(arg.Value) {
    58  		arg.Invalid(MsgNonUniqueCutset)
    59  	}
    60  }
    61  
    62  func unmarshalPointer(name string, arg int) CallCheck {
    63  	return func(call *Call) {
    64  		if !Pointer(call.Args[arg].Value) {
    65  			call.Args[arg].Invalid(fmt.Sprintf("%s expects to unmarshal into a pointer, but the provided value is not a pointer", name))
    66  		}
    67  	}
    68  }
    69  
    70  func pointlessIntMath(call *Call) {
    71  	if ConvertedFromInt(call.Args[0].Value) {
    72  		call.Invalid(fmt.Sprintf("calling %s on a converted integer is pointless", CallName(call.Instr.Common())))
    73  	}
    74  }
    75  
    76  func checkValidHostPort(arg int) CallCheck {
    77  	return func(call *Call) {
    78  		if !ValidHostPort(call.Args[arg].Value) {
    79  			call.Args[arg].Invalid(MsgInvalidHostPort)
    80  		}
    81  	}
    82  }
    83  
    84  var (
    85  	checkRegexpRules = map[string]CallCheck{
    86  		"regexp.MustCompile": validRegexp,
    87  		"regexp.Compile":     validRegexp,
    88  		"regexp.Match":       validRegexp,
    89  		"regexp.MatchReader": validRegexp,
    90  		"regexp.MatchString": validRegexp,
    91  	}
    92  
    93  	checkTimeParseRules = map[string]CallCheck{
    94  		"time.Parse": func(call *Call) {
    95  			arg := call.Args[Arg("time.Parse.layout")]
    96  			err := ValidateTimeLayout(arg.Value)
    97  			if err != nil {
    98  				arg.Invalid(err.Error())
    99  			}
   100  		},
   101  	}
   102  
   103  	checkEncodingBinaryRules = map[string]CallCheck{
   104  		"encoding/binary.Write": func(call *Call) {
   105  			arg := call.Args[Arg("encoding/binary.Write.data")]
   106  			if !CanBinaryMarshal(call.Job, arg.Value) {
   107  				arg.Invalid(fmt.Sprintf("value of type %s cannot be used with binary.Write", arg.Value.Value.Type()))
   108  			}
   109  		},
   110  	}
   111  
   112  	checkURLsRules = map[string]CallCheck{
   113  		"net/url.Parse": func(call *Call) {
   114  			arg := call.Args[Arg("net/url.Parse.rawurl")]
   115  			err := ValidateURL(arg.Value)
   116  			if err != nil {
   117  				arg.Invalid(err.Error())
   118  			}
   119  		},
   120  	}
   121  
   122  	checkSyncPoolValueRules = map[string]CallCheck{
   123  		"(*sync.Pool).Put": func(call *Call) {
   124  			arg := call.Args[Arg("(*sync.Pool).Put.x")]
   125  			typ := arg.Value.Value.Type()
   126  			if !IsPointerLike(typ) {
   127  				arg.Invalid("argument should be pointer-like to avoid allocations")
   128  			}
   129  		},
   130  	}
   131  
   132  	checkRegexpFindAllRules = map[string]CallCheck{
   133  		"(*regexp.Regexp).FindAll":                    RepeatZeroTimes("a FindAll method", 1),
   134  		"(*regexp.Regexp).FindAllIndex":               RepeatZeroTimes("a FindAll method", 1),
   135  		"(*regexp.Regexp).FindAllString":              RepeatZeroTimes("a FindAll method", 1),
   136  		"(*regexp.Regexp).FindAllStringIndex":         RepeatZeroTimes("a FindAll method", 1),
   137  		"(*regexp.Regexp).FindAllStringSubmatch":      RepeatZeroTimes("a FindAll method", 1),
   138  		"(*regexp.Regexp).FindAllStringSubmatchIndex": RepeatZeroTimes("a FindAll method", 1),
   139  		"(*regexp.Regexp).FindAllSubmatch":            RepeatZeroTimes("a FindAll method", 1),
   140  		"(*regexp.Regexp).FindAllSubmatchIndex":       RepeatZeroTimes("a FindAll method", 1),
   141  	}
   142  
   143  	checkUTF8CutsetRules = map[string]CallCheck{
   144  		"strings.IndexAny":     utf8Cutset,
   145  		"strings.LastIndexAny": utf8Cutset,
   146  		"strings.ContainsAny":  utf8Cutset,
   147  		"strings.Trim":         utf8Cutset,
   148  		"strings.TrimLeft":     utf8Cutset,
   149  		"strings.TrimRight":    utf8Cutset,
   150  	}
   151  
   152  	checkUniqueCutsetRules = map[string]CallCheck{
   153  		"strings.Trim":      uniqueCutset,
   154  		"strings.TrimLeft":  uniqueCutset,
   155  		"strings.TrimRight": uniqueCutset,
   156  	}
   157  
   158  	checkUnmarshalPointerRules = map[string]CallCheck{
   159  		"encoding/xml.Unmarshal":                unmarshalPointer("xml.Unmarshal", 1),
   160  		"(*encoding/xml.Decoder).Decode":        unmarshalPointer("Decode", 0),
   161  		"(*encoding/xml.Decoder).DecodeElement": unmarshalPointer("DecodeElement", 0),
   162  		"encoding/json.Unmarshal":               unmarshalPointer("json.Unmarshal", 1),
   163  		"(*encoding/json.Decoder).Decode":       unmarshalPointer("Decode", 0),
   164  	}
   165  
   166  	checkUnbufferedSignalChanRules = map[string]CallCheck{
   167  		"os/signal.Notify": func(call *Call) {
   168  			arg := call.Args[Arg("os/signal.Notify.c")]
   169  			if UnbufferedChannel(arg.Value) {
   170  				arg.Invalid("the channel used with signal.Notify should be buffered")
   171  			}
   172  		},
   173  	}
   174  
   175  	checkMathIntRules = map[string]CallCheck{
   176  		"math.Ceil":  pointlessIntMath,
   177  		"math.Floor": pointlessIntMath,
   178  		"math.IsNaN": pointlessIntMath,
   179  		"math.Trunc": pointlessIntMath,
   180  		"math.IsInf": pointlessIntMath,
   181  	}
   182  
   183  	checkStringsReplaceZeroRules = map[string]CallCheck{
   184  		"strings.Replace": RepeatZeroTimes("strings.Replace", 3),
   185  		"bytes.Replace":   RepeatZeroTimes("bytes.Replace", 3),
   186  	}
   187  
   188  	checkListenAddressRules = map[string]CallCheck{
   189  		"net/http.ListenAndServe":    checkValidHostPort(0),
   190  		"net/http.ListenAndServeTLS": checkValidHostPort(0),
   191  	}
   192  
   193  	checkBytesEqualIPRules = map[string]CallCheck{
   194  		"bytes.Equal": func(call *Call) {
   195  			if ConvertedFrom(call.Args[Arg("bytes.Equal.a")].Value, "net.IP") &&
   196  				ConvertedFrom(call.Args[Arg("bytes.Equal.b")].Value, "net.IP") {
   197  				call.Invalid("use net.IP.Equal to compare net.IPs, not bytes.Equal")
   198  			}
   199  		},
   200  	}
   201  
   202  	checkRegexpMatchLoopRules = map[string]CallCheck{
   203  		"regexp.Match":       loopedRegexp("regexp.Match"),
   204  		"regexp.MatchReader": loopedRegexp("regexp.MatchReader"),
   205  		"regexp.MatchString": loopedRegexp("regexp.MatchString"),
   206  	}
   207  )
   208  
   209  type Checker struct {
   210  	CheckGenerated bool
   211  	funcDescs      *functions.Descriptions
   212  	deprecatedObjs map[types.Object]string
   213  }
   214  
   215  func NewChecker() *Checker {
   216  	return &Checker{}
   217  }
   218  
   219  func (*Checker) Name() string   { return "staticcheck" }
   220  func (*Checker) Prefix() string { return "SA" }
   221  
   222  func (c *Checker) Checks() []lint.Check {
   223  	return []lint.Check{
   224  		{ID: "SA1000", FilterGenerated: false, Fn: c.callChecker(checkRegexpRules)},
   225  		{ID: "SA1001", FilterGenerated: false, Fn: c.CheckTemplate},
   226  		{ID: "SA1002", FilterGenerated: false, Fn: c.callChecker(checkTimeParseRules)},
   227  		{ID: "SA1003", FilterGenerated: false, Fn: c.callChecker(checkEncodingBinaryRules)},
   228  		{ID: "SA1004", FilterGenerated: false, Fn: c.CheckTimeSleepConstant},
   229  		{ID: "SA1005", FilterGenerated: false, Fn: c.CheckExec},
   230  		{ID: "SA1006", FilterGenerated: false, Fn: c.CheckUnsafePrintf},
   231  		{ID: "SA1007", FilterGenerated: false, Fn: c.callChecker(checkURLsRules)},
   232  		{ID: "SA1008", FilterGenerated: false, Fn: c.CheckCanonicalHeaderKey},
   233  		{ID: "SA1010", FilterGenerated: false, Fn: c.callChecker(checkRegexpFindAllRules)},
   234  		{ID: "SA1011", FilterGenerated: false, Fn: c.callChecker(checkUTF8CutsetRules)},
   235  		{ID: "SA1012", FilterGenerated: false, Fn: c.CheckNilContext},
   236  		{ID: "SA1013", FilterGenerated: false, Fn: c.CheckSeeker},
   237  		{ID: "SA1014", FilterGenerated: false, Fn: c.callChecker(checkUnmarshalPointerRules)},
   238  		{ID: "SA1015", FilterGenerated: false, Fn: c.CheckLeakyTimeTick},
   239  		{ID: "SA1016", FilterGenerated: false, Fn: c.CheckUntrappableSignal},
   240  		{ID: "SA1017", FilterGenerated: false, Fn: c.callChecker(checkUnbufferedSignalChanRules)},
   241  		{ID: "SA1018", FilterGenerated: false, Fn: c.callChecker(checkStringsReplaceZeroRules)},
   242  		{ID: "SA1019", FilterGenerated: false, Fn: c.CheckDeprecated},
   243  		{ID: "SA1020", FilterGenerated: false, Fn: c.callChecker(checkListenAddressRules)},
   244  		{ID: "SA1021", FilterGenerated: false, Fn: c.callChecker(checkBytesEqualIPRules)},
   245  		{ID: "SA1023", FilterGenerated: false, Fn: c.CheckWriterBufferModified},
   246  		{ID: "SA1024", FilterGenerated: false, Fn: c.callChecker(checkUniqueCutsetRules)},
   247  		{ID: "SA1025", FilterGenerated: false, Fn: c.CheckTimerResetReturnValue},
   248  
   249  		{ID: "SA2000", FilterGenerated: false, Fn: c.CheckWaitgroupAdd},
   250  		{ID: "SA2001", FilterGenerated: false, Fn: c.CheckEmptyCriticalSection},
   251  		{ID: "SA2002", FilterGenerated: false, Fn: c.CheckConcurrentTesting},
   252  		{ID: "SA2003", FilterGenerated: false, Fn: c.CheckDeferLock},
   253  
   254  		{ID: "SA3000", FilterGenerated: false, Fn: c.CheckTestMainExit},
   255  		{ID: "SA3001", FilterGenerated: false, Fn: c.CheckBenchmarkN},
   256  
   257  		{ID: "SA4000", FilterGenerated: false, Fn: c.CheckLhsRhsIdentical},
   258  		{ID: "SA4001", FilterGenerated: false, Fn: c.CheckIneffectiveCopy},
   259  		{ID: "SA4002", FilterGenerated: false, Fn: c.CheckDiffSizeComparison},
   260  		{ID: "SA4003", FilterGenerated: false, Fn: c.CheckExtremeComparison},
   261  		{ID: "SA4004", FilterGenerated: false, Fn: c.CheckIneffectiveLoop},
   262  		{ID: "SA4006", FilterGenerated: false, Fn: c.CheckUnreadVariableValues},
   263  		{ID: "SA4008", FilterGenerated: false, Fn: c.CheckLoopCondition},
   264  		{ID: "SA4009", FilterGenerated: false, Fn: c.CheckArgOverwritten},
   265  		{ID: "SA4010", FilterGenerated: false, Fn: c.CheckIneffectiveAppend},
   266  		{ID: "SA4011", FilterGenerated: false, Fn: c.CheckScopedBreak},
   267  		{ID: "SA4012", FilterGenerated: false, Fn: c.CheckNaNComparison},
   268  		{ID: "SA4013", FilterGenerated: false, Fn: c.CheckDoubleNegation},
   269  		{ID: "SA4014", FilterGenerated: false, Fn: c.CheckRepeatedIfElse},
   270  		{ID: "SA4015", FilterGenerated: false, Fn: c.callChecker(checkMathIntRules)},
   271  		{ID: "SA4016", FilterGenerated: false, Fn: c.CheckSillyBitwiseOps},
   272  		{ID: "SA4017", FilterGenerated: false, Fn: c.CheckPureFunctions},
   273  		{ID: "SA4018", FilterGenerated: true, Fn: c.CheckSelfAssignment},
   274  		{ID: "SA4019", FilterGenerated: true, Fn: c.CheckDuplicateBuildConstraints},
   275  		{ID: "SA4020", FilterGenerated: false, Fn: c.CheckUnreachableTypeCases},
   276  
   277  		{ID: "SA5000", FilterGenerated: false, Fn: c.CheckNilMaps},
   278  		{ID: "SA5001", FilterGenerated: false, Fn: c.CheckEarlyDefer},
   279  		{ID: "SA5002", FilterGenerated: false, Fn: c.CheckInfiniteEmptyLoop},
   280  		{ID: "SA5003", FilterGenerated: false, Fn: c.CheckDeferInInfiniteLoop},
   281  		{ID: "SA5004", FilterGenerated: false, Fn: c.CheckLoopEmptyDefault},
   282  		{ID: "SA5005", FilterGenerated: false, Fn: c.CheckCyclicFinalizer},
   283  		{ID: "SA5007", FilterGenerated: false, Fn: c.CheckInfiniteRecursion},
   284  
   285  		{ID: "SA6000", FilterGenerated: false, Fn: c.callChecker(checkRegexpMatchLoopRules)},
   286  		{ID: "SA6001", FilterGenerated: false, Fn: c.CheckMapBytesKey},
   287  		{ID: "SA6002", FilterGenerated: false, Fn: c.callChecker(checkSyncPoolValueRules)},
   288  		{ID: "SA6003", FilterGenerated: false, Fn: c.CheckRangeStringRunes},
   289  		// {ID: "SA6004", FilterGenerated: false, Fn: c.CheckSillyRegexp},
   290  		{ID: "SA6005", FilterGenerated: false, Fn: c.CheckToLowerToUpperComparison},
   291  
   292  		{ID: "SA9001", FilterGenerated: false, Fn: c.CheckDubiousDeferInChannelRangeLoop},
   293  		{ID: "SA9002", FilterGenerated: false, Fn: c.CheckNonOctalFileMode},
   294  		{ID: "SA9003", FilterGenerated: false, Fn: c.CheckEmptyBranch},
   295  		{ID: "SA9004", FilterGenerated: false, Fn: c.CheckMissingEnumTypesInDeclaration},
   296  	}
   297  
   298  	// "SA5006": c.CheckSliceOutOfBounds,
   299  	// "SA4007": c.CheckPredeterminedBooleanExprs,
   300  }
   301  
   302  func (c *Checker) findDeprecated(prog *lint.Program) {
   303  	var docs []*ast.CommentGroup
   304  	var names []*ast.Ident
   305  
   306  	doDocs := func(pkg *packages.Package, names []*ast.Ident, docs []*ast.CommentGroup) {
   307  		var alt string
   308  		for _, doc := range docs {
   309  			if doc == nil {
   310  				continue
   311  			}
   312  			parts := strings.Split(doc.Text(), "\n\n")
   313  			last := parts[len(parts)-1]
   314  			if !strings.HasPrefix(last, "Deprecated: ") {
   315  				continue
   316  			}
   317  			alt = last[len("Deprecated: "):]
   318  			alt = strings.Replace(alt, "\n", " ", -1)
   319  			break
   320  		}
   321  		if alt == "" {
   322  			return
   323  		}
   324  
   325  		for _, name := range names {
   326  			obj := pkg.TypesInfo.ObjectOf(name)
   327  			c.deprecatedObjs[obj] = alt
   328  		}
   329  	}
   330  
   331  	for _, pkg := range prog.AllPackages {
   332  		for _, f := range pkg.Syntax {
   333  			fn := func(node ast.Node) bool {
   334  				if node == nil {
   335  					return true
   336  				}
   337  				var ret bool
   338  				switch node := node.(type) {
   339  				case *ast.GenDecl:
   340  					switch node.Tok {
   341  					case token.TYPE, token.CONST, token.VAR:
   342  						docs = append(docs, node.Doc)
   343  						return true
   344  					default:
   345  						return false
   346  					}
   347  				case *ast.FuncDecl:
   348  					docs = append(docs, node.Doc)
   349  					names = []*ast.Ident{node.Name}
   350  					ret = false
   351  				case *ast.TypeSpec:
   352  					docs = append(docs, node.Doc)
   353  					names = []*ast.Ident{node.Name}
   354  					ret = true
   355  				case *ast.ValueSpec:
   356  					docs = append(docs, node.Doc)
   357  					names = node.Names
   358  					ret = false
   359  				case *ast.File:
   360  					return true
   361  				case *ast.StructType:
   362  					for _, field := range node.Fields.List {
   363  						doDocs(pkg, field.Names, []*ast.CommentGroup{field.Doc})
   364  					}
   365  					return false
   366  				case *ast.InterfaceType:
   367  					for _, field := range node.Methods.List {
   368  						doDocs(pkg, field.Names, []*ast.CommentGroup{field.Doc})
   369  					}
   370  					return false
   371  				default:
   372  					return false
   373  				}
   374  				if len(names) == 0 || len(docs) == 0 {
   375  					return ret
   376  				}
   377  				doDocs(pkg, names, docs)
   378  
   379  				docs = docs[:0]
   380  				names = nil
   381  				return ret
   382  			}
   383  			ast.Inspect(f, fn)
   384  		}
   385  	}
   386  }
   387  
   388  func (c *Checker) Init(prog *lint.Program) {
   389  	wg := &sync.WaitGroup{}
   390  	wg.Add(2)
   391  	go func() {
   392  		c.funcDescs = functions.NewDescriptions(prog.SSA)
   393  		for _, fn := range prog.AllFunctions {
   394  			if fn.Blocks != nil {
   395  				applyStdlibKnowledge(fn)
   396  				ssa.OptimizeBlocks(fn)
   397  			}
   398  		}
   399  		wg.Done()
   400  	}()
   401  
   402  	go func() {
   403  		c.deprecatedObjs = map[types.Object]string{}
   404  		c.findDeprecated(prog)
   405  		wg.Done()
   406  	}()
   407  
   408  	wg.Wait()
   409  }
   410  
   411  func (c *Checker) isInLoop(b *ssa.BasicBlock) bool {
   412  	sets := c.funcDescs.Get(b.Parent()).Loops
   413  	for _, set := range sets {
   414  		if set[b] {
   415  			return true
   416  		}
   417  	}
   418  	return false
   419  }
   420  
   421  func applyStdlibKnowledge(fn *ssa.Function) {
   422  	if len(fn.Blocks) == 0 {
   423  		return
   424  	}
   425  
   426  	// comma-ok receiving from a time.Tick channel will never return
   427  	// ok == false, so any branching on the value of ok can be
   428  	// replaced with an unconditional jump. This will primarily match
   429  	// `for range time.Tick(x)` loops, but it can also match
   430  	// user-written code.
   431  	for _, block := range fn.Blocks {
   432  		if len(block.Instrs) < 3 {
   433  			continue
   434  		}
   435  		if len(block.Succs) != 2 {
   436  			continue
   437  		}
   438  		var instrs []*ssa.Instruction
   439  		for i, ins := range block.Instrs {
   440  			if _, ok := ins.(*ssa.DebugRef); ok {
   441  				continue
   442  			}
   443  			instrs = append(instrs, &block.Instrs[i])
   444  		}
   445  
   446  		for i, ins := range instrs {
   447  			unop, ok := (*ins).(*ssa.UnOp)
   448  			if !ok || unop.Op != token.ARROW {
   449  				continue
   450  			}
   451  			call, ok := unop.X.(*ssa.Call)
   452  			if !ok {
   453  				continue
   454  			}
   455  			if !IsCallTo(call.Common(), "time.Tick") {
   456  				continue
   457  			}
   458  			ex, ok := (*instrs[i+1]).(*ssa.Extract)
   459  			if !ok || ex.Tuple != unop || ex.Index != 1 {
   460  				continue
   461  			}
   462  
   463  			ifstmt, ok := (*instrs[i+2]).(*ssa.If)
   464  			if !ok || ifstmt.Cond != ex {
   465  				continue
   466  			}
   467  
   468  			*instrs[i+2] = ssa.NewJump(block)
   469  			succ := block.Succs[1]
   470  			block.Succs = block.Succs[0:1]
   471  			succ.RemovePred(block)
   472  		}
   473  	}
   474  }
   475  
   476  func hasType(j *lint.Job, expr ast.Expr, name string) bool {
   477  	T := TypeOf(j, expr)
   478  	return IsType(T, name)
   479  }
   480  
   481  func (c *Checker) CheckUntrappableSignal(j *lint.Job) {
   482  	fn := func(node ast.Node) bool {
   483  		call, ok := node.(*ast.CallExpr)
   484  		if !ok {
   485  			return true
   486  		}
   487  		if !IsCallToAnyAST(j, call,
   488  			"os/signal.Ignore", "os/signal.Notify", "os/signal.Reset") {
   489  			return true
   490  		}
   491  		for _, arg := range call.Args {
   492  			if conv, ok := arg.(*ast.CallExpr); ok && isName(j, conv.Fun, "os.Signal") {
   493  				arg = conv.Args[0]
   494  			}
   495  
   496  			if isName(j, arg, "os.Kill") || isName(j, arg, "syscall.SIGKILL") {
   497  				j.Errorf(arg, "%s cannot be trapped (did you mean syscall.SIGTERM?)", Render(j, arg))
   498  			}
   499  			if isName(j, arg, "syscall.SIGSTOP") {
   500  				j.Errorf(arg, "%s signal cannot be trapped", Render(j, arg))
   501  			}
   502  		}
   503  		return true
   504  	}
   505  	for _, f := range j.Program.Files {
   506  		ast.Inspect(f, fn)
   507  	}
   508  }
   509  
   510  func (c *Checker) CheckTemplate(j *lint.Job) {
   511  	fn := func(node ast.Node) bool {
   512  		call, ok := node.(*ast.CallExpr)
   513  		if !ok {
   514  			return true
   515  		}
   516  		var kind string
   517  		if IsCallToAST(j, call, "(*text/template.Template).Parse") {
   518  			kind = "text"
   519  		} else if IsCallToAST(j, call, "(*html/template.Template).Parse") {
   520  			kind = "html"
   521  		} else {
   522  			return true
   523  		}
   524  		sel := call.Fun.(*ast.SelectorExpr)
   525  		if !IsCallToAST(j, sel.X, "text/template.New") &&
   526  			!IsCallToAST(j, sel.X, "html/template.New") {
   527  			// TODO(dh): this is a cheap workaround for templates with
   528  			// different delims. A better solution with less false
   529  			// negatives would use data flow analysis to see where the
   530  			// template comes from and where it has been
   531  			return true
   532  		}
   533  		s, ok := ExprToString(j, call.Args[Arg("(*text/template.Template).Parse.text")])
   534  		if !ok {
   535  			return true
   536  		}
   537  		var err error
   538  		switch kind {
   539  		case "text":
   540  			_, err = texttemplate.New("").Parse(s)
   541  		case "html":
   542  			_, err = htmltemplate.New("").Parse(s)
   543  		}
   544  		if err != nil {
   545  			// TODO(dominikh): whitelist other parse errors, if any
   546  			if strings.Contains(err.Error(), "unexpected") {
   547  				j.Errorf(call.Args[Arg("(*text/template.Template).Parse.text")], "%s", err)
   548  			}
   549  		}
   550  		return true
   551  	}
   552  	for _, f := range j.Program.Files {
   553  		ast.Inspect(f, fn)
   554  	}
   555  }
   556  
   557  func (c *Checker) CheckTimeSleepConstant(j *lint.Job) {
   558  	fn := func(node ast.Node) bool {
   559  		call, ok := node.(*ast.CallExpr)
   560  		if !ok {
   561  			return true
   562  		}
   563  		if !IsCallToAST(j, call, "time.Sleep") {
   564  			return true
   565  		}
   566  		lit, ok := call.Args[Arg("time.Sleep.d")].(*ast.BasicLit)
   567  		if !ok {
   568  			return true
   569  		}
   570  		n, err := strconv.Atoi(lit.Value)
   571  		if err != nil {
   572  			return true
   573  		}
   574  		if n == 0 || n > 120 {
   575  			// time.Sleep(0) is a seldom used pattern in concurrency
   576  			// tests. >120 might be intentional. 120 was chosen
   577  			// because the user could've meant 2 minutes.
   578  			return true
   579  		}
   580  		recommendation := "time.Sleep(time.Nanosecond)"
   581  		if n != 1 {
   582  			recommendation = fmt.Sprintf("time.Sleep(%d * time.Nanosecond)", n)
   583  		}
   584  		j.Errorf(call.Args[Arg("time.Sleep.d")],
   585  			"sleeping for %d nanoseconds is probably a bug. Be explicit if it isn't: %s", n, recommendation)
   586  		return true
   587  	}
   588  	for _, f := range j.Program.Files {
   589  		ast.Inspect(f, fn)
   590  	}
   591  }
   592  
   593  func (c *Checker) CheckWaitgroupAdd(j *lint.Job) {
   594  	fn := func(node ast.Node) bool {
   595  		g, ok := node.(*ast.GoStmt)
   596  		if !ok {
   597  			return true
   598  		}
   599  		fun, ok := g.Call.Fun.(*ast.FuncLit)
   600  		if !ok {
   601  			return true
   602  		}
   603  		if len(fun.Body.List) == 0 {
   604  			return true
   605  		}
   606  		stmt, ok := fun.Body.List[0].(*ast.ExprStmt)
   607  		if !ok {
   608  			return true
   609  		}
   610  		call, ok := stmt.X.(*ast.CallExpr)
   611  		if !ok {
   612  			return true
   613  		}
   614  		sel, ok := call.Fun.(*ast.SelectorExpr)
   615  		if !ok {
   616  			return true
   617  		}
   618  		fn, ok := ObjectOf(j, sel.Sel).(*types.Func)
   619  		if !ok {
   620  			return true
   621  		}
   622  		if fn.FullName() == "(*sync.WaitGroup).Add" {
   623  			j.Errorf(sel, "should call %s before starting the goroutine to avoid a race",
   624  				Render(j, stmt))
   625  		}
   626  		return true
   627  	}
   628  	for _, f := range j.Program.Files {
   629  		ast.Inspect(f, fn)
   630  	}
   631  }
   632  
   633  func (c *Checker) CheckInfiniteEmptyLoop(j *lint.Job) {
   634  	fn := func(node ast.Node) bool {
   635  		loop, ok := node.(*ast.ForStmt)
   636  		if !ok || len(loop.Body.List) != 0 || loop.Post != nil {
   637  			return true
   638  		}
   639  
   640  		if loop.Init != nil {
   641  			// TODO(dh): this isn't strictly necessary, it just makes
   642  			// the check easier.
   643  			return true
   644  		}
   645  		// An empty loop is bad news in two cases: 1) The loop has no
   646  		// condition. In that case, it's just a loop that spins
   647  		// forever and as fast as it can, keeping a core busy. 2) The
   648  		// loop condition only consists of variable or field reads and
   649  		// operators on those. The only way those could change their
   650  		// value is with unsynchronised access, which constitutes a
   651  		// data race.
   652  		//
   653  		// If the condition contains any function calls, its behaviour
   654  		// is dynamic and the loop might terminate. Similarly for
   655  		// channel receives.
   656  
   657  		if loop.Cond != nil {
   658  			if hasSideEffects(loop.Cond) {
   659  				return true
   660  			}
   661  			if ident, ok := loop.Cond.(*ast.Ident); ok {
   662  				if k, ok := ObjectOf(j, ident).(*types.Const); ok {
   663  					if !constant.BoolVal(k.Val()) {
   664  						// don't flag `for false {}` loops. They're a debug aid.
   665  						return true
   666  					}
   667  				}
   668  			}
   669  			j.Errorf(loop, "loop condition never changes or has a race condition")
   670  		}
   671  		j.Errorf(loop, "this loop will spin, using 100%% CPU")
   672  
   673  		return true
   674  	}
   675  	for _, f := range j.Program.Files {
   676  		ast.Inspect(f, fn)
   677  	}
   678  }
   679  
   680  func (c *Checker) CheckDeferInInfiniteLoop(j *lint.Job) {
   681  	fn := func(node ast.Node) bool {
   682  		mightExit := false
   683  		var defers []ast.Stmt
   684  		loop, ok := node.(*ast.ForStmt)
   685  		if !ok || loop.Cond != nil {
   686  			return true
   687  		}
   688  		fn2 := func(node ast.Node) bool {
   689  			switch stmt := node.(type) {
   690  			case *ast.ReturnStmt:
   691  				mightExit = true
   692  			case *ast.BranchStmt:
   693  				// TODO(dominikh): if this sees a break in a switch or
   694  				// select, it doesn't check if it breaks the loop or
   695  				// just the select/switch. This causes some false
   696  				// negatives.
   697  				if stmt.Tok == token.BREAK {
   698  					mightExit = true
   699  				}
   700  			case *ast.DeferStmt:
   701  				defers = append(defers, stmt)
   702  			case *ast.FuncLit:
   703  				// Don't look into function bodies
   704  				return false
   705  			}
   706  			return true
   707  		}
   708  		ast.Inspect(loop.Body, fn2)
   709  		if mightExit {
   710  			return true
   711  		}
   712  		for _, stmt := range defers {
   713  			j.Errorf(stmt, "defers in this infinite loop will never run")
   714  		}
   715  		return true
   716  	}
   717  	for _, f := range j.Program.Files {
   718  		ast.Inspect(f, fn)
   719  	}
   720  }
   721  
   722  func (c *Checker) CheckDubiousDeferInChannelRangeLoop(j *lint.Job) {
   723  	fn := func(node ast.Node) bool {
   724  		loop, ok := node.(*ast.RangeStmt)
   725  		if !ok {
   726  			return true
   727  		}
   728  		typ := TypeOf(j, loop.X)
   729  		_, ok = typ.Underlying().(*types.Chan)
   730  		if !ok {
   731  			return true
   732  		}
   733  		fn2 := func(node ast.Node) bool {
   734  			switch stmt := node.(type) {
   735  			case *ast.DeferStmt:
   736  				j.Errorf(stmt, "defers in this range loop won't run unless the channel gets closed")
   737  			case *ast.FuncLit:
   738  				// Don't look into function bodies
   739  				return false
   740  			}
   741  			return true
   742  		}
   743  		ast.Inspect(loop.Body, fn2)
   744  		return true
   745  	}
   746  	for _, f := range j.Program.Files {
   747  		ast.Inspect(f, fn)
   748  	}
   749  }
   750  
   751  func (c *Checker) CheckTestMainExit(j *lint.Job) {
   752  	fn := func(node ast.Node) bool {
   753  		if !isTestMain(j, node) {
   754  			return true
   755  		}
   756  
   757  		arg := ObjectOf(j, node.(*ast.FuncDecl).Type.Params.List[0].Names[0])
   758  		callsRun := false
   759  		fn2 := func(node ast.Node) bool {
   760  			call, ok := node.(*ast.CallExpr)
   761  			if !ok {
   762  				return true
   763  			}
   764  			sel, ok := call.Fun.(*ast.SelectorExpr)
   765  			if !ok {
   766  				return true
   767  			}
   768  			ident, ok := sel.X.(*ast.Ident)
   769  			if !ok {
   770  				return true
   771  			}
   772  			if arg != ObjectOf(j, ident) {
   773  				return true
   774  			}
   775  			if sel.Sel.Name == "Run" {
   776  				callsRun = true
   777  				return false
   778  			}
   779  			return true
   780  		}
   781  		ast.Inspect(node.(*ast.FuncDecl).Body, fn2)
   782  
   783  		callsExit := false
   784  		fn3 := func(node ast.Node) bool {
   785  			if IsCallToAST(j, node, "os.Exit") {
   786  				callsExit = true
   787  				return false
   788  			}
   789  			return true
   790  		}
   791  		ast.Inspect(node.(*ast.FuncDecl).Body, fn3)
   792  		if !callsExit && callsRun {
   793  			j.Errorf(node, "TestMain should call os.Exit to set exit code")
   794  		}
   795  		return true
   796  	}
   797  	for _, f := range j.Program.Files {
   798  		ast.Inspect(f, fn)
   799  	}
   800  }
   801  
   802  func isTestMain(j *lint.Job, node ast.Node) bool {
   803  	decl, ok := node.(*ast.FuncDecl)
   804  	if !ok {
   805  		return false
   806  	}
   807  	if decl.Name.Name != "TestMain" {
   808  		return false
   809  	}
   810  	if len(decl.Type.Params.List) != 1 {
   811  		return false
   812  	}
   813  	arg := decl.Type.Params.List[0]
   814  	if len(arg.Names) != 1 {
   815  		return false
   816  	}
   817  	return IsOfType(j, arg.Type, "*testing.M")
   818  }
   819  
   820  func (c *Checker) CheckExec(j *lint.Job) {
   821  	fn := func(node ast.Node) bool {
   822  		call, ok := node.(*ast.CallExpr)
   823  		if !ok {
   824  			return true
   825  		}
   826  		if !IsCallToAST(j, call, "os/exec.Command") {
   827  			return true
   828  		}
   829  		val, ok := ExprToString(j, call.Args[Arg("os/exec.Command.name")])
   830  		if !ok {
   831  			return true
   832  		}
   833  		if !strings.Contains(val, " ") || strings.Contains(val, `\`) || strings.Contains(val, "/") {
   834  			return true
   835  		}
   836  		j.Errorf(call.Args[Arg("os/exec.Command.name")],
   837  			"first argument to exec.Command looks like a shell command, but a program name or path are expected")
   838  		return true
   839  	}
   840  	for _, f := range j.Program.Files {
   841  		ast.Inspect(f, fn)
   842  	}
   843  }
   844  
   845  func (c *Checker) CheckLoopEmptyDefault(j *lint.Job) {
   846  	fn := func(node ast.Node) bool {
   847  		loop, ok := node.(*ast.ForStmt)
   848  		if !ok || len(loop.Body.List) != 1 || loop.Cond != nil || loop.Init != nil {
   849  			return true
   850  		}
   851  		sel, ok := loop.Body.List[0].(*ast.SelectStmt)
   852  		if !ok {
   853  			return true
   854  		}
   855  		for _, c := range sel.Body.List {
   856  			if comm, ok := c.(*ast.CommClause); ok && comm.Comm == nil && len(comm.Body) == 0 {
   857  				j.Errorf(comm, "should not have an empty default case in a for+select loop. The loop will spin.")
   858  			}
   859  		}
   860  		return true
   861  	}
   862  	for _, f := range j.Program.Files {
   863  		ast.Inspect(f, fn)
   864  	}
   865  }
   866  
   867  func (c *Checker) CheckLhsRhsIdentical(j *lint.Job) {
   868  	fn := func(node ast.Node) bool {
   869  		op, ok := node.(*ast.BinaryExpr)
   870  		if !ok {
   871  			return true
   872  		}
   873  		switch op.Op {
   874  		case token.EQL, token.NEQ:
   875  			if basic, ok := TypeOf(j, op.X).Underlying().(*types.Basic); ok {
   876  				if kind := basic.Kind(); kind == types.Float32 || kind == types.Float64 {
   877  					// f == f and f != f might be used to check for NaN
   878  					return true
   879  				}
   880  			}
   881  		case token.SUB, token.QUO, token.AND, token.REM, token.OR, token.XOR, token.AND_NOT,
   882  			token.LAND, token.LOR, token.LSS, token.GTR, token.LEQ, token.GEQ:
   883  		default:
   884  			// For some ops, such as + and *, it can make sense to
   885  			// have identical operands
   886  			return true
   887  		}
   888  
   889  		if Render(j, op.X) != Render(j, op.Y) {
   890  			return true
   891  		}
   892  		j.Errorf(op, "identical expressions on the left and right side of the '%s' operator", op.Op)
   893  		return true
   894  	}
   895  	for _, f := range j.Program.Files {
   896  		ast.Inspect(f, fn)
   897  	}
   898  }
   899  
   900  func (c *Checker) CheckScopedBreak(j *lint.Job) {
   901  	fn := func(node ast.Node) bool {
   902  		var body *ast.BlockStmt
   903  		switch node := node.(type) {
   904  		case *ast.ForStmt:
   905  			body = node.Body
   906  		case *ast.RangeStmt:
   907  			body = node.Body
   908  		default:
   909  			return true
   910  		}
   911  		for _, stmt := range body.List {
   912  			var blocks [][]ast.Stmt
   913  			switch stmt := stmt.(type) {
   914  			case *ast.SwitchStmt:
   915  				for _, c := range stmt.Body.List {
   916  					blocks = append(blocks, c.(*ast.CaseClause).Body)
   917  				}
   918  			case *ast.SelectStmt:
   919  				for _, c := range stmt.Body.List {
   920  					blocks = append(blocks, c.(*ast.CommClause).Body)
   921  				}
   922  			default:
   923  				continue
   924  			}
   925  
   926  			for _, body := range blocks {
   927  				if len(body) == 0 {
   928  					continue
   929  				}
   930  				lasts := []ast.Stmt{body[len(body)-1]}
   931  				// TODO(dh): unfold all levels of nested block
   932  				// statements, not just a single level if statement
   933  				if ifs, ok := lasts[0].(*ast.IfStmt); ok {
   934  					if len(ifs.Body.List) == 0 {
   935  						continue
   936  					}
   937  					lasts[0] = ifs.Body.List[len(ifs.Body.List)-1]
   938  
   939  					if block, ok := ifs.Else.(*ast.BlockStmt); ok {
   940  						if len(block.List) != 0 {
   941  							lasts = append(lasts, block.List[len(block.List)-1])
   942  						}
   943  					}
   944  				}
   945  				for _, last := range lasts {
   946  					branch, ok := last.(*ast.BranchStmt)
   947  					if !ok || branch.Tok != token.BREAK || branch.Label != nil {
   948  						continue
   949  					}
   950  					j.Errorf(branch, "ineffective break statement. Did you mean to break out of the outer loop?")
   951  				}
   952  			}
   953  		}
   954  		return true
   955  	}
   956  	for _, f := range j.Program.Files {
   957  		ast.Inspect(f, fn)
   958  	}
   959  }
   960  
   961  func (c *Checker) CheckUnsafePrintf(j *lint.Job) {
   962  	fn := func(node ast.Node) bool {
   963  		call, ok := node.(*ast.CallExpr)
   964  		if !ok {
   965  			return true
   966  		}
   967  		var arg int
   968  		if IsCallToAnyAST(j, call, "fmt.Printf", "fmt.Sprintf", "log.Printf") {
   969  			arg = Arg("fmt.Printf.format")
   970  		} else if IsCallToAnyAST(j, call, "fmt.Fprintf") {
   971  			arg = Arg("fmt.Fprintf.format")
   972  		} else {
   973  			return true
   974  		}
   975  		if len(call.Args) != arg+1 {
   976  			return true
   977  		}
   978  		switch call.Args[arg].(type) {
   979  		case *ast.CallExpr, *ast.Ident:
   980  		default:
   981  			return true
   982  		}
   983  		j.Errorf(call.Args[arg],
   984  			"printf-style function with dynamic format string and no further arguments should use print-style function instead")
   985  		return true
   986  	}
   987  	for _, f := range j.Program.Files {
   988  		ast.Inspect(f, fn)
   989  	}
   990  }
   991  
   992  func (c *Checker) CheckEarlyDefer(j *lint.Job) {
   993  	fn := func(node ast.Node) bool {
   994  		block, ok := node.(*ast.BlockStmt)
   995  		if !ok {
   996  			return true
   997  		}
   998  		if len(block.List) < 2 {
   999  			return true
  1000  		}
  1001  		for i, stmt := range block.List {
  1002  			if i == len(block.List)-1 {
  1003  				break
  1004  			}
  1005  			assign, ok := stmt.(*ast.AssignStmt)
  1006  			if !ok {
  1007  				continue
  1008  			}
  1009  			if len(assign.Rhs) != 1 {
  1010  				continue
  1011  			}
  1012  			if len(assign.Lhs) < 2 {
  1013  				continue
  1014  			}
  1015  			if lhs, ok := assign.Lhs[len(assign.Lhs)-1].(*ast.Ident); ok && lhs.Name == "_" {
  1016  				continue
  1017  			}
  1018  			call, ok := assign.Rhs[0].(*ast.CallExpr)
  1019  			if !ok {
  1020  				continue
  1021  			}
  1022  			sig, ok := TypeOf(j, call.Fun).(*types.Signature)
  1023  			if !ok {
  1024  				continue
  1025  			}
  1026  			if sig.Results().Len() < 2 {
  1027  				continue
  1028  			}
  1029  			last := sig.Results().At(sig.Results().Len() - 1)
  1030  			// FIXME(dh): check that it's error from universe, not
  1031  			// another type of the same name
  1032  			if last.Type().String() != "error" {
  1033  				continue
  1034  			}
  1035  			lhs, ok := assign.Lhs[0].(*ast.Ident)
  1036  			if !ok {
  1037  				continue
  1038  			}
  1039  			def, ok := block.List[i+1].(*ast.DeferStmt)
  1040  			if !ok {
  1041  				continue
  1042  			}
  1043  			sel, ok := def.Call.Fun.(*ast.SelectorExpr)
  1044  			if !ok {
  1045  				continue
  1046  			}
  1047  			ident, ok := selectorX(sel).(*ast.Ident)
  1048  			if !ok {
  1049  				continue
  1050  			}
  1051  			if ident.Obj != lhs.Obj {
  1052  				continue
  1053  			}
  1054  			if sel.Sel.Name != "Close" {
  1055  				continue
  1056  			}
  1057  			j.Errorf(def, "should check returned error before deferring %s", Render(j, def.Call))
  1058  		}
  1059  		return true
  1060  	}
  1061  	for _, f := range j.Program.Files {
  1062  		ast.Inspect(f, fn)
  1063  	}
  1064  }
  1065  
  1066  func selectorX(sel *ast.SelectorExpr) ast.Node {
  1067  	switch x := sel.X.(type) {
  1068  	case *ast.SelectorExpr:
  1069  		return selectorX(x)
  1070  	default:
  1071  		return x
  1072  	}
  1073  }
  1074  
  1075  func (c *Checker) CheckEmptyCriticalSection(j *lint.Job) {
  1076  	// Initially it might seem like this check would be easier to
  1077  	// implement in SSA. After all, we're only checking for two
  1078  	// consecutive method calls. In reality, however, there may be any
  1079  	// number of other instructions between the lock and unlock, while
  1080  	// still constituting an empty critical section. For example,
  1081  	// given `m.x().Lock(); m.x().Unlock()`, there will be a call to
  1082  	// x(). In the AST-based approach, this has a tiny potential for a
  1083  	// false positive (the second call to x might be doing work that
  1084  	// is protected by the mutex). In an SSA-based approach, however,
  1085  	// it would miss a lot of real bugs.
  1086  
  1087  	mutexParams := func(s ast.Stmt) (x ast.Expr, funcName string, ok bool) {
  1088  		expr, ok := s.(*ast.ExprStmt)
  1089  		if !ok {
  1090  			return nil, "", false
  1091  		}
  1092  		call, ok := expr.X.(*ast.CallExpr)
  1093  		if !ok {
  1094  			return nil, "", false
  1095  		}
  1096  		sel, ok := call.Fun.(*ast.SelectorExpr)
  1097  		if !ok {
  1098  			return nil, "", false
  1099  		}
  1100  
  1101  		fn, ok := ObjectOf(j, sel.Sel).(*types.Func)
  1102  		if !ok {
  1103  			return nil, "", false
  1104  		}
  1105  		sig := fn.Type().(*types.Signature)
  1106  		if sig.Params().Len() != 0 || sig.Results().Len() != 0 {
  1107  			return nil, "", false
  1108  		}
  1109  
  1110  		return sel.X, fn.Name(), true
  1111  	}
  1112  
  1113  	fn := func(node ast.Node) bool {
  1114  		block, ok := node.(*ast.BlockStmt)
  1115  		if !ok {
  1116  			return true
  1117  		}
  1118  		if len(block.List) < 2 {
  1119  			return true
  1120  		}
  1121  		for i := range block.List[:len(block.List)-1] {
  1122  			sel1, method1, ok1 := mutexParams(block.List[i])
  1123  			sel2, method2, ok2 := mutexParams(block.List[i+1])
  1124  
  1125  			if !ok1 || !ok2 || Render(j, sel1) != Render(j, sel2) {
  1126  				continue
  1127  			}
  1128  			if (method1 == "Lock" && method2 == "Unlock") ||
  1129  				(method1 == "RLock" && method2 == "RUnlock") {
  1130  				j.Errorf(block.List[i+1], "empty critical section")
  1131  			}
  1132  		}
  1133  		return true
  1134  	}
  1135  	for _, f := range j.Program.Files {
  1136  		ast.Inspect(f, fn)
  1137  	}
  1138  }
  1139  
  1140  // cgo produces code like fn(&*_Cvar_kSomeCallbacks) which we don't
  1141  // want to flag.
  1142  var cgoIdent = regexp.MustCompile(`^_C(func|var)_.+$`)
  1143  
  1144  func (c *Checker) CheckIneffectiveCopy(j *lint.Job) {
  1145  	fn := func(node ast.Node) bool {
  1146  		if unary, ok := node.(*ast.UnaryExpr); ok {
  1147  			if star, ok := unary.X.(*ast.StarExpr); ok && unary.Op == token.AND {
  1148  				ident, ok := star.X.(*ast.Ident)
  1149  				if !ok || !cgoIdent.MatchString(ident.Name) {
  1150  					j.Errorf(unary, "&*x will be simplified to x. It will not copy x.")
  1151  				}
  1152  			}
  1153  		}
  1154  
  1155  		if star, ok := node.(*ast.StarExpr); ok {
  1156  			if unary, ok := star.X.(*ast.UnaryExpr); ok && unary.Op == token.AND {
  1157  				j.Errorf(star, "*&x will be simplified to x. It will not copy x.")
  1158  			}
  1159  		}
  1160  		return true
  1161  	}
  1162  	for _, f := range j.Program.Files {
  1163  		ast.Inspect(f, fn)
  1164  	}
  1165  }
  1166  
  1167  func (c *Checker) CheckDiffSizeComparison(j *lint.Job) {
  1168  	for _, ssafn := range j.Program.InitialFunctions {
  1169  		for _, b := range ssafn.Blocks {
  1170  			for _, ins := range b.Instrs {
  1171  				binop, ok := ins.(*ssa.BinOp)
  1172  				if !ok {
  1173  					continue
  1174  				}
  1175  				if binop.Op != token.EQL && binop.Op != token.NEQ {
  1176  					continue
  1177  				}
  1178  				_, ok1 := binop.X.(*ssa.Slice)
  1179  				_, ok2 := binop.Y.(*ssa.Slice)
  1180  				if !ok1 && !ok2 {
  1181  					continue
  1182  				}
  1183  				r := c.funcDescs.Get(ssafn).Ranges
  1184  				r1, ok1 := r.Get(binop.X).(vrp.StringInterval)
  1185  				r2, ok2 := r.Get(binop.Y).(vrp.StringInterval)
  1186  				if !ok1 || !ok2 {
  1187  					continue
  1188  				}
  1189  				if r1.Length.Intersection(r2.Length).Empty() {
  1190  					j.Errorf(binop, "comparing strings of different sizes for equality will always return false")
  1191  				}
  1192  			}
  1193  		}
  1194  	}
  1195  }
  1196  
  1197  func (c *Checker) CheckCanonicalHeaderKey(j *lint.Job) {
  1198  	fn := func(node ast.Node) bool {
  1199  		assign, ok := node.(*ast.AssignStmt)
  1200  		if ok {
  1201  			// TODO(dh): This risks missing some Header reads, for
  1202  			// example in `h1["foo"] = h2["foo"]` – these edge
  1203  			// cases are probably rare enough to ignore for now.
  1204  			for _, expr := range assign.Lhs {
  1205  				op, ok := expr.(*ast.IndexExpr)
  1206  				if !ok {
  1207  					continue
  1208  				}
  1209  				if hasType(j, op.X, "net/http.Header") {
  1210  					return false
  1211  				}
  1212  			}
  1213  			return true
  1214  		}
  1215  		op, ok := node.(*ast.IndexExpr)
  1216  		if !ok {
  1217  			return true
  1218  		}
  1219  		if !hasType(j, op.X, "net/http.Header") {
  1220  			return true
  1221  		}
  1222  		s, ok := ExprToString(j, op.Index)
  1223  		if !ok {
  1224  			return true
  1225  		}
  1226  		if s == http.CanonicalHeaderKey(s) {
  1227  			return true
  1228  		}
  1229  		j.Errorf(op, "keys in http.Header are canonicalized, %q is not canonical; fix the constant or use http.CanonicalHeaderKey", s)
  1230  		return true
  1231  	}
  1232  	for _, f := range j.Program.Files {
  1233  		ast.Inspect(f, fn)
  1234  	}
  1235  }
  1236  
  1237  func (c *Checker) CheckBenchmarkN(j *lint.Job) {
  1238  	fn := func(node ast.Node) bool {
  1239  		assign, ok := node.(*ast.AssignStmt)
  1240  		if !ok {
  1241  			return true
  1242  		}
  1243  		if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
  1244  			return true
  1245  		}
  1246  		sel, ok := assign.Lhs[0].(*ast.SelectorExpr)
  1247  		if !ok {
  1248  			return true
  1249  		}
  1250  		if sel.Sel.Name != "N" {
  1251  			return true
  1252  		}
  1253  		if !hasType(j, sel.X, "*testing.B") {
  1254  			return true
  1255  		}
  1256  		j.Errorf(assign, "should not assign to %s", Render(j, sel))
  1257  		return true
  1258  	}
  1259  	for _, f := range j.Program.Files {
  1260  		ast.Inspect(f, fn)
  1261  	}
  1262  }
  1263  
  1264  func (c *Checker) CheckUnreadVariableValues(j *lint.Job) {
  1265  	for _, ssafn := range j.Program.InitialFunctions {
  1266  		if IsExample(ssafn) {
  1267  			continue
  1268  		}
  1269  		node := ssafn.Syntax()
  1270  		if node == nil {
  1271  			continue
  1272  		}
  1273  
  1274  		ast.Inspect(node, func(node ast.Node) bool {
  1275  			assign, ok := node.(*ast.AssignStmt)
  1276  			if !ok {
  1277  				return true
  1278  			}
  1279  			if len(assign.Lhs) > 1 && len(assign.Rhs) == 1 {
  1280  				// Either a function call with multiple return values,
  1281  				// or a comma-ok assignment
  1282  
  1283  				val, _ := ssafn.ValueForExpr(assign.Rhs[0])
  1284  				if val == nil {
  1285  					return true
  1286  				}
  1287  				refs := val.Referrers()
  1288  				if refs == nil {
  1289  					return true
  1290  				}
  1291  				for _, ref := range *refs {
  1292  					ex, ok := ref.(*ssa.Extract)
  1293  					if !ok {
  1294  						continue
  1295  					}
  1296  					exrefs := ex.Referrers()
  1297  					if exrefs == nil {
  1298  						continue
  1299  					}
  1300  					if len(FilterDebug(*exrefs)) == 0 {
  1301  						lhs := assign.Lhs[ex.Index]
  1302  						if ident, ok := lhs.(*ast.Ident); !ok || ok && ident.Name == "_" {
  1303  							continue
  1304  						}
  1305  						j.Errorf(lhs, "this value of %s is never used", lhs)
  1306  					}
  1307  				}
  1308  				return true
  1309  			}
  1310  			for i, lhs := range assign.Lhs {
  1311  				rhs := assign.Rhs[i]
  1312  				if ident, ok := lhs.(*ast.Ident); !ok || ok && ident.Name == "_" {
  1313  					continue
  1314  				}
  1315  				val, _ := ssafn.ValueForExpr(rhs)
  1316  				if val == nil {
  1317  					continue
  1318  				}
  1319  
  1320  				refs := val.Referrers()
  1321  				if refs == nil {
  1322  					// TODO investigate why refs can be nil
  1323  					return true
  1324  				}
  1325  				if len(FilterDebug(*refs)) == 0 {
  1326  					j.Errorf(lhs, "this value of %s is never used", lhs)
  1327  				}
  1328  			}
  1329  			return true
  1330  		})
  1331  	}
  1332  }
  1333  
  1334  func (c *Checker) CheckPredeterminedBooleanExprs(j *lint.Job) {
  1335  	for _, ssafn := range j.Program.InitialFunctions {
  1336  		for _, block := range ssafn.Blocks {
  1337  			for _, ins := range block.Instrs {
  1338  				ssabinop, ok := ins.(*ssa.BinOp)
  1339  				if !ok {
  1340  					continue
  1341  				}
  1342  				switch ssabinop.Op {
  1343  				case token.GTR, token.LSS, token.EQL, token.NEQ, token.LEQ, token.GEQ:
  1344  				default:
  1345  					continue
  1346  				}
  1347  
  1348  				xs, ok1 := consts(ssabinop.X, nil, nil)
  1349  				ys, ok2 := consts(ssabinop.Y, nil, nil)
  1350  				if !ok1 || !ok2 || len(xs) == 0 || len(ys) == 0 {
  1351  					continue
  1352  				}
  1353  
  1354  				trues := 0
  1355  				for _, x := range xs {
  1356  					for _, y := range ys {
  1357  						if x.Value == nil {
  1358  							if y.Value == nil {
  1359  								trues++
  1360  							}
  1361  							continue
  1362  						}
  1363  						if constant.Compare(x.Value, ssabinop.Op, y.Value) {
  1364  							trues++
  1365  						}
  1366  					}
  1367  				}
  1368  				b := trues != 0
  1369  				if trues == 0 || trues == len(xs)*len(ys) {
  1370  					j.Errorf(ssabinop, "binary expression is always %t for all possible values (%s %s %s)",
  1371  						b, xs, ssabinop.Op, ys)
  1372  				}
  1373  			}
  1374  		}
  1375  	}
  1376  }
  1377  
  1378  func (c *Checker) CheckNilMaps(j *lint.Job) {
  1379  	for _, ssafn := range j.Program.InitialFunctions {
  1380  		for _, block := range ssafn.Blocks {
  1381  			for _, ins := range block.Instrs {
  1382  				mu, ok := ins.(*ssa.MapUpdate)
  1383  				if !ok {
  1384  					continue
  1385  				}
  1386  				c, ok := mu.Map.(*ssa.Const)
  1387  				if !ok {
  1388  					continue
  1389  				}
  1390  				if c.Value != nil {
  1391  					continue
  1392  				}
  1393  				j.Errorf(mu, "assignment to nil map")
  1394  			}
  1395  		}
  1396  	}
  1397  }
  1398  
  1399  func (c *Checker) CheckExtremeComparison(j *lint.Job) {
  1400  	isobj := func(expr ast.Expr, name string) bool {
  1401  		sel, ok := expr.(*ast.SelectorExpr)
  1402  		if !ok {
  1403  			return false
  1404  		}
  1405  		return IsObject(ObjectOf(j, sel.Sel), name)
  1406  	}
  1407  
  1408  	fn := func(node ast.Node) bool {
  1409  		expr, ok := node.(*ast.BinaryExpr)
  1410  		if !ok {
  1411  			return true
  1412  		}
  1413  		tx := TypeOf(j, expr.X)
  1414  		basic, ok := tx.Underlying().(*types.Basic)
  1415  		if !ok {
  1416  			return true
  1417  		}
  1418  
  1419  		var max string
  1420  		var min string
  1421  
  1422  		switch basic.Kind() {
  1423  		case types.Uint8:
  1424  			max = "math.MaxUint8"
  1425  		case types.Uint16:
  1426  			max = "math.MaxUint16"
  1427  		case types.Uint32:
  1428  			max = "math.MaxUint32"
  1429  		case types.Uint64:
  1430  			max = "math.MaxUint64"
  1431  		case types.Uint:
  1432  			max = "math.MaxUint64"
  1433  
  1434  		case types.Int8:
  1435  			min = "math.MinInt8"
  1436  			max = "math.MaxInt8"
  1437  		case types.Int16:
  1438  			min = "math.MinInt16"
  1439  			max = "math.MaxInt16"
  1440  		case types.Int32:
  1441  			min = "math.MinInt32"
  1442  			max = "math.MaxInt32"
  1443  		case types.Int64:
  1444  			min = "math.MinInt64"
  1445  			max = "math.MaxInt64"
  1446  		case types.Int:
  1447  			min = "math.MinInt64"
  1448  			max = "math.MaxInt64"
  1449  		}
  1450  
  1451  		if (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.Y, max) ||
  1452  			(expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.X, max) {
  1453  			j.Errorf(expr, "no value of type %s is greater than %s", basic, max)
  1454  		}
  1455  		if expr.Op == token.LEQ && isobj(expr.Y, max) ||
  1456  			expr.Op == token.GEQ && isobj(expr.X, max) {
  1457  			j.Errorf(expr, "every value of type %s is <= %s", basic, max)
  1458  		}
  1459  
  1460  		if (basic.Info() & types.IsUnsigned) != 0 {
  1461  			if (expr.Op == token.LSS || expr.Op == token.LEQ) && IsIntLiteral(expr.Y, "0") ||
  1462  				(expr.Op == token.GTR || expr.Op == token.GEQ) && IsIntLiteral(expr.X, "0") {
  1463  				j.Errorf(expr, "no value of type %s is less than 0", basic)
  1464  			}
  1465  			if expr.Op == token.GEQ && IsIntLiteral(expr.Y, "0") ||
  1466  				expr.Op == token.LEQ && IsIntLiteral(expr.X, "0") {
  1467  				j.Errorf(expr, "every value of type %s is >= 0", basic)
  1468  			}
  1469  		} else {
  1470  			if (expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.Y, min) ||
  1471  				(expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.X, min) {
  1472  				j.Errorf(expr, "no value of type %s is less than %s", basic, min)
  1473  			}
  1474  			if expr.Op == token.GEQ && isobj(expr.Y, min) ||
  1475  				expr.Op == token.LEQ && isobj(expr.X, min) {
  1476  				j.Errorf(expr, "every value of type %s is >= %s", basic, min)
  1477  			}
  1478  		}
  1479  
  1480  		return true
  1481  	}
  1482  	for _, f := range j.Program.Files {
  1483  		ast.Inspect(f, fn)
  1484  	}
  1485  }
  1486  
  1487  func consts(val ssa.Value, out []*ssa.Const, visitedPhis map[string]bool) ([]*ssa.Const, bool) {
  1488  	if visitedPhis == nil {
  1489  		visitedPhis = map[string]bool{}
  1490  	}
  1491  	var ok bool
  1492  	switch val := val.(type) {
  1493  	case *ssa.Phi:
  1494  		if visitedPhis[val.Name()] {
  1495  			break
  1496  		}
  1497  		visitedPhis[val.Name()] = true
  1498  		vals := val.Operands(nil)
  1499  		for _, phival := range vals {
  1500  			out, ok = consts(*phival, out, visitedPhis)
  1501  			if !ok {
  1502  				return nil, false
  1503  			}
  1504  		}
  1505  	case *ssa.Const:
  1506  		out = append(out, val)
  1507  	case *ssa.Convert:
  1508  		out, ok = consts(val.X, out, visitedPhis)
  1509  		if !ok {
  1510  			return nil, false
  1511  		}
  1512  	default:
  1513  		return nil, false
  1514  	}
  1515  	if len(out) < 2 {
  1516  		return out, true
  1517  	}
  1518  	uniq := []*ssa.Const{out[0]}
  1519  	for _, val := range out[1:] {
  1520  		if val.Value == uniq[len(uniq)-1].Value {
  1521  			continue
  1522  		}
  1523  		uniq = append(uniq, val)
  1524  	}
  1525  	return uniq, true
  1526  }
  1527  
  1528  func (c *Checker) CheckLoopCondition(j *lint.Job) {
  1529  	for _, ssafn := range j.Program.InitialFunctions {
  1530  		fn := func(node ast.Node) bool {
  1531  			loop, ok := node.(*ast.ForStmt)
  1532  			if !ok {
  1533  				return true
  1534  			}
  1535  			if loop.Init == nil || loop.Cond == nil || loop.Post == nil {
  1536  				return true
  1537  			}
  1538  			init, ok := loop.Init.(*ast.AssignStmt)
  1539  			if !ok || len(init.Lhs) != 1 || len(init.Rhs) != 1 {
  1540  				return true
  1541  			}
  1542  			cond, ok := loop.Cond.(*ast.BinaryExpr)
  1543  			if !ok {
  1544  				return true
  1545  			}
  1546  			x, ok := cond.X.(*ast.Ident)
  1547  			if !ok {
  1548  				return true
  1549  			}
  1550  			lhs, ok := init.Lhs[0].(*ast.Ident)
  1551  			if !ok {
  1552  				return true
  1553  			}
  1554  			if x.Obj != lhs.Obj {
  1555  				return true
  1556  			}
  1557  			if _, ok := loop.Post.(*ast.IncDecStmt); !ok {
  1558  				return true
  1559  			}
  1560  
  1561  			v, isAddr := ssafn.ValueForExpr(cond.X)
  1562  			if v == nil || isAddr {
  1563  				return true
  1564  			}
  1565  			switch v := v.(type) {
  1566  			case *ssa.Phi:
  1567  				ops := v.Operands(nil)
  1568  				if len(ops) != 2 {
  1569  					return true
  1570  				}
  1571  				_, ok := (*ops[0]).(*ssa.Const)
  1572  				if !ok {
  1573  					return true
  1574  				}
  1575  				sigma, ok := (*ops[1]).(*ssa.Sigma)
  1576  				if !ok {
  1577  					return true
  1578  				}
  1579  				if sigma.X != v {
  1580  					return true
  1581  				}
  1582  			case *ssa.UnOp:
  1583  				return true
  1584  			}
  1585  			j.Errorf(cond, "variable in loop condition never changes")
  1586  
  1587  			return true
  1588  		}
  1589  		Inspect(ssafn.Syntax(), fn)
  1590  	}
  1591  }
  1592  
  1593  func (c *Checker) CheckArgOverwritten(j *lint.Job) {
  1594  	for _, ssafn := range j.Program.InitialFunctions {
  1595  		fn := func(node ast.Node) bool {
  1596  			var typ *ast.FuncType
  1597  			var body *ast.BlockStmt
  1598  			switch fn := node.(type) {
  1599  			case *ast.FuncDecl:
  1600  				typ = fn.Type
  1601  				body = fn.Body
  1602  			case *ast.FuncLit:
  1603  				typ = fn.Type
  1604  				body = fn.Body
  1605  			}
  1606  			if body == nil {
  1607  				return true
  1608  			}
  1609  			if len(typ.Params.List) == 0 {
  1610  				return true
  1611  			}
  1612  			for _, field := range typ.Params.List {
  1613  				for _, arg := range field.Names {
  1614  					obj := ObjectOf(j, arg)
  1615  					var ssaobj *ssa.Parameter
  1616  					for _, param := range ssafn.Params {
  1617  						if param.Object() == obj {
  1618  							ssaobj = param
  1619  							break
  1620  						}
  1621  					}
  1622  					if ssaobj == nil {
  1623  						continue
  1624  					}
  1625  					refs := ssaobj.Referrers()
  1626  					if refs == nil {
  1627  						continue
  1628  					}
  1629  					if len(FilterDebug(*refs)) != 0 {
  1630  						continue
  1631  					}
  1632  
  1633  					assigned := false
  1634  					ast.Inspect(body, func(node ast.Node) bool {
  1635  						assign, ok := node.(*ast.AssignStmt)
  1636  						if !ok {
  1637  							return true
  1638  						}
  1639  						for _, lhs := range assign.Lhs {
  1640  							ident, ok := lhs.(*ast.Ident)
  1641  							if !ok {
  1642  								continue
  1643  							}
  1644  							if ObjectOf(j, ident) == obj {
  1645  								assigned = true
  1646  								return false
  1647  							}
  1648  						}
  1649  						return true
  1650  					})
  1651  					if assigned {
  1652  						j.Errorf(arg, "argument %s is overwritten before first use", arg)
  1653  					}
  1654  				}
  1655  			}
  1656  			return true
  1657  		}
  1658  		Inspect(ssafn.Syntax(), fn)
  1659  	}
  1660  }
  1661  
  1662  func (c *Checker) CheckIneffectiveLoop(j *lint.Job) {
  1663  	// This check detects some, but not all unconditional loop exits.
  1664  	// We give up in the following cases:
  1665  	//
  1666  	// - a goto anywhere in the loop. The goto might skip over our
  1667  	// return, and we don't check that it doesn't.
  1668  	//
  1669  	// - any nested, unlabelled continue, even if it is in another
  1670  	// loop or closure.
  1671  	fn := func(node ast.Node) bool {
  1672  		var body *ast.BlockStmt
  1673  		switch fn := node.(type) {
  1674  		case *ast.FuncDecl:
  1675  			body = fn.Body
  1676  		case *ast.FuncLit:
  1677  			body = fn.Body
  1678  		default:
  1679  			return true
  1680  		}
  1681  		if body == nil {
  1682  			return true
  1683  		}
  1684  		labels := map[*ast.Object]ast.Stmt{}
  1685  		ast.Inspect(body, func(node ast.Node) bool {
  1686  			label, ok := node.(*ast.LabeledStmt)
  1687  			if !ok {
  1688  				return true
  1689  			}
  1690  			labels[label.Label.Obj] = label.Stmt
  1691  			return true
  1692  		})
  1693  
  1694  		ast.Inspect(body, func(node ast.Node) bool {
  1695  			var loop ast.Node
  1696  			var body *ast.BlockStmt
  1697  			switch node := node.(type) {
  1698  			case *ast.ForStmt:
  1699  				body = node.Body
  1700  				loop = node
  1701  			case *ast.RangeStmt:
  1702  				typ := TypeOf(j, node.X)
  1703  				if _, ok := typ.Underlying().(*types.Map); ok {
  1704  					// looping once over a map is a valid pattern for
  1705  					// getting an arbitrary element.
  1706  					return true
  1707  				}
  1708  				body = node.Body
  1709  				loop = node
  1710  			default:
  1711  				return true
  1712  			}
  1713  			if len(body.List) < 2 {
  1714  				// avoid flagging the somewhat common pattern of using
  1715  				// a range loop to get the first element in a slice,
  1716  				// or the first rune in a string.
  1717  				return true
  1718  			}
  1719  			var unconditionalExit ast.Node
  1720  			hasBranching := false
  1721  			for _, stmt := range body.List {
  1722  				switch stmt := stmt.(type) {
  1723  				case *ast.BranchStmt:
  1724  					switch stmt.Tok {
  1725  					case token.BREAK:
  1726  						if stmt.Label == nil || labels[stmt.Label.Obj] == loop {
  1727  							unconditionalExit = stmt
  1728  						}
  1729  					case token.CONTINUE:
  1730  						if stmt.Label == nil || labels[stmt.Label.Obj] == loop {
  1731  							unconditionalExit = nil
  1732  							return false
  1733  						}
  1734  					}
  1735  				case *ast.ReturnStmt:
  1736  					unconditionalExit = stmt
  1737  				case *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.SelectStmt:
  1738  					hasBranching = true
  1739  				}
  1740  			}
  1741  			if unconditionalExit == nil || !hasBranching {
  1742  				return false
  1743  			}
  1744  			ast.Inspect(body, func(node ast.Node) bool {
  1745  				if branch, ok := node.(*ast.BranchStmt); ok {
  1746  
  1747  					switch branch.Tok {
  1748  					case token.GOTO:
  1749  						unconditionalExit = nil
  1750  						return false
  1751  					case token.CONTINUE:
  1752  						if branch.Label != nil && labels[branch.Label.Obj] != loop {
  1753  							return true
  1754  						}
  1755  						unconditionalExit = nil
  1756  						return false
  1757  					}
  1758  				}
  1759  				return true
  1760  			})
  1761  			if unconditionalExit != nil {
  1762  				j.Errorf(unconditionalExit, "the surrounding loop is unconditionally terminated")
  1763  			}
  1764  			return true
  1765  		})
  1766  		return true
  1767  	}
  1768  	for _, f := range j.Program.Files {
  1769  		ast.Inspect(f, fn)
  1770  	}
  1771  }
  1772  
  1773  func (c *Checker) CheckNilContext(j *lint.Job) {
  1774  	fn := func(node ast.Node) bool {
  1775  		call, ok := node.(*ast.CallExpr)
  1776  		if !ok {
  1777  			return true
  1778  		}
  1779  		if len(call.Args) == 0 {
  1780  			return true
  1781  		}
  1782  		if typ, ok := TypeOf(j, call.Args[0]).(*types.Basic); !ok || typ.Kind() != types.UntypedNil {
  1783  			return true
  1784  		}
  1785  		sig, ok := TypeOf(j, call.Fun).(*types.Signature)
  1786  		if !ok {
  1787  			return true
  1788  		}
  1789  		if sig.Params().Len() == 0 {
  1790  			return true
  1791  		}
  1792  		if !IsType(sig.Params().At(0).Type(), "context.Context") {
  1793  			return true
  1794  		}
  1795  		j.Errorf(call.Args[0],
  1796  			"do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use")
  1797  		return true
  1798  	}
  1799  	for _, f := range j.Program.Files {
  1800  		ast.Inspect(f, fn)
  1801  	}
  1802  }
  1803  
  1804  func (c *Checker) CheckSeeker(j *lint.Job) {
  1805  	fn := func(node ast.Node) bool {
  1806  		call, ok := node.(*ast.CallExpr)
  1807  		if !ok {
  1808  			return true
  1809  		}
  1810  		sel, ok := call.Fun.(*ast.SelectorExpr)
  1811  		if !ok {
  1812  			return true
  1813  		}
  1814  		if sel.Sel.Name != "Seek" {
  1815  			return true
  1816  		}
  1817  		if len(call.Args) != 2 {
  1818  			return true
  1819  		}
  1820  		arg0, ok := call.Args[Arg("(io.Seeker).Seek.offset")].(*ast.SelectorExpr)
  1821  		if !ok {
  1822  			return true
  1823  		}
  1824  		switch arg0.Sel.Name {
  1825  		case "SeekStart", "SeekCurrent", "SeekEnd":
  1826  		default:
  1827  			return true
  1828  		}
  1829  		pkg, ok := arg0.X.(*ast.Ident)
  1830  		if !ok {
  1831  			return true
  1832  		}
  1833  		if pkg.Name != "io" {
  1834  			return true
  1835  		}
  1836  		j.Errorf(call, "the first argument of io.Seeker is the offset, but an io.Seek* constant is being used instead")
  1837  		return true
  1838  	}
  1839  	for _, f := range j.Program.Files {
  1840  		ast.Inspect(f, fn)
  1841  	}
  1842  }
  1843  
  1844  func (c *Checker) CheckIneffectiveAppend(j *lint.Job) {
  1845  	isAppend := func(ins ssa.Value) bool {
  1846  		call, ok := ins.(*ssa.Call)
  1847  		if !ok {
  1848  			return false
  1849  		}
  1850  		if call.Call.IsInvoke() {
  1851  			return false
  1852  		}
  1853  		if builtin, ok := call.Call.Value.(*ssa.Builtin); !ok || builtin.Name() != "append" {
  1854  			return false
  1855  		}
  1856  		return true
  1857  	}
  1858  
  1859  	for _, ssafn := range j.Program.InitialFunctions {
  1860  		for _, block := range ssafn.Blocks {
  1861  			for _, ins := range block.Instrs {
  1862  				val, ok := ins.(ssa.Value)
  1863  				if !ok || !isAppend(val) {
  1864  					continue
  1865  				}
  1866  
  1867  				isUsed := false
  1868  				visited := map[ssa.Instruction]bool{}
  1869  				var walkRefs func(refs []ssa.Instruction)
  1870  				walkRefs = func(refs []ssa.Instruction) {
  1871  				loop:
  1872  					for _, ref := range refs {
  1873  						if visited[ref] {
  1874  							continue
  1875  						}
  1876  						visited[ref] = true
  1877  						if _, ok := ref.(*ssa.DebugRef); ok {
  1878  							continue
  1879  						}
  1880  						switch ref := ref.(type) {
  1881  						case *ssa.Phi:
  1882  							walkRefs(*ref.Referrers())
  1883  						case *ssa.Sigma:
  1884  							walkRefs(*ref.Referrers())
  1885  						case ssa.Value:
  1886  							if !isAppend(ref) {
  1887  								isUsed = true
  1888  							} else {
  1889  								walkRefs(*ref.Referrers())
  1890  							}
  1891  						case ssa.Instruction:
  1892  							isUsed = true
  1893  							break loop
  1894  						}
  1895  					}
  1896  				}
  1897  				refs := val.Referrers()
  1898  				if refs == nil {
  1899  					continue
  1900  				}
  1901  				walkRefs(*refs)
  1902  				if !isUsed {
  1903  					j.Errorf(ins, "this result of append is never used, except maybe in other appends")
  1904  				}
  1905  			}
  1906  		}
  1907  	}
  1908  }
  1909  
  1910  func (c *Checker) CheckConcurrentTesting(j *lint.Job) {
  1911  	for _, ssafn := range j.Program.InitialFunctions {
  1912  		for _, block := range ssafn.Blocks {
  1913  			for _, ins := range block.Instrs {
  1914  				gostmt, ok := ins.(*ssa.Go)
  1915  				if !ok {
  1916  					continue
  1917  				}
  1918  				var fn *ssa.Function
  1919  				switch val := gostmt.Call.Value.(type) {
  1920  				case *ssa.Function:
  1921  					fn = val
  1922  				case *ssa.MakeClosure:
  1923  					fn = val.Fn.(*ssa.Function)
  1924  				default:
  1925  					continue
  1926  				}
  1927  				if fn.Blocks == nil {
  1928  					continue
  1929  				}
  1930  				for _, block := range fn.Blocks {
  1931  					for _, ins := range block.Instrs {
  1932  						call, ok := ins.(*ssa.Call)
  1933  						if !ok {
  1934  							continue
  1935  						}
  1936  						if call.Call.IsInvoke() {
  1937  							continue
  1938  						}
  1939  						callee := call.Call.StaticCallee()
  1940  						if callee == nil {
  1941  							continue
  1942  						}
  1943  						recv := callee.Signature.Recv()
  1944  						if recv == nil {
  1945  							continue
  1946  						}
  1947  						if !IsType(recv.Type(), "*testing.common") {
  1948  							continue
  1949  						}
  1950  						fn, ok := call.Call.StaticCallee().Object().(*types.Func)
  1951  						if !ok {
  1952  							continue
  1953  						}
  1954  						name := fn.Name()
  1955  						switch name {
  1956  						case "FailNow", "Fatal", "Fatalf", "SkipNow", "Skip", "Skipf":
  1957  						default:
  1958  							continue
  1959  						}
  1960  						j.Errorf(gostmt, "the goroutine calls T.%s, which must be called in the same goroutine as the test", name)
  1961  					}
  1962  				}
  1963  			}
  1964  		}
  1965  	}
  1966  }
  1967  
  1968  func (c *Checker) CheckCyclicFinalizer(j *lint.Job) {
  1969  	for _, ssafn := range j.Program.InitialFunctions {
  1970  		node := c.funcDescs.CallGraph.CreateNode(ssafn)
  1971  		for _, edge := range node.Out {
  1972  			if edge.Callee.Func.RelString(nil) != "runtime.SetFinalizer" {
  1973  				continue
  1974  			}
  1975  			arg0 := edge.Site.Common().Args[Arg("runtime.SetFinalizer.obj")]
  1976  			if iface, ok := arg0.(*ssa.MakeInterface); ok {
  1977  				arg0 = iface.X
  1978  			}
  1979  			unop, ok := arg0.(*ssa.UnOp)
  1980  			if !ok {
  1981  				continue
  1982  			}
  1983  			v, ok := unop.X.(*ssa.Alloc)
  1984  			if !ok {
  1985  				continue
  1986  			}
  1987  			arg1 := edge.Site.Common().Args[Arg("runtime.SetFinalizer.finalizer")]
  1988  			if iface, ok := arg1.(*ssa.MakeInterface); ok {
  1989  				arg1 = iface.X
  1990  			}
  1991  			mc, ok := arg1.(*ssa.MakeClosure)
  1992  			if !ok {
  1993  				continue
  1994  			}
  1995  			for _, b := range mc.Bindings {
  1996  				if b == v {
  1997  					pos := j.Program.DisplayPosition(mc.Fn.Pos())
  1998  					j.Errorf(edge.Site, "the finalizer closes over the object, preventing the finalizer from ever running (at %s)", pos)
  1999  				}
  2000  			}
  2001  		}
  2002  	}
  2003  }
  2004  
  2005  func (c *Checker) CheckSliceOutOfBounds(j *lint.Job) {
  2006  	for _, ssafn := range j.Program.InitialFunctions {
  2007  		for _, block := range ssafn.Blocks {
  2008  			for _, ins := range block.Instrs {
  2009  				ia, ok := ins.(*ssa.IndexAddr)
  2010  				if !ok {
  2011  					continue
  2012  				}
  2013  				if _, ok := ia.X.Type().Underlying().(*types.Slice); !ok {
  2014  					continue
  2015  				}
  2016  				sr, ok1 := c.funcDescs.Get(ssafn).Ranges[ia.X].(vrp.SliceInterval)
  2017  				idxr, ok2 := c.funcDescs.Get(ssafn).Ranges[ia.Index].(vrp.IntInterval)
  2018  				if !ok1 || !ok2 || !sr.IsKnown() || !idxr.IsKnown() || sr.Length.Empty() || idxr.Empty() {
  2019  					continue
  2020  				}
  2021  				if idxr.Lower.Cmp(sr.Length.Upper) >= 0 {
  2022  					j.Errorf(ia, "index out of bounds")
  2023  				}
  2024  			}
  2025  		}
  2026  	}
  2027  }
  2028  
  2029  func (c *Checker) CheckDeferLock(j *lint.Job) {
  2030  	for _, ssafn := range j.Program.InitialFunctions {
  2031  		for _, block := range ssafn.Blocks {
  2032  			instrs := FilterDebug(block.Instrs)
  2033  			if len(instrs) < 2 {
  2034  				continue
  2035  			}
  2036  			for i, ins := range instrs[:len(instrs)-1] {
  2037  				call, ok := ins.(*ssa.Call)
  2038  				if !ok {
  2039  					continue
  2040  				}
  2041  				if !IsCallTo(call.Common(), "(*sync.Mutex).Lock") && !IsCallTo(call.Common(), "(*sync.RWMutex).RLock") {
  2042  					continue
  2043  				}
  2044  				nins, ok := instrs[i+1].(*ssa.Defer)
  2045  				if !ok {
  2046  					continue
  2047  				}
  2048  				if !IsCallTo(&nins.Call, "(*sync.Mutex).Lock") && !IsCallTo(&nins.Call, "(*sync.RWMutex).RLock") {
  2049  					continue
  2050  				}
  2051  				if call.Common().Args[0] != nins.Call.Args[0] {
  2052  					continue
  2053  				}
  2054  				name := shortCallName(call.Common())
  2055  				alt := ""
  2056  				switch name {
  2057  				case "Lock":
  2058  					alt = "Unlock"
  2059  				case "RLock":
  2060  					alt = "RUnlock"
  2061  				}
  2062  				j.Errorf(nins, "deferring %s right after having locked already; did you mean to defer %s?", name, alt)
  2063  			}
  2064  		}
  2065  	}
  2066  }
  2067  
  2068  func (c *Checker) CheckNaNComparison(j *lint.Job) {
  2069  	isNaN := func(v ssa.Value) bool {
  2070  		call, ok := v.(*ssa.Call)
  2071  		if !ok {
  2072  			return false
  2073  		}
  2074  		return IsCallTo(call.Common(), "math.NaN")
  2075  	}
  2076  	for _, ssafn := range j.Program.InitialFunctions {
  2077  		for _, block := range ssafn.Blocks {
  2078  			for _, ins := range block.Instrs {
  2079  				ins, ok := ins.(*ssa.BinOp)
  2080  				if !ok {
  2081  					continue
  2082  				}
  2083  				if isNaN(ins.X) || isNaN(ins.Y) {
  2084  					j.Errorf(ins, "no value is equal to NaN, not even NaN itself")
  2085  				}
  2086  			}
  2087  		}
  2088  	}
  2089  }
  2090  
  2091  func (c *Checker) CheckInfiniteRecursion(j *lint.Job) {
  2092  	for _, ssafn := range j.Program.InitialFunctions {
  2093  		node := c.funcDescs.CallGraph.CreateNode(ssafn)
  2094  		for _, edge := range node.Out {
  2095  			if edge.Callee != node {
  2096  				continue
  2097  			}
  2098  			if _, ok := edge.Site.(*ssa.Go); ok {
  2099  				// Recursively spawning goroutines doesn't consume
  2100  				// stack space infinitely, so don't flag it.
  2101  				continue
  2102  			}
  2103  
  2104  			block := edge.Site.Block()
  2105  			canReturn := false
  2106  			for _, b := range ssafn.Blocks {
  2107  				if block.Dominates(b) {
  2108  					continue
  2109  				}
  2110  				if len(b.Instrs) == 0 {
  2111  					continue
  2112  				}
  2113  				if _, ok := b.Instrs[len(b.Instrs)-1].(*ssa.Return); ok {
  2114  					canReturn = true
  2115  					break
  2116  				}
  2117  			}
  2118  			if canReturn {
  2119  				continue
  2120  			}
  2121  			j.Errorf(edge.Site, "infinite recursive call")
  2122  		}
  2123  	}
  2124  }
  2125  
  2126  func objectName(obj types.Object) string {
  2127  	if obj == nil {
  2128  		return "<nil>"
  2129  	}
  2130  	var name string
  2131  	if obj.Pkg() != nil && obj.Pkg().Scope().Lookup(obj.Name()) == obj {
  2132  		s := obj.Pkg().Path()
  2133  		if s != "" {
  2134  			name += s + "."
  2135  		}
  2136  	}
  2137  	name += obj.Name()
  2138  	return name
  2139  }
  2140  
  2141  func isName(j *lint.Job, expr ast.Expr, name string) bool {
  2142  	var obj types.Object
  2143  	switch expr := expr.(type) {
  2144  	case *ast.Ident:
  2145  		obj = ObjectOf(j, expr)
  2146  	case *ast.SelectorExpr:
  2147  		obj = ObjectOf(j, expr.Sel)
  2148  	}
  2149  	return objectName(obj) == name
  2150  }
  2151  
  2152  func (c *Checker) CheckLeakyTimeTick(j *lint.Job) {
  2153  	for _, ssafn := range j.Program.InitialFunctions {
  2154  		if IsInMain(j, ssafn) || IsInTest(j, ssafn) {
  2155  			continue
  2156  		}
  2157  		for _, block := range ssafn.Blocks {
  2158  			for _, ins := range block.Instrs {
  2159  				call, ok := ins.(*ssa.Call)
  2160  				if !ok || !IsCallTo(call.Common(), "time.Tick") {
  2161  					continue
  2162  				}
  2163  				if c.funcDescs.Get(call.Parent()).Infinite {
  2164  					continue
  2165  				}
  2166  				j.Errorf(call, "using time.Tick leaks the underlying ticker, consider using it only in endless functions, tests and the main package, and use time.NewTicker here")
  2167  			}
  2168  		}
  2169  	}
  2170  }
  2171  
  2172  func (c *Checker) CheckDoubleNegation(j *lint.Job) {
  2173  	fn := func(node ast.Node) bool {
  2174  		unary1, ok := node.(*ast.UnaryExpr)
  2175  		if !ok {
  2176  			return true
  2177  		}
  2178  		unary2, ok := unary1.X.(*ast.UnaryExpr)
  2179  		if !ok {
  2180  			return true
  2181  		}
  2182  		if unary1.Op != token.NOT || unary2.Op != token.NOT {
  2183  			return true
  2184  		}
  2185  		j.Errorf(unary1, "negating a boolean twice has no effect; is this a typo?")
  2186  		return true
  2187  	}
  2188  	for _, f := range j.Program.Files {
  2189  		ast.Inspect(f, fn)
  2190  	}
  2191  }
  2192  
  2193  func hasSideEffects(node ast.Node) bool {
  2194  	dynamic := false
  2195  	ast.Inspect(node, func(node ast.Node) bool {
  2196  		switch node := node.(type) {
  2197  		case *ast.CallExpr:
  2198  			dynamic = true
  2199  			return false
  2200  		case *ast.UnaryExpr:
  2201  			if node.Op == token.ARROW {
  2202  				dynamic = true
  2203  				return false
  2204  			}
  2205  		}
  2206  		return true
  2207  	})
  2208  	return dynamic
  2209  }
  2210  
  2211  func (c *Checker) CheckRepeatedIfElse(j *lint.Job) {
  2212  	seen := map[ast.Node]bool{}
  2213  
  2214  	var collectConds func(ifstmt *ast.IfStmt, inits []ast.Stmt, conds []ast.Expr) ([]ast.Stmt, []ast.Expr)
  2215  	collectConds = func(ifstmt *ast.IfStmt, inits []ast.Stmt, conds []ast.Expr) ([]ast.Stmt, []ast.Expr) {
  2216  		seen[ifstmt] = true
  2217  		if ifstmt.Init != nil {
  2218  			inits = append(inits, ifstmt.Init)
  2219  		}
  2220  		conds = append(conds, ifstmt.Cond)
  2221  		if elsestmt, ok := ifstmt.Else.(*ast.IfStmt); ok {
  2222  			return collectConds(elsestmt, inits, conds)
  2223  		}
  2224  		return inits, conds
  2225  	}
  2226  	fn := func(node ast.Node) bool {
  2227  		ifstmt, ok := node.(*ast.IfStmt)
  2228  		if !ok {
  2229  			return true
  2230  		}
  2231  		if seen[ifstmt] {
  2232  			return true
  2233  		}
  2234  		inits, conds := collectConds(ifstmt, nil, nil)
  2235  		if len(inits) > 0 {
  2236  			return true
  2237  		}
  2238  		for _, cond := range conds {
  2239  			if hasSideEffects(cond) {
  2240  				return true
  2241  			}
  2242  		}
  2243  		counts := map[string]int{}
  2244  		for _, cond := range conds {
  2245  			s := Render(j, cond)
  2246  			counts[s]++
  2247  			if counts[s] == 2 {
  2248  				j.Errorf(cond, "this condition occurs multiple times in this if/else if chain")
  2249  			}
  2250  		}
  2251  		return true
  2252  	}
  2253  	for _, f := range j.Program.Files {
  2254  		ast.Inspect(f, fn)
  2255  	}
  2256  }
  2257  
  2258  func (c *Checker) CheckSillyBitwiseOps(j *lint.Job) {
  2259  	for _, ssafn := range j.Program.InitialFunctions {
  2260  		for _, block := range ssafn.Blocks {
  2261  			for _, ins := range block.Instrs {
  2262  				ins, ok := ins.(*ssa.BinOp)
  2263  				if !ok {
  2264  					continue
  2265  				}
  2266  
  2267  				if c, ok := ins.Y.(*ssa.Const); !ok || c.Value == nil || c.Value.Kind() != constant.Int || c.Uint64() != 0 {
  2268  					continue
  2269  				}
  2270  				switch ins.Op {
  2271  				case token.AND, token.OR, token.XOR:
  2272  				default:
  2273  					// we do not flag shifts because too often, x<<0 is part
  2274  					// of a pattern, x<<0, x<<8, x<<16, ...
  2275  					continue
  2276  				}
  2277  				path, _ := astutil.PathEnclosingInterval(j.File(ins), ins.Pos(), ins.Pos())
  2278  				if len(path) == 0 {
  2279  					continue
  2280  				}
  2281  				if node, ok := path[0].(*ast.BinaryExpr); !ok || !IsZero(node.Y) {
  2282  					continue
  2283  				}
  2284  
  2285  				switch ins.Op {
  2286  				case token.AND:
  2287  					j.Errorf(ins, "x & 0 always equals 0")
  2288  				case token.OR, token.XOR:
  2289  					j.Errorf(ins, "x %s 0 always equals x", ins.Op)
  2290  				}
  2291  			}
  2292  		}
  2293  	}
  2294  }
  2295  
  2296  func (c *Checker) CheckNonOctalFileMode(j *lint.Job) {
  2297  	fn := func(node ast.Node) bool {
  2298  		call, ok := node.(*ast.CallExpr)
  2299  		if !ok {
  2300  			return true
  2301  		}
  2302  		sig, ok := TypeOf(j, call.Fun).(*types.Signature)
  2303  		if !ok {
  2304  			return true
  2305  		}
  2306  		n := sig.Params().Len()
  2307  		var args []int
  2308  		for i := 0; i < n; i++ {
  2309  			typ := sig.Params().At(i).Type()
  2310  			if IsType(typ, "os.FileMode") {
  2311  				args = append(args, i)
  2312  			}
  2313  		}
  2314  		for _, i := range args {
  2315  			lit, ok := call.Args[i].(*ast.BasicLit)
  2316  			if !ok {
  2317  				continue
  2318  			}
  2319  			if len(lit.Value) == 3 &&
  2320  				lit.Value[0] != '0' &&
  2321  				lit.Value[0] >= '0' && lit.Value[0] <= '7' &&
  2322  				lit.Value[1] >= '0' && lit.Value[1] <= '7' &&
  2323  				lit.Value[2] >= '0' && lit.Value[2] <= '7' {
  2324  
  2325  				v, err := strconv.ParseInt(lit.Value, 10, 64)
  2326  				if err != nil {
  2327  					continue
  2328  				}
  2329  				j.Errorf(call.Args[i], "file mode '%s' evaluates to %#o; did you mean '0%s'?", lit.Value, v, lit.Value)
  2330  			}
  2331  		}
  2332  		return true
  2333  	}
  2334  	for _, f := range j.Program.Files {
  2335  		ast.Inspect(f, fn)
  2336  	}
  2337  }
  2338  
  2339  func (c *Checker) CheckPureFunctions(j *lint.Job) {
  2340  fnLoop:
  2341  	for _, ssafn := range j.Program.InitialFunctions {
  2342  		if IsInTest(j, ssafn) {
  2343  			params := ssafn.Signature.Params()
  2344  			for i := 0; i < params.Len(); i++ {
  2345  				param := params.At(i)
  2346  				if IsType(param.Type(), "*testing.B") {
  2347  					// Ignore discarded pure functions in code related
  2348  					// to benchmarks. Instead of matching BenchmarkFoo
  2349  					// functions, we match any function accepting a
  2350  					// *testing.B. Benchmarks sometimes call generic
  2351  					// functions for doing the actual work, and
  2352  					// checking for the parameter is a lot easier and
  2353  					// faster than analyzing call trees.
  2354  					continue fnLoop
  2355  				}
  2356  			}
  2357  		}
  2358  
  2359  		for _, b := range ssafn.Blocks {
  2360  			for _, ins := range b.Instrs {
  2361  				ins, ok := ins.(*ssa.Call)
  2362  				if !ok {
  2363  					continue
  2364  				}
  2365  				refs := ins.Referrers()
  2366  				if refs == nil || len(FilterDebug(*refs)) > 0 {
  2367  					continue
  2368  				}
  2369  				callee := ins.Common().StaticCallee()
  2370  				if callee == nil {
  2371  					continue
  2372  				}
  2373  				if c.funcDescs.Get(callee).Pure && !c.funcDescs.Get(callee).Stub {
  2374  					j.Errorf(ins, "%s is a pure function but its return value is ignored", callee.Name())
  2375  					continue
  2376  				}
  2377  			}
  2378  		}
  2379  	}
  2380  }
  2381  
  2382  func (c *Checker) isDeprecated(j *lint.Job, ident *ast.Ident) (bool, string) {
  2383  	obj := ObjectOf(j, ident)
  2384  	if obj.Pkg() == nil {
  2385  		return false, ""
  2386  	}
  2387  	alt := c.deprecatedObjs[obj]
  2388  	return alt != "", alt
  2389  }
  2390  
  2391  func (c *Checker) CheckDeprecated(j *lint.Job) {
  2392  	// Selectors can appear outside of function literals, e.g. when
  2393  	// declaring package level variables.
  2394  
  2395  	var ssafn *ssa.Function
  2396  	stack := 0
  2397  	fn := func(node ast.Node) bool {
  2398  		if node == nil {
  2399  			stack--
  2400  		} else {
  2401  			stack++
  2402  		}
  2403  		if stack == 1 {
  2404  			ssafn = nil
  2405  		}
  2406  		if fn, ok := node.(*ast.FuncDecl); ok {
  2407  			ssafn = j.Program.SSA.FuncValue(ObjectOf(j, fn.Name).(*types.Func))
  2408  		}
  2409  		sel, ok := node.(*ast.SelectorExpr)
  2410  		if !ok {
  2411  			return true
  2412  		}
  2413  
  2414  		obj := ObjectOf(j, sel.Sel)
  2415  		if obj.Pkg() == nil {
  2416  			return true
  2417  		}
  2418  		nodePkg := j.NodePackage(node).Types
  2419  		if nodePkg == obj.Pkg() || obj.Pkg().Path()+"_test" == nodePkg.Path() {
  2420  			// Don't flag stuff in our own package
  2421  			return true
  2422  		}
  2423  		if ok, alt := c.isDeprecated(j, sel.Sel); ok {
  2424  			// Look for the first available alternative, not the first
  2425  			// version something was deprecated in. If a function was
  2426  			// deprecated in Go 1.6, an alternative has been available
  2427  			// already in 1.0, and we're targeting 1.2, it still
  2428  			// makes sense to use the alternative from 1.0, to be
  2429  			// future-proof.
  2430  			minVersion := deprecated.Stdlib[SelectorName(j, sel)].AlternativeAvailableSince
  2431  			if !IsGoVersion(j, minVersion) {
  2432  				return true
  2433  			}
  2434  
  2435  			if ssafn != nil {
  2436  				if _, ok := c.deprecatedObjs[ssafn.Object()]; ok {
  2437  					// functions that are deprecated may use deprecated
  2438  					// symbols
  2439  					return true
  2440  				}
  2441  			}
  2442  			j.Errorf(sel, "%s is deprecated: %s", Render(j, sel), alt)
  2443  			return true
  2444  		}
  2445  		return true
  2446  	}
  2447  	for _, f := range j.Program.Files {
  2448  		ast.Inspect(f, fn)
  2449  	}
  2450  }
  2451  
  2452  func (c *Checker) callChecker(rules map[string]CallCheck) func(j *lint.Job) {
  2453  	return func(j *lint.Job) {
  2454  		c.checkCalls(j, rules)
  2455  	}
  2456  }
  2457  
  2458  func (c *Checker) checkCalls(j *lint.Job, rules map[string]CallCheck) {
  2459  	for _, ssafn := range j.Program.InitialFunctions {
  2460  		node := c.funcDescs.CallGraph.CreateNode(ssafn)
  2461  		for _, edge := range node.Out {
  2462  			callee := edge.Callee.Func
  2463  			obj, ok := callee.Object().(*types.Func)
  2464  			if !ok {
  2465  				continue
  2466  			}
  2467  
  2468  			r, ok := rules[obj.FullName()]
  2469  			if !ok {
  2470  				continue
  2471  			}
  2472  			var args []*Argument
  2473  			ssaargs := edge.Site.Common().Args
  2474  			if callee.Signature.Recv() != nil {
  2475  				ssaargs = ssaargs[1:]
  2476  			}
  2477  			for _, arg := range ssaargs {
  2478  				if iarg, ok := arg.(*ssa.MakeInterface); ok {
  2479  					arg = iarg.X
  2480  				}
  2481  				vr := c.funcDescs.Get(edge.Site.Parent()).Ranges[arg]
  2482  				args = append(args, &Argument{Value: Value{arg, vr}})
  2483  			}
  2484  			call := &Call{
  2485  				Job:     j,
  2486  				Instr:   edge.Site,
  2487  				Args:    args,
  2488  				Checker: c,
  2489  				Parent:  edge.Site.Parent(),
  2490  			}
  2491  			r(call)
  2492  			for idx, arg := range call.Args {
  2493  				_ = idx
  2494  				for _, e := range arg.invalids {
  2495  					// path, _ := astutil.PathEnclosingInterval(f.File, edge.Site.Pos(), edge.Site.Pos())
  2496  					// if len(path) < 2 {
  2497  					// 	continue
  2498  					// }
  2499  					// astcall, ok := path[0].(*ast.CallExpr)
  2500  					// if !ok {
  2501  					// 	continue
  2502  					// }
  2503  					// j.Errorf(astcall.Args[idx], "%s", e)
  2504  
  2505  					j.Errorf(edge.Site, "%s", e)
  2506  				}
  2507  			}
  2508  			for _, e := range call.invalids {
  2509  				j.Errorf(call.Instr.Common(), "%s", e)
  2510  			}
  2511  		}
  2512  	}
  2513  }
  2514  
  2515  func shortCallName(call *ssa.CallCommon) string {
  2516  	if call.IsInvoke() {
  2517  		return ""
  2518  	}
  2519  	switch v := call.Value.(type) {
  2520  	case *ssa.Function:
  2521  		fn, ok := v.Object().(*types.Func)
  2522  		if !ok {
  2523  			return ""
  2524  		}
  2525  		return fn.Name()
  2526  	case *ssa.Builtin:
  2527  		return v.Name()
  2528  	}
  2529  	return ""
  2530  }
  2531  
  2532  func (c *Checker) CheckWriterBufferModified(j *lint.Job) {
  2533  	// TODO(dh): this might be a good candidate for taint analysis.
  2534  	// Taint the argument as MUST_NOT_MODIFY, then propagate that
  2535  	// through functions like bytes.Split
  2536  
  2537  	for _, ssafn := range j.Program.InitialFunctions {
  2538  		sig := ssafn.Signature
  2539  		if ssafn.Name() != "Write" || sig.Recv() == nil || sig.Params().Len() != 1 || sig.Results().Len() != 2 {
  2540  			continue
  2541  		}
  2542  		tArg, ok := sig.Params().At(0).Type().(*types.Slice)
  2543  		if !ok {
  2544  			continue
  2545  		}
  2546  		if basic, ok := tArg.Elem().(*types.Basic); !ok || basic.Kind() != types.Byte {
  2547  			continue
  2548  		}
  2549  		if basic, ok := sig.Results().At(0).Type().(*types.Basic); !ok || basic.Kind() != types.Int {
  2550  			continue
  2551  		}
  2552  		if named, ok := sig.Results().At(1).Type().(*types.Named); !ok || !IsType(named, "error") {
  2553  			continue
  2554  		}
  2555  
  2556  		for _, block := range ssafn.Blocks {
  2557  			for _, ins := range block.Instrs {
  2558  				switch ins := ins.(type) {
  2559  				case *ssa.Store:
  2560  					addr, ok := ins.Addr.(*ssa.IndexAddr)
  2561  					if !ok {
  2562  						continue
  2563  					}
  2564  					if addr.X != ssafn.Params[1] {
  2565  						continue
  2566  					}
  2567  					j.Errorf(ins, "io.Writer.Write must not modify the provided buffer, not even temporarily")
  2568  				case *ssa.Call:
  2569  					if !IsCallTo(ins.Common(), "append") {
  2570  						continue
  2571  					}
  2572  					if ins.Common().Args[0] != ssafn.Params[1] {
  2573  						continue
  2574  					}
  2575  					j.Errorf(ins, "io.Writer.Write must not modify the provided buffer, not even temporarily")
  2576  				}
  2577  			}
  2578  		}
  2579  	}
  2580  }
  2581  
  2582  func loopedRegexp(name string) CallCheck {
  2583  	return func(call *Call) {
  2584  		if len(extractConsts(call.Args[0].Value.Value)) == 0 {
  2585  			return
  2586  		}
  2587  		if !call.Checker.isInLoop(call.Instr.Block()) {
  2588  			return
  2589  		}
  2590  		call.Invalid(fmt.Sprintf("calling %s in a loop has poor performance, consider using regexp.Compile", name))
  2591  	}
  2592  }
  2593  
  2594  func (c *Checker) CheckEmptyBranch(j *lint.Job) {
  2595  	for _, ssafn := range j.Program.InitialFunctions {
  2596  		if ssafn.Syntax() == nil {
  2597  			continue
  2598  		}
  2599  		if IsGenerated(j.File(ssafn.Syntax())) {
  2600  			continue
  2601  		}
  2602  		if IsExample(ssafn) {
  2603  			continue
  2604  		}
  2605  		fn := func(node ast.Node) bool {
  2606  			ifstmt, ok := node.(*ast.IfStmt)
  2607  			if !ok {
  2608  				return true
  2609  			}
  2610  			if ifstmt.Else != nil {
  2611  				b, ok := ifstmt.Else.(*ast.BlockStmt)
  2612  				if !ok || len(b.List) != 0 {
  2613  					return true
  2614  				}
  2615  				j.Errorf(ifstmt.Else, "empty branch")
  2616  			}
  2617  			if len(ifstmt.Body.List) != 0 {
  2618  				return true
  2619  			}
  2620  			j.Errorf(ifstmt, "empty branch")
  2621  			return true
  2622  		}
  2623  		Inspect(ssafn.Syntax(), fn)
  2624  	}
  2625  }
  2626  
  2627  func (c *Checker) CheckMapBytesKey(j *lint.Job) {
  2628  	for _, fn := range j.Program.InitialFunctions {
  2629  		for _, b := range fn.Blocks {
  2630  		insLoop:
  2631  			for _, ins := range b.Instrs {
  2632  				// find []byte -> string conversions
  2633  				conv, ok := ins.(*ssa.Convert)
  2634  				if !ok || conv.Type() != types.Universe.Lookup("string").Type() {
  2635  					continue
  2636  				}
  2637  				if s, ok := conv.X.Type().(*types.Slice); !ok || s.Elem() != types.Universe.Lookup("byte").Type() {
  2638  					continue
  2639  				}
  2640  				refs := conv.Referrers()
  2641  				// need at least two (DebugRef) references: the
  2642  				// conversion and the *ast.Ident
  2643  				if refs == nil || len(*refs) < 2 {
  2644  					continue
  2645  				}
  2646  				ident := false
  2647  				// skip first reference, that's the conversion itself
  2648  				for _, ref := range (*refs)[1:] {
  2649  					switch ref := ref.(type) {
  2650  					case *ssa.DebugRef:
  2651  						if _, ok := ref.Expr.(*ast.Ident); !ok {
  2652  							// the string seems to be used somewhere
  2653  							// unexpected; the default branch should
  2654  							// catch this already, but be safe
  2655  							continue insLoop
  2656  						} else {
  2657  							ident = true
  2658  						}
  2659  					case *ssa.Lookup:
  2660  					default:
  2661  						// the string is used somewhere else than a
  2662  						// map lookup
  2663  						continue insLoop
  2664  					}
  2665  				}
  2666  
  2667  				// the result of the conversion wasn't assigned to an
  2668  				// identifier
  2669  				if !ident {
  2670  					continue
  2671  				}
  2672  				j.Errorf(conv, "m[string(key)] would be more efficient than k := string(key); m[k]")
  2673  			}
  2674  		}
  2675  	}
  2676  }
  2677  
  2678  func (c *Checker) CheckRangeStringRunes(j *lint.Job) {
  2679  	sharedcheck.CheckRangeStringRunes(j)
  2680  }
  2681  
  2682  func (c *Checker) CheckSelfAssignment(j *lint.Job) {
  2683  	fn := func(node ast.Node) bool {
  2684  		assign, ok := node.(*ast.AssignStmt)
  2685  		if !ok {
  2686  			return true
  2687  		}
  2688  		if assign.Tok != token.ASSIGN || len(assign.Lhs) != len(assign.Rhs) {
  2689  			return true
  2690  		}
  2691  		for i, stmt := range assign.Lhs {
  2692  			rlh := Render(j, stmt)
  2693  			rrh := Render(j, assign.Rhs[i])
  2694  			if rlh == rrh {
  2695  				j.Errorf(assign, "self-assignment of %s to %s", rrh, rlh)
  2696  			}
  2697  		}
  2698  		return true
  2699  	}
  2700  	for _, f := range j.Program.Files {
  2701  		ast.Inspect(f, fn)
  2702  	}
  2703  }
  2704  
  2705  func buildTagsIdentical(s1, s2 []string) bool {
  2706  	if len(s1) != len(s2) {
  2707  		return false
  2708  	}
  2709  	s1s := make([]string, len(s1))
  2710  	copy(s1s, s1)
  2711  	sort.Strings(s1s)
  2712  	s2s := make([]string, len(s2))
  2713  	copy(s2s, s2)
  2714  	sort.Strings(s2s)
  2715  	for i, s := range s1s {
  2716  		if s != s2s[i] {
  2717  			return false
  2718  		}
  2719  	}
  2720  	return true
  2721  }
  2722  
  2723  func (c *Checker) CheckDuplicateBuildConstraints(job *lint.Job) {
  2724  	for _, f := range job.Program.Files {
  2725  		constraints := buildTags(f)
  2726  		for i, constraint1 := range constraints {
  2727  			for j, constraint2 := range constraints {
  2728  				if i >= j {
  2729  					continue
  2730  				}
  2731  				if buildTagsIdentical(constraint1, constraint2) {
  2732  					job.Errorf(f, "identical build constraints %q and %q",
  2733  						strings.Join(constraint1, " "),
  2734  						strings.Join(constraint2, " "))
  2735  				}
  2736  			}
  2737  		}
  2738  	}
  2739  }
  2740  
  2741  func (c *Checker) CheckSillyRegexp(j *lint.Job) {
  2742  	// We could use the rule checking engine for this, but the
  2743  	// arguments aren't really invalid.
  2744  	for _, fn := range j.Program.InitialFunctions {
  2745  		for _, b := range fn.Blocks {
  2746  			for _, ins := range b.Instrs {
  2747  				call, ok := ins.(*ssa.Call)
  2748  				if !ok {
  2749  					continue
  2750  				}
  2751  				switch CallName(call.Common()) {
  2752  				case "regexp.MustCompile", "regexp.Compile", "regexp.Match", "regexp.MatchReader", "regexp.MatchString":
  2753  				default:
  2754  					continue
  2755  				}
  2756  				c, ok := call.Common().Args[0].(*ssa.Const)
  2757  				if !ok {
  2758  					continue
  2759  				}
  2760  				s := constant.StringVal(c.Value)
  2761  				re, err := syntax.Parse(s, 0)
  2762  				if err != nil {
  2763  					continue
  2764  				}
  2765  				if re.Op != syntax.OpLiteral && re.Op != syntax.OpEmptyMatch {
  2766  					continue
  2767  				}
  2768  				j.Errorf(call, "regular expression does not contain any meta characters")
  2769  			}
  2770  		}
  2771  	}
  2772  }
  2773  
  2774  func (c *Checker) CheckMissingEnumTypesInDeclaration(j *lint.Job) {
  2775  	fn := func(node ast.Node) bool {
  2776  		decl, ok := node.(*ast.GenDecl)
  2777  		if !ok {
  2778  			return true
  2779  		}
  2780  		if !decl.Lparen.IsValid() {
  2781  			return true
  2782  		}
  2783  		if decl.Tok != token.CONST {
  2784  			return true
  2785  		}
  2786  
  2787  		groups := GroupSpecs(j, decl.Specs)
  2788  	groupLoop:
  2789  		for _, group := range groups {
  2790  			if len(group) < 2 {
  2791  				continue
  2792  			}
  2793  			if group[0].(*ast.ValueSpec).Type == nil {
  2794  				// first constant doesn't have a type
  2795  				continue groupLoop
  2796  			}
  2797  			for i, spec := range group {
  2798  				spec := spec.(*ast.ValueSpec)
  2799  				if len(spec.Names) != 1 || len(spec.Values) != 1 {
  2800  					continue groupLoop
  2801  				}
  2802  				switch v := spec.Values[0].(type) {
  2803  				case *ast.BasicLit:
  2804  				case *ast.UnaryExpr:
  2805  					if _, ok := v.X.(*ast.BasicLit); !ok {
  2806  						continue groupLoop
  2807  					}
  2808  				default:
  2809  					// if it's not a literal it might be typed, such as
  2810  					// time.Microsecond = 1000 * Nanosecond
  2811  					continue groupLoop
  2812  				}
  2813  				if i == 0 {
  2814  					continue
  2815  				}
  2816  				if spec.Type != nil {
  2817  					continue groupLoop
  2818  				}
  2819  			}
  2820  			j.Errorf(group[0], "only the first constant in this group has an explicit type")
  2821  		}
  2822  		return true
  2823  	}
  2824  	for _, f := range j.Program.Files {
  2825  		ast.Inspect(f, fn)
  2826  	}
  2827  }
  2828  
  2829  func (c *Checker) CheckTimerResetReturnValue(j *lint.Job) {
  2830  	for _, fn := range j.Program.InitialFunctions {
  2831  		for _, block := range fn.Blocks {
  2832  			for _, ins := range block.Instrs {
  2833  				call, ok := ins.(*ssa.Call)
  2834  				if !ok {
  2835  					continue
  2836  				}
  2837  				if !IsCallTo(call.Common(), "(*time.Timer).Reset") {
  2838  					continue
  2839  				}
  2840  				refs := call.Referrers()
  2841  				if refs == nil {
  2842  					continue
  2843  				}
  2844  				for _, ref := range FilterDebug(*refs) {
  2845  					ifstmt, ok := ref.(*ssa.If)
  2846  					if !ok {
  2847  						continue
  2848  					}
  2849  
  2850  					found := false
  2851  					for _, succ := range ifstmt.Block().Succs {
  2852  						if len(succ.Preds) != 1 {
  2853  							// Merge point, not a branch in the
  2854  							// syntactical sense.
  2855  
  2856  							// FIXME(dh): this is broken for if
  2857  							// statements a la "if x || y"
  2858  							continue
  2859  						}
  2860  						ssautil.Walk(succ, func(b *ssa.BasicBlock) bool {
  2861  							if !succ.Dominates(b) {
  2862  								// We've reached the end of the branch
  2863  								return false
  2864  							}
  2865  							for _, ins := range b.Instrs {
  2866  								// TODO(dh): we should check that
  2867  								// we're receiving from the channel of
  2868  								// a time.Timer to further reduce
  2869  								// false positives. Not a key
  2870  								// priority, considering the rarity of
  2871  								// Reset and the tiny likeliness of a
  2872  								// false positive
  2873  								if ins, ok := ins.(*ssa.UnOp); ok && ins.Op == token.ARROW && IsType(ins.X.Type(), "<-chan time.Time") {
  2874  									found = true
  2875  									return false
  2876  								}
  2877  							}
  2878  							return true
  2879  						})
  2880  					}
  2881  
  2882  					if found {
  2883  						j.Errorf(call, "it is not possible to use Reset's return value correctly, as there is a race condition between draining the channel and the new timer expiring")
  2884  					}
  2885  				}
  2886  			}
  2887  		}
  2888  	}
  2889  }
  2890  
  2891  func (c *Checker) CheckToLowerToUpperComparison(j *lint.Job) {
  2892  	fn := func(node ast.Node) bool {
  2893  		binExpr, ok := node.(*ast.BinaryExpr)
  2894  		if !ok {
  2895  			return true
  2896  		}
  2897  
  2898  		var negative bool
  2899  		switch binExpr.Op {
  2900  		case token.EQL:
  2901  			negative = false
  2902  		case token.NEQ:
  2903  			negative = true
  2904  		default:
  2905  			return true
  2906  		}
  2907  
  2908  		const (
  2909  			lo = "strings.ToLower"
  2910  			up = "strings.ToUpper"
  2911  		)
  2912  
  2913  		var call string
  2914  		if IsCallToAST(j, binExpr.X, lo) && IsCallToAST(j, binExpr.Y, lo) {
  2915  			call = lo
  2916  		} else if IsCallToAST(j, binExpr.X, up) && IsCallToAST(j, binExpr.Y, up) {
  2917  			call = up
  2918  		} else {
  2919  			return true
  2920  		}
  2921  
  2922  		bang := ""
  2923  		if negative {
  2924  			bang = "!"
  2925  		}
  2926  
  2927  		j.Errorf(binExpr, "should use %sstrings.EqualFold(a, b) instead of %s(a) %s %s(b)", bang, call, binExpr.Op, call)
  2928  		return true
  2929  	}
  2930  
  2931  	for _, f := range j.Program.Files {
  2932  		ast.Inspect(f, fn)
  2933  	}
  2934  }
  2935  
  2936  func (c *Checker) CheckUnreachableTypeCases(j *lint.Job) {
  2937  	// Check if T subsumes V in a type switch. T subsumes V if T is an interface and T's method set is a subset of V's method set.
  2938  	subsumes := func(T, V types.Type) bool {
  2939  		tIface, ok := T.Underlying().(*types.Interface)
  2940  		if !ok {
  2941  			return false
  2942  		}
  2943  
  2944  		return types.Implements(V, tIface)
  2945  	}
  2946  
  2947  	subsumesAny := func(Ts, Vs []types.Type) (types.Type, types.Type, bool) {
  2948  		for _, T := range Ts {
  2949  			for _, V := range Vs {
  2950  				if subsumes(T, V) {
  2951  					return T, V, true
  2952  				}
  2953  			}
  2954  		}
  2955  
  2956  		return nil, nil, false
  2957  	}
  2958  
  2959  	fn := func(node ast.Node) bool {
  2960  		tsStmt, ok := node.(*ast.TypeSwitchStmt)
  2961  		if !ok {
  2962  			return true
  2963  		}
  2964  
  2965  		type ccAndTypes struct {
  2966  			cc    *ast.CaseClause
  2967  			types []types.Type
  2968  		}
  2969  
  2970  		// All asserted types in the order of case clauses.
  2971  		ccs := make([]ccAndTypes, 0, len(tsStmt.Body.List))
  2972  		for _, stmt := range tsStmt.Body.List {
  2973  			cc, _ := stmt.(*ast.CaseClause)
  2974  
  2975  			// Exclude the 'default' case.
  2976  			if len(cc.List) == 0 {
  2977  				continue
  2978  			}
  2979  
  2980  			Ts := make([]types.Type, len(cc.List))
  2981  			for i, expr := range cc.List {
  2982  				Ts[i] = TypeOf(j, expr)
  2983  			}
  2984  
  2985  			ccs = append(ccs, ccAndTypes{cc: cc, types: Ts})
  2986  		}
  2987  
  2988  		if len(ccs) <= 1 {
  2989  			// Zero or one case clauses, nothing to check.
  2990  			return true
  2991  		}
  2992  
  2993  		// Check if case clauses following cc have types that are subsumed by cc.
  2994  		for i, cc := range ccs[:len(ccs)-1] {
  2995  			for _, next := range ccs[i+1:] {
  2996  				if T, V, yes := subsumesAny(cc.types, next.types); yes {
  2997  					j.Errorf(next.cc, "unreachable case clause: %s will always match before %s", T.String(), V.String())
  2998  				}
  2999  			}
  3000  		}
  3001  
  3002  		return true
  3003  	}
  3004  
  3005  	for _, f := range j.Program.Files {
  3006  		ast.Inspect(f, fn)
  3007  	}
  3008  }