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