1// Package staticcheck contains a linter for Go source code. 2package staticcheck // import "honnef.co/go/tools/staticcheck" 3 4import ( 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 44func 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 65func 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 73type runeSlice []rune 74 75func (rs runeSlice) Len() int { return len(rs) } 76func (rs runeSlice) Less(i int, j int) bool { return rs[i] < rs[j] } 77func (rs runeSlice) Swap(i int, j int) { rs[i], rs[j] = rs[j], rs[i] } 78 79func utf8Cutset(call *Call) { 80 arg := call.Args[1] 81 if InvalidUTF8(arg.Value) { 82 arg.Invalid(MsgInvalidUTF8) 83 } 84} 85 86func uniqueCutset(call *Call) { 87 arg := call.Args[1] 88 if !UniqueStringCutset(arg.Value) { 89 arg.Invalid(MsgNonUniqueCutset) 90 } 91} 92 93func 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 101func 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 107func 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 115var ( 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 296func 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 316type verbFlag int 317 318const ( 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 333var 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 356func 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 691func 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 717func 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 750func 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 793func 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 803func 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 813func 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 883func 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 925var ( 926 checkTimeSleepConstantPatternRns = pattern.MustParse(`(BinaryExpr duration "*" (SelectorExpr (Ident "time") (Ident "Nanosecond")))`) 927 checkTimeSleepConstantPatternRs = pattern.MustParse(`(BinaryExpr duration "*" (SelectorExpr (Ident "time") (Ident "Second")))`) 928) 929 930func 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 960var checkWaitgroupAddQ = pattern.MustParse(` 961 (GoStmt 962 (CallExpr 963 (FuncLit 964 _ 965 call@(CallExpr (Function "(*sync.WaitGroup).Add") _):_) _))`) 966 967func 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 978func 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 1022func 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 1064func 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 1088func 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 1150func 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 1164func 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 1184func 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 1210func 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 1278func 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 1337func 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 1369func 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 1438func 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 1447func 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 1512var ( 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 1520func 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 1534func 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 1593func 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 1615func 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 !hasUse(val, nil) { 1725 report.Report(pass, assign, fmt.Sprintf("this value of %s is never used", lhs)) 1726 } 1727 } 1728 return true 1729 }) 1730 } 1731 return nil, nil 1732} 1733 1734func CheckPredeterminedBooleanExprs(pass *analysis.Pass) (interface{}, error) { 1735 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 1736 for _, block := range fn.Blocks { 1737 for _, ins := range block.Instrs { 1738 binop, ok := ins.(*ir.BinOp) 1739 if !ok { 1740 continue 1741 } 1742 switch binop.Op { 1743 case token.GTR, token.LSS, token.EQL, token.NEQ, token.LEQ, token.GEQ: 1744 default: 1745 continue 1746 } 1747 1748 xs, ok1 := consts(binop.X, nil, nil) 1749 ys, ok2 := consts(binop.Y, nil, nil) 1750 if !ok1 || !ok2 || len(xs) == 0 || len(ys) == 0 { 1751 continue 1752 } 1753 1754 trues := 0 1755 for _, x := range xs { 1756 for _, y := range ys { 1757 if x.Value == nil { 1758 if y.Value == nil { 1759 trues++ 1760 } 1761 continue 1762 } 1763 if constant.Compare(x.Value, binop.Op, y.Value) { 1764 trues++ 1765 } 1766 } 1767 } 1768 b := trues != 0 1769 if trues == 0 || trues == len(xs)*len(ys) { 1770 report.Report(pass, binop, fmt.Sprintf("binary expression is always %t for all possible values (%s %s %s)", b, xs, binop.Op, ys)) 1771 } 1772 } 1773 } 1774 } 1775 return nil, nil 1776} 1777 1778func CheckNilMaps(pass *analysis.Pass) (interface{}, error) { 1779 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 1780 for _, block := range fn.Blocks { 1781 for _, ins := range block.Instrs { 1782 mu, ok := ins.(*ir.MapUpdate) 1783 if !ok { 1784 continue 1785 } 1786 c, ok := mu.Map.(*ir.Const) 1787 if !ok { 1788 continue 1789 } 1790 if c.Value != nil { 1791 continue 1792 } 1793 report.Report(pass, mu, "assignment to nil map") 1794 } 1795 } 1796 } 1797 return nil, nil 1798} 1799 1800func CheckExtremeComparison(pass *analysis.Pass) (interface{}, error) { 1801 isobj := func(expr ast.Expr, name string) bool { 1802 sel, ok := expr.(*ast.SelectorExpr) 1803 if !ok { 1804 return false 1805 } 1806 return code.IsObject(pass.TypesInfo.ObjectOf(sel.Sel), name) 1807 } 1808 1809 fn := func(node ast.Node) { 1810 expr := node.(*ast.BinaryExpr) 1811 tx := pass.TypesInfo.TypeOf(expr.X) 1812 basic, ok := tx.Underlying().(*types.Basic) 1813 if !ok { 1814 return 1815 } 1816 1817 var max string 1818 var min string 1819 1820 switch basic.Kind() { 1821 case types.Uint8: 1822 max = "math.MaxUint8" 1823 case types.Uint16: 1824 max = "math.MaxUint16" 1825 case types.Uint32: 1826 max = "math.MaxUint32" 1827 case types.Uint64: 1828 max = "math.MaxUint64" 1829 case types.Uint: 1830 max = "math.MaxUint64" 1831 1832 case types.Int8: 1833 min = "math.MinInt8" 1834 max = "math.MaxInt8" 1835 case types.Int16: 1836 min = "math.MinInt16" 1837 max = "math.MaxInt16" 1838 case types.Int32: 1839 min = "math.MinInt32" 1840 max = "math.MaxInt32" 1841 case types.Int64: 1842 min = "math.MinInt64" 1843 max = "math.MaxInt64" 1844 case types.Int: 1845 min = "math.MinInt64" 1846 max = "math.MaxInt64" 1847 } 1848 1849 if (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.Y, max) || 1850 (expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.X, max) { 1851 report.Report(pass, expr, fmt.Sprintf("no value of type %s is greater than %s", basic, max)) 1852 } 1853 if expr.Op == token.LEQ && isobj(expr.Y, max) || 1854 expr.Op == token.GEQ && isobj(expr.X, max) { 1855 report.Report(pass, expr, fmt.Sprintf("every value of type %s is <= %s", basic, max)) 1856 } 1857 1858 if (basic.Info() & types.IsUnsigned) != 0 { 1859 if (expr.Op == token.LSS && code.IsIntLiteral(expr.Y, "0")) || 1860 (expr.Op == token.GTR && code.IsIntLiteral(expr.X, "0")) { 1861 report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than 0", basic)) 1862 } 1863 if expr.Op == token.GEQ && code.IsIntLiteral(expr.Y, "0") || 1864 expr.Op == token.LEQ && code.IsIntLiteral(expr.X, "0") { 1865 report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= 0", basic)) 1866 } 1867 } else { 1868 if (expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.Y, min) || 1869 (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.X, min) { 1870 report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than %s", basic, min)) 1871 } 1872 if expr.Op == token.GEQ && isobj(expr.Y, min) || 1873 expr.Op == token.LEQ && isobj(expr.X, min) { 1874 report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= %s", basic, min)) 1875 } 1876 } 1877 1878 } 1879 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 1880 return nil, nil 1881} 1882 1883func consts(val ir.Value, out []*ir.Const, visitedPhis map[string]bool) ([]*ir.Const, bool) { 1884 if visitedPhis == nil { 1885 visitedPhis = map[string]bool{} 1886 } 1887 var ok bool 1888 switch val := val.(type) { 1889 case *ir.Phi: 1890 if visitedPhis[val.Name()] { 1891 break 1892 } 1893 visitedPhis[val.Name()] = true 1894 vals := val.Operands(nil) 1895 for _, phival := range vals { 1896 out, ok = consts(*phival, out, visitedPhis) 1897 if !ok { 1898 return nil, false 1899 } 1900 } 1901 case *ir.Const: 1902 out = append(out, val) 1903 case *ir.Convert: 1904 out, ok = consts(val.X, out, visitedPhis) 1905 if !ok { 1906 return nil, false 1907 } 1908 default: 1909 return nil, false 1910 } 1911 if len(out) < 2 { 1912 return out, true 1913 } 1914 uniq := []*ir.Const{out[0]} 1915 for _, val := range out[1:] { 1916 if val.Value == uniq[len(uniq)-1].Value { 1917 continue 1918 } 1919 uniq = append(uniq, val) 1920 } 1921 return uniq, true 1922} 1923 1924func CheckLoopCondition(pass *analysis.Pass) (interface{}, error) { 1925 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 1926 cb := func(node ast.Node) bool { 1927 loop, ok := node.(*ast.ForStmt) 1928 if !ok { 1929 return true 1930 } 1931 if loop.Init == nil || loop.Cond == nil || loop.Post == nil { 1932 return true 1933 } 1934 init, ok := loop.Init.(*ast.AssignStmt) 1935 if !ok || len(init.Lhs) != 1 || len(init.Rhs) != 1 { 1936 return true 1937 } 1938 cond, ok := loop.Cond.(*ast.BinaryExpr) 1939 if !ok { 1940 return true 1941 } 1942 x, ok := cond.X.(*ast.Ident) 1943 if !ok { 1944 return true 1945 } 1946 lhs, ok := init.Lhs[0].(*ast.Ident) 1947 if !ok { 1948 return true 1949 } 1950 if x.Obj != lhs.Obj { 1951 return true 1952 } 1953 if _, ok := loop.Post.(*ast.IncDecStmt); !ok { 1954 return true 1955 } 1956 1957 v, isAddr := fn.ValueForExpr(cond.X) 1958 if v == nil || isAddr { 1959 return true 1960 } 1961 switch v := v.(type) { 1962 case *ir.Phi: 1963 ops := v.Operands(nil) 1964 if len(ops) != 2 { 1965 return true 1966 } 1967 _, ok := (*ops[0]).(*ir.Const) 1968 if !ok { 1969 return true 1970 } 1971 sigma, ok := (*ops[1]).(*ir.Sigma) 1972 if !ok { 1973 return true 1974 } 1975 if sigma.X != v { 1976 return true 1977 } 1978 case *ir.Load: 1979 return true 1980 } 1981 report.Report(pass, cond, "variable in loop condition never changes") 1982 1983 return true 1984 } 1985 Inspect(fn.Source(), cb) 1986 } 1987 return nil, nil 1988} 1989 1990func CheckArgOverwritten(pass *analysis.Pass) (interface{}, error) { 1991 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 1992 cb := func(node ast.Node) bool { 1993 var typ *ast.FuncType 1994 var body *ast.BlockStmt 1995 switch fn := node.(type) { 1996 case *ast.FuncDecl: 1997 typ = fn.Type 1998 body = fn.Body 1999 case *ast.FuncLit: 2000 typ = fn.Type 2001 body = fn.Body 2002 } 2003 if body == nil { 2004 return true 2005 } 2006 if len(typ.Params.List) == 0 { 2007 return true 2008 } 2009 for _, field := range typ.Params.List { 2010 for _, arg := range field.Names { 2011 obj := pass.TypesInfo.ObjectOf(arg) 2012 var irobj *ir.Parameter 2013 for _, param := range fn.Params { 2014 if param.Object() == obj { 2015 irobj = param 2016 break 2017 } 2018 } 2019 if irobj == nil { 2020 continue 2021 } 2022 refs := irobj.Referrers() 2023 if refs == nil { 2024 continue 2025 } 2026 if len(code.FilterDebug(*refs)) != 0 { 2027 continue 2028 } 2029 2030 var assignment ast.Node 2031 ast.Inspect(body, func(node ast.Node) bool { 2032 if assignment != nil { 2033 return false 2034 } 2035 assign, ok := node.(*ast.AssignStmt) 2036 if !ok { 2037 return true 2038 } 2039 for _, lhs := range assign.Lhs { 2040 ident, ok := lhs.(*ast.Ident) 2041 if !ok { 2042 continue 2043 } 2044 if pass.TypesInfo.ObjectOf(ident) == obj { 2045 assignment = assign 2046 return false 2047 } 2048 } 2049 return true 2050 }) 2051 if assignment != nil { 2052 report.Report(pass, arg, fmt.Sprintf("argument %s is overwritten before first use", arg), 2053 report.Related(assignment, fmt.Sprintf("assignment to %s", arg))) 2054 } 2055 } 2056 } 2057 return true 2058 } 2059 Inspect(fn.Source(), cb) 2060 } 2061 return nil, nil 2062} 2063 2064func CheckIneffectiveLoop(pass *analysis.Pass) (interface{}, error) { 2065 // This check detects some, but not all unconditional loop exits. 2066 // We give up in the following cases: 2067 // 2068 // - a goto anywhere in the loop. The goto might skip over our 2069 // return, and we don't check that it doesn't. 2070 // 2071 // - any nested, unlabelled continue, even if it is in another 2072 // loop or closure. 2073 fn := func(node ast.Node) { 2074 var body *ast.BlockStmt 2075 switch fn := node.(type) { 2076 case *ast.FuncDecl: 2077 body = fn.Body 2078 case *ast.FuncLit: 2079 body = fn.Body 2080 default: 2081 ExhaustiveTypeSwitch(node) 2082 } 2083 if body == nil { 2084 return 2085 } 2086 labels := map[*ast.Object]ast.Stmt{} 2087 ast.Inspect(body, func(node ast.Node) bool { 2088 label, ok := node.(*ast.LabeledStmt) 2089 if !ok { 2090 return true 2091 } 2092 labels[label.Label.Obj] = label.Stmt 2093 return true 2094 }) 2095 2096 ast.Inspect(body, func(node ast.Node) bool { 2097 var loop ast.Node 2098 var body *ast.BlockStmt 2099 switch node := node.(type) { 2100 case *ast.ForStmt: 2101 body = node.Body 2102 loop = node 2103 case *ast.RangeStmt: 2104 typ := pass.TypesInfo.TypeOf(node.X) 2105 if _, ok := typ.Underlying().(*types.Map); ok { 2106 // looping once over a map is a valid pattern for 2107 // getting an arbitrary element. 2108 return true 2109 } 2110 body = node.Body 2111 loop = node 2112 default: 2113 return true 2114 } 2115 if len(body.List) < 2 { 2116 // avoid flagging the somewhat common pattern of using 2117 // a range loop to get the first element in a slice, 2118 // or the first rune in a string. 2119 return true 2120 } 2121 var unconditionalExit ast.Node 2122 hasBranching := false 2123 for _, stmt := range body.List { 2124 switch stmt := stmt.(type) { 2125 case *ast.BranchStmt: 2126 switch stmt.Tok { 2127 case token.BREAK: 2128 if stmt.Label == nil || labels[stmt.Label.Obj] == loop { 2129 unconditionalExit = stmt 2130 } 2131 case token.CONTINUE: 2132 if stmt.Label == nil || labels[stmt.Label.Obj] == loop { 2133 unconditionalExit = nil 2134 return false 2135 } 2136 } 2137 case *ast.ReturnStmt: 2138 unconditionalExit = stmt 2139 case *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.SelectStmt: 2140 hasBranching = true 2141 } 2142 } 2143 if unconditionalExit == nil || !hasBranching { 2144 return false 2145 } 2146 ast.Inspect(body, func(node ast.Node) bool { 2147 if branch, ok := node.(*ast.BranchStmt); ok { 2148 2149 switch branch.Tok { 2150 case token.GOTO: 2151 unconditionalExit = nil 2152 return false 2153 case token.CONTINUE: 2154 if branch.Label != nil && labels[branch.Label.Obj] != loop { 2155 return true 2156 } 2157 unconditionalExit = nil 2158 return false 2159 } 2160 } 2161 return true 2162 }) 2163 if unconditionalExit != nil { 2164 report.Report(pass, unconditionalExit, "the surrounding loop is unconditionally terminated") 2165 } 2166 return true 2167 }) 2168 } 2169 code.Preorder(pass, fn, (*ast.FuncDecl)(nil), (*ast.FuncLit)(nil)) 2170 return nil, nil 2171} 2172 2173var checkNilContextQ = pattern.MustParse(`(CallExpr fun@(Function _) (Builtin "nil"):_)`) 2174 2175func CheckNilContext(pass *analysis.Pass) (interface{}, error) { 2176 todo := &ast.CallExpr{ 2177 Fun: Selector("context", "TODO"), 2178 } 2179 bg := &ast.CallExpr{ 2180 Fun: Selector("context", "Background"), 2181 } 2182 fn := func(node ast.Node) { 2183 m, ok := Match(pass, checkNilContextQ, node) 2184 if !ok { 2185 return 2186 } 2187 2188 call := node.(*ast.CallExpr) 2189 fun, ok := m.State["fun"].(*types.Func) 2190 if !ok { 2191 // it might also be a builtin 2192 return 2193 } 2194 sig := fun.Type().(*types.Signature) 2195 if sig.Params().Len() == 0 { 2196 // Our CallExpr might've matched a method expression, like 2197 // (*T).Foo(nil) – here, nil isn't the first argument of 2198 // the Foo method, but the method receiver. 2199 return 2200 } 2201 if !code.IsType(sig.Params().At(0).Type(), "context.Context") { 2202 return 2203 } 2204 report.Report(pass, call.Args[0], 2205 "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( 2206 edit.Fix("use context.TODO", edit.ReplaceWithNode(pass.Fset, call.Args[0], todo)), 2207 edit.Fix("use context.Background", edit.ReplaceWithNode(pass.Fset, call.Args[0], bg)))) 2208 } 2209 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 2210 return nil, nil 2211} 2212 2213var ( 2214 checkSeekerQ = pattern.MustParse(`(CallExpr fun@(SelectorExpr _ (Ident "Seek")) [arg1@(SelectorExpr (Ident "io") (Ident (Or "SeekStart" "SeekCurrent" "SeekEnd"))) arg2])`) 2215 checkSeekerR = pattern.MustParse(`(CallExpr fun [arg2 arg1])`) 2216) 2217 2218func CheckSeeker(pass *analysis.Pass) (interface{}, error) { 2219 fn := func(node ast.Node) { 2220 if _, edits, ok := MatchAndEdit(pass, checkSeekerQ, checkSeekerR, node); ok { 2221 report.Report(pass, node, "the first argument of io.Seeker is the offset, but an io.Seek* constant is being used instead", 2222 report.Fixes(edit.Fix("swap arguments", edits...))) 2223 } 2224 } 2225 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 2226 return nil, nil 2227} 2228 2229func CheckIneffectiveAppend(pass *analysis.Pass) (interface{}, error) { 2230 isAppend := func(ins ir.Value) bool { 2231 call, ok := ins.(*ir.Call) 2232 if !ok { 2233 return false 2234 } 2235 if call.Call.IsInvoke() { 2236 return false 2237 } 2238 if builtin, ok := call.Call.Value.(*ir.Builtin); !ok || builtin.Name() != "append" { 2239 return false 2240 } 2241 return true 2242 } 2243 2244 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2245 for _, block := range fn.Blocks { 2246 for _, ins := range block.Instrs { 2247 val, ok := ins.(ir.Value) 2248 if !ok || !isAppend(val) { 2249 continue 2250 } 2251 2252 isUsed := false 2253 visited := map[ir.Instruction]bool{} 2254 var walkRefs func(refs []ir.Instruction) 2255 walkRefs = func(refs []ir.Instruction) { 2256 loop: 2257 for _, ref := range refs { 2258 if visited[ref] { 2259 continue 2260 } 2261 visited[ref] = true 2262 if _, ok := ref.(*ir.DebugRef); ok { 2263 continue 2264 } 2265 switch ref := ref.(type) { 2266 case *ir.Phi: 2267 walkRefs(*ref.Referrers()) 2268 case *ir.Sigma: 2269 walkRefs(*ref.Referrers()) 2270 case ir.Value: 2271 if !isAppend(ref) { 2272 isUsed = true 2273 } else { 2274 walkRefs(*ref.Referrers()) 2275 } 2276 case ir.Instruction: 2277 isUsed = true 2278 break loop 2279 } 2280 } 2281 } 2282 2283 refs := val.Referrers() 2284 if refs == nil { 2285 continue 2286 } 2287 walkRefs(*refs) 2288 2289 if !isUsed { 2290 report.Report(pass, ins, "this result of append is never used, except maybe in other appends") 2291 } 2292 } 2293 } 2294 } 2295 return nil, nil 2296} 2297 2298func CheckConcurrentTesting(pass *analysis.Pass) (interface{}, error) { 2299 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2300 for _, block := range fn.Blocks { 2301 for _, ins := range block.Instrs { 2302 gostmt, ok := ins.(*ir.Go) 2303 if !ok { 2304 continue 2305 } 2306 var fn *ir.Function 2307 switch val := gostmt.Call.Value.(type) { 2308 case *ir.Function: 2309 fn = val 2310 case *ir.MakeClosure: 2311 fn = val.Fn.(*ir.Function) 2312 default: 2313 continue 2314 } 2315 if fn.Blocks == nil { 2316 continue 2317 } 2318 for _, block := range fn.Blocks { 2319 for _, ins := range block.Instrs { 2320 call, ok := ins.(*ir.Call) 2321 if !ok { 2322 continue 2323 } 2324 if call.Call.IsInvoke() { 2325 continue 2326 } 2327 callee := call.Call.StaticCallee() 2328 if callee == nil { 2329 continue 2330 } 2331 recv := callee.Signature.Recv() 2332 if recv == nil { 2333 continue 2334 } 2335 if !code.IsType(recv.Type(), "*testing.common") { 2336 continue 2337 } 2338 fn, ok := call.Call.StaticCallee().Object().(*types.Func) 2339 if !ok { 2340 continue 2341 } 2342 name := fn.Name() 2343 switch name { 2344 case "FailNow", "Fatal", "Fatalf", "SkipNow", "Skip", "Skipf": 2345 default: 2346 continue 2347 } 2348 // TODO(dh): don't report multiple diagnostics 2349 // for multiple calls to T.Fatal, but do 2350 // collect all of them as related information 2351 report.Report(pass, gostmt, fmt.Sprintf("the goroutine calls T.%s, which must be called in the same goroutine as the test", name), 2352 report.Related(call, fmt.Sprintf("call to T.%s", name))) 2353 } 2354 } 2355 } 2356 } 2357 } 2358 return nil, nil 2359} 2360 2361func eachCall(fn *ir.Function, cb func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function)) { 2362 for _, b := range fn.Blocks { 2363 for _, instr := range b.Instrs { 2364 if site, ok := instr.(ir.CallInstruction); ok { 2365 if g := site.Common().StaticCallee(); g != nil { 2366 cb(fn, site, g) 2367 } 2368 } 2369 } 2370 } 2371} 2372 2373func CheckCyclicFinalizer(pass *analysis.Pass) (interface{}, error) { 2374 cb := func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) { 2375 if callee.RelString(nil) != "runtime.SetFinalizer" { 2376 return 2377 } 2378 arg0 := site.Common().Args[Arg("runtime.SetFinalizer.obj")] 2379 if iface, ok := arg0.(*ir.MakeInterface); ok { 2380 arg0 = iface.X 2381 } 2382 load, ok := arg0.(*ir.Load) 2383 if !ok { 2384 return 2385 } 2386 v, ok := load.X.(*ir.Alloc) 2387 if !ok { 2388 return 2389 } 2390 arg1 := site.Common().Args[Arg("runtime.SetFinalizer.finalizer")] 2391 if iface, ok := arg1.(*ir.MakeInterface); ok { 2392 arg1 = iface.X 2393 } 2394 mc, ok := arg1.(*ir.MakeClosure) 2395 if !ok { 2396 return 2397 } 2398 for _, b := range mc.Bindings { 2399 if b == v { 2400 pos := lint.DisplayPosition(pass.Fset, mc.Fn.Pos()) 2401 report.Report(pass, site, fmt.Sprintf("the finalizer closes over the object, preventing the finalizer from ever running (at %s)", pos)) 2402 } 2403 } 2404 } 2405 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2406 eachCall(fn, cb) 2407 } 2408 return nil, nil 2409} 2410 2411/* 2412func CheckSliceOutOfBounds(pass *analysis.Pass) (interface{}, error) { 2413 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2414 for _, block := range fn.Blocks { 2415 for _, ins := range block.Instrs { 2416 ia, ok := ins.(*ir.IndexAddr) 2417 if !ok { 2418 continue 2419 } 2420 if _, ok := ia.X.Type().Underlying().(*types.Slice); !ok { 2421 continue 2422 } 2423 sr, ok1 := c.funcDescs.Get(fn).Ranges[ia.X].(vrp.SliceInterval) 2424 idxr, ok2 := c.funcDescs.Get(fn).Ranges[ia.Index].(vrp.IntInterval) 2425 if !ok1 || !ok2 || !sr.IsKnown() || !idxr.IsKnown() || sr.Length.Empty() || idxr.Empty() { 2426 continue 2427 } 2428 if idxr.Lower.Cmp(sr.Length.Upper) >= 0 { 2429 report.Nodef(pass, ia, "index out of bounds") 2430 } 2431 } 2432 } 2433 } 2434 return nil, nil 2435} 2436*/ 2437 2438func CheckDeferLock(pass *analysis.Pass) (interface{}, error) { 2439 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2440 for _, block := range fn.Blocks { 2441 instrs := code.FilterDebug(block.Instrs) 2442 if len(instrs) < 2 { 2443 continue 2444 } 2445 for i, ins := range instrs[:len(instrs)-1] { 2446 call, ok := ins.(*ir.Call) 2447 if !ok { 2448 continue 2449 } 2450 if !code.IsCallToAny(call.Common(), "(*sync.Mutex).Lock", "(*sync.RWMutex).RLock") { 2451 continue 2452 } 2453 nins, ok := instrs[i+1].(*ir.Defer) 2454 if !ok { 2455 continue 2456 } 2457 if !code.IsCallToAny(&nins.Call, "(*sync.Mutex).Lock", "(*sync.RWMutex).RLock") { 2458 continue 2459 } 2460 if call.Common().Args[0] != nins.Call.Args[0] { 2461 continue 2462 } 2463 name := shortCallName(call.Common()) 2464 alt := "" 2465 switch name { 2466 case "Lock": 2467 alt = "Unlock" 2468 case "RLock": 2469 alt = "RUnlock" 2470 } 2471 report.Report(pass, nins, fmt.Sprintf("deferring %s right after having locked already; did you mean to defer %s?", name, alt)) 2472 } 2473 } 2474 } 2475 return nil, nil 2476} 2477 2478func CheckNaNComparison(pass *analysis.Pass) (interface{}, error) { 2479 isNaN := func(v ir.Value) bool { 2480 call, ok := v.(*ir.Call) 2481 if !ok { 2482 return false 2483 } 2484 return code.IsCallTo(call.Common(), "math.NaN") 2485 } 2486 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2487 for _, block := range fn.Blocks { 2488 for _, ins := range block.Instrs { 2489 ins, ok := ins.(*ir.BinOp) 2490 if !ok { 2491 continue 2492 } 2493 if isNaN(ins.X) || isNaN(ins.Y) { 2494 report.Report(pass, ins, "no value is equal to NaN, not even NaN itself") 2495 } 2496 } 2497 } 2498 } 2499 return nil, nil 2500} 2501 2502func CheckInfiniteRecursion(pass *analysis.Pass) (interface{}, error) { 2503 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2504 eachCall(fn, func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) { 2505 if callee != fn { 2506 return 2507 } 2508 if _, ok := site.(*ir.Go); ok { 2509 // Recursively spawning goroutines doesn't consume 2510 // stack space infinitely, so don't flag it. 2511 return 2512 } 2513 2514 block := site.Block() 2515 canReturn := false 2516 for _, b := range fn.Blocks { 2517 if block.Dominates(b) { 2518 continue 2519 } 2520 if len(b.Instrs) == 0 { 2521 continue 2522 } 2523 if _, ok := b.Control().(*ir.Return); ok { 2524 canReturn = true 2525 break 2526 } 2527 } 2528 if canReturn { 2529 return 2530 } 2531 report.Report(pass, site, "infinite recursive call") 2532 }) 2533 } 2534 return nil, nil 2535} 2536 2537func objectName(obj types.Object) string { 2538 if obj == nil { 2539 return "<nil>" 2540 } 2541 var name string 2542 if obj.Pkg() != nil && obj.Pkg().Scope().Lookup(obj.Name()) == obj { 2543 s := obj.Pkg().Path() 2544 if s != "" { 2545 name += s + "." 2546 } 2547 } 2548 name += obj.Name() 2549 return name 2550} 2551 2552func isName(pass *analysis.Pass, expr ast.Expr, name string) bool { 2553 var obj types.Object 2554 switch expr := expr.(type) { 2555 case *ast.Ident: 2556 obj = pass.TypesInfo.ObjectOf(expr) 2557 case *ast.SelectorExpr: 2558 obj = pass.TypesInfo.ObjectOf(expr.Sel) 2559 } 2560 return objectName(obj) == name 2561} 2562 2563func CheckLeakyTimeTick(pass *analysis.Pass) (interface{}, error) { 2564 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2565 if code.IsMainLike(pass) || code.IsInTest(pass, fn) { 2566 continue 2567 } 2568 for _, block := range fn.Blocks { 2569 for _, ins := range block.Instrs { 2570 call, ok := ins.(*ir.Call) 2571 if !ok || !code.IsCallTo(call.Common(), "time.Tick") { 2572 continue 2573 } 2574 if !functions.Terminates(call.Parent()) { 2575 continue 2576 } 2577 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") 2578 } 2579 } 2580 } 2581 return nil, nil 2582} 2583 2584var checkDoubleNegationQ = pattern.MustParse(`(UnaryExpr "!" single@(UnaryExpr "!" x))`) 2585 2586func CheckDoubleNegation(pass *analysis.Pass) (interface{}, error) { 2587 fn := func(node ast.Node) { 2588 if m, ok := Match(pass, checkDoubleNegationQ, node); ok { 2589 report.Report(pass, node, "negating a boolean twice has no effect; is this a typo?", report.Fixes( 2590 edit.Fix("turn into single negation", edit.ReplaceWithNode(pass.Fset, node, m.State["single"].(ast.Node))), 2591 edit.Fix("remove double negation", edit.ReplaceWithNode(pass.Fset, node, m.State["x"].(ast.Node))))) 2592 } 2593 } 2594 code.Preorder(pass, fn, (*ast.UnaryExpr)(nil)) 2595 return nil, nil 2596} 2597 2598func CheckRepeatedIfElse(pass *analysis.Pass) (interface{}, error) { 2599 seen := map[ast.Node]bool{} 2600 2601 var collectConds func(ifstmt *ast.IfStmt, conds []ast.Expr) ([]ast.Expr, bool) 2602 collectConds = func(ifstmt *ast.IfStmt, conds []ast.Expr) ([]ast.Expr, bool) { 2603 seen[ifstmt] = true 2604 // Bail if any if-statement has an Init statement or side effects in its condition 2605 if ifstmt.Init != nil { 2606 return nil, false 2607 } 2608 if code.MayHaveSideEffects(pass, ifstmt.Cond, nil) { 2609 return nil, false 2610 } 2611 2612 conds = append(conds, ifstmt.Cond) 2613 if elsestmt, ok := ifstmt.Else.(*ast.IfStmt); ok { 2614 return collectConds(elsestmt, conds) 2615 } 2616 return conds, true 2617 } 2618 fn := func(node ast.Node) { 2619 ifstmt := node.(*ast.IfStmt) 2620 if seen[ifstmt] { 2621 // this if-statement is part of an if/else-if chain that we've already processed 2622 return 2623 } 2624 if ifstmt.Else == nil { 2625 // there can be at most one condition 2626 return 2627 } 2628 conds, ok := collectConds(ifstmt, nil) 2629 if !ok { 2630 return 2631 } 2632 if len(conds) < 2 { 2633 return 2634 } 2635 counts := map[string]int{} 2636 for _, cond := range conds { 2637 s := report.Render(pass, cond) 2638 counts[s]++ 2639 if counts[s] == 2 { 2640 report.Report(pass, cond, "this condition occurs multiple times in this if/else if chain") 2641 } 2642 } 2643 } 2644 code.Preorder(pass, fn, (*ast.IfStmt)(nil)) 2645 return nil, nil 2646} 2647 2648func CheckSillyBitwiseOps(pass *analysis.Pass) (interface{}, error) { 2649 // FIXME(dh): what happened here? 2650 if false { 2651 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2652 for _, block := range fn.Blocks { 2653 for _, ins := range block.Instrs { 2654 ins, ok := ins.(*ir.BinOp) 2655 if !ok { 2656 continue 2657 } 2658 2659 if c, ok := ins.Y.(*ir.Const); !ok || c.Value == nil || c.Value.Kind() != constant.Int || c.Uint64() != 0 { 2660 continue 2661 } 2662 switch ins.Op { 2663 case token.AND, token.OR, token.XOR: 2664 default: 2665 // we do not flag shifts because too often, x<<0 is part 2666 // of a pattern, x<<0, x<<8, x<<16, ... 2667 continue 2668 } 2669 path, _ := astutil.PathEnclosingInterval(code.File(pass, ins), ins.Pos(), ins.Pos()) 2670 if len(path) == 0 { 2671 continue 2672 } 2673 2674 if node, ok := path[0].(*ast.BinaryExpr); !ok || !code.IsIntLiteral(node.Y, "0") { 2675 continue 2676 } 2677 2678 switch ins.Op { 2679 case token.AND: 2680 report.Report(pass, ins, "x & 0 always equals 0") 2681 case token.OR, token.XOR: 2682 report.Report(pass, ins, fmt.Sprintf("x %s 0 always equals x", ins.Op)) 2683 } 2684 } 2685 } 2686 } 2687 } 2688 fn := func(node ast.Node) { 2689 binop := node.(*ast.BinaryExpr) 2690 b, ok := pass.TypesInfo.TypeOf(binop).Underlying().(*types.Basic) 2691 if !ok { 2692 return 2693 } 2694 if (b.Info() & types.IsInteger) == 0 { 2695 return 2696 } 2697 switch binop.Op { 2698 case token.AND, token.OR, token.XOR: 2699 default: 2700 // we do not flag shifts because too often, x<<0 is part 2701 // of a pattern, x<<0, x<<8, x<<16, ... 2702 return 2703 } 2704 switch y := binop.Y.(type) { 2705 case *ast.Ident: 2706 obj, ok := pass.TypesInfo.ObjectOf(y).(*types.Const) 2707 if !ok { 2708 return 2709 } 2710 if v, _ := constant.Int64Val(obj.Val()); v != 0 { 2711 return 2712 } 2713 path, _ := astutil.PathEnclosingInterval(code.File(pass, obj), obj.Pos(), obj.Pos()) 2714 if len(path) < 2 { 2715 return 2716 } 2717 spec, ok := path[1].(*ast.ValueSpec) 2718 if !ok { 2719 return 2720 } 2721 if len(spec.Names) != 1 || len(spec.Values) != 1 { 2722 // TODO(dh): we could support this 2723 return 2724 } 2725 ident, ok := spec.Values[0].(*ast.Ident) 2726 if !ok { 2727 return 2728 } 2729 if !isIota(pass.TypesInfo.ObjectOf(ident)) { 2730 return 2731 } 2732 switch binop.Op { 2733 case token.AND: 2734 report.Report(pass, node, 2735 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))) 2736 case token.OR, token.XOR: 2737 report.Report(pass, node, 2738 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))) 2739 } 2740 case *ast.BasicLit: 2741 if !code.IsIntLiteral(binop.Y, "0") { 2742 return 2743 } 2744 switch binop.Op { 2745 case token.AND: 2746 report.Report(pass, node, fmt.Sprintf("%s always equals 0", report.Render(pass, binop))) 2747 case token.OR, token.XOR: 2748 report.Report(pass, node, fmt.Sprintf("%s always equals %s", report.Render(pass, binop), report.Render(pass, binop.X))) 2749 } 2750 default: 2751 return 2752 } 2753 } 2754 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 2755 return nil, nil 2756} 2757 2758func isIota(obj types.Object) bool { 2759 if obj.Name() != "iota" { 2760 return false 2761 } 2762 c, ok := obj.(*types.Const) 2763 if !ok { 2764 return false 2765 } 2766 return c.Pkg() == nil 2767} 2768 2769func CheckNonOctalFileMode(pass *analysis.Pass) (interface{}, error) { 2770 fn := func(node ast.Node) { 2771 call := node.(*ast.CallExpr) 2772 sig, ok := pass.TypesInfo.TypeOf(call.Fun).(*types.Signature) 2773 if !ok { 2774 return 2775 } 2776 n := sig.Params().Len() 2777 for i := 0; i < n; i++ { 2778 typ := sig.Params().At(i).Type() 2779 if !code.IsType(typ, "os.FileMode") { 2780 continue 2781 } 2782 2783 lit, ok := call.Args[i].(*ast.BasicLit) 2784 if !ok { 2785 continue 2786 } 2787 if len(lit.Value) == 3 && 2788 lit.Value[0] != '0' && 2789 lit.Value[0] >= '0' && lit.Value[0] <= '7' && 2790 lit.Value[1] >= '0' && lit.Value[1] <= '7' && 2791 lit.Value[2] >= '0' && lit.Value[2] <= '7' { 2792 2793 v, err := strconv.ParseInt(lit.Value, 10, 64) 2794 if err != nil { 2795 continue 2796 } 2797 report.Report(pass, call.Args[i], fmt.Sprintf("file mode '%s' evaluates to %#o; did you mean '0%s'?", lit.Value, v, lit.Value), 2798 report.Fixes(edit.Fix("fix octal literal", edit.ReplaceWithString(pass.Fset, call.Args[i], "0"+lit.Value)))) 2799 } 2800 } 2801 } 2802 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 2803 return nil, nil 2804} 2805 2806func CheckPureFunctions(pass *analysis.Pass) (interface{}, error) { 2807 pure := pass.ResultOf[facts.Purity].(facts.PurityResult) 2808 2809fnLoop: 2810 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2811 if code.IsInTest(pass, fn) { 2812 params := fn.Signature.Params() 2813 for i := 0; i < params.Len(); i++ { 2814 param := params.At(i) 2815 if code.IsType(param.Type(), "*testing.B") { 2816 // Ignore discarded pure functions in code related 2817 // to benchmarks. Instead of matching BenchmarkFoo 2818 // functions, we match any function accepting a 2819 // *testing.B. Benchmarks sometimes call generic 2820 // functions for doing the actual work, and 2821 // checking for the parameter is a lot easier and 2822 // faster than analyzing call trees. 2823 continue fnLoop 2824 } 2825 } 2826 } 2827 2828 for _, b := range fn.Blocks { 2829 for _, ins := range b.Instrs { 2830 ins, ok := ins.(*ir.Call) 2831 if !ok { 2832 continue 2833 } 2834 refs := ins.Referrers() 2835 if refs == nil || len(code.FilterDebug(*refs)) > 0 { 2836 continue 2837 } 2838 2839 callee := ins.Common().StaticCallee() 2840 if callee == nil { 2841 continue 2842 } 2843 if callee.Object() == nil { 2844 // TODO(dh): support anonymous functions 2845 continue 2846 } 2847 if _, ok := pure[callee.Object().(*types.Func)]; ok { 2848 if pass.Pkg.Path() == "fmt_test" && callee.Object().(*types.Func).FullName() == "fmt.Sprintf" { 2849 // special case for benchmarks in the fmt package 2850 continue 2851 } 2852 report.Report(pass, ins, fmt.Sprintf("%s is a pure function but its return value is ignored", callee.Name())) 2853 } 2854 } 2855 } 2856 } 2857 return nil, nil 2858} 2859 2860func CheckDeprecated(pass *analysis.Pass) (interface{}, error) { 2861 deprs := pass.ResultOf[facts.Deprecated].(facts.DeprecatedResult) 2862 2863 // Selectors can appear outside of function literals, e.g. when 2864 // declaring package level variables. 2865 2866 var tfn types.Object 2867 stack := 0 2868 fn := func(node ast.Node, push bool) bool { 2869 if !push { 2870 stack-- 2871 return false 2872 } 2873 stack++ 2874 if stack == 1 { 2875 tfn = nil 2876 } 2877 if fn, ok := node.(*ast.FuncDecl); ok { 2878 tfn = pass.TypesInfo.ObjectOf(fn.Name) 2879 } 2880 sel, ok := node.(*ast.SelectorExpr) 2881 if !ok { 2882 return true 2883 } 2884 2885 obj := pass.TypesInfo.ObjectOf(sel.Sel) 2886 if obj.Pkg() == nil { 2887 return true 2888 } 2889 if pass.Pkg == obj.Pkg() || obj.Pkg().Path()+"_test" == pass.Pkg.Path() { 2890 // Don't flag stuff in our own package 2891 return true 2892 } 2893 if depr, ok := deprs.Objects[obj]; ok { 2894 // Look for the first available alternative, not the first 2895 // version something was deprecated in. If a function was 2896 // deprecated in Go 1.6, an alternative has been available 2897 // already in 1.0, and we're targeting 1.2, it still 2898 // makes sense to use the alternative from 1.0, to be 2899 // future-proof. 2900 minVersion := deprecated.Stdlib[code.SelectorName(pass, sel)].AlternativeAvailableSince 2901 if !code.IsGoVersion(pass, minVersion) { 2902 return true 2903 } 2904 2905 if tfn != nil { 2906 if _, ok := deprs.Objects[tfn]; ok { 2907 // functions that are deprecated may use deprecated 2908 // symbols 2909 return true 2910 } 2911 } 2912 report.Report(pass, sel, fmt.Sprintf("%s is deprecated: %s", report.Render(pass, sel), depr.Msg)) 2913 return true 2914 } 2915 return true 2916 } 2917 2918 fn2 := func(node ast.Node) { 2919 spec := node.(*ast.ImportSpec) 2920 var imp *types.Package 2921 if spec.Name != nil { 2922 imp = pass.TypesInfo.ObjectOf(spec.Name).(*types.PkgName).Imported() 2923 } else { 2924 imp = pass.TypesInfo.Implicits[spec].(*types.PkgName).Imported() 2925 } 2926 2927 p := spec.Path.Value 2928 path := p[1 : len(p)-1] 2929 if depr, ok := deprs.Packages[imp]; ok { 2930 report.Report(pass, spec, fmt.Sprintf("package %s is deprecated: %s", path, depr.Msg)) 2931 } 2932 } 2933 pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Nodes(nil, fn) 2934 code.Preorder(pass, fn2, (*ast.ImportSpec)(nil)) 2935 return nil, nil 2936} 2937 2938func callChecker(rules map[string]CallCheck) func(pass *analysis.Pass) (interface{}, error) { 2939 return func(pass *analysis.Pass) (interface{}, error) { 2940 return checkCalls(pass, rules) 2941 } 2942} 2943 2944func checkCalls(pass *analysis.Pass, rules map[string]CallCheck) (interface{}, error) { 2945 cb := func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) { 2946 obj, ok := callee.Object().(*types.Func) 2947 if !ok { 2948 return 2949 } 2950 2951 r, ok := rules[lint.FuncName(obj)] 2952 if !ok { 2953 return 2954 } 2955 var args []*Argument 2956 irargs := site.Common().Args 2957 if callee.Signature.Recv() != nil { 2958 irargs = irargs[1:] 2959 } 2960 for _, arg := range irargs { 2961 if iarg, ok := arg.(*ir.MakeInterface); ok { 2962 arg = iarg.X 2963 } 2964 args = append(args, &Argument{Value: Value{arg}}) 2965 } 2966 call := &Call{ 2967 Pass: pass, 2968 Instr: site, 2969 Args: args, 2970 Parent: site.Parent(), 2971 } 2972 r(call) 2973 path, _ := astutil.PathEnclosingInterval(code.File(pass, site), site.Pos(), site.Pos()) 2974 var astcall *ast.CallExpr 2975 for _, el := range path { 2976 if expr, ok := el.(*ast.CallExpr); ok { 2977 astcall = expr 2978 break 2979 } 2980 } 2981 for idx, arg := range call.Args { 2982 for _, e := range arg.invalids { 2983 if astcall != nil { 2984 report.Report(pass, astcall.Args[idx], e) 2985 } else { 2986 report.Report(pass, site, e) 2987 } 2988 } 2989 } 2990 for _, e := range call.invalids { 2991 report.Report(pass, call.Instr, e) 2992 } 2993 } 2994 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2995 eachCall(fn, cb) 2996 } 2997 return nil, nil 2998} 2999 3000func shortCallName(call *ir.CallCommon) string { 3001 if call.IsInvoke() { 3002 return "" 3003 } 3004 switch v := call.Value.(type) { 3005 case *ir.Function: 3006 fn, ok := v.Object().(*types.Func) 3007 if !ok { 3008 return "" 3009 } 3010 return fn.Name() 3011 case *ir.Builtin: 3012 return v.Name() 3013 } 3014 return "" 3015} 3016 3017func CheckWriterBufferModified(pass *analysis.Pass) (interface{}, error) { 3018 // TODO(dh): this might be a good candidate for taint analysis. 3019 // Taint the argument as MUST_NOT_MODIFY, then propagate that 3020 // through functions like bytes.Split 3021 3022 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3023 sig := fn.Signature 3024 if fn.Name() != "Write" || sig.Recv() == nil || sig.Params().Len() != 1 || sig.Results().Len() != 2 { 3025 continue 3026 } 3027 tArg, ok := sig.Params().At(0).Type().(*types.Slice) 3028 if !ok { 3029 continue 3030 } 3031 if basic, ok := tArg.Elem().(*types.Basic); !ok || basic.Kind() != types.Byte { 3032 continue 3033 } 3034 if basic, ok := sig.Results().At(0).Type().(*types.Basic); !ok || basic.Kind() != types.Int { 3035 continue 3036 } 3037 if named, ok := sig.Results().At(1).Type().(*types.Named); !ok || !code.IsType(named, "error") { 3038 continue 3039 } 3040 3041 for _, block := range fn.Blocks { 3042 for _, ins := range block.Instrs { 3043 switch ins := ins.(type) { 3044 case *ir.Store: 3045 addr, ok := ins.Addr.(*ir.IndexAddr) 3046 if !ok { 3047 continue 3048 } 3049 if addr.X != fn.Params[1] { 3050 continue 3051 } 3052 report.Report(pass, ins, "io.Writer.Write must not modify the provided buffer, not even temporarily") 3053 case *ir.Call: 3054 if !code.IsCallTo(ins.Common(), "append") { 3055 continue 3056 } 3057 if ins.Common().Args[0] != fn.Params[1] { 3058 continue 3059 } 3060 report.Report(pass, ins, "io.Writer.Write must not modify the provided buffer, not even temporarily") 3061 } 3062 } 3063 } 3064 } 3065 return nil, nil 3066} 3067 3068func loopedRegexp(name string) CallCheck { 3069 return func(call *Call) { 3070 if len(extractConsts(call.Args[0].Value.Value)) == 0 { 3071 return 3072 } 3073 if !isInLoop(call.Instr.Block()) { 3074 return 3075 } 3076 call.Invalid(fmt.Sprintf("calling %s in a loop has poor performance, consider using regexp.Compile", name)) 3077 } 3078} 3079 3080func CheckEmptyBranch(pass *analysis.Pass) (interface{}, error) { 3081 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3082 if fn.Source() == nil { 3083 continue 3084 } 3085 if code.IsExample(fn) { 3086 continue 3087 } 3088 cb := func(node ast.Node) bool { 3089 ifstmt, ok := node.(*ast.IfStmt) 3090 if !ok { 3091 return true 3092 } 3093 if ifstmt.Else != nil { 3094 b, ok := ifstmt.Else.(*ast.BlockStmt) 3095 if !ok || len(b.List) != 0 { 3096 return true 3097 } 3098 report.Report(pass, ifstmt.Else, "empty branch", report.FilterGenerated(), report.ShortRange()) 3099 } 3100 if len(ifstmt.Body.List) != 0 { 3101 return true 3102 } 3103 report.Report(pass, ifstmt, "empty branch", report.FilterGenerated(), report.ShortRange()) 3104 return true 3105 } 3106 Inspect(fn.Source(), cb) 3107 } 3108 return nil, nil 3109} 3110 3111func CheckMapBytesKey(pass *analysis.Pass) (interface{}, error) { 3112 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3113 for _, b := range fn.Blocks { 3114 insLoop: 3115 for _, ins := range b.Instrs { 3116 // find []byte -> string conversions 3117 conv, ok := ins.(*ir.Convert) 3118 if !ok || conv.Type() != types.Universe.Lookup("string").Type() { 3119 continue 3120 } 3121 if s, ok := conv.X.Type().(*types.Slice); !ok || s.Elem() != types.Universe.Lookup("byte").Type() { 3122 continue 3123 } 3124 refs := conv.Referrers() 3125 // need at least two (DebugRef) references: the 3126 // conversion and the *ast.Ident 3127 if refs == nil || len(*refs) < 2 { 3128 continue 3129 } 3130 ident := false 3131 // skip first reference, that's the conversion itself 3132 for _, ref := range (*refs)[1:] { 3133 switch ref := ref.(type) { 3134 case *ir.DebugRef: 3135 if _, ok := ref.Expr.(*ast.Ident); !ok { 3136 // the string seems to be used somewhere 3137 // unexpected; the default branch should 3138 // catch this already, but be safe 3139 continue insLoop 3140 } else { 3141 ident = true 3142 } 3143 case *ir.MapLookup: 3144 default: 3145 // the string is used somewhere else than a 3146 // map lookup 3147 continue insLoop 3148 } 3149 } 3150 3151 // the result of the conversion wasn't assigned to an 3152 // identifier 3153 if !ident { 3154 continue 3155 } 3156 report.Report(pass, conv, "m[string(key)] would be more efficient than k := string(key); m[k]") 3157 } 3158 } 3159 } 3160 return nil, nil 3161} 3162 3163func CheckRangeStringRunes(pass *analysis.Pass) (interface{}, error) { 3164 return sharedcheck.CheckRangeStringRunes(pass) 3165} 3166 3167func CheckSelfAssignment(pass *analysis.Pass) (interface{}, error) { 3168 pure := pass.ResultOf[facts.Purity].(facts.PurityResult) 3169 3170 fn := func(node ast.Node) { 3171 assign := node.(*ast.AssignStmt) 3172 if assign.Tok != token.ASSIGN || len(assign.Lhs) != len(assign.Rhs) { 3173 return 3174 } 3175 for i, lhs := range assign.Lhs { 3176 rhs := assign.Rhs[i] 3177 if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) { 3178 continue 3179 } 3180 if code.MayHaveSideEffects(pass, lhs, pure) || code.MayHaveSideEffects(pass, rhs, pure) { 3181 continue 3182 } 3183 3184 rlh := report.Render(pass, lhs) 3185 rrh := report.Render(pass, rhs) 3186 if rlh == rrh { 3187 report.Report(pass, assign, fmt.Sprintf("self-assignment of %s to %s", rrh, rlh), report.FilterGenerated()) 3188 } 3189 } 3190 } 3191 code.Preorder(pass, fn, (*ast.AssignStmt)(nil)) 3192 return nil, nil 3193} 3194 3195func buildTagsIdentical(s1, s2 []string) bool { 3196 if len(s1) != len(s2) { 3197 return false 3198 } 3199 s1s := make([]string, len(s1)) 3200 copy(s1s, s1) 3201 sort.Strings(s1s) 3202 s2s := make([]string, len(s2)) 3203 copy(s2s, s2) 3204 sort.Strings(s2s) 3205 for i, s := range s1s { 3206 if s != s2s[i] { 3207 return false 3208 } 3209 } 3210 return true 3211} 3212 3213func CheckDuplicateBuildConstraints(pass *analysis.Pass) (interface{}, error) { 3214 for _, f := range pass.Files { 3215 constraints := buildTags(f) 3216 for i, constraint1 := range constraints { 3217 for j, constraint2 := range constraints { 3218 if i >= j { 3219 continue 3220 } 3221 if buildTagsIdentical(constraint1, constraint2) { 3222 msg := fmt.Sprintf("identical build constraints %q and %q", 3223 strings.Join(constraint1, " "), 3224 strings.Join(constraint2, " ")) 3225 report.Report(pass, f, msg, report.FilterGenerated(), report.ShortRange()) 3226 } 3227 } 3228 } 3229 } 3230 return nil, nil 3231} 3232 3233func CheckSillyRegexp(pass *analysis.Pass) (interface{}, error) { 3234 // We could use the rule checking engine for this, but the 3235 // arguments aren't really invalid. 3236 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3237 for _, b := range fn.Blocks { 3238 for _, ins := range b.Instrs { 3239 call, ok := ins.(*ir.Call) 3240 if !ok { 3241 continue 3242 } 3243 if !code.IsCallToAny(call.Common(), "regexp.MustCompile", "regexp.Compile", "regexp.Match", "regexp.MatchReader", "regexp.MatchString") { 3244 continue 3245 } 3246 c, ok := call.Common().Args[0].(*ir.Const) 3247 if !ok { 3248 continue 3249 } 3250 s := constant.StringVal(c.Value) 3251 re, err := syntax.Parse(s, 0) 3252 if err != nil { 3253 continue 3254 } 3255 if re.Op != syntax.OpLiteral && re.Op != syntax.OpEmptyMatch { 3256 continue 3257 } 3258 report.Report(pass, call, "regular expression does not contain any meta characters") 3259 } 3260 } 3261 } 3262 return nil, nil 3263} 3264 3265func CheckMissingEnumTypesInDeclaration(pass *analysis.Pass) (interface{}, error) { 3266 fn := func(node ast.Node) { 3267 decl := node.(*ast.GenDecl) 3268 if !decl.Lparen.IsValid() { 3269 return 3270 } 3271 if decl.Tok != token.CONST { 3272 return 3273 } 3274 3275 groups := code.GroupSpecs(pass.Fset, decl.Specs) 3276 groupLoop: 3277 for _, group := range groups { 3278 if len(group) < 2 { 3279 continue 3280 } 3281 if group[0].(*ast.ValueSpec).Type == nil { 3282 // first constant doesn't have a type 3283 continue groupLoop 3284 } 3285 for i, spec := range group { 3286 spec := spec.(*ast.ValueSpec) 3287 if len(spec.Names) != 1 || len(spec.Values) != 1 { 3288 continue groupLoop 3289 } 3290 switch v := spec.Values[0].(type) { 3291 case *ast.BasicLit: 3292 case *ast.UnaryExpr: 3293 if _, ok := v.X.(*ast.BasicLit); !ok { 3294 continue groupLoop 3295 } 3296 default: 3297 // if it's not a literal it might be typed, such as 3298 // time.Microsecond = 1000 * Nanosecond 3299 continue groupLoop 3300 } 3301 if i == 0 { 3302 continue 3303 } 3304 if spec.Type != nil { 3305 continue groupLoop 3306 } 3307 } 3308 var edits []analysis.TextEdit 3309 typ := group[0].(*ast.ValueSpec).Type 3310 for _, spec := range group[1:] { 3311 nspec := *spec.(*ast.ValueSpec) 3312 nspec.Type = typ 3313 edits = append(edits, edit.ReplaceWithNode(pass.Fset, spec, &nspec)) 3314 } 3315 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...))) 3316 } 3317 } 3318 code.Preorder(pass, fn, (*ast.GenDecl)(nil)) 3319 return nil, nil 3320} 3321 3322func CheckTimerResetReturnValue(pass *analysis.Pass) (interface{}, error) { 3323 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3324 for _, block := range fn.Blocks { 3325 for _, ins := range block.Instrs { 3326 call, ok := ins.(*ir.Call) 3327 if !ok { 3328 continue 3329 } 3330 if !code.IsCallTo(call.Common(), "(*time.Timer).Reset") { 3331 continue 3332 } 3333 refs := call.Referrers() 3334 if refs == nil { 3335 continue 3336 } 3337 for _, ref := range code.FilterDebug(*refs) { 3338 ifstmt, ok := ref.(*ir.If) 3339 if !ok { 3340 continue 3341 } 3342 3343 found := false 3344 for _, succ := range ifstmt.Block().Succs { 3345 if len(succ.Preds) != 1 { 3346 // Merge point, not a branch in the 3347 // syntactical sense. 3348 3349 // FIXME(dh): this is broken for if 3350 // statements a la "if x || y" 3351 continue 3352 } 3353 irutil.Walk(succ, func(b *ir.BasicBlock) bool { 3354 if !succ.Dominates(b) { 3355 // We've reached the end of the branch 3356 return false 3357 } 3358 for _, ins := range b.Instrs { 3359 // TODO(dh): we should check that 3360 // we're receiving from the channel of 3361 // a time.Timer to further reduce 3362 // false positives. Not a key 3363 // priority, considering the rarity of 3364 // Reset and the tiny likeliness of a 3365 // false positive 3366 if ins, ok := ins.(*ir.Recv); ok && code.IsType(ins.Chan.Type(), "<-chan time.Time") { 3367 found = true 3368 return false 3369 } 3370 } 3371 return true 3372 }) 3373 } 3374 3375 if found { 3376 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") 3377 } 3378 } 3379 } 3380 } 3381 } 3382 return nil, nil 3383} 3384 3385var ( 3386 checkToLowerToUpperComparisonQ = pattern.MustParse(` 3387 (BinaryExpr 3388 (CallExpr fun@(Function (Or "strings.ToLower" "strings.ToUpper")) [a]) 3389 tok@(Or "==" "!=") 3390 (CallExpr fun [b]))`) 3391 checkToLowerToUpperComparisonR = pattern.MustParse(`(CallExpr (SelectorExpr (Ident "strings") (Ident "EqualFold")) [a b])`) 3392) 3393 3394func CheckToLowerToUpperComparison(pass *analysis.Pass) (interface{}, error) { 3395 fn := func(node ast.Node) { 3396 m, ok := Match(pass, checkToLowerToUpperComparisonQ, node) 3397 if !ok { 3398 return 3399 } 3400 rn := pattern.NodeToAST(checkToLowerToUpperComparisonR.Root, m.State).(ast.Expr) 3401 if m.State["tok"].(token.Token) == token.NEQ { 3402 rn = &ast.UnaryExpr{ 3403 Op: token.NOT, 3404 X: rn, 3405 } 3406 } 3407 3408 report.Report(pass, node, "should use strings.EqualFold instead", report.Fixes(edit.Fix("replace with strings.EqualFold", edit.ReplaceWithNode(pass.Fset, node, rn)))) 3409 } 3410 3411 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 3412 return nil, nil 3413} 3414 3415func CheckUnreachableTypeCases(pass *analysis.Pass) (interface{}, error) { 3416 // 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. 3417 subsumes := func(T, V types.Type) bool { 3418 tIface, ok := T.Underlying().(*types.Interface) 3419 if !ok { 3420 return false 3421 } 3422 3423 return types.Implements(V, tIface) 3424 } 3425 3426 subsumesAny := func(Ts, Vs []types.Type) (types.Type, types.Type, bool) { 3427 for _, T := range Ts { 3428 for _, V := range Vs { 3429 if subsumes(T, V) { 3430 return T, V, true 3431 } 3432 } 3433 } 3434 3435 return nil, nil, false 3436 } 3437 3438 fn := func(node ast.Node) { 3439 tsStmt := node.(*ast.TypeSwitchStmt) 3440 3441 type ccAndTypes struct { 3442 cc *ast.CaseClause 3443 types []types.Type 3444 } 3445 3446 // All asserted types in the order of case clauses. 3447 ccs := make([]ccAndTypes, 0, len(tsStmt.Body.List)) 3448 for _, stmt := range tsStmt.Body.List { 3449 cc, _ := stmt.(*ast.CaseClause) 3450 3451 // Exclude the 'default' case. 3452 if len(cc.List) == 0 { 3453 continue 3454 } 3455 3456 Ts := make([]types.Type, len(cc.List)) 3457 for i, expr := range cc.List { 3458 Ts[i] = pass.TypesInfo.TypeOf(expr) 3459 } 3460 3461 ccs = append(ccs, ccAndTypes{cc: cc, types: Ts}) 3462 } 3463 3464 if len(ccs) <= 1 { 3465 // Zero or one case clauses, nothing to check. 3466 return 3467 } 3468 3469 // Check if case clauses following cc have types that are subsumed by cc. 3470 for i, cc := range ccs[:len(ccs)-1] { 3471 for _, next := range ccs[i+1:] { 3472 if T, V, yes := subsumesAny(cc.types, next.types); yes { 3473 report.Report(pass, next.cc, fmt.Sprintf("unreachable case clause: %s will always match before %s", T.String(), V.String()), 3474 report.ShortRange()) 3475 } 3476 } 3477 } 3478 } 3479 3480 code.Preorder(pass, fn, (*ast.TypeSwitchStmt)(nil)) 3481 return nil, nil 3482} 3483 3484var checkSingleArgAppendQ = pattern.MustParse(`(CallExpr (Builtin "append") [_])`) 3485 3486func CheckSingleArgAppend(pass *analysis.Pass) (interface{}, error) { 3487 fn := func(node ast.Node) { 3488 _, ok := Match(pass, checkSingleArgAppendQ, node) 3489 if !ok { 3490 return 3491 } 3492 report.Report(pass, node, "x = append(y) is equivalent to x = y", report.FilterGenerated()) 3493 } 3494 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 3495 return nil, nil 3496} 3497 3498func CheckStructTags(pass *analysis.Pass) (interface{}, error) { 3499 importsGoFlags := false 3500 3501 // we use the AST instead of (*types.Package).Imports to work 3502 // around vendored packages in GOPATH mode. A vendored package's 3503 // path will include the vendoring subtree as a prefix. 3504 for _, f := range pass.Files { 3505 for _, imp := range f.Imports { 3506 v := imp.Path.Value 3507 if v[1:len(v)-1] == "github.com/jessevdk/go-flags" { 3508 importsGoFlags = true 3509 break 3510 } 3511 } 3512 } 3513 3514 fn := func(node ast.Node) { 3515 for _, field := range node.(*ast.StructType).Fields.List { 3516 if field.Tag == nil { 3517 continue 3518 } 3519 tags, err := parseStructTag(field.Tag.Value[1 : len(field.Tag.Value)-1]) 3520 if err != nil { 3521 report.Report(pass, field.Tag, fmt.Sprintf("unparseable struct tag: %s", err)) 3522 continue 3523 } 3524 for k, v := range tags { 3525 if len(v) > 1 { 3526 isGoFlagsTag := importsGoFlags && 3527 (k == "choice" || k == "optional-value" || k == "default") 3528 if !isGoFlagsTag { 3529 report.Report(pass, field.Tag, fmt.Sprintf("duplicate struct tag %q", k)) 3530 } 3531 } 3532 3533 switch k { 3534 case "json": 3535 checkJSONTag(pass, field, v[0]) 3536 case "xml": 3537 checkXMLTag(pass, field, v[0]) 3538 } 3539 } 3540 } 3541 } 3542 code.Preorder(pass, fn, (*ast.StructType)(nil)) 3543 return nil, nil 3544} 3545 3546func checkJSONTag(pass *analysis.Pass, field *ast.Field, tag string) { 3547 if pass.Pkg.Path() == "encoding/json" || pass.Pkg.Path() == "encoding/json_test" { 3548 // don't flag malformed JSON tags in the encoding/json 3549 // package; it knows what it is doing, and it is testing 3550 // itself. 3551 return 3552 } 3553 //lint:ignore SA9003 TODO(dh): should we flag empty tags? 3554 if len(tag) == 0 { 3555 } 3556 fields := strings.Split(tag, ",") 3557 for _, r := range fields[0] { 3558 if !unicode.IsLetter(r) && !unicode.IsDigit(r) && !strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", r) { 3559 report.Report(pass, field.Tag, fmt.Sprintf("invalid JSON field name %q", fields[0])) 3560 } 3561 } 3562 var co, cs, ci int 3563 for _, s := range fields[1:] { 3564 switch s { 3565 case "omitempty": 3566 co++ 3567 case "": 3568 // allow stuff like "-," 3569 case "string": 3570 cs++ 3571 // only for string, floating point, integer and bool 3572 T := code.Dereference(pass.TypesInfo.TypeOf(field.Type).Underlying()).Underlying() 3573 basic, ok := T.(*types.Basic) 3574 if !ok || (basic.Info()&(types.IsBoolean|types.IsInteger|types.IsFloat|types.IsString)) == 0 { 3575 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") 3576 } 3577 case "inline": 3578 ci++ 3579 default: 3580 report.Report(pass, field.Tag, fmt.Sprintf("unknown JSON option %q", s)) 3581 } 3582 } 3583 if co > 1 { 3584 report.Report(pass, field.Tag, `duplicate JSON option "omitempty"`) 3585 } 3586 if cs > 1 { 3587 report.Report(pass, field.Tag, `duplicate JSON option "string"`) 3588 } 3589 if ci > 1 { 3590 report.Report(pass, field.Tag, `duplicate JSON option "inline"`) 3591 } 3592} 3593 3594func checkXMLTag(pass *analysis.Pass, field *ast.Field, tag string) { 3595 //lint:ignore SA9003 TODO(dh): should we flag empty tags? 3596 if len(tag) == 0 { 3597 } 3598 fields := strings.Split(tag, ",") 3599 counts := map[string]int{} 3600 var exclusives []string 3601 for _, s := range fields[1:] { 3602 switch s { 3603 case "attr", "chardata", "cdata", "innerxml", "comment": 3604 counts[s]++ 3605 if counts[s] == 1 { 3606 exclusives = append(exclusives, s) 3607 } 3608 case "omitempty", "any": 3609 counts[s]++ 3610 case "": 3611 default: 3612 report.Report(pass, field.Tag, fmt.Sprintf("unknown XML option %q", s)) 3613 } 3614 } 3615 for k, v := range counts { 3616 if v > 1 { 3617 report.Report(pass, field.Tag, fmt.Sprintf("duplicate XML option %q", k)) 3618 } 3619 } 3620 if len(exclusives) > 1 { 3621 report.Report(pass, field.Tag, fmt.Sprintf("XML options %s are mutually exclusive", strings.Join(exclusives, " and "))) 3622 } 3623} 3624 3625func CheckImpossibleTypeAssertion(pass *analysis.Pass) (interface{}, error) { 3626 type entry struct { 3627 l, r *types.Func 3628 } 3629 3630 msc := &pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg.Prog.MethodSets 3631 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3632 for _, b := range fn.Blocks { 3633 for _, instr := range b.Instrs { 3634 assert, ok := instr.(*ir.TypeAssert) 3635 if !ok { 3636 continue 3637 } 3638 var wrong []entry 3639 left := assert.X.Type() 3640 right := assert.AssertedType 3641 righti, ok := right.Underlying().(*types.Interface) 3642 3643 if !ok { 3644 // We only care about interface->interface 3645 // assertions. The Go compiler already catches 3646 // impossible interface->concrete assertions. 3647 continue 3648 } 3649 3650 ms := msc.MethodSet(left) 3651 for i := 0; i < righti.NumMethods(); i++ { 3652 mr := righti.Method(i) 3653 sel := ms.Lookup(mr.Pkg(), mr.Name()) 3654 if sel == nil { 3655 continue 3656 } 3657 ml := sel.Obj().(*types.Func) 3658 if types.AssignableTo(ml.Type(), mr.Type()) { 3659 continue 3660 } 3661 3662 wrong = append(wrong, entry{ml, mr}) 3663 } 3664 3665 if len(wrong) != 0 { 3666 s := fmt.Sprintf("impossible type assertion; %s and %s contradict each other:", 3667 types.TypeString(left, types.RelativeTo(pass.Pkg)), 3668 types.TypeString(right, types.RelativeTo(pass.Pkg))) 3669 for _, e := range wrong { 3670 s += fmt.Sprintf("\n\twrong type for %s method", e.l.Name()) 3671 s += fmt.Sprintf("\n\t\thave %s", e.l.Type()) 3672 s += fmt.Sprintf("\n\t\twant %s", e.r.Type()) 3673 } 3674 report.Report(pass, assert, s) 3675 } 3676 } 3677 } 3678 } 3679 return nil, nil 3680} 3681 3682func checkWithValueKey(call *Call) { 3683 arg := call.Args[1] 3684 T := arg.Value.Value.Type() 3685 if T, ok := T.(*types.Basic); ok { 3686 arg.Invalid( 3687 fmt.Sprintf("should not use built-in type %s as key for value; define your own type to avoid collisions", T)) 3688 } 3689 if !types.Comparable(T) { 3690 arg.Invalid(fmt.Sprintf("keys used with context.WithValue must be comparable, but type %s is not comparable", T)) 3691 } 3692} 3693 3694func CheckMaybeNil(pass *analysis.Pass) (interface{}, error) { 3695 // This is an extremely trivial check that doesn't try to reason 3696 // about control flow. That is, phis and sigmas do not propagate 3697 // any information. As such, we can flag this: 3698 // 3699 // _ = *x 3700 // if x == nil { return } 3701 // 3702 // but we cannot flag this: 3703 // 3704 // if x == nil { println(x) } 3705 // _ = *x 3706 // 3707 // nor many other variations of conditional uses of or assignments to x. 3708 // 3709 // However, even this trivial implementation finds plenty of 3710 // real-world bugs, such as dereference before nil pointer check, 3711 // or using t.Error instead of t.Fatal when encountering nil 3712 // pointers. 3713 // 3714 // On the flip side, our naive implementation avoids false positives in branches, such as 3715 // 3716 // if x != nil { _ = *x } 3717 // 3718 // due to the same lack of propagating information through sigma 3719 // nodes. x inside the branch will be independent of the x in the 3720 // nil pointer check. 3721 // 3722 // 3723 // We could implement a more powerful check, but then we'd be 3724 // getting false positives instead of false negatives because 3725 // we're incapable of deducing relationships between variables. 3726 // For example, a function might return a pointer and an error, 3727 // and the error being nil guarantees that the pointer is not nil. 3728 // Depending on the surrounding code, the pointer may still end up 3729 // being checked against nil in one place, and guarded by a check 3730 // on the error in another, which would lead to us marking some 3731 // loads as unsafe. 3732 // 3733 // Unfortunately, simply hard-coding the relationship between 3734 // return values wouldn't eliminate all false positives, either. 3735 // Many other more subtle relationships exist. An abridged example 3736 // from real code: 3737 // 3738 // if a == nil && b == nil { return } 3739 // c := fn(a) 3740 // if c != "" { _ = *a } 3741 // 3742 // where `fn` is guaranteed to return a non-empty string if a 3743 // isn't nil. 3744 // 3745 // We choose to err on the side of false negatives. 3746 3747 isNilConst := func(v ir.Value) bool { 3748 if code.IsPointerLike(v.Type()) { 3749 if k, ok := v.(*ir.Const); ok { 3750 return k.IsNil() 3751 } 3752 } 3753 return false 3754 } 3755 3756 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3757 maybeNil := map[ir.Value]ir.Instruction{} 3758 for _, b := range fn.Blocks { 3759 for _, instr := range b.Instrs { 3760 if instr, ok := instr.(*ir.BinOp); ok { 3761 var ptr ir.Value 3762 if isNilConst(instr.X) { 3763 ptr = instr.Y 3764 } else if isNilConst(instr.Y) { 3765 ptr = instr.X 3766 } 3767 maybeNil[ptr] = instr 3768 } 3769 } 3770 } 3771 3772 for _, b := range fn.Blocks { 3773 for _, instr := range b.Instrs { 3774 var ptr ir.Value 3775 switch instr := instr.(type) { 3776 case *ir.Load: 3777 ptr = instr.X 3778 case *ir.Store: 3779 ptr = instr.Addr 3780 case *ir.IndexAddr: 3781 ptr = instr.X 3782 case *ir.FieldAddr: 3783 ptr = instr.X 3784 } 3785 if ptr != nil { 3786 switch ptr.(type) { 3787 case *ir.Alloc, *ir.FieldAddr, *ir.IndexAddr: 3788 // these cannot be nil 3789 continue 3790 } 3791 if r, ok := maybeNil[ptr]; ok { 3792 report.Report(pass, instr, "possible nil pointer dereference", 3793 report.Related(r, "this check suggests that the pointer can be nil")) 3794 } 3795 } 3796 } 3797 } 3798 } 3799 3800 return nil, nil 3801} 3802 3803var checkAddressIsNilQ = pattern.MustParse( 3804 `(BinaryExpr 3805 (UnaryExpr "&" _) 3806 (Or "==" "!=") 3807 (Builtin "nil"))`) 3808 3809func CheckAddressIsNil(pass *analysis.Pass) (interface{}, error) { 3810 fn := func(node ast.Node) { 3811 _, ok := Match(pass, checkAddressIsNilQ, node) 3812 if !ok { 3813 return 3814 } 3815 report.Report(pass, node, "the address of a variable cannot be nil") 3816 } 3817 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 3818 return nil, nil 3819} 3820