github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/cmd/vet/print.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file contains the printf-checker. 6 7 package main 8 9 import ( 10 "bytes" 11 "flag" 12 "fmt" 13 "go/ast" 14 "go/constant" 15 "go/token" 16 "go/types" 17 "regexp" 18 "strconv" 19 "strings" 20 "unicode/utf8" 21 ) 22 23 var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check") 24 25 func init() { 26 register("printf", 27 "check printf-like invocations", 28 checkFmtPrintfCall, 29 funcDecl, callExpr) 30 } 31 32 func initPrintFlags() { 33 if *printfuncs == "" { 34 return 35 } 36 for _, name := range strings.Split(*printfuncs, ",") { 37 if len(name) == 0 { 38 flag.Usage() 39 } 40 41 // Backwards compatibility: skip optional first argument 42 // index after the colon. 43 if colon := strings.LastIndex(name, ":"); colon > 0 { 44 name = name[:colon] 45 } 46 47 isPrint[strings.ToLower(name)] = true 48 } 49 } 50 51 // TODO(rsc): Incorporate user-defined printf wrappers again. 52 // The general plan is to allow vet of one package P to output 53 // additional information to supply to later vets of packages 54 // importing P. Then vet of P can record a list of printf wrappers 55 // and the later vet using P.Printf will find it in the list and check it. 56 // That's not ready for Go 1.10. 57 // When that does happen, uncomment the user-defined printf 58 // wrapper tests in testdata/print.go. 59 60 // isPrint records the print functions. 61 // If a key ends in 'f' then it is assumed to be a formatted print. 62 var isPrint = map[string]bool{ 63 "fmt.Errorf": true, 64 "fmt.Fprint": true, 65 "fmt.Fprintf": true, 66 "fmt.Fprintln": true, 67 "fmt.Print": true, 68 "fmt.Printf": true, 69 "fmt.Println": true, 70 "fmt.Sprint": true, 71 "fmt.Sprintf": true, 72 "fmt.Sprintln": true, 73 "log.Fatal": true, 74 "log.Fatalf": true, 75 "log.Fatalln": true, 76 "log.Logger.Fatal": true, 77 "log.Logger.Fatalf": true, 78 "log.Logger.Fatalln": true, 79 "log.Logger.Panic": true, 80 "log.Logger.Panicf": true, 81 "log.Logger.Panicln": true, 82 "log.Logger.Printf": true, 83 "log.Logger.Println": true, 84 "log.Panic": true, 85 "log.Panicf": true, 86 "log.Panicln": true, 87 "log.Print": true, 88 "log.Printf": true, 89 "log.Println": true, 90 "testing.B.Error": true, 91 "testing.B.Errorf": true, 92 "testing.B.Fatal": true, 93 "testing.B.Fatalf": true, 94 "testing.B.Log": true, 95 "testing.B.Logf": true, 96 "testing.B.Skip": true, 97 "testing.B.Skipf": true, 98 "testing.T.Error": true, 99 "testing.T.Errorf": true, 100 "testing.T.Fatal": true, 101 "testing.T.Fatalf": true, 102 "testing.T.Log": true, 103 "testing.T.Logf": true, 104 "testing.T.Skip": true, 105 "testing.T.Skipf": true, 106 "testing.TB.Error": true, 107 "testing.TB.Errorf": true, 108 "testing.TB.Fatal": true, 109 "testing.TB.Fatalf": true, 110 "testing.TB.Log": true, 111 "testing.TB.Logf": true, 112 "testing.TB.Skip": true, 113 "testing.TB.Skipf": true, 114 } 115 116 // formatString returns the format string argument and its index within 117 // the given printf-like call expression. 118 // 119 // The last parameter before variadic arguments is assumed to be 120 // a format string. 121 // 122 // The first string literal or string constant is assumed to be a format string 123 // if the call's signature cannot be determined. 124 // 125 // If it cannot find any format string parameter, it returns ("", -1). 126 func formatString(f *File, call *ast.CallExpr) (format string, idx int) { 127 typ := f.pkg.types[call.Fun].Type 128 if typ != nil { 129 if sig, ok := typ.(*types.Signature); ok { 130 if !sig.Variadic() { 131 // Skip checking non-variadic functions. 132 return "", -1 133 } 134 idx := sig.Params().Len() - 2 135 if idx < 0 { 136 // Skip checking variadic functions without 137 // fixed arguments. 138 return "", -1 139 } 140 s, ok := stringConstantArg(f, call, idx) 141 if !ok { 142 // The last argument before variadic args isn't a string. 143 return "", -1 144 } 145 return s, idx 146 } 147 } 148 149 // Cannot determine call's signature. Fall back to scanning for the first 150 // string constant in the call. 151 for idx := range call.Args { 152 if s, ok := stringConstantArg(f, call, idx); ok { 153 return s, idx 154 } 155 if f.pkg.types[call.Args[idx]].Type == types.Typ[types.String] { 156 // Skip checking a call with a non-constant format 157 // string argument, since its contents are unavailable 158 // for validation. 159 return "", -1 160 } 161 } 162 return "", -1 163 } 164 165 // stringConstantArg returns call's string constant argument at the index idx. 166 // 167 // ("", false) is returned if call's argument at the index idx isn't a string 168 // constant. 169 func stringConstantArg(f *File, call *ast.CallExpr, idx int) (string, bool) { 170 if idx >= len(call.Args) { 171 return "", false 172 } 173 arg := call.Args[idx] 174 lit := f.pkg.types[arg].Value 175 if lit != nil && lit.Kind() == constant.String { 176 return constant.StringVal(lit), true 177 } 178 return "", false 179 } 180 181 // checkCall triggers the print-specific checks if the call invokes a print function. 182 func checkFmtPrintfCall(f *File, node ast.Node) { 183 if f.pkg.typesPkg == nil { 184 // This check now requires type information. 185 return 186 } 187 188 if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) { 189 // Remember we saw this. 190 if f.stringers == nil { 191 f.stringers = make(map[*ast.Object]bool) 192 } 193 if l := d.Recv.List; len(l) == 1 { 194 if n := l[0].Names; len(n) == 1 { 195 f.stringers[n[0].Obj] = true 196 } 197 } 198 return 199 } 200 201 call, ok := node.(*ast.CallExpr) 202 if !ok { 203 return 204 } 205 206 // Construct name like pkg.Printf or pkg.Type.Printf for lookup. 207 var name string 208 switch x := call.Fun.(type) { 209 case *ast.Ident: 210 if fn, ok := f.pkg.uses[x].(*types.Func); ok { 211 var pkg string 212 if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg { 213 pkg = vcfg.ImportPath 214 } else { 215 pkg = fn.Pkg().Path() 216 } 217 name = pkg + "." + x.Name 218 break 219 } 220 221 case *ast.SelectorExpr: 222 // Check for "fmt.Printf". 223 if id, ok := x.X.(*ast.Ident); ok { 224 if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok { 225 name = pkgName.Imported().Path() + "." + x.Sel.Name 226 break 227 } 228 } 229 230 // Check for t.Logf where t is a *testing.T. 231 if sel := f.pkg.selectors[x]; sel != nil { 232 recv := sel.Recv() 233 if p, ok := recv.(*types.Pointer); ok { 234 recv = p.Elem() 235 } 236 if named, ok := recv.(*types.Named); ok { 237 obj := named.Obj() 238 var pkg string 239 if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg { 240 pkg = vcfg.ImportPath 241 } else { 242 pkg = obj.Pkg().Path() 243 } 244 name = pkg + "." + obj.Name() + "." + x.Sel.Name 245 break 246 } 247 } 248 } 249 if name == "" { 250 return 251 } 252 253 shortName := name[strings.LastIndex(name, ".")+1:] 254 255 _, ok = isPrint[name] 256 if !ok { 257 // Next look up just "printf", for use with -printfuncs. 258 _, ok = isPrint[strings.ToLower(shortName)] 259 } 260 if ok { 261 if strings.HasSuffix(name, "f") { 262 f.checkPrintf(call, shortName) 263 } else { 264 f.checkPrint(call, shortName) 265 } 266 } 267 } 268 269 // isStringer returns true if the provided declaration is a "String() string" 270 // method, an implementation of fmt.Stringer. 271 func isStringer(f *File, d *ast.FuncDecl) bool { 272 return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil && 273 len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 && 274 f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String] 275 } 276 277 // isFormatter reports whether t satisfies fmt.Formatter. 278 // Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt. 279 func (f *File) isFormatter(t types.Type) bool { 280 return formatterType != nil && types.Implements(t, formatterType) 281 } 282 283 // formatState holds the parsed representation of a printf directive such as "%3.*[4]d". 284 // It is constructed by parsePrintfVerb. 285 type formatState struct { 286 verb rune // the format verb: 'd' for "%d" 287 format string // the full format directive from % through verb, "%.3d". 288 name string // Printf, Sprintf etc. 289 flags []byte // the list of # + etc. 290 argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call 291 firstArg int // Index of first argument after the format in the Printf call. 292 // Used only during parse. 293 file *File 294 call *ast.CallExpr 295 argNum int // Which argument we're expecting to format now. 296 indexPending bool // Whether we have an indexed argument that has not resolved. 297 nbytes int // number of bytes of the format string consumed. 298 } 299 300 // checkPrintf checks a call to a formatted print routine such as Printf. 301 func (f *File) checkPrintf(call *ast.CallExpr, name string) { 302 format, idx := formatString(f, call) 303 if idx < 0 { 304 if *verbose { 305 f.Warn(call.Pos(), "can't check non-constant format in call to", name) 306 } 307 return 308 } 309 310 firstArg := idx + 1 // Arguments are immediately after format string. 311 if !strings.Contains(format, "%") { 312 if len(call.Args) > firstArg { 313 f.Badf(call.Pos(), "%s call has arguments but no formatting directives", name) 314 } 315 return 316 } 317 // Hard part: check formats against args. 318 argNum := firstArg 319 maxArgNum := firstArg 320 for i, w := 0, 0; i < len(format); i += w { 321 w = 1 322 if format[i] != '%' { 323 continue 324 } 325 state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum) 326 if state == nil { 327 return 328 } 329 w = len(state.format) 330 if !f.okPrintfArg(call, state) { // One error per format is enough. 331 return 332 } 333 if len(state.argNums) > 0 { 334 // Continue with the next sequential argument. 335 argNum = state.argNums[len(state.argNums)-1] + 1 336 } 337 for _, n := range state.argNums { 338 if n >= maxArgNum { 339 maxArgNum = n + 1 340 } 341 } 342 } 343 // Dotdotdot is hard. 344 if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 { 345 return 346 } 347 // There should be no leftover arguments. 348 if maxArgNum != len(call.Args) { 349 expect := maxArgNum - firstArg 350 numArgs := len(call.Args) - firstArg 351 f.Badf(call.Pos(), "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg")) 352 } 353 } 354 355 // parseFlags accepts any printf flags. 356 func (s *formatState) parseFlags() { 357 for s.nbytes < len(s.format) { 358 switch c := s.format[s.nbytes]; c { 359 case '#', '0', '+', '-', ' ': 360 s.flags = append(s.flags, c) 361 s.nbytes++ 362 default: 363 return 364 } 365 } 366 } 367 368 // scanNum advances through a decimal number if present. 369 func (s *formatState) scanNum() { 370 for ; s.nbytes < len(s.format); s.nbytes++ { 371 c := s.format[s.nbytes] 372 if c < '0' || '9' < c { 373 return 374 } 375 } 376 } 377 378 // parseIndex scans an index expression. It returns false if there is a syntax error. 379 func (s *formatState) parseIndex() bool { 380 if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { 381 return true 382 } 383 // Argument index present. 384 s.nbytes++ // skip '[' 385 start := s.nbytes 386 s.scanNum() 387 ok := true 388 if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { 389 ok = false 390 s.nbytes = strings.Index(s.format, "]") 391 if s.nbytes < 0 { 392 s.file.Badf(s.call.Pos(), "%s format %s is missing closing ]", s.name, s.format) 393 return false 394 } 395 } 396 arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) 397 if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) { 398 s.file.Badf(s.call.Pos(), "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes]) 399 return false 400 } 401 s.nbytes++ // skip ']' 402 arg := int(arg32) 403 arg += s.firstArg - 1 // We want to zero-index the actual arguments. 404 s.argNum = arg 405 s.indexPending = true 406 return true 407 } 408 409 // parseNum scans a width or precision (or *). It returns false if there's a bad index expression. 410 func (s *formatState) parseNum() bool { 411 if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { 412 if s.indexPending { // Absorb it. 413 s.indexPending = false 414 } 415 s.nbytes++ 416 s.argNums = append(s.argNums, s.argNum) 417 s.argNum++ 418 } else { 419 s.scanNum() 420 } 421 return true 422 } 423 424 // parsePrecision scans for a precision. It returns false if there's a bad index expression. 425 func (s *formatState) parsePrecision() bool { 426 // If there's a period, there may be a precision. 427 if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { 428 s.flags = append(s.flags, '.') // Treat precision as a flag. 429 s.nbytes++ 430 if !s.parseIndex() { 431 return false 432 } 433 if !s.parseNum() { 434 return false 435 } 436 } 437 return true 438 } 439 440 // parsePrintfVerb looks the formatting directive that begins the format string 441 // and returns a formatState that encodes what the directive wants, without looking 442 // at the actual arguments present in the call. The result is nil if there is an error. 443 func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState { 444 state := &formatState{ 445 format: format, 446 name: name, 447 flags: make([]byte, 0, 5), 448 argNum: argNum, 449 argNums: make([]int, 0, 1), 450 nbytes: 1, // There's guaranteed to be a percent sign. 451 firstArg: firstArg, 452 file: f, 453 call: call, 454 } 455 // There may be flags. 456 state.parseFlags() 457 // There may be an index. 458 if !state.parseIndex() { 459 return nil 460 } 461 // There may be a width. 462 if !state.parseNum() { 463 return nil 464 } 465 // There may be a precision. 466 if !state.parsePrecision() { 467 return nil 468 } 469 // Now a verb, possibly prefixed by an index (which we may already have). 470 if !state.indexPending && !state.parseIndex() { 471 return nil 472 } 473 if state.nbytes == len(state.format) { 474 f.Badf(call.Pos(), "%s format %s is missing verb at end of string", name, state.format) 475 return nil 476 } 477 verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) 478 state.verb = verb 479 state.nbytes += w 480 if verb != '%' { 481 state.argNums = append(state.argNums, state.argNum) 482 } 483 state.format = state.format[:state.nbytes] 484 return state 485 } 486 487 // printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask. 488 type printfArgType int 489 490 const ( 491 argBool printfArgType = 1 << iota 492 argInt 493 argRune 494 argString 495 argFloat 496 argComplex 497 argPointer 498 anyType printfArgType = ^0 499 ) 500 501 type printVerb struct { 502 verb rune // User may provide verb through Formatter; could be a rune. 503 flags string // known flags are all ASCII 504 typ printfArgType 505 } 506 507 // Common flag sets for printf verbs. 508 const ( 509 noFlag = "" 510 numFlag = " -+.0" 511 sharpNumFlag = " -+.0#" 512 allFlags = " -+.0#" 513 ) 514 515 // printVerbs identifies which flags are known to printf for each verb. 516 var printVerbs = []printVerb{ 517 // '-' is a width modifier, always valid. 518 // '.' is a precision for float, max width for strings. 519 // '+' is required sign for numbers, Go format for %v. 520 // '#' is alternate format for several verbs. 521 // ' ' is spacer for numbers 522 {'%', noFlag, 0}, 523 {'b', numFlag, argInt | argFloat | argComplex}, 524 {'c', "-", argRune | argInt}, 525 {'d', numFlag, argInt}, 526 {'e', sharpNumFlag, argFloat | argComplex}, 527 {'E', sharpNumFlag, argFloat | argComplex}, 528 {'f', sharpNumFlag, argFloat | argComplex}, 529 {'F', sharpNumFlag, argFloat | argComplex}, 530 {'g', sharpNumFlag, argFloat | argComplex}, 531 {'G', sharpNumFlag, argFloat | argComplex}, 532 {'o', sharpNumFlag, argInt}, 533 {'p', "-#", argPointer}, 534 {'q', " -+.0#", argRune | argInt | argString}, 535 {'s', " -+.0", argString}, 536 {'t', "-", argBool}, 537 {'T', "-", anyType}, 538 {'U', "-#", argRune | argInt}, 539 {'v', allFlags, anyType}, 540 {'x', sharpNumFlag, argRune | argInt | argString}, 541 {'X', sharpNumFlag, argRune | argInt | argString}, 542 } 543 544 // okPrintfArg compares the formatState to the arguments actually present, 545 // reporting any discrepancies it can discern. If the final argument is ellipsissed, 546 // there's little it can do for that. 547 func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) { 548 var v printVerb 549 found := false 550 // Linear scan is fast enough for a small list. 551 for _, v = range printVerbs { 552 if v.verb == state.verb { 553 found = true 554 break 555 } 556 } 557 558 // Does current arg implement fmt.Formatter? 559 formatter := false 560 if state.argNum < len(call.Args) { 561 if tv, ok := f.pkg.types[call.Args[state.argNum]]; ok { 562 formatter = f.isFormatter(tv.Type) 563 } 564 } 565 566 if !formatter { 567 if !found { 568 f.Badf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb) 569 return false 570 } 571 for _, flag := range state.flags { 572 if !strings.ContainsRune(v.flags, rune(flag)) { 573 f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag) 574 return false 575 } 576 } 577 } 578 // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all 579 // but the final arg must be an integer. 580 trueArgs := 1 581 if state.verb == '%' { 582 trueArgs = 0 583 } 584 nargs := len(state.argNums) 585 for i := 0; i < nargs-trueArgs; i++ { 586 argNum := state.argNums[i] 587 if !f.argCanBeChecked(call, i, state) { 588 return 589 } 590 arg := call.Args[argNum] 591 if !f.matchArgType(argInt, nil, arg) { 592 f.Badf(call.Pos(), "%s format %s uses non-int %s as argument of *", state.name, state.format, f.gofmt(arg)) 593 return false 594 } 595 } 596 if state.verb == '%' || formatter { 597 return true 598 } 599 argNum := state.argNums[len(state.argNums)-1] 600 if !f.argCanBeChecked(call, len(state.argNums)-1, state) { 601 return false 602 } 603 arg := call.Args[argNum] 604 if f.isFunctionValue(arg) && state.verb != 'p' && state.verb != 'T' { 605 f.Badf(call.Pos(), "%s format %s arg %s is a func value, not called", state.name, state.format, f.gofmt(arg)) 606 return false 607 } 608 if !f.matchArgType(v.typ, nil, arg) { 609 typeString := "" 610 if typ := f.pkg.types[arg].Type; typ != nil { 611 typeString = typ.String() 612 } 613 f.Badf(call.Pos(), "%s format %s has arg %s of wrong type %s", state.name, state.format, f.gofmt(arg), typeString) 614 return false 615 } 616 if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) { 617 f.Badf(call.Pos(), "%s format %s with arg %s causes recursive String method call", state.name, state.format, f.gofmt(arg)) 618 return false 619 } 620 return true 621 } 622 623 // recursiveStringer reports whether the provided argument is r or &r for the 624 // fmt.Stringer receiver identifier r. 625 func (f *File) recursiveStringer(e ast.Expr) bool { 626 if len(f.stringers) == 0 { 627 return false 628 } 629 var obj *ast.Object 630 switch e := e.(type) { 631 case *ast.Ident: 632 obj = e.Obj 633 case *ast.UnaryExpr: 634 if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND { 635 obj = id.Obj 636 } 637 } 638 639 // It's unlikely to be a recursive stringer if it has a Format method. 640 if typ := f.pkg.types[e].Type; typ != nil { 641 // Not a perfect match; see issue 6259. 642 if f.hasMethod(typ, "Format") { 643 return false 644 } 645 } 646 647 // We compare the underlying Object, which checks that the identifier 648 // is the one we declared as the receiver for the String method in 649 // which this printf appears. 650 return f.stringers[obj] 651 } 652 653 // isFunctionValue reports whether the expression is a function as opposed to a function call. 654 // It is almost always a mistake to print a function value. 655 func (f *File) isFunctionValue(e ast.Expr) bool { 656 if typ := f.pkg.types[e].Type; typ != nil { 657 _, ok := typ.(*types.Signature) 658 return ok 659 } 660 return false 661 } 662 663 // argCanBeChecked reports whether the specified argument is statically present; 664 // it may be beyond the list of arguments or in a terminal slice... argument, which 665 // means we can't see it. 666 func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, state *formatState) bool { 667 argNum := state.argNums[formatArg] 668 if argNum <= 0 { 669 // Shouldn't happen, so catch it with prejudice. 670 panic("negative arg num") 671 } 672 if argNum < len(call.Args)-1 { 673 return true // Always OK. 674 } 675 if call.Ellipsis.IsValid() { 676 return false // We just can't tell; there could be many more arguments. 677 } 678 if argNum < len(call.Args) { 679 return true 680 } 681 // There are bad indexes in the format or there are fewer arguments than the format needs. 682 // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi". 683 arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed. 684 f.Badf(call.Pos(), "%s format %s reads arg #%d, but call has only %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg")) 685 return false 686 } 687 688 // printFormatRE is the regexp we match and report as a possible format string 689 // in the first argument to unformatted prints like fmt.Print. 690 // We exclude the space flag, so that printing a string like "x % y" is not reported as a format. 691 var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE) 692 693 const ( 694 flagsRE = `[+\-#]*` 695 indexOptRE = `(\[[0-9]+\])?` 696 numOptRE = `([0-9]+|` + indexOptRE + `\*)?` 697 verbRE = `[bcdefgopqstvxEFGUX]` 698 ) 699 700 // checkPrint checks a call to an unformatted print routine such as Println. 701 func (f *File) checkPrint(call *ast.CallExpr, name string) { 702 firstArg := 0 703 typ := f.pkg.types[call.Fun].Type 704 if typ == nil { 705 // Skip checking functions with unknown type. 706 return 707 } 708 if sig, ok := typ.(*types.Signature); ok { 709 if !sig.Variadic() { 710 // Skip checking non-variadic functions. 711 return 712 } 713 params := sig.Params() 714 firstArg = params.Len() - 1 715 716 typ := params.At(firstArg).Type() 717 typ = typ.(*types.Slice).Elem() 718 it, ok := typ.(*types.Interface) 719 if !ok || !it.Empty() { 720 // Skip variadic functions accepting non-interface{} args. 721 return 722 } 723 } 724 args := call.Args 725 if len(args) <= firstArg { 726 // Skip calls without variadic args. 727 return 728 } 729 args = args[firstArg:] 730 731 if firstArg == 0 { 732 if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { 733 if x, ok := sel.X.(*ast.Ident); ok { 734 if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { 735 f.Badf(call.Pos(), "%s does not take io.Writer but has first arg %s", name, f.gofmt(call.Args[0])) 736 } 737 } 738 } 739 } 740 741 arg := args[0] 742 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { 743 // Ignore trailing % character in lit.Value. 744 // The % in "abc 0.0%" couldn't be a formatting directive. 745 s := strings.TrimSuffix(lit.Value, `%"`) 746 if strings.Contains(s, "%") { 747 m := printFormatRE.FindStringSubmatch(s) 748 if m != nil { 749 f.Badf(call.Pos(), "%s call has possible formatting directive %s", name, m[0]) 750 } 751 } 752 } 753 if strings.HasSuffix(name, "ln") { 754 // The last item, if a string, should not have a newline. 755 arg = args[len(args)-1] 756 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { 757 str, _ := strconv.Unquote(lit.Value) 758 if strings.HasSuffix(str, "\n") { 759 f.Badf(call.Pos(), "%s arg list ends with redundant newline", name) 760 } 761 } 762 } 763 for _, arg := range args { 764 if f.isFunctionValue(arg) { 765 f.Badf(call.Pos(), "%s arg %s is a func value, not called", name, f.gofmt(arg)) 766 } 767 if f.recursiveStringer(arg) { 768 f.Badf(call.Pos(), "%s arg %s causes recursive call to String method", name, f.gofmt(arg)) 769 } 770 } 771 } 772 773 // count(n, what) returns "1 what" or "N whats" 774 // (assuming the plural of what is whats). 775 func count(n int, what string) string { 776 if n == 1 { 777 return "1 " + what 778 } 779 return fmt.Sprintf("%d %ss", n, what) 780 }