github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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.stringerPtrs == nil { 191 f.stringerPtrs = 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 typ := f.pkg.types[l[0].Type] 196 _, ptrRecv := typ.Type.(*types.Pointer) 197 f.stringerPtrs[n[0].Obj] = ptrRecv 198 } 199 } 200 return 201 } 202 203 call, ok := node.(*ast.CallExpr) 204 if !ok { 205 return 206 } 207 208 // Construct name like pkg.Printf or pkg.Type.Printf for lookup. 209 var name string 210 switch x := call.Fun.(type) { 211 case *ast.Ident: 212 if fn, ok := f.pkg.uses[x].(*types.Func); ok { 213 var pkg string 214 if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg { 215 pkg = vcfg.ImportPath 216 } else { 217 pkg = fn.Pkg().Path() 218 } 219 name = pkg + "." + x.Name 220 break 221 } 222 223 case *ast.SelectorExpr: 224 // Check for "fmt.Printf". 225 if id, ok := x.X.(*ast.Ident); ok { 226 if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok { 227 name = pkgName.Imported().Path() + "." + x.Sel.Name 228 break 229 } 230 } 231 232 // Check for t.Logf where t is a *testing.T. 233 if sel := f.pkg.selectors[x]; sel != nil { 234 recv := sel.Recv() 235 if p, ok := recv.(*types.Pointer); ok { 236 recv = p.Elem() 237 } 238 if named, ok := recv.(*types.Named); ok { 239 obj := named.Obj() 240 var pkg string 241 if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg { 242 pkg = vcfg.ImportPath 243 } else { 244 pkg = obj.Pkg().Path() 245 } 246 name = pkg + "." + obj.Name() + "." + x.Sel.Name 247 break 248 } 249 } 250 } 251 if name == "" { 252 return 253 } 254 255 shortName := name[strings.LastIndex(name, ".")+1:] 256 257 _, ok = isPrint[name] 258 if !ok { 259 // Next look up just "printf", for use with -printfuncs. 260 _, ok = isPrint[strings.ToLower(shortName)] 261 } 262 if ok { 263 if strings.HasSuffix(name, "f") { 264 f.checkPrintf(call, shortName) 265 } else { 266 f.checkPrint(call, shortName) 267 } 268 } 269 } 270 271 // isStringer returns true if the provided declaration is a "String() string" 272 // method, an implementation of fmt.Stringer. 273 func isStringer(f *File, d *ast.FuncDecl) bool { 274 return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil && 275 len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 && 276 f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String] 277 } 278 279 // isFormatter reports whether t satisfies fmt.Formatter. 280 // Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt. 281 func (f *File) isFormatter(t types.Type) bool { 282 return formatterType != nil && types.Implements(t, formatterType) 283 } 284 285 // formatState holds the parsed representation of a printf directive such as "%3.*[4]d". 286 // It is constructed by parsePrintfVerb. 287 type formatState struct { 288 verb rune // the format verb: 'd' for "%d" 289 format string // the full format directive from % through verb, "%.3d". 290 name string // Printf, Sprintf etc. 291 flags []byte // the list of # + etc. 292 argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call 293 firstArg int // Index of first argument after the format in the Printf call. 294 // Used only during parse. 295 file *File 296 call *ast.CallExpr 297 argNum int // Which argument we're expecting to format now. 298 hasIndex bool // Whether the argument is indexed. 299 indexPending bool // Whether we have an indexed argument that has not resolved. 300 nbytes int // number of bytes of the format string consumed. 301 } 302 303 // checkPrintf checks a call to a formatted print routine such as Printf. 304 func (f *File) checkPrintf(call *ast.CallExpr, name string) { 305 format, idx := formatString(f, call) 306 if idx < 0 { 307 if *verbose { 308 f.Warn(call.Pos(), "can't check non-constant format in call to", name) 309 } 310 return 311 } 312 313 firstArg := idx + 1 // Arguments are immediately after format string. 314 if !strings.Contains(format, "%") { 315 if len(call.Args) > firstArg { 316 f.Badf(call.Pos(), "%s call has arguments but no formatting directives", name) 317 } 318 return 319 } 320 // Hard part: check formats against args. 321 argNum := firstArg 322 maxArgNum := firstArg 323 anyIndex := false 324 for i, w := 0, 0; i < len(format); i += w { 325 w = 1 326 if format[i] != '%' { 327 continue 328 } 329 state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum) 330 if state == nil { 331 return 332 } 333 w = len(state.format) 334 if !f.okPrintfArg(call, state) { // One error per format is enough. 335 return 336 } 337 if state.hasIndex { 338 anyIndex = true 339 } 340 if len(state.argNums) > 0 { 341 // Continue with the next sequential argument. 342 argNum = state.argNums[len(state.argNums)-1] + 1 343 } 344 for _, n := range state.argNums { 345 if n >= maxArgNum { 346 maxArgNum = n + 1 347 } 348 } 349 } 350 // Dotdotdot is hard. 351 if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 { 352 return 353 } 354 // If any formats are indexed, extra arguments are ignored. 355 if anyIndex { 356 return 357 } 358 // There should be no leftover arguments. 359 if maxArgNum != len(call.Args) { 360 expect := maxArgNum - firstArg 361 numArgs := len(call.Args) - firstArg 362 f.Badf(call.Pos(), "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg")) 363 } 364 } 365 366 // parseFlags accepts any printf flags. 367 func (s *formatState) parseFlags() { 368 for s.nbytes < len(s.format) { 369 switch c := s.format[s.nbytes]; c { 370 case '#', '0', '+', '-', ' ': 371 s.flags = append(s.flags, c) 372 s.nbytes++ 373 default: 374 return 375 } 376 } 377 } 378 379 // scanNum advances through a decimal number if present. 380 func (s *formatState) scanNum() { 381 for ; s.nbytes < len(s.format); s.nbytes++ { 382 c := s.format[s.nbytes] 383 if c < '0' || '9' < c { 384 return 385 } 386 } 387 } 388 389 // parseIndex scans an index expression. It returns false if there is a syntax error. 390 func (s *formatState) parseIndex() bool { 391 if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { 392 return true 393 } 394 // Argument index present. 395 s.nbytes++ // skip '[' 396 start := s.nbytes 397 s.scanNum() 398 ok := true 399 if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { 400 ok = false 401 s.nbytes = strings.Index(s.format, "]") 402 if s.nbytes < 0 { 403 s.file.Badf(s.call.Pos(), "%s format %s is missing closing ]", s.name, s.format) 404 return false 405 } 406 } 407 arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) 408 if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) { 409 s.file.Badf(s.call.Pos(), "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes]) 410 return false 411 } 412 s.nbytes++ // skip ']' 413 arg := int(arg32) 414 arg += s.firstArg - 1 // We want to zero-index the actual arguments. 415 s.argNum = arg 416 s.hasIndex = true 417 s.indexPending = true 418 return true 419 } 420 421 // parseNum scans a width or precision (or *). It returns false if there's a bad index expression. 422 func (s *formatState) parseNum() bool { 423 if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { 424 if s.indexPending { // Absorb it. 425 s.indexPending = false 426 } 427 s.nbytes++ 428 s.argNums = append(s.argNums, s.argNum) 429 s.argNum++ 430 } else { 431 s.scanNum() 432 } 433 return true 434 } 435 436 // parsePrecision scans for a precision. It returns false if there's a bad index expression. 437 func (s *formatState) parsePrecision() bool { 438 // If there's a period, there may be a precision. 439 if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { 440 s.flags = append(s.flags, '.') // Treat precision as a flag. 441 s.nbytes++ 442 if !s.parseIndex() { 443 return false 444 } 445 if !s.parseNum() { 446 return false 447 } 448 } 449 return true 450 } 451 452 // parsePrintfVerb looks the formatting directive that begins the format string 453 // and returns a formatState that encodes what the directive wants, without looking 454 // at the actual arguments present in the call. The result is nil if there is an error. 455 func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState { 456 state := &formatState{ 457 format: format, 458 name: name, 459 flags: make([]byte, 0, 5), 460 argNum: argNum, 461 argNums: make([]int, 0, 1), 462 nbytes: 1, // There's guaranteed to be a percent sign. 463 firstArg: firstArg, 464 file: f, 465 call: call, 466 } 467 // There may be flags. 468 state.parseFlags() 469 // There may be an index. 470 if !state.parseIndex() { 471 return nil 472 } 473 // There may be a width. 474 if !state.parseNum() { 475 return nil 476 } 477 // There may be a precision. 478 if !state.parsePrecision() { 479 return nil 480 } 481 // Now a verb, possibly prefixed by an index (which we may already have). 482 if !state.indexPending && !state.parseIndex() { 483 return nil 484 } 485 if state.nbytes == len(state.format) { 486 f.Badf(call.Pos(), "%s format %s is missing verb at end of string", name, state.format) 487 return nil 488 } 489 verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) 490 state.verb = verb 491 state.nbytes += w 492 if verb != '%' { 493 state.argNums = append(state.argNums, state.argNum) 494 } 495 state.format = state.format[:state.nbytes] 496 return state 497 } 498 499 // printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask. 500 type printfArgType int 501 502 const ( 503 argBool printfArgType = 1 << iota 504 argInt 505 argRune 506 argString 507 argFloat 508 argComplex 509 argPointer 510 anyType printfArgType = ^0 511 ) 512 513 type printVerb struct { 514 verb rune // User may provide verb through Formatter; could be a rune. 515 flags string // known flags are all ASCII 516 typ printfArgType 517 } 518 519 // Common flag sets for printf verbs. 520 const ( 521 noFlag = "" 522 numFlag = " -+.0" 523 sharpNumFlag = " -+.0#" 524 allFlags = " -+.0#" 525 ) 526 527 // printVerbs identifies which flags are known to printf for each verb. 528 var printVerbs = []printVerb{ 529 // '-' is a width modifier, always valid. 530 // '.' is a precision for float, max width for strings. 531 // '+' is required sign for numbers, Go format for %v. 532 // '#' is alternate format for several verbs. 533 // ' ' is spacer for numbers 534 {'%', noFlag, 0}, 535 {'b', numFlag, argInt | argFloat | argComplex}, 536 {'c', "-", argRune | argInt}, 537 {'d', numFlag, argInt}, 538 {'e', sharpNumFlag, argFloat | argComplex}, 539 {'E', sharpNumFlag, argFloat | argComplex}, 540 {'f', sharpNumFlag, argFloat | argComplex}, 541 {'F', sharpNumFlag, argFloat | argComplex}, 542 {'g', sharpNumFlag, argFloat | argComplex}, 543 {'G', sharpNumFlag, argFloat | argComplex}, 544 {'o', sharpNumFlag, argInt}, 545 {'p', "-#", argPointer}, 546 {'q', " -+.0#", argRune | argInt | argString}, 547 {'s', " -+.0", argString}, 548 {'t', "-", argBool}, 549 {'T', "-", anyType}, 550 {'U', "-#", argRune | argInt}, 551 {'v', allFlags, anyType}, 552 {'x', sharpNumFlag, argRune | argInt | argString}, 553 {'X', sharpNumFlag, argRune | argInt | argString}, 554 } 555 556 // okPrintfArg compares the formatState to the arguments actually present, 557 // reporting any discrepancies it can discern. If the final argument is ellipsissed, 558 // there's little it can do for that. 559 func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) { 560 var v printVerb 561 found := false 562 // Linear scan is fast enough for a small list. 563 for _, v = range printVerbs { 564 if v.verb == state.verb { 565 found = true 566 break 567 } 568 } 569 570 // Does current arg implement fmt.Formatter? 571 formatter := false 572 if state.argNum < len(call.Args) { 573 if tv, ok := f.pkg.types[call.Args[state.argNum]]; ok { 574 formatter = f.isFormatter(tv.Type) 575 } 576 } 577 578 if !formatter { 579 if !found { 580 f.Badf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb) 581 return false 582 } 583 for _, flag := range state.flags { 584 // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11. 585 // See issues 23598 and 23605. 586 if flag == '0' { 587 continue 588 } 589 if !strings.ContainsRune(v.flags, rune(flag)) { 590 f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag) 591 return false 592 } 593 } 594 } 595 // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all 596 // but the final arg must be an integer. 597 trueArgs := 1 598 if state.verb == '%' { 599 trueArgs = 0 600 } 601 nargs := len(state.argNums) 602 for i := 0; i < nargs-trueArgs; i++ { 603 argNum := state.argNums[i] 604 if !f.argCanBeChecked(call, i, state) { 605 return 606 } 607 arg := call.Args[argNum] 608 if !f.matchArgType(argInt, nil, arg) { 609 f.Badf(call.Pos(), "%s format %s uses non-int %s as argument of *", state.name, state.format, f.gofmt(arg)) 610 return false 611 } 612 } 613 if state.verb == '%' || formatter { 614 return true 615 } 616 argNum := state.argNums[len(state.argNums)-1] 617 if !f.argCanBeChecked(call, len(state.argNums)-1, state) { 618 return false 619 } 620 arg := call.Args[argNum] 621 if f.isFunctionValue(arg) && state.verb != 'p' && state.verb != 'T' { 622 f.Badf(call.Pos(), "%s format %s arg %s is a func value, not called", state.name, state.format, f.gofmt(arg)) 623 return false 624 } 625 if !f.matchArgType(v.typ, nil, arg) { 626 typeString := "" 627 if typ := f.pkg.types[arg].Type; typ != nil { 628 typeString = typ.String() 629 } 630 f.Badf(call.Pos(), "%s format %s has arg %s of wrong type %s", state.name, state.format, f.gofmt(arg), typeString) 631 return false 632 } 633 if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) { 634 f.Badf(call.Pos(), "%s format %s with arg %s causes recursive String method call", state.name, state.format, f.gofmt(arg)) 635 return false 636 } 637 return true 638 } 639 640 // recursiveStringer reports whether the provided argument is r or &r for the 641 // fmt.Stringer receiver identifier r. 642 func (f *File) recursiveStringer(e ast.Expr) bool { 643 if len(f.stringerPtrs) == 0 { 644 return false 645 } 646 ptr := false 647 var obj *ast.Object 648 switch e := e.(type) { 649 case *ast.Ident: 650 obj = e.Obj 651 case *ast.UnaryExpr: 652 if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND { 653 obj = id.Obj 654 ptr = true 655 } 656 } 657 658 // It's unlikely to be a recursive stringer if it has a Format method. 659 if typ := f.pkg.types[e].Type; typ != nil { 660 // Not a perfect match; see issue 6259. 661 if f.hasMethod(typ, "Format") { 662 return false 663 } 664 } 665 666 // We compare the underlying Object, which checks that the identifier 667 // is the one we declared as the receiver for the String method in 668 // which this printf appears. 669 ptrRecv, exist := f.stringerPtrs[obj] 670 if !exist { 671 return false 672 } 673 // We also need to check that using &t when we declared String 674 // on (t *T) is ok; in such a case, the address is printed. 675 if ptr && ptrRecv { 676 return false 677 } 678 return true 679 } 680 681 // isFunctionValue reports whether the expression is a function as opposed to a function call. 682 // It is almost always a mistake to print a function value. 683 func (f *File) isFunctionValue(e ast.Expr) bool { 684 if typ := f.pkg.types[e].Type; typ != nil { 685 _, ok := typ.(*types.Signature) 686 return ok 687 } 688 return false 689 } 690 691 // argCanBeChecked reports whether the specified argument is statically present; 692 // it may be beyond the list of arguments or in a terminal slice... argument, which 693 // means we can't see it. 694 func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, state *formatState) bool { 695 argNum := state.argNums[formatArg] 696 if argNum <= 0 { 697 // Shouldn't happen, so catch it with prejudice. 698 panic("negative arg num") 699 } 700 if argNum < len(call.Args)-1 { 701 return true // Always OK. 702 } 703 if call.Ellipsis.IsValid() { 704 return false // We just can't tell; there could be many more arguments. 705 } 706 if argNum < len(call.Args) { 707 return true 708 } 709 // There are bad indexes in the format or there are fewer arguments than the format needs. 710 // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi". 711 arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed. 712 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")) 713 return false 714 } 715 716 // printFormatRE is the regexp we match and report as a possible format string 717 // in the first argument to unformatted prints like fmt.Print. 718 // We exclude the space flag, so that printing a string like "x % y" is not reported as a format. 719 var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE) 720 721 const ( 722 flagsRE = `[+\-#]*` 723 indexOptRE = `(\[[0-9]+\])?` 724 numOptRE = `([0-9]+|` + indexOptRE + `\*)?` 725 verbRE = `[bcdefgopqstvxEFGUX]` 726 ) 727 728 // checkPrint checks a call to an unformatted print routine such as Println. 729 func (f *File) checkPrint(call *ast.CallExpr, name string) { 730 firstArg := 0 731 typ := f.pkg.types[call.Fun].Type 732 if typ == nil { 733 // Skip checking functions with unknown type. 734 return 735 } 736 if sig, ok := typ.(*types.Signature); ok { 737 if !sig.Variadic() { 738 // Skip checking non-variadic functions. 739 return 740 } 741 params := sig.Params() 742 firstArg = params.Len() - 1 743 744 typ := params.At(firstArg).Type() 745 typ = typ.(*types.Slice).Elem() 746 it, ok := typ.(*types.Interface) 747 if !ok || !it.Empty() { 748 // Skip variadic functions accepting non-interface{} args. 749 return 750 } 751 } 752 args := call.Args 753 if len(args) <= firstArg { 754 // Skip calls without variadic args. 755 return 756 } 757 args = args[firstArg:] 758 759 if firstArg == 0 { 760 if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { 761 if x, ok := sel.X.(*ast.Ident); ok { 762 if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { 763 f.Badf(call.Pos(), "%s does not take io.Writer but has first arg %s", name, f.gofmt(call.Args[0])) 764 } 765 } 766 } 767 } 768 769 arg := args[0] 770 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { 771 // Ignore trailing % character in lit.Value. 772 // The % in "abc 0.0%" couldn't be a formatting directive. 773 s := strings.TrimSuffix(lit.Value, `%"`) 774 if strings.Contains(s, "%") { 775 m := printFormatRE.FindStringSubmatch(s) 776 if m != nil { 777 f.Badf(call.Pos(), "%s call has possible formatting directive %s", name, m[0]) 778 } 779 } 780 } 781 if strings.HasSuffix(name, "ln") { 782 // The last item, if a string, should not have a newline. 783 arg = args[len(args)-1] 784 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { 785 str, _ := strconv.Unquote(lit.Value) 786 if strings.HasSuffix(str, "\n") { 787 f.Badf(call.Pos(), "%s arg list ends with redundant newline", name) 788 } 789 } 790 } 791 for _, arg := range args { 792 if f.isFunctionValue(arg) { 793 f.Badf(call.Pos(), "%s arg %s is a func value, not called", name, f.gofmt(arg)) 794 } 795 if f.recursiveStringer(arg) { 796 f.Badf(call.Pos(), "%s arg %s causes recursive call to String method", name, f.gofmt(arg)) 797 } 798 } 799 } 800 801 // count(n, what) returns "1 what" or "N whats" 802 // (assuming the plural of what is whats). 803 func count(n int, what string) string { 804 if n == 1 { 805 return "1 " + what 806 } 807 return fmt.Sprintf("%d %ss", n, what) 808 }