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