honnef.co/go/tools@v0.4.7/staticcheck/lint.go (about)

     1  package staticcheck
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/constant"
     7  	"go/token"
     8  	"go/types"
     9  	htmltemplate "html/template"
    10  	"net/http"
    11  	"os"
    12  	"reflect"
    13  	"regexp"
    14  	"regexp/syntax"
    15  	"sort"
    16  	"strconv"
    17  	"strings"
    18  	texttemplate "text/template"
    19  	"unicode"
    20  
    21  	"honnef.co/go/tools/analysis/code"
    22  	"honnef.co/go/tools/analysis/edit"
    23  	"honnef.co/go/tools/analysis/facts/deprecated"
    24  	"honnef.co/go/tools/analysis/facts/generated"
    25  	"honnef.co/go/tools/analysis/facts/nilness"
    26  	"honnef.co/go/tools/analysis/facts/purity"
    27  	"honnef.co/go/tools/analysis/facts/typedness"
    28  	"honnef.co/go/tools/analysis/lint"
    29  	"honnef.co/go/tools/analysis/report"
    30  	"honnef.co/go/tools/go/ast/astutil"
    31  	"honnef.co/go/tools/go/ir"
    32  	"honnef.co/go/tools/go/ir/irutil"
    33  	"honnef.co/go/tools/go/types/typeutil"
    34  	"honnef.co/go/tools/internal/passes/buildir"
    35  	"honnef.co/go/tools/internal/sharedcheck"
    36  	"honnef.co/go/tools/knowledge"
    37  	"honnef.co/go/tools/pattern"
    38  	"honnef.co/go/tools/printf"
    39  	"honnef.co/go/tools/staticcheck/fakejson"
    40  	"honnef.co/go/tools/staticcheck/fakereflect"
    41  	"honnef.co/go/tools/staticcheck/fakexml"
    42  
    43  	"golang.org/x/exp/typeparams"
    44  	"golang.org/x/tools/go/analysis"
    45  	"golang.org/x/tools/go/analysis/passes/inspect"
    46  	"golang.org/x/tools/go/ast/inspector"
    47  )
    48  
    49  func checkSortSlice(call *Call) {
    50  	c := call.Instr.Common().StaticCallee()
    51  	arg := call.Args[0]
    52  
    53  	T := arg.Value.Value.Type().Underlying()
    54  	switch T.(type) {
    55  	case *types.Interface:
    56  		// we don't know.
    57  		// TODO(dh): if the value is a phi node we can look at its edges
    58  		if k, ok := arg.Value.Value.(*ir.Const); ok && k.Value == nil {
    59  			// literal nil, e.g. sort.Sort(nil, ...)
    60  			arg.Invalid(fmt.Sprintf("cannot call %s on nil literal", c))
    61  		}
    62  	case *types.Slice:
    63  		// this is fine
    64  	default:
    65  		// this is not fine
    66  		arg.Invalid(fmt.Sprintf("%s must only be called on slices, was called on %s", c, T))
    67  	}
    68  }
    69  
    70  func validRegexp(call *Call) {
    71  	arg := call.Args[0]
    72  	err := ValidateRegexp(arg.Value)
    73  	if err != nil {
    74  		arg.Invalid(err.Error())
    75  	}
    76  }
    77  
    78  type runeSlice []rune
    79  
    80  func (rs runeSlice) Len() int               { return len(rs) }
    81  func (rs runeSlice) Less(i int, j int) bool { return rs[i] < rs[j] }
    82  func (rs runeSlice) Swap(i int, j int)      { rs[i], rs[j] = rs[j], rs[i] }
    83  
    84  func utf8Cutset(call *Call) {
    85  	arg := call.Args[1]
    86  	if InvalidUTF8(arg.Value) {
    87  		arg.Invalid(MsgInvalidUTF8)
    88  	}
    89  }
    90  
    91  func uniqueCutset(call *Call) {
    92  	arg := call.Args[1]
    93  	if !UniqueStringCutset(arg.Value) {
    94  		arg.Invalid(MsgNonUniqueCutset)
    95  	}
    96  }
    97  
    98  func unmarshalPointer(name string, arg int) CallCheck {
    99  	return func(call *Call) {
   100  		if !Pointer(call.Args[arg].Value) {
   101  			call.Args[arg].Invalid(fmt.Sprintf("%s expects to unmarshal into a pointer, but the provided value is not a pointer", name))
   102  		}
   103  	}
   104  }
   105  
   106  func pointlessIntMath(call *Call) {
   107  	if ConvertedFromInt(call.Args[0].Value) {
   108  		call.Invalid(fmt.Sprintf("calling %s on a converted integer is pointless", irutil.CallName(call.Instr.Common())))
   109  	}
   110  }
   111  
   112  func checkValidHostPort(arg int) CallCheck {
   113  	return func(call *Call) {
   114  		if !ValidHostPort(call.Args[arg].Value) {
   115  			call.Args[arg].Invalid(MsgInvalidHostPort)
   116  		}
   117  	}
   118  }
   119  
   120  var (
   121  	checkRegexpRules = map[string]CallCheck{
   122  		"regexp.MustCompile": validRegexp,
   123  		"regexp.Compile":     validRegexp,
   124  		"regexp.Match":       validRegexp,
   125  		"regexp.MatchReader": validRegexp,
   126  		"regexp.MatchString": validRegexp,
   127  	}
   128  
   129  	checkTimeParseRules = map[string]CallCheck{
   130  		"time.Parse": func(call *Call) {
   131  			arg := call.Args[knowledge.Arg("time.Parse.layout")]
   132  			err := ValidateTimeLayout(arg.Value)
   133  			if err != nil {
   134  				arg.Invalid(err.Error())
   135  			}
   136  		},
   137  	}
   138  
   139  	checkEncodingBinaryRules = map[string]CallCheck{
   140  		"encoding/binary.Write": func(call *Call) {
   141  			arg := call.Args[knowledge.Arg("encoding/binary.Write.data")]
   142  			if !CanBinaryMarshal(call.Pass, arg.Value) {
   143  				arg.Invalid(fmt.Sprintf("value of type %s cannot be used with binary.Write", arg.Value.Value.Type()))
   144  			}
   145  		},
   146  	}
   147  
   148  	checkURLsRules = map[string]CallCheck{
   149  		"net/url.Parse": func(call *Call) {
   150  			arg := call.Args[knowledge.Arg("net/url.Parse.rawurl")]
   151  			err := ValidateURL(arg.Value)
   152  			if err != nil {
   153  				arg.Invalid(err.Error())
   154  			}
   155  		},
   156  	}
   157  
   158  	checkSyncPoolValueRules = map[string]CallCheck{
   159  		"(*sync.Pool).Put": func(call *Call) {
   160  			arg := call.Args[knowledge.Arg("(*sync.Pool).Put.x")]
   161  			typ := arg.Value.Value.Type()
   162  			_, isSlice := typ.Underlying().(*types.Slice)
   163  			if !typeutil.IsPointerLike(typ) || isSlice {
   164  				arg.Invalid("argument should be pointer-like to avoid allocations")
   165  			}
   166  		},
   167  	}
   168  
   169  	checkRegexpFindAllRules = map[string]CallCheck{
   170  		"(*regexp.Regexp).FindAll":                    RepeatZeroTimes("a FindAll method", 1),
   171  		"(*regexp.Regexp).FindAllIndex":               RepeatZeroTimes("a FindAll method", 1),
   172  		"(*regexp.Regexp).FindAllString":              RepeatZeroTimes("a FindAll method", 1),
   173  		"(*regexp.Regexp).FindAllStringIndex":         RepeatZeroTimes("a FindAll method", 1),
   174  		"(*regexp.Regexp).FindAllStringSubmatch":      RepeatZeroTimes("a FindAll method", 1),
   175  		"(*regexp.Regexp).FindAllStringSubmatchIndex": RepeatZeroTimes("a FindAll method", 1),
   176  		"(*regexp.Regexp).FindAllSubmatch":            RepeatZeroTimes("a FindAll method", 1),
   177  		"(*regexp.Regexp).FindAllSubmatchIndex":       RepeatZeroTimes("a FindAll method", 1),
   178  	}
   179  
   180  	checkUTF8CutsetRules = map[string]CallCheck{
   181  		"strings.IndexAny":     utf8Cutset,
   182  		"strings.LastIndexAny": utf8Cutset,
   183  		"strings.ContainsAny":  utf8Cutset,
   184  		"strings.Trim":         utf8Cutset,
   185  		"strings.TrimLeft":     utf8Cutset,
   186  		"strings.TrimRight":    utf8Cutset,
   187  	}
   188  
   189  	checkUniqueCutsetRules = map[string]CallCheck{
   190  		"strings.Trim":      uniqueCutset,
   191  		"strings.TrimLeft":  uniqueCutset,
   192  		"strings.TrimRight": uniqueCutset,
   193  	}
   194  
   195  	checkUnmarshalPointerRules = map[string]CallCheck{
   196  		"encoding/xml.Unmarshal":                unmarshalPointer("xml.Unmarshal", 1),
   197  		"(*encoding/xml.Decoder).Decode":        unmarshalPointer("Decode", 0),
   198  		"(*encoding/xml.Decoder).DecodeElement": unmarshalPointer("DecodeElement", 0),
   199  		"encoding/json.Unmarshal":               unmarshalPointer("json.Unmarshal", 1),
   200  		"(*encoding/json.Decoder).Decode":       unmarshalPointer("Decode", 0),
   201  	}
   202  
   203  	checkUnbufferedSignalChanRules = map[string]CallCheck{
   204  		"os/signal.Notify": func(call *Call) {
   205  			arg := call.Args[knowledge.Arg("os/signal.Notify.c")]
   206  			if UnbufferedChannel(arg.Value) {
   207  				arg.Invalid("the channel used with signal.Notify should be buffered")
   208  			}
   209  		},
   210  	}
   211  
   212  	checkMathIntRules = map[string]CallCheck{
   213  		"math.Ceil":  pointlessIntMath,
   214  		"math.Floor": pointlessIntMath,
   215  		"math.IsNaN": pointlessIntMath,
   216  		"math.Trunc": pointlessIntMath,
   217  		"math.IsInf": pointlessIntMath,
   218  	}
   219  
   220  	checkStringsReplaceZeroRules = map[string]CallCheck{
   221  		"strings.Replace": RepeatZeroTimes("strings.Replace", 3),
   222  		"bytes.Replace":   RepeatZeroTimes("bytes.Replace", 3),
   223  	}
   224  
   225  	checkListenAddressRules = map[string]CallCheck{
   226  		"net/http.ListenAndServe":    checkValidHostPort(0),
   227  		"net/http.ListenAndServeTLS": checkValidHostPort(0),
   228  	}
   229  
   230  	checkBytesEqualIPRules = map[string]CallCheck{
   231  		"bytes.Equal": func(call *Call) {
   232  			if ConvertedFrom(call.Args[knowledge.Arg("bytes.Equal.a")].Value, "net.IP") &&
   233  				ConvertedFrom(call.Args[knowledge.Arg("bytes.Equal.b")].Value, "net.IP") {
   234  				call.Invalid("use net.IP.Equal to compare net.IPs, not bytes.Equal")
   235  			}
   236  		},
   237  	}
   238  
   239  	checkRegexpMatchLoopRules = map[string]CallCheck{
   240  		"regexp.Match":       loopedRegexp("regexp.Match"),
   241  		"regexp.MatchReader": loopedRegexp("regexp.MatchReader"),
   242  		"regexp.MatchString": loopedRegexp("regexp.MatchString"),
   243  	}
   244  
   245  	checkNoopMarshal = map[string]CallCheck{
   246  		// TODO(dh): should we really flag XML? Even an empty struct
   247  		// produces a non-zero amount of data, namely its type name.
   248  		// Let's see if we encounter any false positives.
   249  		//
   250  		// Also, should we flag gob?
   251  		"encoding/json.Marshal":           checkNoopMarshalImpl(knowledge.Arg("json.Marshal.v"), "MarshalJSON", "MarshalText"),
   252  		"encoding/xml.Marshal":            checkNoopMarshalImpl(knowledge.Arg("xml.Marshal.v"), "MarshalXML", "MarshalText"),
   253  		"(*encoding/json.Encoder).Encode": checkNoopMarshalImpl(knowledge.Arg("(*encoding/json.Encoder).Encode.v"), "MarshalJSON", "MarshalText"),
   254  		"(*encoding/xml.Encoder).Encode":  checkNoopMarshalImpl(knowledge.Arg("(*encoding/xml.Encoder).Encode.v"), "MarshalXML", "MarshalText"),
   255  
   256  		"encoding/json.Unmarshal":         checkNoopMarshalImpl(knowledge.Arg("json.Unmarshal.v"), "UnmarshalJSON", "UnmarshalText"),
   257  		"encoding/xml.Unmarshal":          checkNoopMarshalImpl(knowledge.Arg("xml.Unmarshal.v"), "UnmarshalXML", "UnmarshalText"),
   258  		"(*encoding/json.Decoder).Decode": checkNoopMarshalImpl(knowledge.Arg("(*encoding/json.Decoder).Decode.v"), "UnmarshalJSON", "UnmarshalText"),
   259  		"(*encoding/xml.Decoder).Decode":  checkNoopMarshalImpl(knowledge.Arg("(*encoding/xml.Decoder).Decode.v"), "UnmarshalXML", "UnmarshalText"),
   260  	}
   261  
   262  	checkUnsupportedMarshal = map[string]CallCheck{
   263  		"encoding/json.Marshal":           checkUnsupportedMarshalJSON,
   264  		"encoding/xml.Marshal":            checkUnsupportedMarshalXML,
   265  		"(*encoding/json.Encoder).Encode": checkUnsupportedMarshalJSON,
   266  		"(*encoding/xml.Encoder).Encode":  checkUnsupportedMarshalXML,
   267  	}
   268  
   269  	checkAtomicAlignment = map[string]CallCheck{
   270  		"sync/atomic.AddInt64":             checkAtomicAlignmentImpl,
   271  		"sync/atomic.AddUint64":            checkAtomicAlignmentImpl,
   272  		"sync/atomic.CompareAndSwapInt64":  checkAtomicAlignmentImpl,
   273  		"sync/atomic.CompareAndSwapUint64": checkAtomicAlignmentImpl,
   274  		"sync/atomic.LoadInt64":            checkAtomicAlignmentImpl,
   275  		"sync/atomic.LoadUint64":           checkAtomicAlignmentImpl,
   276  		"sync/atomic.StoreInt64":           checkAtomicAlignmentImpl,
   277  		"sync/atomic.StoreUint64":          checkAtomicAlignmentImpl,
   278  		"sync/atomic.SwapInt64":            checkAtomicAlignmentImpl,
   279  		"sync/atomic.SwapUint64":           checkAtomicAlignmentImpl,
   280  	}
   281  
   282  	// TODO(dh): detect printf wrappers
   283  	checkPrintfRules = map[string]CallCheck{
   284  		"fmt.Errorf":                  func(call *Call) { checkPrintfCall(call, 0, 1) },
   285  		"fmt.Printf":                  func(call *Call) { checkPrintfCall(call, 0, 1) },
   286  		"fmt.Sprintf":                 func(call *Call) { checkPrintfCall(call, 0, 1) },
   287  		"fmt.Fprintf":                 func(call *Call) { checkPrintfCall(call, 1, 2) },
   288  		"golang.org/x/xerrors.Errorf": func(call *Call) { checkPrintfCall(call, 0, 1) },
   289  	}
   290  
   291  	checkSortSliceRules = map[string]CallCheck{
   292  		"sort.Slice":         checkSortSlice,
   293  		"sort.SliceIsSorted": checkSortSlice,
   294  		"sort.SliceStable":   checkSortSlice,
   295  	}
   296  
   297  	checkWithValueKeyRules = map[string]CallCheck{
   298  		"context.WithValue": checkWithValueKey,
   299  	}
   300  
   301  	checkStrconvRules = map[string]CallCheck{
   302  		"strconv.ParseComplex": func(call *Call) {
   303  			validateComplexBitSize(call.Args[knowledge.Arg("strconv.ParseComplex.bitSize")])
   304  		},
   305  		"strconv.ParseFloat": func(call *Call) {
   306  			validateFloatBitSize(call.Args[knowledge.Arg("strconv.ParseFloat.bitSize")])
   307  		},
   308  		"strconv.ParseInt": func(call *Call) {
   309  			validateContinuousBitSize(call.Args[knowledge.Arg("strconv.ParseInt.bitSize")], 0, 64)
   310  			validateIntBaseAllowZero(call.Args[knowledge.Arg("strconv.ParseInt.base")])
   311  		},
   312  		"strconv.ParseUint": func(call *Call) {
   313  			validateContinuousBitSize(call.Args[knowledge.Arg("strconv.ParseUint.bitSize")], 0, 64)
   314  			validateIntBaseAllowZero(call.Args[knowledge.Arg("strconv.ParseUint.base")])
   315  		},
   316  
   317  		"strconv.FormatComplex": func(call *Call) {
   318  			validateComplexFormat(call.Args[knowledge.Arg("strconv.FormatComplex.fmt")])
   319  			validateComplexBitSize(call.Args[knowledge.Arg("strconv.FormatComplex.bitSize")])
   320  		},
   321  		"strconv.FormatFloat": func(call *Call) {
   322  			validateFloatFormat(call.Args[knowledge.Arg("strconv.FormatFloat.fmt")])
   323  			validateFloatBitSize(call.Args[knowledge.Arg("strconv.FormatFloat.bitSize")])
   324  		},
   325  		"strconv.FormatInt": func(call *Call) {
   326  			validateIntBase(call.Args[knowledge.Arg("strconv.FormatInt.base")])
   327  		},
   328  		"strconv.FormatUint": func(call *Call) {
   329  			validateIntBase(call.Args[knowledge.Arg("strconv.FormatUint.base")])
   330  		},
   331  
   332  		"strconv.AppendFloat": func(call *Call) {
   333  			validateFloatFormat(call.Args[knowledge.Arg("strconv.AppendFloat.fmt")])
   334  			validateFloatBitSize(call.Args[knowledge.Arg("strconv.AppendFloat.bitSize")])
   335  		},
   336  		"strconv.AppendInt": func(call *Call) {
   337  			validateIntBase(call.Args[knowledge.Arg("strconv.AppendInt.base")])
   338  		},
   339  		"strconv.AppendUint": func(call *Call) {
   340  			validateIntBase(call.Args[knowledge.Arg("strconv.AppendUint.base")])
   341  		},
   342  	}
   343  )
   344  
   345  func validateIntBase(arg *Argument) {
   346  	if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil {
   347  		val, _ := constant.Int64Val(c.Value)
   348  		if val < 2 {
   349  			arg.Invalid("'base' must not be smaller than 2")
   350  		}
   351  		if val > 36 {
   352  			arg.Invalid("'base' must not be larger than 36")
   353  		}
   354  	}
   355  }
   356  
   357  func validateIntBaseAllowZero(arg *Argument) {
   358  	if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil {
   359  		val, _ := constant.Int64Val(c.Value)
   360  		if val < 2 && val != 0 {
   361  			arg.Invalid("'base' must not be smaller than 2, unless it is 0")
   362  		}
   363  		if val > 36 {
   364  			arg.Invalid("'base' must not be larger than 36")
   365  		}
   366  	}
   367  }
   368  
   369  func validateComplexFormat(arg *Argument) {
   370  	validateFloatFormat(arg)
   371  }
   372  
   373  func validateFloatFormat(arg *Argument) {
   374  	if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil {
   375  		val, _ := constant.Int64Val(c.Value)
   376  		switch val {
   377  		case 'b', 'e', 'E', 'f', 'g', 'G', 'x', 'X':
   378  		default:
   379  			arg.Invalid(fmt.Sprintf("'fmt' argument is invalid: unknown format %q", val))
   380  		}
   381  	}
   382  }
   383  
   384  func validateComplexBitSize(arg *Argument) { validateDiscreetBitSize(arg, 64, 128) }
   385  func validateFloatBitSize(arg *Argument)   { validateDiscreetBitSize(arg, 32, 64) }
   386  
   387  func validateDiscreetBitSize(arg *Argument, size1 int, size2 int) {
   388  	if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil {
   389  		val, _ := constant.Int64Val(c.Value)
   390  		if val != int64(size1) && val != int64(size2) {
   391  			arg.Invalid(fmt.Sprintf("'bitSize' argument is invalid, must be either %d or %d", size1, size2))
   392  		}
   393  	}
   394  }
   395  
   396  func validateContinuousBitSize(arg *Argument, min int, max int) {
   397  	if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil {
   398  		val, _ := constant.Int64Val(c.Value)
   399  		if val < int64(min) || val > int64(max) {
   400  			arg.Invalid(fmt.Sprintf("'bitSize' argument is invalid, must be within %d and %d", min, max))
   401  		}
   402  	}
   403  }
   404  
   405  func checkPrintfCall(call *Call, fIdx, vIdx int) {
   406  	f := call.Args[fIdx]
   407  	var args []ir.Value
   408  	switch v := call.Args[vIdx].Value.Value.(type) {
   409  	case *ir.Slice:
   410  		var ok bool
   411  		args, ok = irutil.Vararg(v)
   412  		if !ok {
   413  			// We don't know what the actual arguments to the function are
   414  			return
   415  		}
   416  	case *ir.Const:
   417  		// nil, i.e. no arguments
   418  	default:
   419  		// We don't know what the actual arguments to the function are
   420  		return
   421  	}
   422  	checkPrintfCallImpl(f, f.Value.Value, args)
   423  }
   424  
   425  type verbFlag int
   426  
   427  const (
   428  	isInt verbFlag = 1 << iota
   429  	isBool
   430  	isFP
   431  	isString
   432  	isPointer
   433  	// Verbs that accept "pseudo pointers" will sometimes dereference
   434  	// non-nil pointers. For example, %x on a non-nil *struct will print the
   435  	// individual fields, but on a nil pointer it will print the address.
   436  	isPseudoPointer
   437  	isSlice
   438  	isAny
   439  	noRecurse
   440  )
   441  
   442  var verbs = [...]verbFlag{
   443  	'b': isPseudoPointer | isInt | isFP,
   444  	'c': isInt,
   445  	'd': isPseudoPointer | isInt,
   446  	'e': isFP,
   447  	'E': isFP,
   448  	'f': isFP,
   449  	'F': isFP,
   450  	'g': isFP,
   451  	'G': isFP,
   452  	'o': isPseudoPointer | isInt,
   453  	'O': isPseudoPointer | isInt,
   454  	'p': isSlice | isPointer | noRecurse,
   455  	'q': isInt | isString,
   456  	's': isString,
   457  	't': isBool,
   458  	'T': isAny,
   459  	'U': isInt,
   460  	'v': isAny,
   461  	'X': isPseudoPointer | isInt | isFP | isString,
   462  	'x': isPseudoPointer | isInt | isFP | isString,
   463  }
   464  
   465  func checkPrintfCallImpl(carg *Argument, f ir.Value, args []ir.Value) {
   466  	var msCache *typeutil.MethodSetCache
   467  	if f.Parent() != nil {
   468  		msCache = &f.Parent().Prog.MethodSets
   469  	}
   470  
   471  	elem := func(T types.Type, verb rune) ([]types.Type, bool) {
   472  		if verbs[verb]&noRecurse != 0 {
   473  			return []types.Type{T}, false
   474  		}
   475  		switch T := T.(type) {
   476  		case *types.Slice:
   477  			if verbs[verb]&isSlice != 0 {
   478  				return []types.Type{T}, false
   479  			}
   480  			if verbs[verb]&isString != 0 && typeutil.IsType(T.Elem().Underlying(), "byte") {
   481  				return []types.Type{T}, false
   482  			}
   483  			return []types.Type{T.Elem()}, true
   484  		case *types.Map:
   485  			key := T.Key()
   486  			val := T.Elem()
   487  			return []types.Type{key, val}, true
   488  		case *types.Struct:
   489  			out := make([]types.Type, 0, T.NumFields())
   490  			for i := 0; i < T.NumFields(); i++ {
   491  				out = append(out, T.Field(i).Type())
   492  			}
   493  			return out, true
   494  		case *types.Array:
   495  			return []types.Type{T.Elem()}, true
   496  		default:
   497  			return []types.Type{T}, false
   498  		}
   499  	}
   500  	isInfo := func(T types.Type, info types.BasicInfo) bool {
   501  		basic, ok := T.Underlying().(*types.Basic)
   502  		return ok && basic.Info()&info != 0
   503  	}
   504  
   505  	isFormatter := func(T types.Type, ms *types.MethodSet) bool {
   506  		sel := ms.Lookup(nil, "Format")
   507  		if sel == nil {
   508  			return false
   509  		}
   510  		fn, ok := sel.Obj().(*types.Func)
   511  		if !ok {
   512  			// should be unreachable
   513  			return false
   514  		}
   515  		sig := fn.Type().(*types.Signature)
   516  		if sig.Params().Len() != 2 {
   517  			return false
   518  		}
   519  		// TODO(dh): check the types of the arguments for more
   520  		// precision
   521  		if sig.Results().Len() != 0 {
   522  			return false
   523  		}
   524  		return true
   525  	}
   526  
   527  	var seen typeutil.Map[struct{}]
   528  	var checkType func(verb rune, T types.Type, top bool) bool
   529  	checkType = func(verb rune, T types.Type, top bool) bool {
   530  		if top {
   531  			seen = typeutil.Map[struct{}]{}
   532  		}
   533  		if _, ok := seen.At(T); ok {
   534  			return true
   535  		}
   536  		seen.Set(T, struct{}{})
   537  		if int(verb) >= len(verbs) {
   538  			// Unknown verb
   539  			return true
   540  		}
   541  
   542  		flags := verbs[verb]
   543  		if flags == 0 {
   544  			// Unknown verb
   545  			return true
   546  		}
   547  
   548  		ms := msCache.MethodSet(T)
   549  		if isFormatter(T, ms) {
   550  			// the value is responsible for formatting itself
   551  			return true
   552  		}
   553  
   554  		if flags&isString != 0 && (types.Implements(T, knowledge.Interfaces["fmt.Stringer"]) || types.Implements(T, knowledge.Interfaces["error"])) {
   555  			// Check for stringer early because we're about to dereference
   556  			return true
   557  		}
   558  
   559  		T = T.Underlying()
   560  		if flags&(isPointer|isPseudoPointer) == 0 && top {
   561  			T = typeutil.Dereference(T)
   562  		}
   563  		if flags&isPseudoPointer != 0 && top {
   564  			t := typeutil.Dereference(T)
   565  			if _, ok := t.Underlying().(*types.Struct); ok {
   566  				T = t
   567  			}
   568  		}
   569  
   570  		if _, ok := T.(*types.Interface); ok {
   571  			// We don't know what's in the interface
   572  			return true
   573  		}
   574  
   575  		var info types.BasicInfo
   576  		if flags&isInt != 0 {
   577  			info |= types.IsInteger
   578  		}
   579  		if flags&isBool != 0 {
   580  			info |= types.IsBoolean
   581  		}
   582  		if flags&isFP != 0 {
   583  			info |= types.IsFloat | types.IsComplex
   584  		}
   585  		if flags&isString != 0 {
   586  			info |= types.IsString
   587  		}
   588  
   589  		if info != 0 && isInfo(T, info) {
   590  			return true
   591  		}
   592  
   593  		if flags&isString != 0 {
   594  			isStringyElem := func(typ types.Type) bool {
   595  				if typ, ok := typ.Underlying().(*types.Basic); ok {
   596  					return typ.Kind() == types.Byte
   597  				}
   598  				return false
   599  			}
   600  			switch T := T.(type) {
   601  			case *types.Slice:
   602  				if isStringyElem(T.Elem()) {
   603  					return true
   604  				}
   605  			case *types.Array:
   606  				if isStringyElem(T.Elem()) {
   607  					return true
   608  				}
   609  			}
   610  			if types.Implements(T, knowledge.Interfaces["fmt.Stringer"]) || types.Implements(T, knowledge.Interfaces["error"]) {
   611  				return true
   612  			}
   613  		}
   614  
   615  		if flags&isPointer != 0 && typeutil.IsPointerLike(T) {
   616  			return true
   617  		}
   618  		if flags&isPseudoPointer != 0 {
   619  			switch U := T.Underlying().(type) {
   620  			case *types.Pointer:
   621  				if !top {
   622  					return true
   623  				}
   624  
   625  				if _, ok := U.Elem().Underlying().(*types.Struct); !ok {
   626  					// TODO(dh): can this condition ever be false? For
   627  					// *T, if T is a struct, we'll already have
   628  					// dereferenced it, meaning the *types.Pointer
   629  					// branch couldn't have been taken. For T that
   630  					// aren't structs, this condition will always
   631  					// evaluate to true.
   632  					return true
   633  				}
   634  			case *types.Chan, *types.Signature:
   635  				// Channels and functions are always treated as
   636  				// pointers and never recursed into.
   637  				return true
   638  			case *types.Basic:
   639  				if U.Kind() == types.UnsafePointer {
   640  					return true
   641  				}
   642  			case *types.Interface:
   643  				// we will already have bailed if the type is an
   644  				// interface.
   645  				panic("unreachable")
   646  			default:
   647  				// other pointer-like types, such as maps or slices,
   648  				// will be printed element-wise.
   649  			}
   650  		}
   651  
   652  		if flags&isSlice != 0 {
   653  			if _, ok := T.(*types.Slice); ok {
   654  				return true
   655  			}
   656  		}
   657  
   658  		if flags&isAny != 0 {
   659  			return true
   660  		}
   661  
   662  		elems, ok := elem(T.Underlying(), verb)
   663  		if !ok {
   664  			return false
   665  		}
   666  		for _, elem := range elems {
   667  			if !checkType(verb, elem, false) {
   668  				return false
   669  			}
   670  		}
   671  
   672  		return true
   673  	}
   674  
   675  	k, ok := irutil.Flatten(f).(*ir.Const)
   676  	if !ok {
   677  		return
   678  	}
   679  	actions, err := printf.Parse(constant.StringVal(k.Value))
   680  	if err != nil {
   681  		carg.Invalid("couldn't parse format string")
   682  		return
   683  	}
   684  
   685  	ptr := 1
   686  	hasExplicit := false
   687  
   688  	checkStar := func(verb printf.Verb, star printf.Argument) bool {
   689  		if star, ok := star.(printf.Star); ok {
   690  			idx := 0
   691  			if star.Index == -1 {
   692  				idx = ptr
   693  				ptr++
   694  			} else {
   695  				hasExplicit = true
   696  				idx = star.Index
   697  				ptr = star.Index + 1
   698  			}
   699  			if idx == 0 {
   700  				carg.Invalid(fmt.Sprintf("Printf format %s reads invalid arg 0; indices are 1-based", verb.Raw))
   701  				return false
   702  			}
   703  			if idx > len(args) {
   704  				carg.Invalid(
   705  					fmt.Sprintf("Printf format %s reads arg #%d, but call has only %d args",
   706  						verb.Raw, idx, len(args)))
   707  				return false
   708  			}
   709  			if arg, ok := args[idx-1].(*ir.MakeInterface); ok {
   710  				if !isInfo(arg.X.Type(), types.IsInteger) {
   711  					carg.Invalid(fmt.Sprintf("Printf format %s reads non-int arg #%d as argument of *", verb.Raw, idx))
   712  				}
   713  			}
   714  		}
   715  		return true
   716  	}
   717  
   718  	// We only report one problem per format string. Making a
   719  	// mistake with an index tends to invalidate all future
   720  	// implicit indices.
   721  	for _, action := range actions {
   722  		verb, ok := action.(printf.Verb)
   723  		if !ok {
   724  			continue
   725  		}
   726  
   727  		if !checkStar(verb, verb.Width) || !checkStar(verb, verb.Precision) {
   728  			return
   729  		}
   730  
   731  		off := ptr
   732  		if verb.Value != -1 {
   733  			hasExplicit = true
   734  			off = verb.Value
   735  		}
   736  		if off > len(args) {
   737  			carg.Invalid(
   738  				fmt.Sprintf("Printf format %s reads arg #%d, but call has only %d args",
   739  					verb.Raw, off, len(args)))
   740  			return
   741  		} else if verb.Value == 0 && verb.Letter != '%' {
   742  			carg.Invalid(fmt.Sprintf("Printf format %s reads invalid arg 0; indices are 1-based", verb.Raw))
   743  			return
   744  		} else if off != 0 {
   745  			arg, ok := args[off-1].(*ir.MakeInterface)
   746  			if ok {
   747  				if !checkType(verb.Letter, arg.X.Type(), true) {
   748  					carg.Invalid(fmt.Sprintf("Printf format %s has arg #%d of wrong type %s",
   749  						verb.Raw, ptr, args[ptr-1].(*ir.MakeInterface).X.Type()))
   750  					return
   751  				}
   752  			}
   753  		}
   754  
   755  		switch verb.Value {
   756  		case -1:
   757  			// Consume next argument
   758  			ptr++
   759  		case 0:
   760  			// Don't consume any arguments
   761  		default:
   762  			ptr = verb.Value + 1
   763  		}
   764  	}
   765  
   766  	if !hasExplicit && ptr <= len(args) {
   767  		carg.Invalid(fmt.Sprintf("Printf call needs %d args but has %d args", ptr-1, len(args)))
   768  	}
   769  }
   770  
   771  func checkAtomicAlignmentImpl(call *Call) {
   772  	sizes := call.Pass.TypesSizes
   773  	if sizes.Sizeof(types.Typ[types.Uintptr]) != 4 {
   774  		// Not running on a 32-bit platform
   775  		return
   776  	}
   777  	v, ok := irutil.Flatten(call.Args[0].Value.Value).(*ir.FieldAddr)
   778  	if !ok {
   779  		// TODO(dh): also check indexing into arrays and slices
   780  		return
   781  	}
   782  	T := v.X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct)
   783  	fields := make([]*types.Var, 0, T.NumFields())
   784  	for i := 0; i < T.NumFields() && i <= v.Field; i++ {
   785  		fields = append(fields, T.Field(i))
   786  	}
   787  
   788  	off := sizes.Offsetsof(fields)[v.Field]
   789  	if off%8 != 0 {
   790  		msg := fmt.Sprintf("address of non 64-bit aligned field %s passed to %s",
   791  			T.Field(v.Field).Name(),
   792  			irutil.CallName(call.Instr.Common()))
   793  		call.Invalid(msg)
   794  	}
   795  }
   796  
   797  func checkNoopMarshalImpl(argN int, meths ...string) CallCheck {
   798  	return func(call *Call) {
   799  		if code.IsGenerated(call.Pass, call.Instr.Pos()) {
   800  			return
   801  		}
   802  		arg := call.Args[argN]
   803  		T := arg.Value.Value.Type()
   804  		Ts, ok := typeutil.Dereference(T).Underlying().(*types.Struct)
   805  		if !ok {
   806  			return
   807  		}
   808  		if Ts.NumFields() == 0 {
   809  			return
   810  		}
   811  		fields := typeutil.FlattenFields(Ts)
   812  		for _, field := range fields {
   813  			if field.Var.Exported() {
   814  				return
   815  			}
   816  		}
   817  		// OPT(dh): we could use a method set cache here
   818  		ms := call.Instr.Parent().Prog.MethodSets.MethodSet(T)
   819  		// TODO(dh): we're not checking the signature, which can cause false negatives.
   820  		// This isn't a huge problem, however, since vet complains about incorrect signatures.
   821  		for _, meth := range meths {
   822  			if ms.Lookup(nil, meth) != nil {
   823  				return
   824  			}
   825  		}
   826  		arg.Invalid(fmt.Sprintf("struct type '%s' doesn't have any exported fields, nor custom marshaling", typeutil.Dereference(T)))
   827  	}
   828  }
   829  
   830  func checkUnsupportedMarshalJSON(call *Call) {
   831  	arg := call.Args[0]
   832  	T := arg.Value.Value.Type()
   833  	if err := fakejson.Marshal(T); err != nil {
   834  		typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg))
   835  		if err.Path == "x" {
   836  			arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ))
   837  		} else {
   838  			arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path))
   839  		}
   840  	}
   841  }
   842  
   843  func checkUnsupportedMarshalXML(call *Call) {
   844  	arg := call.Args[0]
   845  	T := arg.Value.Value.Type()
   846  	if err := fakexml.Marshal(T); err != nil {
   847  		switch err := err.(type) {
   848  		case *fakexml.UnsupportedTypeError:
   849  			typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg))
   850  			if err.Path == "x" {
   851  				arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ))
   852  			} else {
   853  				arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path))
   854  			}
   855  		case *fakexml.CyclicTypeError:
   856  			typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg))
   857  			if err.Path == "x" {
   858  				arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s", typ))
   859  			} else {
   860  				arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s, via %s", typ, err.Path))
   861  			}
   862  		case *fakexml.TagPathError:
   863  			// Vet does a better job at reporting this error, because it can flag the actual struct tags, not just the call to Marshal
   864  		default:
   865  			// These errors get reported by SA5008 instead, which can flag the actual fields, independently of calls to xml.Marshal
   866  		}
   867  	}
   868  }
   869  
   870  func isInLoop(b *ir.BasicBlock) bool {
   871  	sets := irutil.FindLoops(b.Parent())
   872  	for _, set := range sets {
   873  		if set.Has(b) {
   874  			return true
   875  		}
   876  	}
   877  	return false
   878  }
   879  
   880  func CheckUntrappableSignal(pass *analysis.Pass) (interface{}, error) {
   881  	isSignal := func(pass *analysis.Pass, expr ast.Expr, name string) bool {
   882  		if expr, ok := expr.(*ast.SelectorExpr); ok {
   883  			return code.SelectorName(pass, expr) == name
   884  		} else {
   885  			return false
   886  		}
   887  	}
   888  
   889  	fn := func(node ast.Node) {
   890  		call := node.(*ast.CallExpr)
   891  		if !code.IsCallToAny(pass, call,
   892  			"os/signal.Ignore", "os/signal.Notify", "os/signal.Reset") {
   893  			return
   894  		}
   895  
   896  		hasSigterm := false
   897  		for _, arg := range call.Args {
   898  			if conv, ok := arg.(*ast.CallExpr); ok && isSignal(pass, conv.Fun, "os.Signal") {
   899  				arg = conv.Args[0]
   900  			}
   901  
   902  			if isSignal(pass, arg, "syscall.SIGTERM") {
   903  				hasSigterm = true
   904  				break
   905  			}
   906  
   907  		}
   908  		for i, arg := range call.Args {
   909  			if conv, ok := arg.(*ast.CallExpr); ok && isSignal(pass, conv.Fun, "os.Signal") {
   910  				arg = conv.Args[0]
   911  			}
   912  
   913  			if isSignal(pass, arg, "os.Kill") || isSignal(pass, arg, "syscall.SIGKILL") {
   914  				var fixes []analysis.SuggestedFix
   915  				if !hasSigterm {
   916  					nargs := make([]ast.Expr, len(call.Args))
   917  					for j, a := range call.Args {
   918  						if i == j {
   919  							nargs[j] = edit.Selector("syscall", "SIGTERM")
   920  						} else {
   921  							nargs[j] = a
   922  						}
   923  					}
   924  					ncall := *call
   925  					ncall.Args = nargs
   926  					fixes = append(fixes, edit.Fix(fmt.Sprintf("use syscall.SIGTERM instead of %s", report.Render(pass, arg)), edit.ReplaceWithNode(pass.Fset, call, &ncall)))
   927  				}
   928  				nargs := make([]ast.Expr, 0, len(call.Args))
   929  				for j, a := range call.Args {
   930  					if i == j {
   931  						continue
   932  					}
   933  					nargs = append(nargs, a)
   934  				}
   935  				ncall := *call
   936  				ncall.Args = nargs
   937  				fixes = append(fixes, edit.Fix(fmt.Sprintf("remove %s from list of arguments", report.Render(pass, arg)), edit.ReplaceWithNode(pass.Fset, call, &ncall)))
   938  				report.Report(pass, arg, fmt.Sprintf("%s cannot be trapped (did you mean syscall.SIGTERM?)", report.Render(pass, arg)), report.Fixes(fixes...))
   939  			}
   940  			if isSignal(pass, arg, "syscall.SIGSTOP") {
   941  				nargs := make([]ast.Expr, 0, len(call.Args)-1)
   942  				for j, a := range call.Args {
   943  					if i == j {
   944  						continue
   945  					}
   946  					nargs = append(nargs, a)
   947  				}
   948  				ncall := *call
   949  				ncall.Args = nargs
   950  				report.Report(pass, arg, "syscall.SIGSTOP cannot be trapped", report.Fixes(edit.Fix("remove syscall.SIGSTOP from list of arguments", edit.ReplaceWithNode(pass.Fset, call, &ncall))))
   951  			}
   952  		}
   953  	}
   954  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
   955  	return nil, nil
   956  }
   957  
   958  func CheckTemplate(pass *analysis.Pass) (interface{}, error) {
   959  	fn := func(node ast.Node) {
   960  		call := node.(*ast.CallExpr)
   961  		// OPT(dh): use integer for kind
   962  		var kind string
   963  		switch code.CallName(pass, call) {
   964  		case "(*text/template.Template).Parse":
   965  			kind = "text"
   966  		case "(*html/template.Template).Parse":
   967  			kind = "html"
   968  		default:
   969  			return
   970  		}
   971  		sel := call.Fun.(*ast.SelectorExpr)
   972  		if !code.IsCallToAny(pass, sel.X, "text/template.New", "html/template.New") {
   973  			// TODO(dh): this is a cheap workaround for templates with
   974  			// different delims. A better solution with less false
   975  			// negatives would use data flow analysis to see where the
   976  			// template comes from and where it has been
   977  			return
   978  		}
   979  		s, ok := code.ExprToString(pass, call.Args[knowledge.Arg("(*text/template.Template).Parse.text")])
   980  		if !ok {
   981  			return
   982  		}
   983  		var err error
   984  		switch kind {
   985  		case "text":
   986  			_, err = texttemplate.New("").Parse(s)
   987  		case "html":
   988  			_, err = htmltemplate.New("").Parse(s)
   989  		}
   990  		if err != nil {
   991  			// TODO(dominikh): whitelist other parse errors, if any
   992  			if strings.Contains(err.Error(), "unexpected") ||
   993  				strings.Contains(err.Error(), "bad character") {
   994  				report.Report(pass, call.Args[knowledge.Arg("(*text/template.Template).Parse.text")], err.Error())
   995  			}
   996  		}
   997  	}
   998  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
   999  	return nil, nil
  1000  }
  1001  
  1002  var (
  1003  	checkTimeSleepConstantPatternQ   = pattern.MustParse(`(CallExpr (Symbol "time.Sleep") lit@(IntegerLiteral value))`)
  1004  	checkTimeSleepConstantPatternRns = pattern.MustParse(`(BinaryExpr duration "*" (SelectorExpr (Ident "time") (Ident "Nanosecond")))`)
  1005  	checkTimeSleepConstantPatternRs  = pattern.MustParse(`(BinaryExpr duration "*" (SelectorExpr (Ident "time") (Ident "Second")))`)
  1006  )
  1007  
  1008  func CheckTimeSleepConstant(pass *analysis.Pass) (interface{}, error) {
  1009  	fn := func(node ast.Node) {
  1010  		m, ok := code.Match(pass, checkTimeSleepConstantPatternQ, node)
  1011  		if !ok {
  1012  			return
  1013  		}
  1014  		n, ok := constant.Int64Val(m.State["value"].(types.TypeAndValue).Value)
  1015  		if !ok {
  1016  			return
  1017  		}
  1018  		if n == 0 || n > 120 {
  1019  			// time.Sleep(0) is a seldom used pattern in concurrency
  1020  			// tests. >120 might be intentional. 120 was chosen
  1021  			// because the user could've meant 2 minutes.
  1022  			return
  1023  		}
  1024  
  1025  		lit := m.State["lit"].(ast.Node)
  1026  		report.Report(pass, lit,
  1027  			fmt.Sprintf("sleeping for %d nanoseconds is probably a bug; be explicit if it isn't", n), report.Fixes(
  1028  				edit.Fix("explicitly use nanoseconds", edit.ReplaceWithPattern(pass.Fset, lit, checkTimeSleepConstantPatternRns, pattern.State{"duration": lit})),
  1029  				edit.Fix("use seconds", edit.ReplaceWithPattern(pass.Fset, lit, checkTimeSleepConstantPatternRs, pattern.State{"duration": lit}))))
  1030  	}
  1031  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  1032  	return nil, nil
  1033  }
  1034  
  1035  var checkWaitgroupAddQ = pattern.MustParse(`
  1036  	(GoStmt
  1037  		(CallExpr
  1038  			(FuncLit
  1039  				_
  1040  				call@(CallExpr (Symbol "(*sync.WaitGroup).Add") _):_) _))`)
  1041  
  1042  func CheckWaitgroupAdd(pass *analysis.Pass) (interface{}, error) {
  1043  	fn := func(node ast.Node) {
  1044  		if m, ok := code.Match(pass, checkWaitgroupAddQ, node); ok {
  1045  			call := m.State["call"].(ast.Node)
  1046  			report.Report(pass, call, fmt.Sprintf("should call %s before starting the goroutine to avoid a race", report.Render(pass, call)))
  1047  		}
  1048  	}
  1049  	code.Preorder(pass, fn, (*ast.GoStmt)(nil))
  1050  	return nil, nil
  1051  }
  1052  
  1053  func CheckInfiniteEmptyLoop(pass *analysis.Pass) (interface{}, error) {
  1054  	fn := func(node ast.Node) {
  1055  		loop := node.(*ast.ForStmt)
  1056  		if len(loop.Body.List) != 0 || loop.Post != nil {
  1057  			return
  1058  		}
  1059  
  1060  		if loop.Init != nil {
  1061  			// TODO(dh): this isn't strictly necessary, it just makes
  1062  			// the check easier.
  1063  			return
  1064  		}
  1065  		// An empty loop is bad news in two cases: 1) The loop has no
  1066  		// condition. In that case, it's just a loop that spins
  1067  		// forever and as fast as it can, keeping a core busy. 2) The
  1068  		// loop condition only consists of variable or field reads and
  1069  		// operators on those. The only way those could change their
  1070  		// value is with unsynchronised access, which constitutes a
  1071  		// data race.
  1072  		//
  1073  		// If the condition contains any function calls, its behaviour
  1074  		// is dynamic and the loop might terminate. Similarly for
  1075  		// channel receives.
  1076  
  1077  		if loop.Cond != nil {
  1078  			if code.MayHaveSideEffects(pass, loop.Cond, nil) {
  1079  				return
  1080  			}
  1081  			if ident, ok := loop.Cond.(*ast.Ident); ok {
  1082  				if k, ok := pass.TypesInfo.ObjectOf(ident).(*types.Const); ok {
  1083  					if !constant.BoolVal(k.Val()) {
  1084  						// don't flag `for false {}` loops. They're a debug aid.
  1085  						return
  1086  					}
  1087  				}
  1088  			}
  1089  			report.Report(pass, loop, "loop condition never changes or has a race condition")
  1090  		}
  1091  		report.Report(pass, loop, "this loop will spin, using 100% CPU", report.ShortRange())
  1092  	}
  1093  	code.Preorder(pass, fn, (*ast.ForStmt)(nil))
  1094  	return nil, nil
  1095  }
  1096  
  1097  func CheckDeferInInfiniteLoop(pass *analysis.Pass) (interface{}, error) {
  1098  	fn := func(node ast.Node) {
  1099  		mightExit := false
  1100  		var defers []ast.Stmt
  1101  		loop := node.(*ast.ForStmt)
  1102  		if loop.Cond != nil {
  1103  			return
  1104  		}
  1105  		fn2 := func(node ast.Node) bool {
  1106  			switch stmt := node.(type) {
  1107  			case *ast.ReturnStmt:
  1108  				mightExit = true
  1109  				return false
  1110  			case *ast.BranchStmt:
  1111  				// TODO(dominikh): if this sees a break in a switch or
  1112  				// select, it doesn't check if it breaks the loop or
  1113  				// just the select/switch. This causes some false
  1114  				// negatives.
  1115  				if stmt.Tok == token.BREAK {
  1116  					mightExit = true
  1117  					return false
  1118  				}
  1119  			case *ast.DeferStmt:
  1120  				defers = append(defers, stmt)
  1121  			case *ast.FuncLit:
  1122  				// Don't look into function bodies
  1123  				return false
  1124  			}
  1125  			return true
  1126  		}
  1127  		ast.Inspect(loop.Body, fn2)
  1128  		if mightExit {
  1129  			return
  1130  		}
  1131  		for _, stmt := range defers {
  1132  			report.Report(pass, stmt, "defers in this infinite loop will never run")
  1133  		}
  1134  	}
  1135  	code.Preorder(pass, fn, (*ast.ForStmt)(nil))
  1136  	return nil, nil
  1137  }
  1138  
  1139  func CheckDubiousDeferInChannelRangeLoop(pass *analysis.Pass) (interface{}, error) {
  1140  	fn := func(node ast.Node) {
  1141  		loop := node.(*ast.RangeStmt)
  1142  		typ := pass.TypesInfo.TypeOf(loop.X)
  1143  		_, ok := typeutil.CoreType(typ).(*types.Chan)
  1144  		if !ok {
  1145  			return
  1146  		}
  1147  
  1148  		stmts := []*ast.DeferStmt{}
  1149  		exits := false
  1150  		fn2 := func(node ast.Node) bool {
  1151  			switch stmt := node.(type) {
  1152  			case *ast.DeferStmt:
  1153  				stmts = append(stmts, stmt)
  1154  			case *ast.FuncLit:
  1155  				// Don't look into function bodies
  1156  				return false
  1157  			case *ast.ReturnStmt:
  1158  				exits = true
  1159  			case *ast.BranchStmt:
  1160  				exits = node.(*ast.BranchStmt).Tok == token.BREAK
  1161  			}
  1162  			return true
  1163  		}
  1164  		ast.Inspect(loop.Body, fn2)
  1165  
  1166  		if exits {
  1167  			return
  1168  		}
  1169  		for _, stmt := range stmts {
  1170  			report.Report(pass, stmt, "defers in this range loop won't run unless the channel gets closed")
  1171  		}
  1172  	}
  1173  	code.Preorder(pass, fn, (*ast.RangeStmt)(nil))
  1174  	return nil, nil
  1175  }
  1176  
  1177  func CheckTestMainExit(pass *analysis.Pass) (interface{}, error) {
  1178  	if code.IsGoVersion(pass, 15) {
  1179  		// Beginning with Go 1.15, the test framework will call
  1180  		// os.Exit for us.
  1181  		return nil, nil
  1182  	}
  1183  
  1184  	var (
  1185  		fnmain    ast.Node
  1186  		callsExit bool
  1187  		callsRun  bool
  1188  		arg       types.Object
  1189  	)
  1190  	fn := func(node ast.Node, push bool) bool {
  1191  		if !push {
  1192  			if fnmain != nil && node == fnmain {
  1193  				if !callsExit && callsRun {
  1194  					report.Report(pass, fnmain, "TestMain should call os.Exit to set exit code")
  1195  				}
  1196  				fnmain = nil
  1197  				callsExit = false
  1198  				callsRun = false
  1199  				arg = nil
  1200  			}
  1201  			return true
  1202  		}
  1203  
  1204  		switch node := node.(type) {
  1205  		case *ast.FuncDecl:
  1206  			if fnmain != nil {
  1207  				return true
  1208  			}
  1209  			if !isTestMain(pass, node) {
  1210  				return false
  1211  			}
  1212  			fnmain = node
  1213  			arg = pass.TypesInfo.ObjectOf(node.Type.Params.List[0].Names[0])
  1214  			return true
  1215  		case *ast.CallExpr:
  1216  			if code.IsCallTo(pass, node, "os.Exit") {
  1217  				callsExit = true
  1218  				return false
  1219  			}
  1220  			sel, ok := node.Fun.(*ast.SelectorExpr)
  1221  			if !ok {
  1222  				return true
  1223  			}
  1224  			ident, ok := sel.X.(*ast.Ident)
  1225  			if !ok {
  1226  				return true
  1227  			}
  1228  			if arg != pass.TypesInfo.ObjectOf(ident) {
  1229  				return true
  1230  			}
  1231  			if sel.Sel.Name == "Run" {
  1232  				callsRun = true
  1233  				return false
  1234  			}
  1235  			return true
  1236  		default:
  1237  			lint.ExhaustiveTypeSwitch(node)
  1238  			return true
  1239  		}
  1240  	}
  1241  	pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Nodes([]ast.Node{(*ast.FuncDecl)(nil), (*ast.CallExpr)(nil)}, fn)
  1242  	return nil, nil
  1243  }
  1244  
  1245  func isTestMain(pass *analysis.Pass, decl *ast.FuncDecl) bool {
  1246  	if decl.Name.Name != "TestMain" {
  1247  		return false
  1248  	}
  1249  	if len(decl.Type.Params.List) != 1 {
  1250  		return false
  1251  	}
  1252  	arg := decl.Type.Params.List[0]
  1253  	if len(arg.Names) != 1 {
  1254  		return false
  1255  	}
  1256  	return code.IsOfType(pass, arg.Type, "*testing.M")
  1257  }
  1258  
  1259  func CheckExec(pass *analysis.Pass) (interface{}, error) {
  1260  	fn := func(node ast.Node) {
  1261  		call := node.(*ast.CallExpr)
  1262  		if !code.IsCallTo(pass, call, "os/exec.Command") {
  1263  			return
  1264  		}
  1265  		val, ok := code.ExprToString(pass, call.Args[knowledge.Arg("os/exec.Command.name")])
  1266  		if !ok {
  1267  			return
  1268  		}
  1269  		if !strings.Contains(val, " ") || strings.Contains(val, `\`) || strings.Contains(val, "/") {
  1270  			return
  1271  		}
  1272  		report.Report(pass, call.Args[knowledge.Arg("os/exec.Command.name")],
  1273  			"first argument to exec.Command looks like a shell command, but a program name or path are expected")
  1274  	}
  1275  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  1276  	return nil, nil
  1277  }
  1278  
  1279  func CheckLoopEmptyDefault(pass *analysis.Pass) (interface{}, error) {
  1280  	fn := func(node ast.Node) {
  1281  		loop := node.(*ast.ForStmt)
  1282  		if len(loop.Body.List) != 1 || loop.Cond != nil || loop.Init != nil {
  1283  			return
  1284  		}
  1285  		sel, ok := loop.Body.List[0].(*ast.SelectStmt)
  1286  		if !ok {
  1287  			return
  1288  		}
  1289  		for _, c := range sel.Body.List {
  1290  			// FIXME this leaves behind an empty line, and possibly
  1291  			// comments in the default branch. We can't easily fix
  1292  			// either.
  1293  			if comm, ok := c.(*ast.CommClause); ok && comm.Comm == nil && len(comm.Body) == 0 {
  1294  				report.Report(pass, comm, "should not have an empty default case in a for+select loop; the loop will spin",
  1295  					report.Fixes(edit.Fix("remove empty default branch", edit.Delete(comm))))
  1296  				// there can only be one default case
  1297  				break
  1298  			}
  1299  		}
  1300  	}
  1301  	code.Preorder(pass, fn, (*ast.ForStmt)(nil))
  1302  	return nil, nil
  1303  }
  1304  
  1305  func CheckLhsRhsIdentical(pass *analysis.Pass) (interface{}, error) {
  1306  	var isFloat func(T types.Type) bool
  1307  	isFloat = func(T types.Type) bool {
  1308  		tset := typeutil.NewTypeSet(T)
  1309  		if len(tset.Terms) == 0 {
  1310  			// no terms, so floats are a possibility
  1311  			return true
  1312  		}
  1313  		return tset.Any(func(term *types.Term) bool {
  1314  			switch typ := term.Type().Underlying().(type) {
  1315  			case *types.Basic:
  1316  				kind := typ.Kind()
  1317  				return kind == types.Float32 || kind == types.Float64
  1318  			case *types.Array:
  1319  				return isFloat(typ.Elem())
  1320  			case *types.Struct:
  1321  				for i := 0; i < typ.NumFields(); i++ {
  1322  					if !isFloat(typ.Field(i).Type()) {
  1323  						return false
  1324  					}
  1325  				}
  1326  				return true
  1327  			default:
  1328  				return false
  1329  			}
  1330  		})
  1331  	}
  1332  
  1333  	// TODO(dh): this check ignores the existence of side-effects and
  1334  	// happily flags fn() == fn() – so far, we've had nobody complain
  1335  	// about a false positive, and it's caught several bugs in real
  1336  	// code.
  1337  	//
  1338  	// We special case functions from the math/rand package. Someone ran
  1339  	// into the following false positive: "rand.Intn(2) - rand.Intn(2), which I wrote to generate values {-1, 0, 1} with {0.25, 0.5, 0.25} probability."
  1340  	fn := func(node ast.Node) {
  1341  		op := node.(*ast.BinaryExpr)
  1342  		switch op.Op {
  1343  		case token.EQL, token.NEQ:
  1344  		case token.SUB, token.QUO, token.AND, token.REM, token.OR, token.XOR, token.AND_NOT,
  1345  			token.LAND, token.LOR, token.LSS, token.GTR, token.LEQ, token.GEQ:
  1346  		default:
  1347  			// For some ops, such as + and *, it can make sense to
  1348  			// have identical operands
  1349  			return
  1350  		}
  1351  
  1352  		if isFloat(pass.TypesInfo.TypeOf(op.X)) {
  1353  			// 'float <op> float' makes sense for several operators.
  1354  			// We've tried keeping an exact list of operators to allow, but floats keep surprising us. Let's just give up instead.
  1355  			return
  1356  		}
  1357  
  1358  		if reflect.TypeOf(op.X) != reflect.TypeOf(op.Y) {
  1359  			return
  1360  		}
  1361  		if report.Render(pass, op.X) != report.Render(pass, op.Y) {
  1362  			return
  1363  		}
  1364  		l1, ok1 := op.X.(*ast.BasicLit)
  1365  		l2, ok2 := op.Y.(*ast.BasicLit)
  1366  		if ok1 && ok2 && l1.Kind == token.INT && l2.Kind == l1.Kind && l1.Value == "0" && l2.Value == l1.Value && code.IsGenerated(pass, l1.Pos()) {
  1367  			// cgo generates the following function call:
  1368  			// _cgoCheckPointer(_cgoBase0, 0 == 0) – it uses 0 == 0
  1369  			// instead of true in case the user shadowed the
  1370  			// identifier. Ideally we'd restrict this exception to
  1371  			// calls of _cgoCheckPointer, but it's not worth the
  1372  			// hassle of keeping track of the stack. <lit> <op> <lit>
  1373  			// are very rare to begin with, and we're mostly checking
  1374  			// for them to catch typos such as 1 == 1 where the user
  1375  			// meant to type i == 1. The odds of a false negative for
  1376  			// 0 == 0 are slim.
  1377  			return
  1378  		}
  1379  
  1380  		if expr, ok := op.X.(*ast.CallExpr); ok {
  1381  			call := code.CallName(pass, expr)
  1382  			switch call {
  1383  			case "math/rand.Int",
  1384  				"math/rand.Int31",
  1385  				"math/rand.Int31n",
  1386  				"math/rand.Int63",
  1387  				"math/rand.Int63n",
  1388  				"math/rand.Intn",
  1389  				"math/rand.Uint32",
  1390  				"math/rand.Uint64",
  1391  				"math/rand.ExpFloat64",
  1392  				"math/rand.Float32",
  1393  				"math/rand.Float64",
  1394  				"math/rand.NormFloat64",
  1395  				"(*math/rand.Rand).Int",
  1396  				"(*math/rand.Rand).Int31",
  1397  				"(*math/rand.Rand).Int31n",
  1398  				"(*math/rand.Rand).Int63",
  1399  				"(*math/rand.Rand).Int63n",
  1400  				"(*math/rand.Rand).Intn",
  1401  				"(*math/rand.Rand).Uint32",
  1402  				"(*math/rand.Rand).Uint64",
  1403  				"(*math/rand.Rand).ExpFloat64",
  1404  				"(*math/rand.Rand).Float32",
  1405  				"(*math/rand.Rand).Float64",
  1406  				"(*math/rand.Rand).NormFloat64":
  1407  				return
  1408  			}
  1409  		}
  1410  
  1411  		report.Report(pass, op, fmt.Sprintf("identical expressions on the left and right side of the '%s' operator", op.Op))
  1412  	}
  1413  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  1414  	return nil, nil
  1415  }
  1416  
  1417  func CheckScopedBreak(pass *analysis.Pass) (interface{}, error) {
  1418  	fn := func(node ast.Node) {
  1419  		var body *ast.BlockStmt
  1420  		switch node := node.(type) {
  1421  		case *ast.ForStmt:
  1422  			body = node.Body
  1423  		case *ast.RangeStmt:
  1424  			body = node.Body
  1425  		default:
  1426  			lint.ExhaustiveTypeSwitch(node)
  1427  		}
  1428  		for _, stmt := range body.List {
  1429  			var blocks [][]ast.Stmt
  1430  			switch stmt := stmt.(type) {
  1431  			case *ast.SwitchStmt:
  1432  				for _, c := range stmt.Body.List {
  1433  					blocks = append(blocks, c.(*ast.CaseClause).Body)
  1434  				}
  1435  			case *ast.SelectStmt:
  1436  				for _, c := range stmt.Body.List {
  1437  					blocks = append(blocks, c.(*ast.CommClause).Body)
  1438  				}
  1439  			default:
  1440  				continue
  1441  			}
  1442  
  1443  			for _, body := range blocks {
  1444  				if len(body) == 0 {
  1445  					continue
  1446  				}
  1447  				lasts := []ast.Stmt{body[len(body)-1]}
  1448  				// TODO(dh): unfold all levels of nested block
  1449  				// statements, not just a single level if statement
  1450  				if ifs, ok := lasts[0].(*ast.IfStmt); ok {
  1451  					if len(ifs.Body.List) == 0 {
  1452  						continue
  1453  					}
  1454  					lasts[0] = ifs.Body.List[len(ifs.Body.List)-1]
  1455  
  1456  					if block, ok := ifs.Else.(*ast.BlockStmt); ok {
  1457  						if len(block.List) != 0 {
  1458  							lasts = append(lasts, block.List[len(block.List)-1])
  1459  						}
  1460  					}
  1461  				}
  1462  				for _, last := range lasts {
  1463  					branch, ok := last.(*ast.BranchStmt)
  1464  					if !ok || branch.Tok != token.BREAK || branch.Label != nil {
  1465  						continue
  1466  					}
  1467  					report.Report(pass, branch, "ineffective break statement. Did you mean to break out of the outer loop?")
  1468  				}
  1469  			}
  1470  		}
  1471  	}
  1472  	code.Preorder(pass, fn, (*ast.ForStmt)(nil), (*ast.RangeStmt)(nil))
  1473  	return nil, nil
  1474  }
  1475  
  1476  func CheckUnsafePrintf(pass *analysis.Pass) (interface{}, error) {
  1477  	fn := func(node ast.Node) {
  1478  		call := node.(*ast.CallExpr)
  1479  		name := code.CallName(pass, call)
  1480  		var arg int
  1481  
  1482  		switch name {
  1483  		case "fmt.Printf", "fmt.Sprintf", "log.Printf":
  1484  			arg = knowledge.Arg("fmt.Printf.format")
  1485  		case "fmt.Fprintf":
  1486  			arg = knowledge.Arg("fmt.Fprintf.format")
  1487  		default:
  1488  			return
  1489  		}
  1490  		if len(call.Args) != arg+1 {
  1491  			return
  1492  		}
  1493  		switch call.Args[arg].(type) {
  1494  		case *ast.CallExpr, *ast.Ident:
  1495  		default:
  1496  			return
  1497  		}
  1498  
  1499  		if _, ok := pass.TypesInfo.TypeOf(call.Args[arg]).(*types.Tuple); ok {
  1500  			// the called function returns multiple values and got
  1501  			// splatted into the call. for all we know, it is
  1502  			// returning good arguments.
  1503  			return
  1504  		}
  1505  
  1506  		alt := name[:len(name)-1]
  1507  		report.Report(pass, call,
  1508  			"printf-style function with dynamic format string and no further arguments should use print-style function instead",
  1509  			report.Fixes(edit.Fix(fmt.Sprintf("use %s instead of %s", alt, name), edit.ReplaceWithString(call.Fun, alt))))
  1510  	}
  1511  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  1512  	return nil, nil
  1513  }
  1514  
  1515  func CheckEarlyDefer(pass *analysis.Pass) (interface{}, error) {
  1516  	fn := func(node ast.Node) {
  1517  		block := node.(*ast.BlockStmt)
  1518  		if len(block.List) < 2 {
  1519  			return
  1520  		}
  1521  		for i, stmt := range block.List {
  1522  			if i == len(block.List)-1 {
  1523  				break
  1524  			}
  1525  			assign, ok := stmt.(*ast.AssignStmt)
  1526  			if !ok {
  1527  				continue
  1528  			}
  1529  			if len(assign.Rhs) != 1 {
  1530  				continue
  1531  			}
  1532  			if len(assign.Lhs) < 2 {
  1533  				continue
  1534  			}
  1535  			if lhs, ok := assign.Lhs[len(assign.Lhs)-1].(*ast.Ident); ok && lhs.Name == "_" {
  1536  				continue
  1537  			}
  1538  			call, ok := assign.Rhs[0].(*ast.CallExpr)
  1539  			if !ok {
  1540  				continue
  1541  			}
  1542  			sig, ok := pass.TypesInfo.TypeOf(call.Fun).(*types.Signature)
  1543  			if !ok {
  1544  				continue
  1545  			}
  1546  			if sig.Results().Len() < 2 {
  1547  				continue
  1548  			}
  1549  			last := sig.Results().At(sig.Results().Len() - 1)
  1550  			// FIXME(dh): check that it's error from universe, not
  1551  			// another type of the same name
  1552  			if last.Type().String() != "error" {
  1553  				continue
  1554  			}
  1555  			lhs, ok := assign.Lhs[0].(*ast.Ident)
  1556  			if !ok {
  1557  				continue
  1558  			}
  1559  			def, ok := block.List[i+1].(*ast.DeferStmt)
  1560  			if !ok {
  1561  				continue
  1562  			}
  1563  			sel, ok := def.Call.Fun.(*ast.SelectorExpr)
  1564  			if !ok {
  1565  				continue
  1566  			}
  1567  			ident, ok := selectorX(sel).(*ast.Ident)
  1568  			if !ok {
  1569  				continue
  1570  			}
  1571  			if pass.TypesInfo.ObjectOf(ident) != pass.TypesInfo.ObjectOf(lhs) {
  1572  				continue
  1573  			}
  1574  			if sel.Sel.Name != "Close" {
  1575  				continue
  1576  			}
  1577  			report.Report(pass, def, fmt.Sprintf("should check returned error before deferring %s", report.Render(pass, def.Call)))
  1578  		}
  1579  	}
  1580  	code.Preorder(pass, fn, (*ast.BlockStmt)(nil))
  1581  	return nil, nil
  1582  }
  1583  
  1584  func selectorX(sel *ast.SelectorExpr) ast.Node {
  1585  	switch x := sel.X.(type) {
  1586  	case *ast.SelectorExpr:
  1587  		return selectorX(x)
  1588  	default:
  1589  		return x
  1590  	}
  1591  }
  1592  
  1593  func CheckEmptyCriticalSection(pass *analysis.Pass) (interface{}, error) {
  1594  	if pass.Pkg.Path() == "sync_test" {
  1595  		// exception for the sync package's tests
  1596  		return nil, nil
  1597  	}
  1598  
  1599  	// Initially it might seem like this check would be easier to
  1600  	// implement using IR. After all, we're only checking for two
  1601  	// consecutive method calls. In reality, however, there may be any
  1602  	// number of other instructions between the lock and unlock, while
  1603  	// still constituting an empty critical section. For example,
  1604  	// given `m.x().Lock(); m.x().Unlock()`, there will be a call to
  1605  	// x(). In the AST-based approach, this has a tiny potential for a
  1606  	// false positive (the second call to x might be doing work that
  1607  	// is protected by the mutex). In an IR-based approach, however,
  1608  	// it would miss a lot of real bugs.
  1609  
  1610  	mutexParams := func(s ast.Stmt) (x ast.Expr, funcName string, ok bool) {
  1611  		expr, ok := s.(*ast.ExprStmt)
  1612  		if !ok {
  1613  			return nil, "", false
  1614  		}
  1615  		call, ok := astutil.Unparen(expr.X).(*ast.CallExpr)
  1616  		if !ok {
  1617  			return nil, "", false
  1618  		}
  1619  		sel, ok := call.Fun.(*ast.SelectorExpr)
  1620  		if !ok {
  1621  			return nil, "", false
  1622  		}
  1623  
  1624  		fn, ok := pass.TypesInfo.ObjectOf(sel.Sel).(*types.Func)
  1625  		if !ok {
  1626  			return nil, "", false
  1627  		}
  1628  		sig := fn.Type().(*types.Signature)
  1629  		if sig.Params().Len() != 0 || sig.Results().Len() != 0 {
  1630  			return nil, "", false
  1631  		}
  1632  
  1633  		return sel.X, fn.Name(), true
  1634  	}
  1635  
  1636  	fn := func(node ast.Node) {
  1637  		block := node.(*ast.BlockStmt)
  1638  		if len(block.List) < 2 {
  1639  			return
  1640  		}
  1641  		for i := range block.List[:len(block.List)-1] {
  1642  			sel1, method1, ok1 := mutexParams(block.List[i])
  1643  			sel2, method2, ok2 := mutexParams(block.List[i+1])
  1644  
  1645  			if !ok1 || !ok2 || report.Render(pass, sel1) != report.Render(pass, sel2) {
  1646  				continue
  1647  			}
  1648  			if (method1 == "Lock" && method2 == "Unlock") ||
  1649  				(method1 == "RLock" && method2 == "RUnlock") {
  1650  				report.Report(pass, block.List[i+1], "empty critical section")
  1651  			}
  1652  		}
  1653  	}
  1654  	code.Preorder(pass, fn, (*ast.BlockStmt)(nil))
  1655  	return nil, nil
  1656  }
  1657  
  1658  var (
  1659  	// cgo produces code like fn(&*_Cvar_kSomeCallbacks) which we don't
  1660  	// want to flag.
  1661  	cgoIdent               = regexp.MustCompile(`^_C(func|var)_.+$`)
  1662  	checkIneffectiveCopyQ1 = pattern.MustParse(`(UnaryExpr "&" (StarExpr obj))`)
  1663  	checkIneffectiveCopyQ2 = pattern.MustParse(`(StarExpr (UnaryExpr "&" _))`)
  1664  )
  1665  
  1666  func CheckIneffectiveCopy(pass *analysis.Pass) (interface{}, error) {
  1667  	fn := func(node ast.Node) {
  1668  		if m, ok := code.Match(pass, checkIneffectiveCopyQ1, node); ok {
  1669  			if ident, ok := m.State["obj"].(*ast.Ident); !ok || !cgoIdent.MatchString(ident.Name) {
  1670  				report.Report(pass, node, "&*x will be simplified to x. It will not copy x.")
  1671  			}
  1672  		} else if _, ok := code.Match(pass, checkIneffectiveCopyQ2, node); ok {
  1673  			report.Report(pass, node, "*&x will be simplified to x. It will not copy x.")
  1674  		}
  1675  	}
  1676  	code.Preorder(pass, fn, (*ast.UnaryExpr)(nil), (*ast.StarExpr)(nil))
  1677  	return nil, nil
  1678  }
  1679  
  1680  func CheckCanonicalHeaderKey(pass *analysis.Pass) (interface{}, error) {
  1681  	fn := func(node ast.Node, push bool) bool {
  1682  		if !push {
  1683  			return false
  1684  		}
  1685  		if assign, ok := node.(*ast.AssignStmt); ok {
  1686  			// TODO(dh): This risks missing some Header reads, for
  1687  			// example in `h1["foo"] = h2["foo"]` – these edge
  1688  			// cases are probably rare enough to ignore for now.
  1689  			for _, expr := range assign.Lhs {
  1690  				op, ok := expr.(*ast.IndexExpr)
  1691  				if !ok {
  1692  					continue
  1693  				}
  1694  				if code.IsOfType(pass, op.X, "net/http.Header") {
  1695  					return false
  1696  				}
  1697  			}
  1698  			return true
  1699  		}
  1700  		op, ok := node.(*ast.IndexExpr)
  1701  		if !ok {
  1702  			return true
  1703  		}
  1704  		if !code.IsOfType(pass, op.X, "net/http.Header") {
  1705  			return true
  1706  		}
  1707  		s, ok := code.ExprToString(pass, op.Index)
  1708  		if !ok {
  1709  			return true
  1710  		}
  1711  		canonical := http.CanonicalHeaderKey(s)
  1712  		if s == canonical {
  1713  			return true
  1714  		}
  1715  		var fix analysis.SuggestedFix
  1716  		switch op.Index.(type) {
  1717  		case *ast.BasicLit:
  1718  			fix = edit.Fix("canonicalize header key", edit.ReplaceWithString(op.Index, strconv.Quote(canonical)))
  1719  		case *ast.Ident:
  1720  			call := &ast.CallExpr{
  1721  				Fun:  edit.Selector("http", "CanonicalHeaderKey"),
  1722  				Args: []ast.Expr{op.Index},
  1723  			}
  1724  			fix = edit.Fix("wrap in http.CanonicalHeaderKey", edit.ReplaceWithNode(pass.Fset, op.Index, call))
  1725  		}
  1726  		msg := fmt.Sprintf("keys in http.Header are canonicalized, %q is not canonical; fix the constant or use http.CanonicalHeaderKey", s)
  1727  		if fix.Message != "" {
  1728  			report.Report(pass, op, msg, report.Fixes(fix))
  1729  		} else {
  1730  			report.Report(pass, op, msg)
  1731  		}
  1732  		return true
  1733  	}
  1734  	pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Nodes([]ast.Node{(*ast.AssignStmt)(nil), (*ast.IndexExpr)(nil)}, fn)
  1735  	return nil, nil
  1736  }
  1737  
  1738  func CheckBenchmarkN(pass *analysis.Pass) (interface{}, error) {
  1739  	fn := func(node ast.Node) {
  1740  		assign := node.(*ast.AssignStmt)
  1741  		if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 {
  1742  			return
  1743  		}
  1744  		sel, ok := assign.Lhs[0].(*ast.SelectorExpr)
  1745  		if !ok {
  1746  			return
  1747  		}
  1748  		if sel.Sel.Name != "N" {
  1749  			return
  1750  		}
  1751  		if !code.IsOfType(pass, sel.X, "*testing.B") {
  1752  			return
  1753  		}
  1754  		report.Report(pass, assign, fmt.Sprintf("should not assign to %s", report.Render(pass, sel)))
  1755  	}
  1756  	code.Preorder(pass, fn, (*ast.AssignStmt)(nil))
  1757  	return nil, nil
  1758  }
  1759  
  1760  func CheckUnreadVariableValues(pass *analysis.Pass) (interface{}, error) {
  1761  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  1762  		if irutil.IsExample(fn) {
  1763  			continue
  1764  		}
  1765  		node := fn.Source()
  1766  		if node == nil {
  1767  			continue
  1768  		}
  1769  		if gen, ok := code.Generator(pass, node.Pos()); ok && gen == generated.Goyacc {
  1770  			// Don't flag unused values in code generated by goyacc.
  1771  			// There may be hundreds of those due to the way the state
  1772  			// machine is constructed.
  1773  			continue
  1774  		}
  1775  
  1776  		switchTags := map[ir.Value]struct{}{}
  1777  		ast.Inspect(node, func(node ast.Node) bool {
  1778  			s, ok := node.(*ast.SwitchStmt)
  1779  			if !ok {
  1780  				return true
  1781  			}
  1782  			v, _ := fn.ValueForExpr(s.Tag)
  1783  			switchTags[v] = struct{}{}
  1784  			return true
  1785  		})
  1786  
  1787  		// OPT(dh): don't use a map, possibly use a bitset
  1788  		var hasUse func(v ir.Value, seen map[ir.Value]struct{}) bool
  1789  		hasUse = func(v ir.Value, seen map[ir.Value]struct{}) bool {
  1790  			if _, ok := seen[v]; ok {
  1791  				return false
  1792  			}
  1793  			if _, ok := switchTags[v]; ok {
  1794  				return true
  1795  			}
  1796  			refs := v.Referrers()
  1797  			if refs == nil {
  1798  				// TODO investigate why refs can be nil
  1799  				return true
  1800  			}
  1801  			for _, ref := range *refs {
  1802  				switch ref := ref.(type) {
  1803  				case *ir.DebugRef:
  1804  				case *ir.Sigma:
  1805  					if seen == nil {
  1806  						seen = map[ir.Value]struct{}{}
  1807  					}
  1808  					seen[v] = struct{}{}
  1809  					if hasUse(ref, seen) {
  1810  						return true
  1811  					}
  1812  				case *ir.Phi:
  1813  					if seen == nil {
  1814  						seen = map[ir.Value]struct{}{}
  1815  					}
  1816  					seen[v] = struct{}{}
  1817  					if hasUse(ref, seen) {
  1818  						return true
  1819  					}
  1820  				default:
  1821  					return true
  1822  				}
  1823  			}
  1824  			return false
  1825  		}
  1826  
  1827  		ast.Inspect(node, func(node ast.Node) bool {
  1828  			assign, ok := node.(*ast.AssignStmt)
  1829  			if !ok {
  1830  				return true
  1831  			}
  1832  			if len(assign.Lhs) > 1 && len(assign.Rhs) == 1 {
  1833  				// Either a function call with multiple return values,
  1834  				// or a comma-ok assignment
  1835  
  1836  				val, _ := fn.ValueForExpr(assign.Rhs[0])
  1837  				if val == nil {
  1838  					return true
  1839  				}
  1840  				refs := val.Referrers()
  1841  				if refs == nil {
  1842  					return true
  1843  				}
  1844  				for _, ref := range *refs {
  1845  					ex, ok := ref.(*ir.Extract)
  1846  					if !ok {
  1847  						continue
  1848  					}
  1849  					if !hasUse(ex, nil) {
  1850  						lhs := assign.Lhs[ex.Index]
  1851  						if ident, ok := lhs.(*ast.Ident); !ok || ok && ident.Name == "_" {
  1852  							continue
  1853  						}
  1854  						report.Report(pass, assign, fmt.Sprintf("this value of %s is never used", lhs))
  1855  					}
  1856  				}
  1857  				return true
  1858  			}
  1859  			for i, lhs := range assign.Lhs {
  1860  				rhs := assign.Rhs[i]
  1861  				if ident, ok := lhs.(*ast.Ident); !ok || ok && ident.Name == "_" {
  1862  					continue
  1863  				}
  1864  				val, _ := fn.ValueForExpr(rhs)
  1865  				if val == nil {
  1866  					continue
  1867  				}
  1868  
  1869  				if _, ok := val.(*ir.Const); ok {
  1870  					// a zero-valued constant, for example in 'foo := []string(nil)'
  1871  					continue
  1872  				}
  1873  				if !hasUse(val, nil) {
  1874  					report.Report(pass, assign, fmt.Sprintf("this value of %s is never used", lhs))
  1875  				}
  1876  			}
  1877  			return true
  1878  		})
  1879  	}
  1880  	return nil, nil
  1881  }
  1882  
  1883  func CheckPredeterminedBooleanExprs(pass *analysis.Pass) (interface{}, error) {
  1884  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  1885  		for _, block := range fn.Blocks {
  1886  			for _, ins := range block.Instrs {
  1887  				binop, ok := ins.(*ir.BinOp)
  1888  				if !ok {
  1889  					continue
  1890  				}
  1891  				switch binop.Op {
  1892  				case token.GTR, token.LSS, token.EQL, token.NEQ, token.LEQ, token.GEQ:
  1893  				default:
  1894  					continue
  1895  				}
  1896  
  1897  				xs, ok1 := consts(binop.X, nil, nil)
  1898  				ys, ok2 := consts(binop.Y, nil, nil)
  1899  				if !ok1 || !ok2 || len(xs) == 0 || len(ys) == 0 {
  1900  					continue
  1901  				}
  1902  
  1903  				trues := 0
  1904  				for _, x := range xs {
  1905  					for _, y := range ys {
  1906  						if x.Value == nil {
  1907  							if y.Value == nil {
  1908  								trues++
  1909  							}
  1910  							continue
  1911  						}
  1912  						if constant.Compare(x.Value, binop.Op, y.Value) {
  1913  							trues++
  1914  						}
  1915  					}
  1916  				}
  1917  				b := trues != 0
  1918  				if trues == 0 || trues == len(xs)*len(ys) {
  1919  					report.Report(pass, binop, fmt.Sprintf("binary expression is always %t for all possible values (%s %s %s)", b, xs, binop.Op, ys))
  1920  				}
  1921  			}
  1922  		}
  1923  	}
  1924  	return nil, nil
  1925  }
  1926  
  1927  func CheckNilMaps(pass *analysis.Pass) (interface{}, error) {
  1928  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  1929  		for _, block := range fn.Blocks {
  1930  			for _, ins := range block.Instrs {
  1931  				mu, ok := ins.(*ir.MapUpdate)
  1932  				if !ok {
  1933  					continue
  1934  				}
  1935  				c, ok := irutil.Flatten(mu.Map).(*ir.Const)
  1936  				if !ok {
  1937  					continue
  1938  				}
  1939  				if c.Value != nil {
  1940  					continue
  1941  				}
  1942  				report.Report(pass, mu, "assignment to nil map")
  1943  			}
  1944  		}
  1945  	}
  1946  	return nil, nil
  1947  }
  1948  
  1949  func CheckExtremeComparison(pass *analysis.Pass) (interface{}, error) {
  1950  	isobj := func(expr ast.Expr, name string) bool {
  1951  		sel, ok := expr.(*ast.SelectorExpr)
  1952  		if !ok {
  1953  			return false
  1954  		}
  1955  		return typeutil.IsObject(pass.TypesInfo.ObjectOf(sel.Sel), name)
  1956  	}
  1957  
  1958  	fn := func(node ast.Node) {
  1959  		expr := node.(*ast.BinaryExpr)
  1960  		tx := pass.TypesInfo.TypeOf(expr.X)
  1961  		basic, ok := tx.Underlying().(*types.Basic)
  1962  		if !ok {
  1963  			return
  1964  		}
  1965  
  1966  		var max string
  1967  		var min string
  1968  
  1969  		switch basic.Kind() {
  1970  		case types.Uint8:
  1971  			max = "math.MaxUint8"
  1972  		case types.Uint16:
  1973  			max = "math.MaxUint16"
  1974  		case types.Uint32:
  1975  			max = "math.MaxUint32"
  1976  		case types.Uint64:
  1977  			max = "math.MaxUint64"
  1978  		case types.Uint:
  1979  			max = "math.MaxUint64"
  1980  
  1981  		case types.Int8:
  1982  			min = "math.MinInt8"
  1983  			max = "math.MaxInt8"
  1984  		case types.Int16:
  1985  			min = "math.MinInt16"
  1986  			max = "math.MaxInt16"
  1987  		case types.Int32:
  1988  			min = "math.MinInt32"
  1989  			max = "math.MaxInt32"
  1990  		case types.Int64:
  1991  			min = "math.MinInt64"
  1992  			max = "math.MaxInt64"
  1993  		case types.Int:
  1994  			min = "math.MinInt64"
  1995  			max = "math.MaxInt64"
  1996  		}
  1997  
  1998  		if (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.Y, max) ||
  1999  			(expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.X, max) {
  2000  			report.Report(pass, expr, fmt.Sprintf("no value of type %s is greater than %s", basic, max))
  2001  		}
  2002  		if expr.Op == token.LEQ && isobj(expr.Y, max) ||
  2003  			expr.Op == token.GEQ && isobj(expr.X, max) {
  2004  			report.Report(pass, expr, fmt.Sprintf("every value of type %s is <= %s", basic, max))
  2005  		}
  2006  
  2007  		isZeroLiteral := func(expr ast.Expr) bool {
  2008  			return code.IsIntegerLiteral(pass, expr, constant.MakeInt64(0))
  2009  		}
  2010  		if (basic.Info() & types.IsUnsigned) != 0 {
  2011  			if (expr.Op == token.LSS && isZeroLiteral(expr.Y)) ||
  2012  				(expr.Op == token.GTR && isZeroLiteral(expr.X)) {
  2013  				report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than 0", basic))
  2014  			}
  2015  			if expr.Op == token.GEQ && isZeroLiteral(expr.Y) ||
  2016  				expr.Op == token.LEQ && isZeroLiteral(expr.X) {
  2017  				report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= 0", basic))
  2018  			}
  2019  		} else {
  2020  			if (expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.Y, min) ||
  2021  				(expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.X, min) {
  2022  				report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than %s", basic, min))
  2023  			}
  2024  			if expr.Op == token.GEQ && isobj(expr.Y, min) ||
  2025  				expr.Op == token.LEQ && isobj(expr.X, min) {
  2026  				report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= %s", basic, min))
  2027  			}
  2028  		}
  2029  
  2030  	}
  2031  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  2032  	return nil, nil
  2033  }
  2034  
  2035  func consts(val ir.Value, out []*ir.Const, visitedPhis map[string]bool) ([]*ir.Const, bool) {
  2036  	if visitedPhis == nil {
  2037  		visitedPhis = map[string]bool{}
  2038  	}
  2039  	var ok bool
  2040  	switch val := val.(type) {
  2041  	case *ir.Phi:
  2042  		if visitedPhis[val.Name()] {
  2043  			break
  2044  		}
  2045  		visitedPhis[val.Name()] = true
  2046  		vals := val.Operands(nil)
  2047  		for _, phival := range vals {
  2048  			out, ok = consts(*phival, out, visitedPhis)
  2049  			if !ok {
  2050  				return nil, false
  2051  			}
  2052  		}
  2053  	case *ir.Const:
  2054  		out = append(out, val)
  2055  	case *ir.Convert:
  2056  		out, ok = consts(val.X, out, visitedPhis)
  2057  		if !ok {
  2058  			return nil, false
  2059  		}
  2060  	default:
  2061  		return nil, false
  2062  	}
  2063  	if len(out) < 2 {
  2064  		return out, true
  2065  	}
  2066  	uniq := []*ir.Const{out[0]}
  2067  	for _, val := range out[1:] {
  2068  		if val.Value == uniq[len(uniq)-1].Value {
  2069  			continue
  2070  		}
  2071  		uniq = append(uniq, val)
  2072  	}
  2073  	return uniq, true
  2074  }
  2075  
  2076  func CheckLoopCondition(pass *analysis.Pass) (interface{}, error) {
  2077  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2078  		cb := func(node ast.Node) bool {
  2079  			loop, ok := node.(*ast.ForStmt)
  2080  			if !ok {
  2081  				return true
  2082  			}
  2083  			if loop.Init == nil || loop.Cond == nil || loop.Post == nil {
  2084  				return true
  2085  			}
  2086  			init, ok := loop.Init.(*ast.AssignStmt)
  2087  			if !ok || len(init.Lhs) != 1 || len(init.Rhs) != 1 {
  2088  				return true
  2089  			}
  2090  			cond, ok := loop.Cond.(*ast.BinaryExpr)
  2091  			if !ok {
  2092  				return true
  2093  			}
  2094  			x, ok := cond.X.(*ast.Ident)
  2095  			if !ok {
  2096  				return true
  2097  			}
  2098  			lhs, ok := init.Lhs[0].(*ast.Ident)
  2099  			if !ok {
  2100  				return true
  2101  			}
  2102  			if pass.TypesInfo.ObjectOf(x) != pass.TypesInfo.ObjectOf(lhs) {
  2103  				return true
  2104  			}
  2105  			if _, ok := loop.Post.(*ast.IncDecStmt); !ok {
  2106  				return true
  2107  			}
  2108  
  2109  			v, isAddr := fn.ValueForExpr(cond.X)
  2110  			if v == nil || isAddr {
  2111  				return true
  2112  			}
  2113  			switch v := v.(type) {
  2114  			case *ir.Phi:
  2115  				ops := v.Operands(nil)
  2116  				if len(ops) != 2 {
  2117  					return true
  2118  				}
  2119  				_, ok := (*ops[0]).(*ir.Const)
  2120  				if !ok {
  2121  					return true
  2122  				}
  2123  				sigma, ok := (*ops[1]).(*ir.Sigma)
  2124  				if !ok {
  2125  					return true
  2126  				}
  2127  				if sigma.X != v {
  2128  					return true
  2129  				}
  2130  			case *ir.Load:
  2131  				return true
  2132  			}
  2133  			report.Report(pass, cond, "variable in loop condition never changes")
  2134  
  2135  			return true
  2136  		}
  2137  		if source := fn.Source(); source != nil {
  2138  			ast.Inspect(source, cb)
  2139  		}
  2140  	}
  2141  	return nil, nil
  2142  }
  2143  
  2144  func CheckArgOverwritten(pass *analysis.Pass) (interface{}, error) {
  2145  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2146  		cb := func(node ast.Node) bool {
  2147  			var typ *ast.FuncType
  2148  			var body *ast.BlockStmt
  2149  			switch fn := node.(type) {
  2150  			case *ast.FuncDecl:
  2151  				typ = fn.Type
  2152  				body = fn.Body
  2153  			case *ast.FuncLit:
  2154  				typ = fn.Type
  2155  				body = fn.Body
  2156  			}
  2157  			if body == nil {
  2158  				return true
  2159  			}
  2160  			if len(typ.Params.List) == 0 {
  2161  				return true
  2162  			}
  2163  			for _, field := range typ.Params.List {
  2164  				for _, arg := range field.Names {
  2165  					obj := pass.TypesInfo.ObjectOf(arg)
  2166  					var irobj *ir.Parameter
  2167  					for _, param := range fn.Params {
  2168  						if param.Object() == obj {
  2169  							irobj = param
  2170  							break
  2171  						}
  2172  					}
  2173  					if irobj == nil {
  2174  						continue
  2175  					}
  2176  					refs := irobj.Referrers()
  2177  					if refs == nil {
  2178  						continue
  2179  					}
  2180  					if len(irutil.FilterDebug(*refs)) != 0 {
  2181  						continue
  2182  					}
  2183  
  2184  					var assignment ast.Node
  2185  					ast.Inspect(body, func(node ast.Node) bool {
  2186  						if assignment != nil {
  2187  							return false
  2188  						}
  2189  						assign, ok := node.(*ast.AssignStmt)
  2190  						if !ok {
  2191  							return true
  2192  						}
  2193  						for _, lhs := range assign.Lhs {
  2194  							ident, ok := lhs.(*ast.Ident)
  2195  							if !ok {
  2196  								continue
  2197  							}
  2198  							if pass.TypesInfo.ObjectOf(ident) == obj {
  2199  								assignment = assign
  2200  								return false
  2201  							}
  2202  						}
  2203  						return true
  2204  					})
  2205  					if assignment != nil {
  2206  						report.Report(pass, arg, fmt.Sprintf("argument %s is overwritten before first use", arg),
  2207  							report.Related(assignment, fmt.Sprintf("assignment to %s", arg)))
  2208  					}
  2209  				}
  2210  			}
  2211  			return true
  2212  		}
  2213  		if source := fn.Source(); source != nil {
  2214  			ast.Inspect(source, cb)
  2215  		}
  2216  	}
  2217  	return nil, nil
  2218  }
  2219  
  2220  func CheckIneffectiveLoop(pass *analysis.Pass) (interface{}, error) {
  2221  	// This check detects some, but not all unconditional loop exits.
  2222  	// We give up in the following cases:
  2223  	//
  2224  	// - a goto anywhere in the loop. The goto might skip over our
  2225  	// return, and we don't check that it doesn't.
  2226  	//
  2227  	// - any nested, unlabelled continue, even if it is in another
  2228  	// loop or closure.
  2229  	fn := func(node ast.Node) {
  2230  		var body *ast.BlockStmt
  2231  		switch fn := node.(type) {
  2232  		case *ast.FuncDecl:
  2233  			body = fn.Body
  2234  		case *ast.FuncLit:
  2235  			body = fn.Body
  2236  		default:
  2237  			lint.ExhaustiveTypeSwitch(node)
  2238  		}
  2239  		if body == nil {
  2240  			return
  2241  		}
  2242  		labels := map[types.Object]ast.Stmt{}
  2243  		ast.Inspect(body, func(node ast.Node) bool {
  2244  			label, ok := node.(*ast.LabeledStmt)
  2245  			if !ok {
  2246  				return true
  2247  			}
  2248  			labels[pass.TypesInfo.ObjectOf(label.Label)] = label.Stmt
  2249  			return true
  2250  		})
  2251  
  2252  		ast.Inspect(body, func(node ast.Node) bool {
  2253  			var loop ast.Node
  2254  			var body *ast.BlockStmt
  2255  			switch node := node.(type) {
  2256  			case *ast.ForStmt:
  2257  				body = node.Body
  2258  				loop = node
  2259  			case *ast.RangeStmt:
  2260  				ok := typeutil.All(pass.TypesInfo.TypeOf(node.X), func(term *types.Term) bool {
  2261  					switch term.Type().Underlying().(type) {
  2262  					case *types.Slice, *types.Chan, *types.Basic, *types.Pointer, *types.Array:
  2263  						return true
  2264  					case *types.Map:
  2265  						// looping once over a map is a valid pattern for
  2266  						// getting an arbitrary element.
  2267  						return false
  2268  					default:
  2269  						lint.ExhaustiveTypeSwitch(term.Type().Underlying())
  2270  						return false
  2271  					}
  2272  				})
  2273  				if !ok {
  2274  					return true
  2275  				}
  2276  				body = node.Body
  2277  				loop = node
  2278  			default:
  2279  				return true
  2280  			}
  2281  			if len(body.List) < 2 {
  2282  				// TODO(dh): is this check needed? when body.List < 2,
  2283  				// then we can't find both an unconditional exit and a
  2284  				// branching statement (if, ...). and we don't flag
  2285  				// unconditional exits if there has been no branching
  2286  				// in the loop body.
  2287  
  2288  				// avoid flagging the somewhat common pattern of using
  2289  				// a range loop to get the first element in a slice,
  2290  				// or the first rune in a string.
  2291  				return true
  2292  			}
  2293  			var unconditionalExit ast.Node
  2294  			hasBranching := false
  2295  			for _, stmt := range body.List {
  2296  				switch stmt := stmt.(type) {
  2297  				case *ast.BranchStmt:
  2298  					switch stmt.Tok {
  2299  					case token.BREAK:
  2300  						if stmt.Label == nil || labels[pass.TypesInfo.ObjectOf(stmt.Label)] == loop {
  2301  							unconditionalExit = stmt
  2302  						}
  2303  					case token.CONTINUE:
  2304  						if stmt.Label == nil || labels[pass.TypesInfo.ObjectOf(stmt.Label)] == loop {
  2305  							unconditionalExit = nil
  2306  							return false
  2307  						}
  2308  					}
  2309  				case *ast.ReturnStmt:
  2310  					unconditionalExit = stmt
  2311  				case *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.SelectStmt:
  2312  					hasBranching = true
  2313  				}
  2314  			}
  2315  			if unconditionalExit == nil || !hasBranching {
  2316  				return false
  2317  			}
  2318  			ast.Inspect(body, func(node ast.Node) bool {
  2319  				if branch, ok := node.(*ast.BranchStmt); ok {
  2320  
  2321  					switch branch.Tok {
  2322  					case token.GOTO:
  2323  						unconditionalExit = nil
  2324  						return false
  2325  					case token.CONTINUE:
  2326  						if branch.Label != nil && labels[pass.TypesInfo.ObjectOf(branch.Label)] != loop {
  2327  							return true
  2328  						}
  2329  						unconditionalExit = nil
  2330  						return false
  2331  					}
  2332  				}
  2333  				return true
  2334  			})
  2335  			if unconditionalExit != nil {
  2336  				report.Report(pass, unconditionalExit, "the surrounding loop is unconditionally terminated")
  2337  			}
  2338  			return true
  2339  		})
  2340  	}
  2341  	code.Preorder(pass, fn, (*ast.FuncDecl)(nil), (*ast.FuncLit)(nil))
  2342  	return nil, nil
  2343  }
  2344  
  2345  var checkNilContextQ = pattern.MustParse(`(CallExpr fun@(Symbol _) (Builtin "nil"):_)`)
  2346  
  2347  func CheckNilContext(pass *analysis.Pass) (interface{}, error) {
  2348  	todo := &ast.CallExpr{
  2349  		Fun: edit.Selector("context", "TODO"),
  2350  	}
  2351  	bg := &ast.CallExpr{
  2352  		Fun: edit.Selector("context", "Background"),
  2353  	}
  2354  	fn := func(node ast.Node) {
  2355  		m, ok := code.Match(pass, checkNilContextQ, node)
  2356  		if !ok {
  2357  			return
  2358  		}
  2359  
  2360  		call := node.(*ast.CallExpr)
  2361  		fun, ok := m.State["fun"].(*types.Func)
  2362  		if !ok {
  2363  			// it might also be a builtin
  2364  			return
  2365  		}
  2366  		sig := fun.Type().(*types.Signature)
  2367  		if sig.Params().Len() == 0 {
  2368  			// Our CallExpr might've matched a method expression, like
  2369  			// (*T).Foo(nil) – here, nil isn't the first argument of
  2370  			// the Foo method, but the method receiver.
  2371  			return
  2372  		}
  2373  		if !typeutil.IsType(sig.Params().At(0).Type(), "context.Context") {
  2374  			return
  2375  		}
  2376  		report.Report(pass, call.Args[0],
  2377  			"do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use", report.Fixes(
  2378  				edit.Fix("use context.TODO", edit.ReplaceWithNode(pass.Fset, call.Args[0], todo)),
  2379  				edit.Fix("use context.Background", edit.ReplaceWithNode(pass.Fset, call.Args[0], bg))))
  2380  	}
  2381  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  2382  	return nil, nil
  2383  }
  2384  
  2385  var (
  2386  	checkSeekerQ = pattern.MustParse(`(CallExpr fun@(SelectorExpr _ (Ident "Seek")) [arg1@(SelectorExpr _ (Symbol (Or "io.SeekStart" "io.SeekCurrent" "io.SeekEnd"))) arg2])`)
  2387  	checkSeekerR = pattern.MustParse(`(CallExpr fun [arg2 arg1])`)
  2388  )
  2389  
  2390  func CheckSeeker(pass *analysis.Pass) (interface{}, error) {
  2391  	fn := func(node ast.Node) {
  2392  		if m, edits, ok := code.MatchAndEdit(pass, checkSeekerQ, checkSeekerR, node); ok {
  2393  			if !code.IsMethod(pass, m.State["fun"].(*ast.SelectorExpr), "Seek", knowledge.Signatures["(io.Seeker).Seek"]) {
  2394  				return
  2395  			}
  2396  			report.Report(pass, node, "the first argument of io.Seeker is the offset, but an io.Seek* constant is being used instead",
  2397  				report.Fixes(edit.Fix("swap arguments", edits...)))
  2398  		}
  2399  	}
  2400  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  2401  	return nil, nil
  2402  }
  2403  
  2404  func CheckIneffectiveAppend(pass *analysis.Pass) (interface{}, error) {
  2405  	isAppend := func(ins ir.Value) bool {
  2406  		call, ok := ins.(*ir.Call)
  2407  		if !ok {
  2408  			return false
  2409  		}
  2410  		if call.Call.IsInvoke() {
  2411  			return false
  2412  		}
  2413  		if builtin, ok := call.Call.Value.(*ir.Builtin); !ok || builtin.Name() != "append" {
  2414  			return false
  2415  		}
  2416  		return true
  2417  	}
  2418  
  2419  	// We have to be careful about aliasing.
  2420  	// Multiple slices may refer to the same backing array,
  2421  	// making appends observable even when we don't see the result of append be used anywhere.
  2422  	//
  2423  	// We will have to restrict ourselves to slices that have been allocated within the function,
  2424  	// haven't been sliced,
  2425  	// and haven't been passed anywhere that could retain them (such as function calls or memory stores).
  2426  	//
  2427  	// We check whether an append should be flagged in two steps.
  2428  	//
  2429  	// In the first step, we look at the data flow graph, starting in reverse from the argument to append, till we reach the root.
  2430  	// This graph must only consist of the following instructions:
  2431  	//
  2432  	// - phi
  2433  	// - sigma
  2434  	// - slice
  2435  	// - const nil
  2436  	// - MakeSlice
  2437  	// - Alloc
  2438  	// - calls to append
  2439  	//
  2440  	// If this step succeeds, we look at all referrers of the values found in the first step, recursively.
  2441  	// These referrers must either be in the set of values found in the first step,
  2442  	// be DebugRefs,
  2443  	// or fulfill the same type requirements as step 1, with the exception of appends, which are forbidden.
  2444  	//
  2445  	// If both steps succeed then we know that the backing array hasn't been aliased in an observable manner.
  2446  	//
  2447  	// We could relax these restrictions by making use of additional information:
  2448  	// - if we passed the slice to a function that doesn't retain the slice then we can still flag it
  2449  	// - if a slice has been sliced but is dead afterwards, we can flag appends to the new slice
  2450  
  2451  	// OPT(dh): We could cache the results of both validate functions.
  2452  	// However, we only use these functions on values that we otherwise want to flag, which are very few.
  2453  	// Not caching values hasn't increased the runtimes for the standard library nor k8s.
  2454  	var validateArgument func(v ir.Value, seen map[ir.Value]struct{}) bool
  2455  	validateArgument = func(v ir.Value, seen map[ir.Value]struct{}) bool {
  2456  		if _, ok := seen[v]; ok {
  2457  			// break cycle
  2458  			return true
  2459  		}
  2460  		seen[v] = struct{}{}
  2461  		switch v := v.(type) {
  2462  		case *ir.Phi:
  2463  			for _, edge := range v.Edges {
  2464  				if !validateArgument(edge, seen) {
  2465  					return false
  2466  				}
  2467  			}
  2468  			return true
  2469  		case *ir.Sigma:
  2470  			return validateArgument(v.X, seen)
  2471  		case *ir.Slice:
  2472  			return validateArgument(v.X, seen)
  2473  		case *ir.Const:
  2474  			return true
  2475  		case *ir.MakeSlice:
  2476  			return true
  2477  		case *ir.Alloc:
  2478  			return true
  2479  		case *ir.Call:
  2480  			if isAppend(v) {
  2481  				return validateArgument(v.Call.Args[0], seen)
  2482  			}
  2483  			return false
  2484  		default:
  2485  			return false
  2486  		}
  2487  	}
  2488  
  2489  	var validateReferrers func(v ir.Value, seen map[ir.Instruction]struct{}) bool
  2490  	validateReferrers = func(v ir.Value, seen map[ir.Instruction]struct{}) bool {
  2491  		for _, ref := range *v.Referrers() {
  2492  			if _, ok := seen[ref]; ok {
  2493  				continue
  2494  			}
  2495  
  2496  			seen[ref] = struct{}{}
  2497  			switch ref.(type) {
  2498  			case *ir.Phi:
  2499  			case *ir.Sigma:
  2500  			case *ir.Slice:
  2501  			case *ir.Const:
  2502  			case *ir.MakeSlice:
  2503  			case *ir.Alloc:
  2504  			case *ir.DebugRef:
  2505  			default:
  2506  				return false
  2507  			}
  2508  
  2509  			if ref, ok := ref.(ir.Value); ok {
  2510  				if !validateReferrers(ref, seen) {
  2511  					return false
  2512  				}
  2513  			}
  2514  		}
  2515  		return true
  2516  	}
  2517  
  2518  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2519  		for _, block := range fn.Blocks {
  2520  			for _, ins := range block.Instrs {
  2521  				val, ok := ins.(ir.Value)
  2522  				if !ok || !isAppend(val) {
  2523  					continue
  2524  				}
  2525  
  2526  				isUsed := false
  2527  				visited := map[ir.Instruction]bool{}
  2528  				var walkRefs func(refs []ir.Instruction)
  2529  				walkRefs = func(refs []ir.Instruction) {
  2530  				loop:
  2531  					for _, ref := range refs {
  2532  						if visited[ref] {
  2533  							continue
  2534  						}
  2535  						visited[ref] = true
  2536  						if _, ok := ref.(*ir.DebugRef); ok {
  2537  							continue
  2538  						}
  2539  						switch ref := ref.(type) {
  2540  						case *ir.Phi:
  2541  							walkRefs(*ref.Referrers())
  2542  						case *ir.Sigma:
  2543  							walkRefs(*ref.Referrers())
  2544  						case ir.Value:
  2545  							if !isAppend(ref) {
  2546  								isUsed = true
  2547  							} else {
  2548  								walkRefs(*ref.Referrers())
  2549  							}
  2550  						case ir.Instruction:
  2551  							isUsed = true
  2552  							break loop
  2553  						}
  2554  					}
  2555  				}
  2556  
  2557  				refs := val.Referrers()
  2558  				if refs == nil {
  2559  					continue
  2560  				}
  2561  				walkRefs(*refs)
  2562  
  2563  				if isUsed {
  2564  					continue
  2565  				}
  2566  
  2567  				seen := map[ir.Value]struct{}{}
  2568  				if !validateArgument(ins.(*ir.Call).Call.Args[0], seen) {
  2569  					continue
  2570  				}
  2571  
  2572  				seen2 := map[ir.Instruction]struct{}{}
  2573  				for k := range seen {
  2574  					// the only values we allow are also instructions, so this type assertion cannot fail
  2575  					seen2[k.(ir.Instruction)] = struct{}{}
  2576  				}
  2577  				seen2[ins] = struct{}{}
  2578  				failed := false
  2579  				for v := range seen {
  2580  					if !validateReferrers(v, seen2) {
  2581  						failed = true
  2582  						break
  2583  					}
  2584  				}
  2585  				if !failed {
  2586  					report.Report(pass, ins, "this result of append is never used, except maybe in other appends")
  2587  				}
  2588  			}
  2589  		}
  2590  	}
  2591  	return nil, nil
  2592  }
  2593  
  2594  func CheckConcurrentTesting(pass *analysis.Pass) (interface{}, error) {
  2595  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2596  		for _, block := range fn.Blocks {
  2597  			for _, ins := range block.Instrs {
  2598  				gostmt, ok := ins.(*ir.Go)
  2599  				if !ok {
  2600  					continue
  2601  				}
  2602  				var fn *ir.Function
  2603  				switch val := gostmt.Call.Value.(type) {
  2604  				case *ir.Function:
  2605  					fn = val
  2606  				case *ir.MakeClosure:
  2607  					fn = val.Fn.(*ir.Function)
  2608  				default:
  2609  					continue
  2610  				}
  2611  				if fn.Blocks == nil {
  2612  					continue
  2613  				}
  2614  				for _, block := range fn.Blocks {
  2615  					for _, ins := range block.Instrs {
  2616  						call, ok := ins.(*ir.Call)
  2617  						if !ok {
  2618  							continue
  2619  						}
  2620  						if call.Call.IsInvoke() {
  2621  							continue
  2622  						}
  2623  						callee := call.Call.StaticCallee()
  2624  						if callee == nil {
  2625  							continue
  2626  						}
  2627  						recv := callee.Signature.Recv()
  2628  						if recv == nil {
  2629  							continue
  2630  						}
  2631  						if !typeutil.IsType(recv.Type(), "*testing.common") {
  2632  							continue
  2633  						}
  2634  						fn, ok := call.Call.StaticCallee().Object().(*types.Func)
  2635  						if !ok {
  2636  							continue
  2637  						}
  2638  						name := fn.Name()
  2639  						switch name {
  2640  						case "FailNow", "Fatal", "Fatalf", "SkipNow", "Skip", "Skipf":
  2641  						default:
  2642  							continue
  2643  						}
  2644  						// TODO(dh): don't report multiple diagnostics
  2645  						// for multiple calls to T.Fatal, but do
  2646  						// collect all of them as related information
  2647  						report.Report(pass, gostmt, fmt.Sprintf("the goroutine calls T.%s, which must be called in the same goroutine as the test", name),
  2648  							report.Related(call, fmt.Sprintf("call to T.%s", name)))
  2649  					}
  2650  				}
  2651  			}
  2652  		}
  2653  	}
  2654  	return nil, nil
  2655  }
  2656  
  2657  func eachCall(fn *ir.Function, cb func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function)) {
  2658  	for _, b := range fn.Blocks {
  2659  		for _, instr := range b.Instrs {
  2660  			if site, ok := instr.(ir.CallInstruction); ok {
  2661  				if g := site.Common().StaticCallee(); g != nil {
  2662  					cb(fn, site, g)
  2663  				}
  2664  			}
  2665  		}
  2666  	}
  2667  }
  2668  
  2669  func CheckCyclicFinalizer(pass *analysis.Pass) (interface{}, error) {
  2670  	cb := func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) {
  2671  		if callee.RelString(nil) != "runtime.SetFinalizer" {
  2672  			return
  2673  		}
  2674  		arg0 := site.Common().Args[knowledge.Arg("runtime.SetFinalizer.obj")]
  2675  		if iface, ok := arg0.(*ir.MakeInterface); ok {
  2676  			arg0 = iface.X
  2677  		}
  2678  		load, ok := arg0.(*ir.Load)
  2679  		if !ok {
  2680  			return
  2681  		}
  2682  		v, ok := load.X.(*ir.Alloc)
  2683  		if !ok {
  2684  			return
  2685  		}
  2686  		arg1 := site.Common().Args[knowledge.Arg("runtime.SetFinalizer.finalizer")]
  2687  		if iface, ok := arg1.(*ir.MakeInterface); ok {
  2688  			arg1 = iface.X
  2689  		}
  2690  		mc, ok := arg1.(*ir.MakeClosure)
  2691  		if !ok {
  2692  			return
  2693  		}
  2694  		for _, b := range mc.Bindings {
  2695  			if b == v {
  2696  				pos := report.DisplayPosition(pass.Fset, mc.Fn.Pos())
  2697  				report.Report(pass, site, fmt.Sprintf("the finalizer closes over the object, preventing the finalizer from ever running (at %s)", pos))
  2698  			}
  2699  		}
  2700  	}
  2701  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2702  		eachCall(fn, cb)
  2703  	}
  2704  	return nil, nil
  2705  }
  2706  
  2707  /*
  2708  func CheckSliceOutOfBounds(pass *analysis.Pass) (interface{}, error) {
  2709  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2710  		for _, block := range fn.Blocks {
  2711  			for _, ins := range block.Instrs {
  2712  				ia, ok := ins.(*ir.IndexAddr)
  2713  				if !ok {
  2714  					continue
  2715  				}
  2716  				if _, ok := ia.X.Type().Underlying().(*types.Slice); !ok {
  2717  					continue
  2718  				}
  2719  				sr, ok1 := c.funcDescs.Get(fn).Ranges[ia.X].(vrp.SliceInterval)
  2720  				idxr, ok2 := c.funcDescs.Get(fn).Ranges[ia.Index].(vrp.IntInterval)
  2721  				if !ok1 || !ok2 || !sr.IsKnown() || !idxr.IsKnown() || sr.Length.Empty() || idxr.Empty() {
  2722  					continue
  2723  				}
  2724  				if idxr.Lower.Cmp(sr.Length.Upper) >= 0 {
  2725  					report.Nodef(pass, ia, "index out of bounds")
  2726  				}
  2727  			}
  2728  		}
  2729  	}
  2730  	return nil, nil
  2731  }
  2732  */
  2733  
  2734  func CheckDeferLock(pass *analysis.Pass) (interface{}, error) {
  2735  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2736  		for _, block := range fn.Blocks {
  2737  			instrs := irutil.FilterDebug(block.Instrs)
  2738  			if len(instrs) < 2 {
  2739  				continue
  2740  			}
  2741  			for i, ins := range instrs[:len(instrs)-1] {
  2742  				call, ok := ins.(*ir.Call)
  2743  				if !ok {
  2744  					continue
  2745  				}
  2746  				if !irutil.IsCallToAny(call.Common(), "(*sync.Mutex).Lock", "(*sync.RWMutex).RLock") {
  2747  					continue
  2748  				}
  2749  				nins, ok := instrs[i+1].(*ir.Defer)
  2750  				if !ok {
  2751  					continue
  2752  				}
  2753  				if !irutil.IsCallToAny(&nins.Call, "(*sync.Mutex).Lock", "(*sync.RWMutex).RLock") {
  2754  					continue
  2755  				}
  2756  				if call.Common().Args[0] != nins.Call.Args[0] {
  2757  					continue
  2758  				}
  2759  				name := shortCallName(call.Common())
  2760  				alt := ""
  2761  				switch name {
  2762  				case "Lock":
  2763  					alt = "Unlock"
  2764  				case "RLock":
  2765  					alt = "RUnlock"
  2766  				}
  2767  				report.Report(pass, nins, fmt.Sprintf("deferring %s right after having locked already; did you mean to defer %s?", name, alt))
  2768  			}
  2769  		}
  2770  	}
  2771  	return nil, nil
  2772  }
  2773  
  2774  func CheckNaNComparison(pass *analysis.Pass) (interface{}, error) {
  2775  	isNaN := func(v ir.Value) bool {
  2776  		call, ok := v.(*ir.Call)
  2777  		if !ok {
  2778  			return false
  2779  		}
  2780  		return irutil.IsCallTo(call.Common(), "math.NaN")
  2781  	}
  2782  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2783  		for _, block := range fn.Blocks {
  2784  			for _, ins := range block.Instrs {
  2785  				ins, ok := ins.(*ir.BinOp)
  2786  				if !ok {
  2787  					continue
  2788  				}
  2789  				if isNaN(irutil.Flatten(ins.X)) || isNaN(irutil.Flatten(ins.Y)) {
  2790  					report.Report(pass, ins, "no value is equal to NaN, not even NaN itself")
  2791  				}
  2792  			}
  2793  		}
  2794  	}
  2795  	return nil, nil
  2796  }
  2797  
  2798  func CheckInfiniteRecursion(pass *analysis.Pass) (interface{}, error) {
  2799  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2800  		eachCall(fn, func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) {
  2801  			if callee != fn {
  2802  				return
  2803  			}
  2804  			if _, ok := site.(*ir.Go); ok {
  2805  				// Recursively spawning goroutines doesn't consume
  2806  				// stack space infinitely, so don't flag it.
  2807  				return
  2808  			}
  2809  
  2810  			block := site.Block()
  2811  			for _, b := range fn.Blocks {
  2812  				if block.Dominates(b) {
  2813  					continue
  2814  				}
  2815  				if len(b.Instrs) == 0 {
  2816  					continue
  2817  				}
  2818  				if _, ok := b.Control().(*ir.Return); ok {
  2819  					return
  2820  				}
  2821  			}
  2822  			report.Report(pass, site, "infinite recursive call")
  2823  		})
  2824  	}
  2825  	return nil, nil
  2826  }
  2827  
  2828  func CheckLeakyTimeTick(pass *analysis.Pass) (interface{}, error) {
  2829  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  2830  		if code.IsMainLike(pass) || code.IsInTest(pass, fn) {
  2831  			continue
  2832  		}
  2833  		for _, block := range fn.Blocks {
  2834  			for _, ins := range block.Instrs {
  2835  				call, ok := ins.(*ir.Call)
  2836  				if !ok || !irutil.IsCallTo(call.Common(), "time.Tick") {
  2837  					continue
  2838  				}
  2839  				if !irutil.Terminates(call.Parent()) {
  2840  					continue
  2841  				}
  2842  				report.Report(pass, 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")
  2843  			}
  2844  		}
  2845  	}
  2846  	return nil, nil
  2847  }
  2848  
  2849  var checkDoubleNegationQ = pattern.MustParse(`(UnaryExpr "!" single@(UnaryExpr "!" x))`)
  2850  
  2851  func CheckDoubleNegation(pass *analysis.Pass) (interface{}, error) {
  2852  	fn := func(node ast.Node) {
  2853  		if m, ok := code.Match(pass, checkDoubleNegationQ, node); ok {
  2854  			report.Report(pass, node, "negating a boolean twice has no effect; is this a typo?", report.Fixes(
  2855  				edit.Fix("turn into single negation", edit.ReplaceWithNode(pass.Fset, node, m.State["single"].(ast.Node))),
  2856  				edit.Fix("remove double negation", edit.ReplaceWithNode(pass.Fset, node, m.State["x"].(ast.Node)))))
  2857  		}
  2858  	}
  2859  	code.Preorder(pass, fn, (*ast.UnaryExpr)(nil))
  2860  	return nil, nil
  2861  }
  2862  
  2863  func CheckRepeatedIfElse(pass *analysis.Pass) (interface{}, error) {
  2864  	seen := map[ast.Node]bool{}
  2865  
  2866  	var collectConds func(ifstmt *ast.IfStmt, conds []ast.Expr) ([]ast.Expr, bool)
  2867  	collectConds = func(ifstmt *ast.IfStmt, conds []ast.Expr) ([]ast.Expr, bool) {
  2868  		seen[ifstmt] = true
  2869  		// Bail if any if-statement has an Init statement or side effects in its condition
  2870  		if ifstmt.Init != nil {
  2871  			return nil, false
  2872  		}
  2873  		if code.MayHaveSideEffects(pass, ifstmt.Cond, nil) {
  2874  			return nil, false
  2875  		}
  2876  
  2877  		conds = append(conds, ifstmt.Cond)
  2878  		if elsestmt, ok := ifstmt.Else.(*ast.IfStmt); ok {
  2879  			return collectConds(elsestmt, conds)
  2880  		}
  2881  		return conds, true
  2882  	}
  2883  	fn := func(node ast.Node) {
  2884  		ifstmt := node.(*ast.IfStmt)
  2885  		if seen[ifstmt] {
  2886  			// this if-statement is part of an if/else-if chain that we've already processed
  2887  			return
  2888  		}
  2889  		if ifstmt.Else == nil {
  2890  			// there can be at most one condition
  2891  			return
  2892  		}
  2893  		conds, ok := collectConds(ifstmt, nil)
  2894  		if !ok {
  2895  			return
  2896  		}
  2897  		if len(conds) < 2 {
  2898  			return
  2899  		}
  2900  		counts := map[string]int{}
  2901  		for _, cond := range conds {
  2902  			s := report.Render(pass, cond)
  2903  			counts[s]++
  2904  			if counts[s] == 2 {
  2905  				report.Report(pass, cond, "this condition occurs multiple times in this if/else if chain")
  2906  			}
  2907  		}
  2908  	}
  2909  	code.Preorder(pass, fn, (*ast.IfStmt)(nil))
  2910  	return nil, nil
  2911  }
  2912  
  2913  func CheckSillyBitwiseOps(pass *analysis.Pass) (interface{}, error) {
  2914  	fn := func(node ast.Node) {
  2915  		binop := node.(*ast.BinaryExpr)
  2916  		if !typeutil.All(pass.TypesInfo.TypeOf(binop), func(term *types.Term) bool {
  2917  			b, ok := term.Type().Underlying().(*types.Basic)
  2918  			if !ok {
  2919  				return false
  2920  			}
  2921  			return (b.Info() & types.IsInteger) != 0
  2922  		}) {
  2923  			return
  2924  		}
  2925  		switch binop.Op {
  2926  		case token.AND, token.OR, token.XOR:
  2927  		default:
  2928  			// we do not flag shifts because too often, x<<0 is part
  2929  			// of a pattern, x<<0, x<<8, x<<16, ...
  2930  			return
  2931  		}
  2932  		if y, ok := binop.Y.(*ast.Ident); ok {
  2933  			obj, ok := pass.TypesInfo.ObjectOf(y).(*types.Const)
  2934  			if !ok {
  2935  				return
  2936  			}
  2937  			if obj.Pkg() != pass.Pkg {
  2938  				// identifier was dot-imported
  2939  				return
  2940  			}
  2941  			if v, _ := constant.Int64Val(obj.Val()); v != 0 {
  2942  				return
  2943  			}
  2944  			path, _ := astutil.PathEnclosingInterval(code.File(pass, obj), obj.Pos(), obj.Pos())
  2945  			if len(path) < 2 {
  2946  				return
  2947  			}
  2948  			spec, ok := path[1].(*ast.ValueSpec)
  2949  			if !ok {
  2950  				return
  2951  			}
  2952  			if len(spec.Names) != 1 || len(spec.Values) != 1 {
  2953  				// TODO(dh): we could support this
  2954  				return
  2955  			}
  2956  			ident, ok := spec.Values[0].(*ast.Ident)
  2957  			if !ok {
  2958  				return
  2959  			}
  2960  			if !isIota(pass.TypesInfo.ObjectOf(ident)) {
  2961  				return
  2962  			}
  2963  			switch binop.Op {
  2964  			case token.AND:
  2965  				report.Report(pass, node,
  2966  					fmt.Sprintf("%s always equals 0; %s is defined as iota and has value 0, maybe %s is meant to be 1 << iota?", report.Render(pass, binop), report.Render(pass, binop.Y), report.Render(pass, binop.Y)))
  2967  			case token.OR, token.XOR:
  2968  				report.Report(pass, node,
  2969  					fmt.Sprintf("%s always equals %s; %s is defined as iota and has value 0, maybe %s is meant to be 1 << iota?", report.Render(pass, binop), report.Render(pass, binop.X), report.Render(pass, binop.Y), report.Render(pass, binop.Y)))
  2970  			}
  2971  		} else if code.IsIntegerLiteral(pass, binop.Y, constant.MakeInt64(0)) {
  2972  			switch binop.Op {
  2973  			case token.AND:
  2974  				report.Report(pass, node, fmt.Sprintf("%s always equals 0", report.Render(pass, binop)))
  2975  			case token.OR, token.XOR:
  2976  				report.Report(pass, node, fmt.Sprintf("%s always equals %s", report.Render(pass, binop), report.Render(pass, binop.X)))
  2977  			}
  2978  		}
  2979  	}
  2980  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  2981  	return nil, nil
  2982  }
  2983  
  2984  func isIota(obj types.Object) bool {
  2985  	if obj.Name() != "iota" {
  2986  		return false
  2987  	}
  2988  	c, ok := obj.(*types.Const)
  2989  	if !ok {
  2990  		return false
  2991  	}
  2992  	return c.Pkg() == nil
  2993  }
  2994  
  2995  func CheckNonOctalFileMode(pass *analysis.Pass) (interface{}, error) {
  2996  	fn := func(node ast.Node) {
  2997  		call := node.(*ast.CallExpr)
  2998  		for _, arg := range call.Args {
  2999  			lit, ok := arg.(*ast.BasicLit)
  3000  			if !ok {
  3001  				continue
  3002  			}
  3003  			if !typeutil.IsType(pass.TypesInfo.TypeOf(lit), "os.FileMode") &&
  3004  				!typeutil.IsType(pass.TypesInfo.TypeOf(lit), "io/fs.FileMode") {
  3005  				continue
  3006  			}
  3007  			if len(lit.Value) == 3 &&
  3008  				lit.Value[0] != '0' &&
  3009  				lit.Value[0] >= '0' && lit.Value[0] <= '7' &&
  3010  				lit.Value[1] >= '0' && lit.Value[1] <= '7' &&
  3011  				lit.Value[2] >= '0' && lit.Value[2] <= '7' {
  3012  
  3013  				v, err := strconv.ParseInt(lit.Value, 10, 64)
  3014  				if err != nil {
  3015  					continue
  3016  				}
  3017  				report.Report(pass, arg, fmt.Sprintf("file mode '%s' evaluates to %#o; did you mean '0%s'?", lit.Value, v, lit.Value),
  3018  					report.Fixes(edit.Fix("fix octal literal", edit.ReplaceWithString(arg, "0"+lit.Value))))
  3019  			}
  3020  		}
  3021  	}
  3022  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  3023  	return nil, nil
  3024  }
  3025  
  3026  func CheckSideEffectFreeCalls(pass *analysis.Pass) (interface{}, error) {
  3027  	pure := pass.ResultOf[purity.Analyzer].(purity.Result)
  3028  
  3029  fnLoop:
  3030  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  3031  		if code.IsInTest(pass, fn) {
  3032  			params := fn.Signature.Params()
  3033  			for i := 0; i < params.Len(); i++ {
  3034  				param := params.At(i)
  3035  				if typeutil.IsType(param.Type(), "*testing.B") {
  3036  					// Ignore discarded pure functions in code related
  3037  					// to benchmarks. Instead of matching BenchmarkFoo
  3038  					// functions, we match any function accepting a
  3039  					// *testing.B. Benchmarks sometimes call generic
  3040  					// functions for doing the actual work, and
  3041  					// checking for the parameter is a lot easier and
  3042  					// faster than analyzing call trees.
  3043  					continue fnLoop
  3044  				}
  3045  			}
  3046  		}
  3047  
  3048  		for _, b := range fn.Blocks {
  3049  			for _, ins := range b.Instrs {
  3050  				ins, ok := ins.(*ir.Call)
  3051  				if !ok {
  3052  					continue
  3053  				}
  3054  				refs := ins.Referrers()
  3055  				if refs == nil || len(irutil.FilterDebug(*refs)) > 0 {
  3056  					continue
  3057  				}
  3058  
  3059  				callee := ins.Common().StaticCallee()
  3060  				if callee == nil {
  3061  					continue
  3062  				}
  3063  				if callee.Object() == nil {
  3064  					// TODO(dh): support anonymous functions
  3065  					continue
  3066  				}
  3067  				if _, ok := pure[callee.Object().(*types.Func)]; ok {
  3068  					if pass.Pkg.Path() == "fmt_test" && callee.Object().(*types.Func).FullName() == "fmt.Sprintf" {
  3069  						// special case for benchmarks in the fmt package
  3070  						continue
  3071  					}
  3072  					report.Report(pass, ins, fmt.Sprintf("%s doesn't have side effects and its return value is ignored", callee.Object().Name()))
  3073  				}
  3074  			}
  3075  		}
  3076  	}
  3077  	return nil, nil
  3078  }
  3079  
  3080  func CheckDeprecated(pass *analysis.Pass) (interface{}, error) {
  3081  	deprs := pass.ResultOf[deprecated.Analyzer].(deprecated.Result)
  3082  
  3083  	// Selectors can appear outside of function literals, e.g. when
  3084  	// declaring package level variables.
  3085  
  3086  	isStdlibPath := func(path string) bool {
  3087  		// Modules with no dot in the first path element are reserved for the standard library and tooling.
  3088  		// This is the best we can currently do.
  3089  		// Nobody tells us which import paths are part of the standard library.
  3090  		//
  3091  		// We check the entire path instead of just the first path element, because the standard library doesn't contain paths with any dots, anyway.
  3092  
  3093  		return !strings.Contains(path, ".")
  3094  	}
  3095  
  3096  	handleDeprecation := func(depr *deprecated.IsDeprecated, node ast.Node, deprecatedObjName string, pkgPath string, tfn types.Object) {
  3097  		// Note: gopls doesn't correctly run analyzers on
  3098  		// dependencies, so we'll never be able to find deprecated
  3099  		// objects in imported code. We've experimented with
  3100  		// lifting the stdlib handling out of the general check,
  3101  		// to at least work for deprecated objects in the stdlib,
  3102  		// but we gave up on that, because we wouldn't have access
  3103  		// to the deprecation message.
  3104  		std, ok := knowledge.StdlibDeprecations[deprecatedObjName]
  3105  		if !ok && isStdlibPath(pkgPath) {
  3106  			// Deprecated object in the standard library, but we don't know the details of the deprecation.
  3107  			// Don't flag it at all, to avoid flagging an object that was deprecated in 1.N when targeting 1.N-1.
  3108  			// See https://staticcheck.io/issues/1108 for the background on this.
  3109  			return
  3110  		}
  3111  		if ok {
  3112  			// In the past, we made use of the AlternativeAvailableSince field. If a function was deprecated in Go
  3113  			// 1.6 and an alternative had been available in Go 1.0, then we'd recommend using the alternative even
  3114  			// if targeting Go 1.2. The idea was to suggest writing future-proof code by using already-existing
  3115  			// alternatives. This had a major flaw, however: the user would need to use at least Go 1.6 for
  3116  			// Staticcheck to know that the function had been deprecated. Thus, targeting Go 1.2 and using Go 1.2
  3117  			// would behave differently from targeting Go 1.2 and using Go 1.6. This is especially a problem if the
  3118  			// user tries to ignore the warning. Depending on the Go version in use, the ignore directive may or may
  3119  			// not match, causing a warning of its own.
  3120  			//
  3121  			// To avoid this issue, we no longer try to be smart. We now only compare the targeted version against
  3122  			// the version that deprecated an object.
  3123  			//
  3124  			// Unfortunately, this issue also applies to AlternativeAvailableSince == DeprecatedNeverUse. Even though it
  3125  			// is only applied to seriously flawed API, such as broken cryptography, users may wish to ignore those
  3126  			// warnings.
  3127  			//
  3128  			// See also https://staticcheck.io/issues/1318.
  3129  			if !code.IsGoVersion(pass, std.DeprecatedSince) {
  3130  				return
  3131  			}
  3132  		}
  3133  
  3134  		if tfn != nil {
  3135  			if _, ok := deprs.Objects[tfn]; ok {
  3136  				// functions that are deprecated may use deprecated
  3137  				// symbols
  3138  				return
  3139  			}
  3140  		}
  3141  
  3142  		if ok {
  3143  			switch std.AlternativeAvailableSince {
  3144  			case knowledge.DeprecatedNeverUse:
  3145  				report.Report(pass, node,
  3146  					fmt.Sprintf("%s has been deprecated since Go 1.%d because it shouldn't be used: %s",
  3147  						report.Render(pass, node), std.DeprecatedSince, depr.Msg))
  3148  			case std.DeprecatedSince, knowledge.DeprecatedUseNoLonger:
  3149  				report.Report(pass, node,
  3150  					fmt.Sprintf("%s has been deprecated since Go 1.%d: %s",
  3151  						report.Render(pass, node), std.DeprecatedSince, depr.Msg))
  3152  			default:
  3153  				report.Report(pass, node,
  3154  					fmt.Sprintf("%s has been deprecated since Go 1.%d and an alternative has been available since Go 1.%d: %s",
  3155  						report.Render(pass, node), std.DeprecatedSince, std.AlternativeAvailableSince, depr.Msg))
  3156  			}
  3157  		} else {
  3158  			report.Report(pass, node, fmt.Sprintf("%s is deprecated: %s", report.Render(pass, node), depr.Msg))
  3159  		}
  3160  	}
  3161  
  3162  	var tfn types.Object
  3163  	stack := 0
  3164  	fn := func(node ast.Node, push bool) bool {
  3165  		if !push {
  3166  			stack--
  3167  			return false
  3168  		}
  3169  		stack++
  3170  		if stack == 1 {
  3171  			tfn = nil
  3172  		}
  3173  		if fn, ok := node.(*ast.FuncDecl); ok {
  3174  			tfn = pass.TypesInfo.ObjectOf(fn.Name)
  3175  		}
  3176  
  3177  		// FIXME(dh): this misses dot-imported objects
  3178  		sel, ok := node.(*ast.SelectorExpr)
  3179  		if !ok {
  3180  			return true
  3181  		}
  3182  
  3183  		obj := pass.TypesInfo.ObjectOf(sel.Sel)
  3184  		if obj_, ok := obj.(*types.Func); ok {
  3185  			obj = obj_.Origin()
  3186  		}
  3187  		if obj.Pkg() == nil {
  3188  			return true
  3189  		}
  3190  
  3191  		if obj.Pkg() == pass.Pkg {
  3192  			// A package is allowed to use its own deprecated objects
  3193  			return true
  3194  		}
  3195  
  3196  		// A package "foo" has two related packages "foo_test" and "foo.test", for external tests and the package main
  3197  		// generated by 'go test' respectively. "foo_test" can import and use "foo", "foo.test" imports and uses "foo"
  3198  		// and "foo_test".
  3199  
  3200  		if strings.TrimSuffix(pass.Pkg.Path(), "_test") == obj.Pkg().Path() {
  3201  			// foo_test (the external tests of foo) can use objects from foo.
  3202  			return true
  3203  		}
  3204  		if strings.TrimSuffix(pass.Pkg.Path(), ".test") == obj.Pkg().Path() {
  3205  			// foo.test (the main package of foo's tests) can use objects from foo.
  3206  			return true
  3207  		}
  3208  		if strings.TrimSuffix(pass.Pkg.Path(), ".test") == strings.TrimSuffix(obj.Pkg().Path(), "_test") {
  3209  			// foo.test (the main package of foo's tests) can use objects from foo's external tests.
  3210  			return true
  3211  		}
  3212  
  3213  		if depr, ok := deprs.Objects[obj]; ok {
  3214  			handleDeprecation(depr, sel, code.SelectorName(pass, sel), obj.Pkg().Path(), tfn)
  3215  		}
  3216  		return true
  3217  	}
  3218  
  3219  	fn2 := func(node ast.Node) {
  3220  		spec := node.(*ast.ImportSpec)
  3221  		var imp *types.Package
  3222  		if spec.Name != nil {
  3223  			imp = pass.TypesInfo.ObjectOf(spec.Name).(*types.PkgName).Imported()
  3224  		} else {
  3225  			imp = pass.TypesInfo.Implicits[spec].(*types.PkgName).Imported()
  3226  		}
  3227  
  3228  		p := spec.Path.Value
  3229  		path := p[1 : len(p)-1]
  3230  		if depr, ok := deprs.Packages[imp]; ok {
  3231  			if path == "github.com/golang/protobuf/proto" {
  3232  				gen, ok := code.Generator(pass, spec.Path.Pos())
  3233  				if ok && gen == generated.ProtocGenGo {
  3234  					return
  3235  				}
  3236  			}
  3237  
  3238  			if strings.TrimSuffix(pass.Pkg.Path(), "_test") == path {
  3239  				// foo_test can import foo
  3240  				return
  3241  			}
  3242  			if strings.TrimSuffix(pass.Pkg.Path(), ".test") == path {
  3243  				// foo.test can import foo
  3244  				return
  3245  			}
  3246  			if strings.TrimSuffix(pass.Pkg.Path(), ".test") == strings.TrimSuffix(path, "_test") {
  3247  				// foo.test can import foo_test
  3248  				return
  3249  			}
  3250  
  3251  			handleDeprecation(depr, spec.Path, path, path, nil)
  3252  		}
  3253  	}
  3254  	pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Nodes(nil, fn)
  3255  	code.Preorder(pass, fn2, (*ast.ImportSpec)(nil))
  3256  	return nil, nil
  3257  }
  3258  
  3259  func callChecker(rules map[string]CallCheck) func(pass *analysis.Pass) (interface{}, error) {
  3260  	return func(pass *analysis.Pass) (interface{}, error) {
  3261  		return checkCalls(pass, rules)
  3262  	}
  3263  }
  3264  
  3265  func checkCalls(pass *analysis.Pass, rules map[string]CallCheck) (interface{}, error) {
  3266  	cb := func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) {
  3267  		obj, ok := callee.Object().(*types.Func)
  3268  		if !ok {
  3269  			return
  3270  		}
  3271  
  3272  		r, ok := rules[typeutil.FuncName(obj)]
  3273  		if !ok {
  3274  			return
  3275  		}
  3276  		var args []*Argument
  3277  		irargs := site.Common().Args
  3278  		if callee.Signature.Recv() != nil {
  3279  			irargs = irargs[1:]
  3280  		}
  3281  		for _, arg := range irargs {
  3282  			if iarg, ok := arg.(*ir.MakeInterface); ok {
  3283  				arg = iarg.X
  3284  			}
  3285  			args = append(args, &Argument{Value: Value{arg}})
  3286  		}
  3287  		call := &Call{
  3288  			Pass:   pass,
  3289  			Instr:  site,
  3290  			Args:   args,
  3291  			Parent: site.Parent(),
  3292  		}
  3293  		r(call)
  3294  
  3295  		var astcall *ast.CallExpr
  3296  		switch source := site.Source().(type) {
  3297  		case *ast.CallExpr:
  3298  			astcall = source
  3299  		case *ast.DeferStmt:
  3300  			astcall = source.Call
  3301  		case *ast.GoStmt:
  3302  			astcall = source.Call
  3303  		case nil:
  3304  			// TODO(dh): I am not sure this can actually happen. If it
  3305  			// can't, we should remove this case, and also stop
  3306  			// checking for astcall == nil in the code that follows.
  3307  		default:
  3308  			panic(fmt.Sprintf("unhandled case %T", source))
  3309  		}
  3310  
  3311  		for idx, arg := range call.Args {
  3312  			for _, e := range arg.invalids {
  3313  				if astcall != nil {
  3314  					if idx < len(astcall.Args) {
  3315  						report.Report(pass, astcall.Args[idx], e)
  3316  					} else {
  3317  						// this is an instance of fn1(fn2()) where fn2
  3318  						// returns multiple values. Report the error
  3319  						// at the next-best position that we have, the
  3320  						// first argument. An example of a check that
  3321  						// triggers this is checkEncodingBinaryRules.
  3322  						report.Report(pass, astcall.Args[0], e)
  3323  					}
  3324  				} else {
  3325  					report.Report(pass, site, e)
  3326  				}
  3327  			}
  3328  		}
  3329  		for _, e := range call.invalids {
  3330  			report.Report(pass, call.Instr, e)
  3331  		}
  3332  	}
  3333  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  3334  		eachCall(fn, cb)
  3335  	}
  3336  	return nil, nil
  3337  }
  3338  
  3339  func shortCallName(call *ir.CallCommon) string {
  3340  	if call.IsInvoke() {
  3341  		return ""
  3342  	}
  3343  	switch v := call.Value.(type) {
  3344  	case *ir.Function:
  3345  		fn, ok := v.Object().(*types.Func)
  3346  		if !ok {
  3347  			return ""
  3348  		}
  3349  		return fn.Name()
  3350  	case *ir.Builtin:
  3351  		return v.Name()
  3352  	}
  3353  	return ""
  3354  }
  3355  
  3356  func CheckWriterBufferModified(pass *analysis.Pass) (interface{}, error) {
  3357  	// TODO(dh): this might be a good candidate for taint analysis.
  3358  	// Taint the argument as MUST_NOT_MODIFY, then propagate that
  3359  	// through functions like bytes.Split
  3360  
  3361  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  3362  		sig := fn.Signature
  3363  		if fn.Name() != "Write" || sig.Recv() == nil || sig.Params().Len() != 1 || sig.Results().Len() != 2 {
  3364  			continue
  3365  		}
  3366  		tArg, ok := sig.Params().At(0).Type().(*types.Slice)
  3367  		if !ok {
  3368  			continue
  3369  		}
  3370  		if basic, ok := tArg.Elem().(*types.Basic); !ok || basic.Kind() != types.Byte {
  3371  			continue
  3372  		}
  3373  		if basic, ok := sig.Results().At(0).Type().(*types.Basic); !ok || basic.Kind() != types.Int {
  3374  			continue
  3375  		}
  3376  		if named, ok := sig.Results().At(1).Type().(*types.Named); !ok || !typeutil.IsType(named, "error") {
  3377  			continue
  3378  		}
  3379  
  3380  		for _, block := range fn.Blocks {
  3381  			for _, ins := range block.Instrs {
  3382  				switch ins := ins.(type) {
  3383  				case *ir.Store:
  3384  					addr, ok := ins.Addr.(*ir.IndexAddr)
  3385  					if !ok {
  3386  						continue
  3387  					}
  3388  					if addr.X != fn.Params[1] {
  3389  						continue
  3390  					}
  3391  					report.Report(pass, ins, "io.Writer.Write must not modify the provided buffer, not even temporarily")
  3392  				case *ir.Call:
  3393  					if !irutil.IsCallTo(ins.Common(), "append") {
  3394  						continue
  3395  					}
  3396  					if ins.Common().Args[0] != fn.Params[1] {
  3397  						continue
  3398  					}
  3399  					report.Report(pass, ins, "io.Writer.Write must not modify the provided buffer, not even temporarily")
  3400  				}
  3401  			}
  3402  		}
  3403  	}
  3404  	return nil, nil
  3405  }
  3406  
  3407  func loopedRegexp(name string) CallCheck {
  3408  	return func(call *Call) {
  3409  		if extractConst(call.Args[0].Value.Value) == nil {
  3410  			return
  3411  		}
  3412  		if !isInLoop(call.Instr.Block()) {
  3413  			return
  3414  		}
  3415  		call.Invalid(fmt.Sprintf("calling %s in a loop has poor performance, consider using regexp.Compile", name))
  3416  	}
  3417  }
  3418  
  3419  func CheckEmptyBranch(pass *analysis.Pass) (interface{}, error) {
  3420  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  3421  		if fn.Source() == nil {
  3422  			continue
  3423  		}
  3424  		if irutil.IsExample(fn) {
  3425  			continue
  3426  		}
  3427  		cb := func(node ast.Node) bool {
  3428  			ifstmt, ok := node.(*ast.IfStmt)
  3429  			if !ok {
  3430  				return true
  3431  			}
  3432  			if ifstmt.Else != nil {
  3433  				b, ok := ifstmt.Else.(*ast.BlockStmt)
  3434  				if !ok || len(b.List) != 0 {
  3435  					return true
  3436  				}
  3437  				report.Report(pass, ifstmt.Else, "empty branch", report.FilterGenerated(), report.ShortRange())
  3438  			}
  3439  			if len(ifstmt.Body.List) != 0 {
  3440  				return true
  3441  			}
  3442  			report.Report(pass, ifstmt, "empty branch", report.FilterGenerated(), report.ShortRange())
  3443  			return true
  3444  		}
  3445  		if source := fn.Source(); source != nil {
  3446  			ast.Inspect(source, cb)
  3447  		}
  3448  	}
  3449  	return nil, nil
  3450  }
  3451  
  3452  func CheckMapBytesKey(pass *analysis.Pass) (interface{}, error) {
  3453  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  3454  		for _, b := range fn.Blocks {
  3455  		insLoop:
  3456  			for _, ins := range b.Instrs {
  3457  				// find []byte -> string conversions
  3458  				conv, ok := ins.(*ir.Convert)
  3459  				if !ok || conv.Type() != types.Universe.Lookup("string").Type() {
  3460  					continue
  3461  				}
  3462  				tset := typeutil.NewTypeSet(conv.X.Type())
  3463  				// If at least one of the types is []byte, then it's more efficient to inline the conversion
  3464  				if !tset.Any(func(term *types.Term) bool {
  3465  					s, ok := term.Type().Underlying().(*types.Slice)
  3466  					return ok && s.Elem().Underlying() == types.Universe.Lookup("byte").Type()
  3467  				}) {
  3468  					continue
  3469  				}
  3470  				refs := conv.Referrers()
  3471  				// need at least two (DebugRef) references: the
  3472  				// conversion and the *ast.Ident
  3473  				if refs == nil || len(*refs) < 2 {
  3474  					continue
  3475  				}
  3476  				ident := false
  3477  				// skip first reference, that's the conversion itself
  3478  				for _, ref := range (*refs)[1:] {
  3479  					switch ref := ref.(type) {
  3480  					case *ir.DebugRef:
  3481  						if _, ok := ref.Expr.(*ast.Ident); !ok {
  3482  							// the string seems to be used somewhere
  3483  							// unexpected; the default branch should
  3484  							// catch this already, but be safe
  3485  							continue insLoop
  3486  						} else {
  3487  							ident = true
  3488  						}
  3489  					case *ir.MapLookup:
  3490  					default:
  3491  						// the string is used somewhere else than a
  3492  						// map lookup
  3493  						continue insLoop
  3494  					}
  3495  				}
  3496  
  3497  				// the result of the conversion wasn't assigned to an
  3498  				// identifier
  3499  				if !ident {
  3500  					continue
  3501  				}
  3502  				report.Report(pass, conv, "m[string(key)] would be more efficient than k := string(key); m[k]")
  3503  			}
  3504  		}
  3505  	}
  3506  	return nil, nil
  3507  }
  3508  
  3509  func CheckRangeStringRunes(pass *analysis.Pass) (interface{}, error) {
  3510  	return sharedcheck.CheckRangeStringRunes(pass)
  3511  }
  3512  
  3513  func CheckSelfAssignment(pass *analysis.Pass) (interface{}, error) {
  3514  	pure := pass.ResultOf[purity.Analyzer].(purity.Result)
  3515  
  3516  	fn := func(node ast.Node) {
  3517  		assign := node.(*ast.AssignStmt)
  3518  		if assign.Tok != token.ASSIGN || len(assign.Lhs) != len(assign.Rhs) {
  3519  			return
  3520  		}
  3521  		for i, lhs := range assign.Lhs {
  3522  			rhs := assign.Rhs[i]
  3523  			if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
  3524  				continue
  3525  			}
  3526  			if code.MayHaveSideEffects(pass, lhs, pure) || code.MayHaveSideEffects(pass, rhs, pure) {
  3527  				continue
  3528  			}
  3529  
  3530  			rlh := report.Render(pass, lhs)
  3531  			rrh := report.Render(pass, rhs)
  3532  			if rlh == rrh {
  3533  				report.Report(pass, assign, fmt.Sprintf("self-assignment of %s to %s", rrh, rlh), report.FilterGenerated())
  3534  			}
  3535  		}
  3536  	}
  3537  	code.Preorder(pass, fn, (*ast.AssignStmt)(nil))
  3538  	return nil, nil
  3539  }
  3540  
  3541  func buildTagsIdentical(s1, s2 []string) bool {
  3542  	if len(s1) != len(s2) {
  3543  		return false
  3544  	}
  3545  	s1s := make([]string, len(s1))
  3546  	copy(s1s, s1)
  3547  	sort.Strings(s1s)
  3548  	s2s := make([]string, len(s2))
  3549  	copy(s2s, s2)
  3550  	sort.Strings(s2s)
  3551  	for i, s := range s1s {
  3552  		if s != s2s[i] {
  3553  			return false
  3554  		}
  3555  	}
  3556  	return true
  3557  }
  3558  
  3559  func CheckDuplicateBuildConstraints(pass *analysis.Pass) (interface{}, error) {
  3560  	for _, f := range pass.Files {
  3561  		constraints := buildTags(f)
  3562  		for i, constraint1 := range constraints {
  3563  			for j, constraint2 := range constraints {
  3564  				if i >= j {
  3565  					continue
  3566  				}
  3567  				if buildTagsIdentical(constraint1, constraint2) {
  3568  					msg := fmt.Sprintf("identical build constraints %q and %q",
  3569  						strings.Join(constraint1, " "),
  3570  						strings.Join(constraint2, " "))
  3571  					report.Report(pass, f, msg, report.FilterGenerated(), report.ShortRange())
  3572  				}
  3573  			}
  3574  		}
  3575  	}
  3576  	return nil, nil
  3577  }
  3578  
  3579  func CheckSillyRegexp(pass *analysis.Pass) (interface{}, error) {
  3580  	// We could use the rule checking engine for this, but the
  3581  	// arguments aren't really invalid.
  3582  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  3583  		for _, b := range fn.Blocks {
  3584  			for _, ins := range b.Instrs {
  3585  				call, ok := ins.(*ir.Call)
  3586  				if !ok {
  3587  					continue
  3588  				}
  3589  				if !irutil.IsCallToAny(call.Common(), "regexp.MustCompile", "regexp.Compile", "regexp.Match", "regexp.MatchReader", "regexp.MatchString") {
  3590  					continue
  3591  				}
  3592  				c, ok := call.Common().Args[0].(*ir.Const)
  3593  				if !ok {
  3594  					continue
  3595  				}
  3596  				s := constant.StringVal(c.Value)
  3597  				re, err := syntax.Parse(s, 0)
  3598  				if err != nil {
  3599  					continue
  3600  				}
  3601  				if re.Op != syntax.OpLiteral && re.Op != syntax.OpEmptyMatch {
  3602  					continue
  3603  				}
  3604  				report.Report(pass, call, "regular expression does not contain any meta characters")
  3605  			}
  3606  		}
  3607  	}
  3608  	return nil, nil
  3609  }
  3610  
  3611  func CheckMissingEnumTypesInDeclaration(pass *analysis.Pass) (interface{}, error) {
  3612  	convertibleTo := func(V, T types.Type) bool {
  3613  		if types.ConvertibleTo(V, T) {
  3614  			return true
  3615  		}
  3616  		// Go <1.16 returns false for untyped string to string conversion
  3617  		if V, ok := V.(*types.Basic); ok && V.Kind() == types.UntypedString {
  3618  			if T, ok := T.Underlying().(*types.Basic); ok && T.Kind() == types.String {
  3619  				return true
  3620  			}
  3621  		}
  3622  		return false
  3623  	}
  3624  	fn := func(node ast.Node) {
  3625  		decl := node.(*ast.GenDecl)
  3626  		if !decl.Lparen.IsValid() {
  3627  			return
  3628  		}
  3629  		if decl.Tok != token.CONST {
  3630  			return
  3631  		}
  3632  
  3633  		groups := astutil.GroupSpecs(pass.Fset, decl.Specs)
  3634  	groupLoop:
  3635  		for _, group := range groups {
  3636  			if len(group) < 2 {
  3637  				continue
  3638  			}
  3639  			if group[0].(*ast.ValueSpec).Type == nil {
  3640  				// first constant doesn't have a type
  3641  				continue groupLoop
  3642  			}
  3643  
  3644  			firstType := pass.TypesInfo.TypeOf(group[0].(*ast.ValueSpec).Values[0])
  3645  			for i, spec := range group {
  3646  				spec := spec.(*ast.ValueSpec)
  3647  				if i > 0 && spec.Type != nil {
  3648  					continue groupLoop
  3649  				}
  3650  				if len(spec.Names) != 1 || len(spec.Values) != 1 {
  3651  					continue groupLoop
  3652  				}
  3653  
  3654  				if !convertibleTo(pass.TypesInfo.TypeOf(spec.Values[0]), firstType) {
  3655  					continue groupLoop
  3656  				}
  3657  
  3658  				switch v := spec.Values[0].(type) {
  3659  				case *ast.BasicLit:
  3660  				case *ast.UnaryExpr:
  3661  					if _, ok := v.X.(*ast.BasicLit); !ok {
  3662  						continue groupLoop
  3663  					}
  3664  				default:
  3665  					// if it's not a literal it might be typed, such as
  3666  					// time.Microsecond = 1000 * Nanosecond
  3667  					continue groupLoop
  3668  				}
  3669  			}
  3670  			var edits []analysis.TextEdit
  3671  			typ := group[0].(*ast.ValueSpec).Type
  3672  			for _, spec := range group[1:] {
  3673  				nspec := *spec.(*ast.ValueSpec)
  3674  				nspec.Type = typ
  3675  				// The position of `spec` node excludes comments (if any).
  3676  				// However, on generating the source back from the node, the comments are included. Setting `Comment` to nil ensures deduplication of comments.
  3677  				nspec.Comment = nil
  3678  				edits = append(edits, edit.ReplaceWithNode(pass.Fset, spec, &nspec))
  3679  			}
  3680  			report.Report(pass, group[0], "only the first constant in this group has an explicit type", report.Fixes(edit.Fix("add type to all constants in group", edits...)))
  3681  		}
  3682  	}
  3683  	code.Preorder(pass, fn, (*ast.GenDecl)(nil))
  3684  	return nil, nil
  3685  }
  3686  
  3687  func CheckTimerResetReturnValue(pass *analysis.Pass) (interface{}, error) {
  3688  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  3689  		for _, block := range fn.Blocks {
  3690  			for _, ins := range block.Instrs {
  3691  				call, ok := ins.(*ir.Call)
  3692  				if !ok {
  3693  					continue
  3694  				}
  3695  				if !irutil.IsCallTo(call.Common(), "(*time.Timer).Reset") {
  3696  					continue
  3697  				}
  3698  				refs := call.Referrers()
  3699  				if refs == nil {
  3700  					continue
  3701  				}
  3702  				for _, ref := range irutil.FilterDebug(*refs) {
  3703  					ifstmt, ok := ref.(*ir.If)
  3704  					if !ok {
  3705  						continue
  3706  					}
  3707  
  3708  					found := false
  3709  					for _, succ := range ifstmt.Block().Succs {
  3710  						if len(succ.Preds) != 1 {
  3711  							// Merge point, not a branch in the
  3712  							// syntactical sense.
  3713  
  3714  							// FIXME(dh): this is broken for if
  3715  							// statements a la "if x || y"
  3716  							continue
  3717  						}
  3718  						irutil.Walk(succ, func(b *ir.BasicBlock) bool {
  3719  							if !succ.Dominates(b) {
  3720  								// We've reached the end of the branch
  3721  								return false
  3722  							}
  3723  							for _, ins := range b.Instrs {
  3724  								// TODO(dh): we should check that
  3725  								// we're receiving from the channel of
  3726  								// a time.Timer to further reduce
  3727  								// false positives. Not a key
  3728  								// priority, considering the rarity of
  3729  								// Reset and the tiny likeliness of a
  3730  								// false positive
  3731  								if ins, ok := ins.(*ir.Recv); ok && typeutil.IsType(ins.Chan.Type(), "<-chan time.Time") {
  3732  									found = true
  3733  									return false
  3734  								}
  3735  							}
  3736  							return true
  3737  						})
  3738  					}
  3739  
  3740  					if found {
  3741  						report.Report(pass, 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")
  3742  					}
  3743  				}
  3744  			}
  3745  		}
  3746  	}
  3747  	return nil, nil
  3748  }
  3749  
  3750  var (
  3751  	checkToLowerToUpperComparisonQ = pattern.MustParse(`
  3752  	(BinaryExpr
  3753  		(CallExpr fun@(Symbol (Or "strings.ToLower" "strings.ToUpper")) [a])
  3754   		tok@(Or "==" "!=")
  3755   		(CallExpr fun [b]))`)
  3756  	checkToLowerToUpperComparisonR = pattern.MustParse(`(CallExpr (SelectorExpr (Ident "strings") (Ident "EqualFold")) [a b])`)
  3757  )
  3758  
  3759  func CheckToLowerToUpperComparison(pass *analysis.Pass) (interface{}, error) {
  3760  	fn := func(node ast.Node) {
  3761  		m, ok := code.Match(pass, checkToLowerToUpperComparisonQ, node)
  3762  		if !ok {
  3763  			return
  3764  		}
  3765  		rn := pattern.NodeToAST(checkToLowerToUpperComparisonR.Root, m.State).(ast.Expr)
  3766  		if m.State["tok"].(token.Token) == token.NEQ {
  3767  			rn = &ast.UnaryExpr{
  3768  				Op: token.NOT,
  3769  				X:  rn,
  3770  			}
  3771  		}
  3772  
  3773  		report.Report(pass, node, "should use strings.EqualFold instead", report.Fixes(edit.Fix("replace with strings.EqualFold", edit.ReplaceWithNode(pass.Fset, node, rn))))
  3774  	}
  3775  
  3776  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  3777  	return nil, nil
  3778  }
  3779  
  3780  func CheckUnreachableTypeCases(pass *analysis.Pass) (interface{}, error) {
  3781  	// Check if T subsumes V in a type switch. T subsumes V if T is an interface and T's method set is a subset of V's method set.
  3782  	subsumes := func(T, V types.Type) bool {
  3783  		if typeparams.IsTypeParam(T) {
  3784  			return false
  3785  		}
  3786  		tIface, ok := T.Underlying().(*types.Interface)
  3787  		if !ok {
  3788  			return false
  3789  		}
  3790  
  3791  		return types.Implements(V, tIface)
  3792  	}
  3793  
  3794  	subsumesAny := func(Ts, Vs []types.Type) (types.Type, types.Type, bool) {
  3795  		for _, T := range Ts {
  3796  			for _, V := range Vs {
  3797  				if subsumes(T, V) {
  3798  					return T, V, true
  3799  				}
  3800  			}
  3801  		}
  3802  
  3803  		return nil, nil, false
  3804  	}
  3805  
  3806  	fn := func(node ast.Node) {
  3807  		tsStmt := node.(*ast.TypeSwitchStmt)
  3808  
  3809  		type ccAndTypes struct {
  3810  			cc    *ast.CaseClause
  3811  			types []types.Type
  3812  		}
  3813  
  3814  		// All asserted types in the order of case clauses.
  3815  		ccs := make([]ccAndTypes, 0, len(tsStmt.Body.List))
  3816  		for _, stmt := range tsStmt.Body.List {
  3817  			cc, _ := stmt.(*ast.CaseClause)
  3818  
  3819  			// Exclude the 'default' case.
  3820  			if len(cc.List) == 0 {
  3821  				continue
  3822  			}
  3823  
  3824  			Ts := make([]types.Type, 0, len(cc.List))
  3825  			for _, expr := range cc.List {
  3826  				// Exclude the 'nil' value from any 'case' statement (it is always reachable).
  3827  				if typ := pass.TypesInfo.TypeOf(expr); typ != types.Typ[types.UntypedNil] {
  3828  					Ts = append(Ts, typ)
  3829  				}
  3830  			}
  3831  
  3832  			ccs = append(ccs, ccAndTypes{cc: cc, types: Ts})
  3833  		}
  3834  
  3835  		if len(ccs) <= 1 {
  3836  			// Zero or one case clauses, nothing to check.
  3837  			return
  3838  		}
  3839  
  3840  		// Check if case clauses following cc have types that are subsumed by cc.
  3841  		for i, cc := range ccs[:len(ccs)-1] {
  3842  			for _, next := range ccs[i+1:] {
  3843  				if T, V, yes := subsumesAny(cc.types, next.types); yes {
  3844  					report.Report(pass, next.cc, fmt.Sprintf("unreachable case clause: %s will always match before %s", T.String(), V.String()),
  3845  						report.ShortRange())
  3846  				}
  3847  			}
  3848  		}
  3849  	}
  3850  
  3851  	code.Preorder(pass, fn, (*ast.TypeSwitchStmt)(nil))
  3852  	return nil, nil
  3853  }
  3854  
  3855  var checkSingleArgAppendQ = pattern.MustParse(`(CallExpr (Builtin "append") [_])`)
  3856  
  3857  func CheckSingleArgAppend(pass *analysis.Pass) (interface{}, error) {
  3858  	fn := func(node ast.Node) {
  3859  		_, ok := code.Match(pass, checkSingleArgAppendQ, node)
  3860  		if !ok {
  3861  			return
  3862  		}
  3863  		report.Report(pass, node, "x = append(y) is equivalent to x = y", report.FilterGenerated())
  3864  	}
  3865  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  3866  	return nil, nil
  3867  }
  3868  
  3869  func CheckStructTags(pass *analysis.Pass) (interface{}, error) {
  3870  	importsGoFlags := false
  3871  
  3872  	// we use the AST instead of (*types.Package).Imports to work
  3873  	// around vendored packages in GOPATH mode. A vendored package's
  3874  	// path will include the vendoring subtree as a prefix.
  3875  	for _, f := range pass.Files {
  3876  		for _, imp := range f.Imports {
  3877  			v := imp.Path.Value
  3878  			if v[1:len(v)-1] == "github.com/jessevdk/go-flags" {
  3879  				importsGoFlags = true
  3880  				break
  3881  			}
  3882  		}
  3883  	}
  3884  
  3885  	fn := func(node ast.Node) {
  3886  		structNode := node.(*ast.StructType)
  3887  		T := pass.TypesInfo.Types[structNode].Type.(*types.Struct)
  3888  		rt := fakereflect.TypeAndCanAddr{
  3889  			Type: T,
  3890  		}
  3891  		for i, field := range structNode.Fields.List {
  3892  			if field.Tag == nil {
  3893  				continue
  3894  			}
  3895  			tags, err := parseStructTag(field.Tag.Value[1 : len(field.Tag.Value)-1])
  3896  			if err != nil {
  3897  				report.Report(pass, field.Tag, fmt.Sprintf("unparseable struct tag: %s", err))
  3898  				continue
  3899  			}
  3900  			for k, v := range tags {
  3901  				if len(v) > 1 {
  3902  					isGoFlagsTag := importsGoFlags &&
  3903  						(k == "choice" || k == "optional-value" || k == "default")
  3904  					if !isGoFlagsTag {
  3905  						report.Report(pass, field.Tag, fmt.Sprintf("duplicate struct tag %q", k))
  3906  					}
  3907  				}
  3908  
  3909  				switch k {
  3910  				case "json":
  3911  					checkJSONTag(pass, field, v[0])
  3912  				case "xml":
  3913  					if _, err := fakexml.StructFieldInfo(rt.Field(i)); err != nil {
  3914  						report.Report(pass, field.Tag, fmt.Sprintf("invalid XML tag: %s", err))
  3915  					}
  3916  					checkXMLTag(pass, field, v[0])
  3917  				}
  3918  			}
  3919  		}
  3920  	}
  3921  	code.Preorder(pass, fn, (*ast.StructType)(nil))
  3922  	return nil, nil
  3923  }
  3924  
  3925  func checkJSONTag(pass *analysis.Pass, field *ast.Field, tag string) {
  3926  	if pass.Pkg.Path() == "encoding/json" || pass.Pkg.Path() == "encoding/json_test" {
  3927  		// don't flag malformed JSON tags in the encoding/json
  3928  		// package; it knows what it is doing, and it is testing
  3929  		// itself.
  3930  		return
  3931  	}
  3932  	//lint:ignore SA9003 TODO(dh): should we flag empty tags?
  3933  	if len(tag) == 0 {
  3934  	}
  3935  	if i := strings.Index(tag, ",format:"); i >= 0 {
  3936  		tag = tag[:i]
  3937  	}
  3938  	fields := strings.Split(tag, ",")
  3939  	for _, r := range fields[0] {
  3940  		if !unicode.IsLetter(r) && !unicode.IsDigit(r) && !strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", r) {
  3941  			report.Report(pass, field.Tag, fmt.Sprintf("invalid JSON field name %q", fields[0]))
  3942  		}
  3943  	}
  3944  	options := make(map[string]int)
  3945  	for _, s := range fields[1:] {
  3946  		switch s {
  3947  		case "":
  3948  			// allow stuff like "-,"
  3949  		case "string":
  3950  			// only for string, floating point, integer and bool
  3951  			options[s]++
  3952  			tset := typeutil.NewTypeSet(pass.TypesInfo.TypeOf(field.Type))
  3953  			if len(tset.Terms) == 0 {
  3954  				// TODO(dh): improve message, call out the use of type parameters
  3955  				report.Report(pass, field.Tag, "the JSON string option only applies to fields of type string, floating point, integer or bool, or pointers to those")
  3956  				continue
  3957  			}
  3958  			for _, term := range tset.Terms {
  3959  				T := typeutil.Dereference(term.Type().Underlying())
  3960  				for _, term2 := range typeutil.NewTypeSet(T).Terms {
  3961  					basic, ok := term2.Type().Underlying().(*types.Basic)
  3962  					if !ok || (basic.Info()&(types.IsBoolean|types.IsInteger|types.IsFloat|types.IsString)) == 0 {
  3963  						// TODO(dh): improve message, show how we arrived at the type
  3964  						report.Report(pass, field.Tag, "the JSON string option only applies to fields of type string, floating point, integer or bool, or pointers to those")
  3965  					}
  3966  				}
  3967  			}
  3968  		case "omitzero", "omitempty", "nocase", "inline", "unknown":
  3969  			options[s]++
  3970  		default:
  3971  			report.Report(pass, field.Tag, fmt.Sprintf("unknown JSON option %q", s))
  3972  		}
  3973  	}
  3974  	var duplicates []string
  3975  	for option, n := range options {
  3976  		if n > 1 {
  3977  			duplicates = append(duplicates, option)
  3978  		}
  3979  	}
  3980  	if len(duplicates) > 0 {
  3981  		sort.Strings(duplicates)
  3982  		for _, option := range duplicates {
  3983  			report.Report(pass, field.Tag, fmt.Sprintf("duplicate JSON option %q", option))
  3984  		}
  3985  	}
  3986  }
  3987  
  3988  func checkXMLTag(pass *analysis.Pass, field *ast.Field, tag string) {
  3989  	//lint:ignore SA9003 TODO(dh): should we flag empty tags?
  3990  	if len(tag) == 0 {
  3991  	}
  3992  	fields := strings.Split(tag, ",")
  3993  	counts := map[string]int{}
  3994  	for _, s := range fields[1:] {
  3995  		switch s {
  3996  		case "attr", "chardata", "cdata", "innerxml", "comment":
  3997  			counts[s]++
  3998  		case "omitempty", "any":
  3999  			counts[s]++
  4000  		case "":
  4001  		default:
  4002  			report.Report(pass, field.Tag, fmt.Sprintf("invalid XML tag: unknown option %q", s))
  4003  		}
  4004  	}
  4005  	for k, v := range counts {
  4006  		if v > 1 {
  4007  			report.Report(pass, field.Tag, fmt.Sprintf("invalid XML tag: duplicate option %q", k))
  4008  		}
  4009  	}
  4010  }
  4011  
  4012  func CheckImpossibleTypeAssertion(pass *analysis.Pass) (interface{}, error) {
  4013  	type entry struct {
  4014  		l, r *types.Func
  4015  	}
  4016  
  4017  	msc := &pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg.Prog.MethodSets
  4018  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  4019  		for _, b := range fn.Blocks {
  4020  			for _, instr := range b.Instrs {
  4021  				assert, ok := instr.(*ir.TypeAssert)
  4022  				if !ok {
  4023  					continue
  4024  				}
  4025  				var wrong []entry
  4026  				left := assert.X.Type()
  4027  				right := assert.AssertedType
  4028  				righti, ok := right.Underlying().(*types.Interface)
  4029  
  4030  				if !ok {
  4031  					// We only care about interface->interface
  4032  					// assertions. The Go compiler already catches
  4033  					// impossible interface->concrete assertions.
  4034  					continue
  4035  				}
  4036  
  4037  				ms := msc.MethodSet(left)
  4038  				for i := 0; i < righti.NumMethods(); i++ {
  4039  					mr := righti.Method(i).Origin()
  4040  					sel := ms.Lookup(mr.Pkg(), mr.Name())
  4041  					if sel == nil {
  4042  						continue
  4043  					}
  4044  					ml := sel.Obj().(*types.Func).Origin()
  4045  					if types.AssignableTo(ml.Type(), mr.Type()) {
  4046  						continue
  4047  					}
  4048  
  4049  					wrong = append(wrong, entry{ml, mr})
  4050  				}
  4051  
  4052  				if len(wrong) != 0 {
  4053  					s := fmt.Sprintf("impossible type assertion; %s and %s contradict each other:",
  4054  						types.TypeString(left, types.RelativeTo(pass.Pkg)),
  4055  						types.TypeString(right, types.RelativeTo(pass.Pkg)))
  4056  					for _, e := range wrong {
  4057  						s += fmt.Sprintf("\n\twrong type for %s method", e.l.Name())
  4058  						s += fmt.Sprintf("\n\t\thave %s", e.l.Type())
  4059  						s += fmt.Sprintf("\n\t\twant %s", e.r.Type())
  4060  					}
  4061  					report.Report(pass, assert, s)
  4062  				}
  4063  			}
  4064  		}
  4065  	}
  4066  	return nil, nil
  4067  }
  4068  
  4069  func checkWithValueKey(call *Call) {
  4070  	arg := call.Args[1]
  4071  	T := arg.Value.Value.Type()
  4072  	if T, ok := T.(*types.Basic); ok {
  4073  		arg.Invalid(
  4074  			fmt.Sprintf("should not use built-in type %s as key for value; define your own type to avoid collisions", T))
  4075  	}
  4076  	if !types.Comparable(T) {
  4077  		arg.Invalid(fmt.Sprintf("keys used with context.WithValue must be comparable, but type %s is not comparable", T))
  4078  	}
  4079  }
  4080  
  4081  func CheckMaybeNil(pass *analysis.Pass) (interface{}, error) {
  4082  	// This is an extremely trivial check that doesn't try to reason
  4083  	// about control flow. That is, phis and sigmas do not propagate
  4084  	// any information. As such, we can flag this:
  4085  	//
  4086  	// 	_ = *x
  4087  	// 	if x == nil { return }
  4088  	//
  4089  	// but we cannot flag this:
  4090  	//
  4091  	// 	if x == nil { println(x) }
  4092  	// 	_ = *x
  4093  	//
  4094  	// but we can flag this, because the if's body doesn't use x:
  4095  	//
  4096  	// 	if x == nil { println("this is bad") }
  4097  	//  _ = *x
  4098  	//
  4099  	// nor many other variations of conditional uses of or assignments to x.
  4100  	//
  4101  	// However, even this trivial implementation finds plenty of
  4102  	// real-world bugs, such as dereference before nil pointer check,
  4103  	// or using t.Error instead of t.Fatal when encountering nil
  4104  	// pointers.
  4105  	//
  4106  	// On the flip side, our naive implementation avoids false positives in branches, such as
  4107  	//
  4108  	// 	if x != nil { _ = *x }
  4109  	//
  4110  	// due to the same lack of propagating information through sigma
  4111  	// nodes. x inside the branch will be independent of the x in the
  4112  	// nil pointer check.
  4113  	//
  4114  	//
  4115  	// We could implement a more powerful check, but then we'd be
  4116  	// getting false positives instead of false negatives because
  4117  	// we're incapable of deducing relationships between variables.
  4118  	// For example, a function might return a pointer and an error,
  4119  	// and the error being nil guarantees that the pointer is not nil.
  4120  	// Depending on the surrounding code, the pointer may still end up
  4121  	// being checked against nil in one place, and guarded by a check
  4122  	// on the error in another, which would lead to us marking some
  4123  	// loads as unsafe.
  4124  	//
  4125  	// Unfortunately, simply hard-coding the relationship between
  4126  	// return values wouldn't eliminate all false positives, either.
  4127  	// Many other more subtle relationships exist. An abridged example
  4128  	// from real code:
  4129  	//
  4130  	// if a == nil && b == nil { return }
  4131  	// c := fn(a)
  4132  	// if c != "" { _ = *a }
  4133  	//
  4134  	// where `fn` is guaranteed to return a non-empty string if a
  4135  	// isn't nil.
  4136  	//
  4137  	// We choose to err on the side of false negatives.
  4138  
  4139  	isNilConst := func(v ir.Value) bool {
  4140  		if typeutil.IsPointerLike(v.Type()) {
  4141  			if k, ok := v.(*ir.Const); ok {
  4142  				return k.IsNil()
  4143  			}
  4144  		}
  4145  		return false
  4146  	}
  4147  
  4148  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  4149  		maybeNil := map[ir.Value]ir.Instruction{}
  4150  		for _, b := range fn.Blocks {
  4151  			for _, instr := range b.Instrs {
  4152  				// Originally we looked at all ir.BinOp, but that would lead to calls like 'assert(x != nil)' causing false positives.
  4153  				// Restrict ourselves to actual if statements, as these are more likely to affect control flow in a way we can observe.
  4154  				if instr, ok := instr.(*ir.If); ok {
  4155  					if cond, ok := instr.Cond.(*ir.BinOp); ok {
  4156  						var ptr ir.Value
  4157  						if isNilConst(cond.X) {
  4158  							ptr = cond.Y
  4159  						} else if isNilConst(cond.Y) {
  4160  							ptr = cond.X
  4161  						}
  4162  						maybeNil[ptr] = cond
  4163  					}
  4164  				}
  4165  			}
  4166  		}
  4167  
  4168  		for _, b := range fn.Blocks {
  4169  			for _, instr := range b.Instrs {
  4170  				var ptr ir.Value
  4171  				switch instr := instr.(type) {
  4172  				case *ir.Load:
  4173  					ptr = instr.X
  4174  				case *ir.Store:
  4175  					ptr = instr.Addr
  4176  				case *ir.IndexAddr:
  4177  					ptr = instr.X
  4178  					if typeutil.All(ptr.Type(), func(term *types.Term) bool {
  4179  						if _, ok := term.Type().Underlying().(*types.Slice); ok {
  4180  							return true
  4181  						}
  4182  						return false
  4183  					}) {
  4184  						// indexing a nil slice does not cause a nil pointer panic
  4185  						//
  4186  						// Note: This also works around the bad lowering of range loops over slices
  4187  						// (https://github.com/dominikh/go-tools/issues/1053)
  4188  						continue
  4189  					}
  4190  				case *ir.FieldAddr:
  4191  					ptr = instr.X
  4192  				}
  4193  				if ptr != nil {
  4194  					switch ptr.(type) {
  4195  					case *ir.Alloc, *ir.FieldAddr, *ir.IndexAddr:
  4196  						// these cannot be nil
  4197  						continue
  4198  					}
  4199  					if r, ok := maybeNil[ptr]; ok {
  4200  						report.Report(pass, instr, "possible nil pointer dereference",
  4201  							report.Related(r, "this check suggests that the pointer can be nil"))
  4202  					}
  4203  				}
  4204  			}
  4205  		}
  4206  	}
  4207  
  4208  	return nil, nil
  4209  }
  4210  
  4211  var checkAddressIsNilQ = pattern.MustParse(
  4212  	`(BinaryExpr
  4213  		(UnaryExpr "&" _)
  4214  		(Or "==" "!=")
  4215  		(Builtin "nil"))`)
  4216  
  4217  func CheckAddressIsNil(pass *analysis.Pass) (interface{}, error) {
  4218  	fn := func(node ast.Node) {
  4219  		_, ok := code.Match(pass, checkAddressIsNilQ, node)
  4220  		if !ok {
  4221  			return
  4222  		}
  4223  		report.Report(pass, node, "the address of a variable cannot be nil")
  4224  	}
  4225  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  4226  	return nil, nil
  4227  }
  4228  
  4229  var (
  4230  	checkFixedLengthTypeShiftQ = pattern.MustParse(`
  4231  		(Or
  4232  			(AssignStmt _ (Or ">>=" "<<=") _)
  4233  			(BinaryExpr _ (Or ">>" "<<") _))
  4234  	`)
  4235  )
  4236  
  4237  func CheckStaticBitShift(pass *analysis.Pass) (interface{}, error) {
  4238  	isDubiousShift := func(x, y ast.Expr) (int64, int64, bool) {
  4239  		typ, ok := pass.TypesInfo.TypeOf(x).Underlying().(*types.Basic)
  4240  		if !ok {
  4241  			return 0, 0, false
  4242  		}
  4243  		switch typ.Kind() {
  4244  		case types.Int8, types.Int16, types.Int32, types.Int64,
  4245  			types.Uint8, types.Uint16, types.Uint32, types.Uint64:
  4246  			// We're only interested in fixed–size types.
  4247  		default:
  4248  			return 0, 0, false
  4249  		}
  4250  
  4251  		const bitsInByte = 8
  4252  		typeBits := pass.TypesSizes.Sizeof(typ) * bitsInByte
  4253  
  4254  		shiftLength, ok := code.ExprToInt(pass, y)
  4255  		if !ok {
  4256  			return 0, 0, false
  4257  		}
  4258  
  4259  		return typeBits, shiftLength, shiftLength >= typeBits
  4260  	}
  4261  
  4262  	fn := func(node ast.Node) {
  4263  		if _, ok := code.Match(pass, checkFixedLengthTypeShiftQ, node); !ok {
  4264  			return
  4265  		}
  4266  
  4267  		switch e := node.(type) {
  4268  		case *ast.AssignStmt:
  4269  			if size, shift, yes := isDubiousShift(e.Lhs[0], e.Rhs[0]); yes {
  4270  				report.Report(pass, e, fmt.Sprintf("shifting %d-bit value by %d bits will always clear it", size, shift))
  4271  			}
  4272  		case *ast.BinaryExpr:
  4273  			if size, shift, yes := isDubiousShift(e.X, e.Y); yes {
  4274  				report.Report(pass, e, fmt.Sprintf("shifting %d-bit value by %d bits will always clear it", size, shift))
  4275  			}
  4276  		}
  4277  	}
  4278  	code.Preorder(pass, fn, (*ast.AssignStmt)(nil), (*ast.BinaryExpr)(nil))
  4279  
  4280  	return nil, nil
  4281  }
  4282  
  4283  func findSliceLenChecks(pass *analysis.Pass) {
  4284  	// mark all function parameters that have to be of even length
  4285  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  4286  		for _, b := range fn.Blocks {
  4287  			// all paths go through this block
  4288  			if !b.Dominates(fn.Exit) {
  4289  				continue
  4290  			}
  4291  
  4292  			// if foo % 2 != 0
  4293  			ifi, ok := b.Control().(*ir.If)
  4294  			if !ok {
  4295  				continue
  4296  			}
  4297  			cmp, ok := ifi.Cond.(*ir.BinOp)
  4298  			if !ok {
  4299  				continue
  4300  			}
  4301  			var needle uint64
  4302  			switch cmp.Op {
  4303  			case token.NEQ:
  4304  				// look for != 0
  4305  				needle = 0
  4306  			case token.EQL:
  4307  				// look for == 1
  4308  				needle = 1
  4309  			default:
  4310  				continue
  4311  			}
  4312  
  4313  			rem, ok1 := cmp.X.(*ir.BinOp)
  4314  			k, ok2 := cmp.Y.(*ir.Const)
  4315  			if ok1 != ok2 {
  4316  				continue
  4317  			}
  4318  			if !ok1 {
  4319  				rem, ok1 = cmp.Y.(*ir.BinOp)
  4320  				k, ok2 = cmp.X.(*ir.Const)
  4321  			}
  4322  			if !ok1 || !ok2 || rem.Op != token.REM || k.Value.Kind() != constant.Int || k.Uint64() != needle {
  4323  				continue
  4324  			}
  4325  			k, ok = rem.Y.(*ir.Const)
  4326  			if !ok || k.Value.Kind() != constant.Int || k.Uint64() != 2 {
  4327  				continue
  4328  			}
  4329  
  4330  			// if len(foo) % 2 != 0
  4331  			call, ok := rem.X.(*ir.Call)
  4332  			if !ok || !irutil.IsCallTo(call.Common(), "len") {
  4333  				continue
  4334  			}
  4335  
  4336  			// we're checking the length of a parameter that is a slice
  4337  			// TODO(dh): support parameters that have flown through sigmas and phis
  4338  			param, ok := call.Call.Args[0].(*ir.Parameter)
  4339  			if !ok {
  4340  				continue
  4341  			}
  4342  			if !typeutil.All(param.Type(), typeutil.IsSlice) {
  4343  				continue
  4344  			}
  4345  
  4346  			// if len(foo) % 2 != 0 then panic
  4347  			if _, ok := b.Succs[0].Control().(*ir.Panic); !ok {
  4348  				continue
  4349  			}
  4350  
  4351  			pass.ExportObjectFact(param.Object(), new(evenElements))
  4352  		}
  4353  	}
  4354  }
  4355  
  4356  func findIndirectSliceLenChecks(pass *analysis.Pass) {
  4357  	seen := map[*ir.Function]struct{}{}
  4358  
  4359  	var doFunction func(fn *ir.Function)
  4360  	doFunction = func(fn *ir.Function) {
  4361  		if _, ok := seen[fn]; ok {
  4362  			return
  4363  		}
  4364  		seen[fn] = struct{}{}
  4365  
  4366  		for _, b := range fn.Blocks {
  4367  			// all paths go through this block
  4368  			if !b.Dominates(fn.Exit) {
  4369  				continue
  4370  			}
  4371  
  4372  			for _, instr := range b.Instrs {
  4373  				call, ok := instr.(*ir.Call)
  4374  				if !ok {
  4375  					continue
  4376  				}
  4377  				callee := call.Call.StaticCallee()
  4378  				if callee == nil {
  4379  					continue
  4380  				}
  4381  
  4382  				if callee.Pkg == fn.Pkg || callee.Pkg == nil {
  4383  					doFunction(callee)
  4384  				}
  4385  
  4386  				for argi, arg := range call.Call.Args {
  4387  					if callee.Signature.Recv() != nil {
  4388  						if argi == 0 {
  4389  							continue
  4390  						}
  4391  						argi--
  4392  					}
  4393  
  4394  					// TODO(dh): support parameters that have flown through length-preserving instructions
  4395  					param, ok := arg.(*ir.Parameter)
  4396  					if !ok {
  4397  						continue
  4398  					}
  4399  					if !typeutil.All(param.Type(), typeutil.IsSlice) {
  4400  						continue
  4401  					}
  4402  
  4403  					// We can't use callee.Params to look up the
  4404  					// parameter, because Params is not populated for
  4405  					// external functions. In our modular analysis.
  4406  					// any function in any package that isn't the
  4407  					// current package is considered "external", as it
  4408  					// has been loaded from export data only.
  4409  					sigParams := callee.Signature.Params()
  4410  
  4411  					if !pass.ImportObjectFact(sigParams.At(argi), new(evenElements)) {
  4412  						continue
  4413  					}
  4414  					pass.ExportObjectFact(param.Object(), new(evenElements))
  4415  				}
  4416  			}
  4417  		}
  4418  	}
  4419  
  4420  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  4421  		doFunction(fn)
  4422  	}
  4423  }
  4424  
  4425  func findSliceLength(v ir.Value) int {
  4426  	// TODO(dh): VRP would help here
  4427  
  4428  	v = irutil.Flatten(v)
  4429  	val := func(v ir.Value) int {
  4430  		if v, ok := v.(*ir.Const); ok {
  4431  			return int(v.Int64())
  4432  		}
  4433  		return -1
  4434  	}
  4435  	switch v := v.(type) {
  4436  	case *ir.Slice:
  4437  		low := 0
  4438  		high := -1
  4439  		if v.Low != nil {
  4440  			low = val(v.Low)
  4441  		}
  4442  		if v.High != nil {
  4443  			high = val(v.High)
  4444  		} else {
  4445  			switch vv := v.X.(type) {
  4446  			case *ir.Alloc:
  4447  				high = int(typeutil.Dereference(vv.Type()).Underlying().(*types.Array).Len())
  4448  			case *ir.Slice:
  4449  				high = findSliceLength(vv)
  4450  			}
  4451  		}
  4452  		if low == -1 || high == -1 {
  4453  			return -1
  4454  		}
  4455  		return high - low
  4456  	default:
  4457  		return -1
  4458  	}
  4459  }
  4460  
  4461  type evenElements struct{}
  4462  
  4463  func (evenElements) AFact() {}
  4464  
  4465  func (evenElements) String() string { return "needs even elements" }
  4466  
  4467  func flagSliceLens(pass *analysis.Pass) {
  4468  	var tag evenElements
  4469  
  4470  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  4471  		for _, b := range fn.Blocks {
  4472  			for _, instr := range b.Instrs {
  4473  				call, ok := instr.(ir.CallInstruction)
  4474  				if !ok {
  4475  					continue
  4476  				}
  4477  				callee := call.Common().StaticCallee()
  4478  				if callee == nil {
  4479  					continue
  4480  				}
  4481  				for argi, arg := range call.Common().Args {
  4482  					if callee.Signature.Recv() != nil {
  4483  						if argi == 0 {
  4484  							continue
  4485  						}
  4486  						argi--
  4487  					}
  4488  
  4489  					_, ok := arg.Type().Underlying().(*types.Slice)
  4490  					if !ok {
  4491  						continue
  4492  					}
  4493  					param := callee.Signature.Params().At(argi)
  4494  					if !pass.ImportObjectFact(param, &tag) {
  4495  						continue
  4496  					}
  4497  
  4498  					// TODO handle stubs
  4499  
  4500  					// we know the argument has to have even length.
  4501  					// now let's try to find its length
  4502  					if n := findSliceLength(arg); n > -1 && n%2 != 0 {
  4503  						src := call.Source().(*ast.CallExpr).Args[argi]
  4504  						sig := call.Common().Signature()
  4505  						var label string
  4506  						if argi == sig.Params().Len()-1 && sig.Variadic() {
  4507  							label = "variadic argument"
  4508  						} else {
  4509  							label = "argument"
  4510  						}
  4511  						// Note that param.Name() is guaranteed to not
  4512  						// be empty, otherwise the function couldn't
  4513  						// have enforced its length.
  4514  						report.Report(pass, src, fmt.Sprintf("%s %q is expected to have even number of elements, but has %d elements", label, param.Name(), n))
  4515  					}
  4516  				}
  4517  			}
  4518  		}
  4519  	}
  4520  }
  4521  
  4522  func CheckEvenSliceLength(pass *analysis.Pass) (interface{}, error) {
  4523  	findSliceLenChecks(pass)
  4524  	findIndirectSliceLenChecks(pass)
  4525  	flagSliceLens(pass)
  4526  
  4527  	return nil, nil
  4528  }
  4529  
  4530  func CheckTypedNilInterface(pass *analysis.Pass) (interface{}, error) {
  4531  	// The comparison 'fn() == nil' can never be true if fn() returns
  4532  	// an interface value and only returns typed nils. This is usually
  4533  	// a mistake in the function itself, but all we can say for
  4534  	// certain is that the comparison is pointless.
  4535  	//
  4536  	// Flag results if no untyped nils are being returned, but either
  4537  	// known typed nils, or typed unknown nilness are being returned.
  4538  
  4539  	irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR)
  4540  	typedness := pass.ResultOf[typedness.Analysis].(*typedness.Result)
  4541  	nilness := pass.ResultOf[nilness.Analysis].(*nilness.Result)
  4542  	for _, fn := range irpkg.SrcFuncs {
  4543  		for _, b := range fn.Blocks {
  4544  			for _, instr := range b.Instrs {
  4545  				binop, ok := instr.(*ir.BinOp)
  4546  				if !ok || !(binop.Op == token.EQL || binop.Op == token.NEQ) {
  4547  					continue
  4548  				}
  4549  				if _, ok := binop.X.Type().Underlying().(*types.Interface); !ok || typeparams.IsTypeParam(binop.X.Type()) {
  4550  					// TODO support swapped X and Y
  4551  					continue
  4552  				}
  4553  
  4554  				k, ok := binop.Y.(*ir.Const)
  4555  				if !ok || !k.IsNil() {
  4556  					// if binop.X is an interface, then binop.Y can
  4557  					// only be a Const if its untyped. A typed nil
  4558  					// constant would first be passed to
  4559  					// MakeInterface.
  4560  					continue
  4561  				}
  4562  
  4563  				var idx int
  4564  				var obj *types.Func
  4565  				switch x := irutil.Flatten(binop.X).(type) {
  4566  				case *ir.Call:
  4567  					callee := x.Call.StaticCallee()
  4568  					if callee == nil {
  4569  						continue
  4570  					}
  4571  					obj, _ = callee.Object().(*types.Func)
  4572  					idx = 0
  4573  				case *ir.Extract:
  4574  					call, ok := irutil.Flatten(x.Tuple).(*ir.Call)
  4575  					if !ok {
  4576  						continue
  4577  					}
  4578  					callee := call.Call.StaticCallee()
  4579  					if callee == nil {
  4580  						continue
  4581  					}
  4582  					obj, _ = callee.Object().(*types.Func)
  4583  					idx = x.Index
  4584  				case *ir.MakeInterface:
  4585  					var qualifier string
  4586  					switch binop.Op {
  4587  					case token.EQL:
  4588  						qualifier = "never"
  4589  					case token.NEQ:
  4590  						qualifier = "always"
  4591  					default:
  4592  						panic("unreachable")
  4593  					}
  4594  
  4595  					terms, err := typeparams.NormalTerms(x.X.Type())
  4596  					if len(terms) == 0 || err != nil {
  4597  						// Type is a type parameter with no type terms (or we couldn't determine the terms). Such a type
  4598  						// _can_ be nil when put in an interface value.
  4599  						continue
  4600  					}
  4601  
  4602  					if report.HasRange(x.X) {
  4603  						report.Report(pass, binop, fmt.Sprintf("this comparison is %s true", qualifier),
  4604  							report.Related(x.X, "the lhs of the comparison gets its value from here and has a concrete type"))
  4605  					} else {
  4606  						// we can't generate related information for this, so make the diagnostic itself slightly more useful
  4607  						report.Report(pass, binop, fmt.Sprintf("this comparison is %s true; the lhs of the comparison has been assigned a concretely typed value", qualifier))
  4608  					}
  4609  					continue
  4610  				}
  4611  				if obj == nil {
  4612  					continue
  4613  				}
  4614  
  4615  				isNil, onlyGlobal := nilness.MayReturnNil(obj, idx)
  4616  				if typedness.MustReturnTyped(obj, idx) && isNil && !onlyGlobal && !code.IsInTest(pass, binop) {
  4617  					// Don't flag these comparisons in tests. Tests
  4618  					// may be explicitly enforcing the invariant that
  4619  					// a value isn't nil.
  4620  
  4621  					var qualifier string
  4622  					switch binop.Op {
  4623  					case token.EQL:
  4624  						qualifier = "never"
  4625  					case token.NEQ:
  4626  						qualifier = "always"
  4627  					default:
  4628  						panic("unreachable")
  4629  					}
  4630  					report.Report(pass, binop, fmt.Sprintf("this comparison is %s true", qualifier),
  4631  						// TODO support swapped X and Y
  4632  						report.Related(binop.X, fmt.Sprintf("the lhs of the comparison is the %s return value of this function call", report.Ordinal(idx+1))),
  4633  						report.Related(obj, fmt.Sprintf("%s never returns a nil interface value", typeutil.FuncName(obj))))
  4634  				}
  4635  			}
  4636  		}
  4637  	}
  4638  
  4639  	return nil, nil
  4640  }
  4641  
  4642  var builtinLessThanZeroQ = pattern.MustParse(`
  4643  	(Or
  4644  		(BinaryExpr
  4645  			(IntegerLiteral "0")
  4646  			">"
  4647  			(CallExpr builtin@(Builtin (Or "len" "cap")) _))
  4648  		(BinaryExpr
  4649  			(CallExpr builtin@(Builtin (Or "len" "cap")) _)
  4650  			"<"
  4651  			(IntegerLiteral "0")))
  4652  `)
  4653  
  4654  func CheckBuiltinZeroComparison(pass *analysis.Pass) (interface{}, error) {
  4655  	fn := func(node ast.Node) {
  4656  		matcher, ok := code.Match(pass, builtinLessThanZeroQ, node)
  4657  		if !ok {
  4658  			return
  4659  		}
  4660  
  4661  		builtin := matcher.State["builtin"].(*ast.Ident)
  4662  		report.Report(pass, node, fmt.Sprintf("builtin function %s does not return negative values", builtin.Name))
  4663  	}
  4664  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  4665  
  4666  	return nil, nil
  4667  }
  4668  
  4669  var integerDivisionQ = pattern.MustParse(`(BinaryExpr (IntegerLiteral _) "/" (IntegerLiteral _))`)
  4670  
  4671  func CheckIntegerDivisionEqualsZero(pass *analysis.Pass) (interface{}, error) {
  4672  	fn := func(node ast.Node) {
  4673  		_, ok := code.Match(pass, integerDivisionQ, node)
  4674  		if !ok {
  4675  			return
  4676  		}
  4677  
  4678  		val := constant.ToInt(pass.TypesInfo.Types[node.(ast.Expr)].Value)
  4679  		if v, ok := constant.Uint64Val(val); ok && v == 0 {
  4680  			report.Report(pass, node, fmt.Sprintf("the integer division '%s' results in zero", report.Render(pass, node)))
  4681  		}
  4682  
  4683  		// TODO: we could offer a suggested fix here, but I am not
  4684  		// sure what it should be. There are many options to choose
  4685  		// from.
  4686  
  4687  		// Note: we experimented with flagging divisions that truncate
  4688  		// (e.g. 4 / 3), but it ran into false positives in Go's
  4689  		// 'time' package, which does this, deliberately:
  4690  		//
  4691  		//   unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
  4692  		//
  4693  		// The check also found a real bug in other code, but I don't
  4694  		// think we can outright ban this kind of division.
  4695  	}
  4696  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  4697  
  4698  	return nil, nil
  4699  }
  4700  
  4701  func CheckIneffectiveFieldAssignments(pass *analysis.Pass) (interface{}, error) {
  4702  	// The analysis only considers the receiver and its first level
  4703  	// fields. It doesn't look at other parameters, nor at nested
  4704  	// fields.
  4705  	//
  4706  	// The analysis does not detect all kinds of dead stores, only
  4707  	// those of fields that are never read after the write. That is,
  4708  	// we do not flag 'a.x = 1; a.x = 2; _ = a.x'. We might explore
  4709  	// this again if we add support for SROA to go/ir and implement
  4710  	// https://github.com/dominikh/go-tools/issues/191.
  4711  
  4712  	irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR)
  4713  fnLoop:
  4714  	for _, fn := range irpkg.SrcFuncs {
  4715  		if recv := fn.Signature.Recv(); recv == nil {
  4716  			continue
  4717  		} else if _, ok := recv.Type().Underlying().(*types.Struct); !ok {
  4718  			continue
  4719  		}
  4720  
  4721  		recv := fn.Params[0]
  4722  		refs := irutil.FilterDebug(*recv.Referrers())
  4723  		if len(refs) != 1 {
  4724  			continue
  4725  		}
  4726  		store, ok := refs[0].(*ir.Store)
  4727  		if !ok {
  4728  			continue
  4729  		}
  4730  		alloc, ok := store.Addr.(*ir.Alloc)
  4731  		if !ok || alloc.Heap {
  4732  			continue
  4733  		}
  4734  
  4735  		reads := map[int][]ir.Instruction{}
  4736  		writes := map[int][]ir.Instruction{}
  4737  		for _, ref := range *alloc.Referrers() {
  4738  			switch ref := ref.(type) {
  4739  			case *ir.FieldAddr:
  4740  				for _, refref := range *ref.Referrers() {
  4741  					switch refref.(type) {
  4742  					case *ir.Store:
  4743  						writes[ref.Field] = append(writes[ref.Field], refref)
  4744  					case *ir.Load:
  4745  						reads[ref.Field] = append(reads[ref.Field], refref)
  4746  					case *ir.DebugRef:
  4747  						continue
  4748  					default:
  4749  						// this should be safe… if the field address
  4750  						// escapes, then alloc.Heap will be true.
  4751  						// there should be no instructions left that,
  4752  						// given this FieldAddr, without escaping, can
  4753  						// effect a load or store.
  4754  						continue
  4755  					}
  4756  				}
  4757  			case *ir.Store:
  4758  				// we could treat this as a store to every field, but
  4759  				// we don't want to decide the semantics of partial
  4760  				// struct initializers. should `v = t{x: 1}` also mark
  4761  				// v.y as being written to?
  4762  				if ref != store {
  4763  					continue fnLoop
  4764  				}
  4765  			case *ir.Load:
  4766  				// a load of the entire struct loads every field
  4767  				for i := 0; i < recv.Type().Underlying().(*types.Struct).NumFields(); i++ {
  4768  					reads[i] = append(reads[i], ref)
  4769  				}
  4770  			case *ir.DebugRef:
  4771  				continue
  4772  			default:
  4773  				continue fnLoop
  4774  			}
  4775  		}
  4776  
  4777  		offset := func(instr ir.Instruction) int {
  4778  			for i, other := range instr.Block().Instrs {
  4779  				if instr == other {
  4780  					return i
  4781  				}
  4782  			}
  4783  			panic("couldn't find instruction in its block")
  4784  		}
  4785  
  4786  		for field, ws := range writes {
  4787  			rs := reads[field]
  4788  		wLoop:
  4789  			for _, w := range ws {
  4790  				for _, r := range rs {
  4791  					if w.Block() == r.Block() {
  4792  						if offset(r) > offset(w) {
  4793  							// found a reachable read of our write
  4794  							continue wLoop
  4795  						}
  4796  					} else if irutil.Reachable(w.Block(), r.Block()) {
  4797  						// found a reachable read of our write
  4798  						continue wLoop
  4799  					}
  4800  				}
  4801  				fieldName := recv.Type().Underlying().(*types.Struct).Field(field).Name()
  4802  				report.Report(pass, w, fmt.Sprintf("ineffective assignment to field %s.%s", recv.Type().(*types.Named).Obj().Name(), fieldName))
  4803  			}
  4804  		}
  4805  	}
  4806  	return nil, nil
  4807  }
  4808  
  4809  var negativeZeroFloatQ = pattern.MustParse(`
  4810  	(Or
  4811  		(UnaryExpr
  4812  			"-"
  4813  			(BasicLit "FLOAT" "0.0"))
  4814  
  4815  		(UnaryExpr
  4816  			"-"
  4817  			(CallExpr conv@(Object (Or "float32" "float64")) lit@(Or (BasicLit "INT" "0") (BasicLit "FLOAT" "0.0"))))
  4818  
  4819  		(CallExpr
  4820  			conv@(Object (Or "float32" "float64"))
  4821  			(UnaryExpr "-" lit@(BasicLit "INT" "0"))))`)
  4822  
  4823  func CheckNegativeZeroFloat(pass *analysis.Pass) (interface{}, error) {
  4824  	fn := func(node ast.Node) {
  4825  		m, ok := code.Match(pass, negativeZeroFloatQ, node)
  4826  		if !ok {
  4827  			return
  4828  		}
  4829  
  4830  		if conv, ok := m.State["conv"].(*types.TypeName); ok {
  4831  			var replacement string
  4832  			// TODO(dh): how does this handle type aliases?
  4833  			if conv.Name() == "float32" {
  4834  				replacement = `float32(math.Copysign(0, -1))`
  4835  			} else {
  4836  				replacement = `math.Copysign(0, -1)`
  4837  			}
  4838  			report.Report(pass, node,
  4839  				fmt.Sprintf("in Go, the floating-point expression '%s' is the same as '%s(%s)', it does not produce a negative zero",
  4840  					report.Render(pass, node),
  4841  					conv.Name(),
  4842  					report.Render(pass, m.State["lit"])),
  4843  				report.Fixes(edit.Fix("use math.Copysign to create negative zero", edit.ReplaceWithString(node, replacement))))
  4844  		} else {
  4845  			const replacement = `math.Copysign(0, -1)`
  4846  			report.Report(pass, node,
  4847  				"in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero",
  4848  				report.Fixes(edit.Fix("use math.Copysign to create negative zero", edit.ReplaceWithString(node, replacement))))
  4849  		}
  4850  	}
  4851  	code.Preorder(pass, fn, (*ast.UnaryExpr)(nil), (*ast.CallExpr)(nil))
  4852  	return nil, nil
  4853  }
  4854  
  4855  var ineffectiveURLQueryAddQ = pattern.MustParse(`(CallExpr (SelectorExpr (CallExpr (SelectorExpr recv (Ident "Query")) []) (Ident meth)) _)`)
  4856  
  4857  func CheckIneffectiveURLQueryModification(pass *analysis.Pass) (interface{}, error) {
  4858  	// TODO(dh): We could make this check more complex and detect
  4859  	// pointless modifications of net/url.Values in general, but that
  4860  	// requires us to get the state machine correct, else we'll cause
  4861  	// false positives.
  4862  
  4863  	fn := func(node ast.Node) {
  4864  		m, ok := code.Match(pass, ineffectiveURLQueryAddQ, node)
  4865  		if !ok {
  4866  			return
  4867  		}
  4868  		if !code.IsOfType(pass, m.State["recv"].(ast.Expr), "*net/url.URL") {
  4869  			return
  4870  		}
  4871  		switch m.State["meth"].(string) {
  4872  		case "Add", "Del", "Set":
  4873  		default:
  4874  			return
  4875  		}
  4876  		report.Report(pass, node, "(*net/url.URL).Query returns a copy, modifying it doesn't change the URL")
  4877  	}
  4878  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  4879  	return nil, nil
  4880  }
  4881  
  4882  func CheckBadRemoveAll(pass *analysis.Pass) (interface{}, error) {
  4883  	for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs {
  4884  		for _, b := range fn.Blocks {
  4885  			for _, instr := range b.Instrs {
  4886  				call, ok := instr.(ir.CallInstruction)
  4887  				if !ok {
  4888  					continue
  4889  				}
  4890  				if !irutil.IsCallTo(call.Common(), "os.RemoveAll") {
  4891  					continue
  4892  				}
  4893  
  4894  				kind := ""
  4895  				ex := ""
  4896  				callName := ""
  4897  				arg := irutil.Flatten(call.Common().Args[0])
  4898  				switch arg := arg.(type) {
  4899  				case *ir.Call:
  4900  					callName = irutil.CallName(&arg.Call)
  4901  					if callName != "os.TempDir" {
  4902  						continue
  4903  					}
  4904  					kind = "temporary"
  4905  					ex = os.TempDir()
  4906  				case *ir.Extract:
  4907  					if arg.Index != 0 {
  4908  						continue
  4909  					}
  4910  					first, ok := arg.Tuple.(*ir.Call)
  4911  					if !ok {
  4912  						continue
  4913  					}
  4914  					callName = irutil.CallName(&first.Call)
  4915  					switch callName {
  4916  					case "os.UserCacheDir":
  4917  						kind = "cache"
  4918  						ex, _ = os.UserCacheDir()
  4919  					case "os.UserConfigDir":
  4920  						kind = "config"
  4921  						ex, _ = os.UserConfigDir()
  4922  					case "os.UserHomeDir":
  4923  						kind = "home"
  4924  						ex, _ = os.UserHomeDir()
  4925  					default:
  4926  						continue
  4927  					}
  4928  				default:
  4929  					continue
  4930  				}
  4931  
  4932  				if ex == "" {
  4933  					report.Report(pass, call, fmt.Sprintf("this call to os.RemoveAll deletes the user's entire %s directory, not a subdirectory therein", kind),
  4934  						report.Related(arg, fmt.Sprintf("this call to %s returns the user's %s directory", callName, kind)))
  4935  				} else {
  4936  					report.Report(pass, call, fmt.Sprintf("this call to os.RemoveAll deletes the user's entire %s directory, not a subdirectory therein", kind),
  4937  						report.Related(arg, fmt.Sprintf("this call to %s returns the user's %s directory, for example %s", callName, kind, ex)))
  4938  				}
  4939  			}
  4940  		}
  4941  	}
  4942  	return nil, nil
  4943  }
  4944  
  4945  var moduloOneQ = pattern.MustParse(`(BinaryExpr _ "%" (IntegerLiteral "1"))`)
  4946  
  4947  func CheckModuloOne(pass *analysis.Pass) (interface{}, error) {
  4948  	fn := func(node ast.Node) {
  4949  		_, ok := code.Match(pass, moduloOneQ, node)
  4950  		if !ok {
  4951  			return
  4952  		}
  4953  		report.Report(pass, node, "x % 1 is always zero")
  4954  	}
  4955  	code.Preorder(pass, fn, (*ast.BinaryExpr)(nil))
  4956  	return nil, nil
  4957  }
  4958  
  4959  var typeAssertionShadowingElseQ = pattern.MustParse(`(IfStmt (AssignStmt [obj@(Ident _) ok@(Ident _)] ":=" assert@(TypeAssertExpr obj _)) ok _ elseBranch)`)
  4960  
  4961  func CheckTypeAssertionShadowingElse(pass *analysis.Pass) (interface{}, error) {
  4962  	// TODO(dh): without the IR-based verification, this check is able
  4963  	// to find more bugs, but also more prone to false positives. It
  4964  	// would be a good candidate for the 'codereview' category of
  4965  	// checks.
  4966  
  4967  	irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg
  4968  	fn := func(node ast.Node) {
  4969  		m, ok := code.Match(pass, typeAssertionShadowingElseQ, node)
  4970  		if !ok {
  4971  			return
  4972  		}
  4973  		shadow := pass.TypesInfo.ObjectOf(m.State["obj"].(*ast.Ident))
  4974  		shadowed := m.State["assert"].(*ast.TypeAssertExpr).X
  4975  
  4976  		path, exact := astutil.PathEnclosingInterval(code.File(pass, shadow), shadow.Pos(), shadow.Pos())
  4977  		if !exact {
  4978  			// TODO(dh): when can this happen?
  4979  			return
  4980  		}
  4981  		irfn := ir.EnclosingFunction(irpkg, path)
  4982  		if irfn == nil {
  4983  			// For example for functions named "_", because we don't generate IR for them.
  4984  			return
  4985  		}
  4986  
  4987  		shadoweeIR, isAddr := irfn.ValueForExpr(m.State["obj"].(*ast.Ident))
  4988  		if shadoweeIR == nil || isAddr {
  4989  			// TODO(dh): is this possible?
  4990  			return
  4991  		}
  4992  
  4993  		var branch ast.Node
  4994  		switch br := m.State["elseBranch"].(type) {
  4995  		case ast.Node:
  4996  			branch = br
  4997  		case []ast.Stmt:
  4998  			branch = &ast.BlockStmt{List: br}
  4999  		case nil:
  5000  			return
  5001  		default:
  5002  			panic(fmt.Sprintf("unexpected type %T", br))
  5003  		}
  5004  
  5005  		ast.Inspect(branch, func(node ast.Node) bool {
  5006  			ident, ok := node.(*ast.Ident)
  5007  			if !ok {
  5008  				return true
  5009  			}
  5010  			if pass.TypesInfo.ObjectOf(ident) != shadow {
  5011  				return true
  5012  			}
  5013  
  5014  			v, isAddr := irfn.ValueForExpr(ident)
  5015  			if v == nil || isAddr {
  5016  				return true
  5017  			}
  5018  			if irutil.Flatten(v) != shadoweeIR {
  5019  				// Same types.Object, but different IR value. This
  5020  				// either means that the variable has been
  5021  				// assigned to since the type assertion, or that
  5022  				// the variable has escaped to the heap. Either
  5023  				// way, we shouldn't flag reads of it.
  5024  				return true
  5025  			}
  5026  
  5027  			report.Report(pass, ident,
  5028  				fmt.Sprintf("%s refers to the result of a failed type assertion and is a zero value, not the value that was being type-asserted", report.Render(pass, ident)),
  5029  				report.Related(shadow, "this is the variable being read"),
  5030  				report.Related(shadowed, "this is the variable being shadowed"))
  5031  			return true
  5032  		})
  5033  	}
  5034  	code.Preorder(pass, fn, (*ast.IfStmt)(nil))
  5035  	return nil, nil
  5036  }
  5037  
  5038  var ineffectiveSortQ = pattern.MustParse(`(AssignStmt target@(Ident _) "=" (CallExpr typ@(Symbol (Or "sort.Float64Slice" "sort.IntSlice" "sort.StringSlice")) [target]))`)
  5039  
  5040  func CheckIneffectiveSort(pass *analysis.Pass) (interface{}, error) {
  5041  	fn := func(node ast.Node) {
  5042  		m, ok := code.Match(pass, ineffectiveSortQ, node)
  5043  		if !ok {
  5044  			return
  5045  		}
  5046  
  5047  		_, ok = pass.TypesInfo.TypeOf(m.State["target"].(ast.Expr)).(*types.Slice)
  5048  		if !ok {
  5049  			// Avoid flagging 'x = sort.StringSlice(x)' where TypeOf(x) == sort.StringSlice
  5050  			return
  5051  		}
  5052  
  5053  		var alternative string
  5054  		typeName := types.TypeString(m.State["typ"].(*types.TypeName).Type(), nil)
  5055  		switch typeName {
  5056  		case "sort.Float64Slice":
  5057  			alternative = "Float64s"
  5058  		case "sort.IntSlice":
  5059  			alternative = "Ints"
  5060  		case "sort.StringSlice":
  5061  			alternative = "Strings"
  5062  		default:
  5063  			panic(fmt.Sprintf("unreachable: %q", typeName))
  5064  		}
  5065  
  5066  		r := &ast.CallExpr{
  5067  			Fun: &ast.SelectorExpr{
  5068  				X:   &ast.Ident{Name: "sort"},
  5069  				Sel: &ast.Ident{Name: alternative},
  5070  			},
  5071  			Args: []ast.Expr{m.State["target"].(ast.Expr)},
  5072  		}
  5073  
  5074  		report.Report(pass, node,
  5075  			fmt.Sprintf("%s is a type, not a function, and %s doesn't sort your values; consider using sort.%s instead",
  5076  				typeName,
  5077  				report.Render(pass, node.(*ast.AssignStmt).Rhs[0]),
  5078  				alternative),
  5079  			report.Fixes(edit.Fix(fmt.Sprintf("replace with call to sort.%s", alternative), edit.ReplaceWithNode(pass.Fset, node, r))))
  5080  	}
  5081  	code.Preorder(pass, fn, (*ast.AssignStmt)(nil))
  5082  	return nil, nil
  5083  }
  5084  
  5085  var ineffectiveRandIntQ = pattern.MustParse(`
  5086  	(CallExpr
  5087  		(Symbol
  5088  			name@(Or
  5089  				"math/rand.Int31n"
  5090  				"math/rand.Int63n"
  5091  				"math/rand.Intn"
  5092  				"(*math/rand.Rand).Int31n"
  5093  				"(*math/rand.Rand).Int63n"
  5094  				"(*math/rand.Rand).Intn"))
  5095  		[(IntegerLiteral "1")])`)
  5096  
  5097  func CheckIneffectiveRandInt(pass *analysis.Pass) (interface{}, error) {
  5098  	fn := func(node ast.Node) {
  5099  		m, ok := code.Match(pass, ineffectiveRandIntQ, node)
  5100  		if !ok {
  5101  			return
  5102  		}
  5103  
  5104  		report.Report(pass, node,
  5105  			fmt.Sprintf("%s(n) generates a random value 0 <= x < n; that is, the generated values don't include n; %s therefore always returns 0",
  5106  				m.State["name"], report.Render(pass, node)))
  5107  	}
  5108  
  5109  	code.Preorder(pass, fn, (*ast.CallExpr)(nil))
  5110  	return nil, nil
  5111  }
  5112  
  5113  var allocationNilCheckQ = pattern.MustParse(`(IfStmt _ cond@(BinaryExpr lhs op@(Or "==" "!=") (Builtin "nil")) _ _)`)
  5114  
  5115  func CheckAllocationNilCheck(pass *analysis.Pass) (interface{}, error) {
  5116  	irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg
  5117  
  5118  	var path []ast.Node
  5119  	fn := func(node ast.Node, stack []ast.Node) {
  5120  		m, ok := code.Match(pass, allocationNilCheckQ, node)
  5121  		if !ok {
  5122  			return
  5123  		}
  5124  		cond := m.State["cond"].(ast.Node)
  5125  		if _, ok := code.Match(pass, checkAddressIsNilQ, cond); ok {
  5126  			// Don't duplicate diagnostics reported by SA4022
  5127  			return
  5128  		}
  5129  		lhs := m.State["lhs"].(ast.Expr)
  5130  		path = path[:0]
  5131  		for i := len(stack) - 1; i >= 0; i-- {
  5132  			path = append(path, stack[i])
  5133  		}
  5134  		irfn := ir.EnclosingFunction(irpkg, path)
  5135  		if irfn == nil {
  5136  			// For example for functions named "_", because we don't generate IR for them.
  5137  			return
  5138  		}
  5139  		v, isAddr := irfn.ValueForExpr(lhs)
  5140  		if isAddr {
  5141  			return
  5142  		}
  5143  
  5144  		seen := map[ir.Value]struct{}{}
  5145  		var values []ir.Value
  5146  		var neverNil func(v ir.Value, track bool) bool
  5147  		neverNil = func(v ir.Value, track bool) bool {
  5148  			if _, ok := seen[v]; ok {
  5149  				return true
  5150  			}
  5151  			seen[v] = struct{}{}
  5152  			switch v := v.(type) {
  5153  			case *ir.MakeClosure, *ir.Function:
  5154  				if track {
  5155  					values = append(values, v)
  5156  				}
  5157  				return true
  5158  			case *ir.MakeChan, *ir.MakeMap, *ir.MakeSlice, *ir.Alloc:
  5159  				if track {
  5160  					values = append(values, v)
  5161  				}
  5162  				return true
  5163  			case *ir.Slice:
  5164  				if track {
  5165  					values = append(values, v)
  5166  				}
  5167  				return neverNil(v.X, false)
  5168  			case *ir.FieldAddr:
  5169  				if track {
  5170  					values = append(values, v)
  5171  				}
  5172  				return neverNil(v.X, false)
  5173  			case *ir.Sigma:
  5174  				return neverNil(v.X, true)
  5175  			case *ir.Phi:
  5176  				for _, e := range v.Edges {
  5177  					if !neverNil(e, true) {
  5178  						return false
  5179  					}
  5180  				}
  5181  				return true
  5182  			default:
  5183  				return false
  5184  			}
  5185  		}
  5186  
  5187  		if !neverNil(v, true) {
  5188  			return
  5189  		}
  5190  
  5191  		var qualifier string
  5192  		if op := m.State["op"].(token.Token); op == token.EQL {
  5193  			qualifier = "never"
  5194  		} else {
  5195  			qualifier = "always"
  5196  		}
  5197  		fallback := fmt.Sprintf("this nil check is %s true", qualifier)
  5198  
  5199  		sort.Slice(values, func(i, j int) bool { return values[i].Pos() < values[j].Pos() })
  5200  
  5201  		if ident, ok := m.State["lhs"].(*ast.Ident); ok {
  5202  			if _, ok := pass.TypesInfo.ObjectOf(ident).(*types.Var); ok {
  5203  				var opts []report.Option
  5204  				if v.Parent() == irfn {
  5205  					if len(values) == 1 {
  5206  						opts = append(opts, report.Related(values[0], fmt.Sprintf("this is the value of %s", ident.Name)))
  5207  					} else {
  5208  						for _, vv := range values {
  5209  							opts = append(opts, report.Related(vv, fmt.Sprintf("this is one of the value of %s", ident.Name)))
  5210  						}
  5211  					}
  5212  				}
  5213  
  5214  				switch v.(type) {
  5215  				case *ir.MakeClosure, *ir.Function:
  5216  					report.Report(pass, cond, "the checked variable contains a function and is never nil; did you mean to call it?", opts...)
  5217  				default:
  5218  					report.Report(pass, cond, fallback, opts...)
  5219  				}
  5220  			} else {
  5221  				if _, ok := v.(*ir.Function); ok {
  5222  					report.Report(pass, cond, "functions are never nil; did you mean to call it?")
  5223  				} else {
  5224  					report.Report(pass, cond, fallback)
  5225  				}
  5226  			}
  5227  		} else {
  5228  			if _, ok := v.(*ir.Function); ok {
  5229  				report.Report(pass, cond, "functions are never nil; did you mean to call it?")
  5230  			} else {
  5231  				report.Report(pass, cond, fallback)
  5232  			}
  5233  		}
  5234  	}
  5235  	code.PreorderStack(pass, fn, (*ast.IfStmt)(nil))
  5236  	return nil, nil
  5237  }