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