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

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