PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/cmd/govet/govet.go

https://bitbucket.org/adkulkar/goose
Go | 573 lines | 429 code | 52 blank | 92 comment | 115 complexity | 27168f6ef8ae460af52f9e3d656ffbce MD5 | raw file
Possible License(s): BSD-3-Clause
  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. // Govet is a simple checker for static errors in Go source code.
  5. // See doc.go for more information.
  6. package main
  7. import (
  8. "bytes"
  9. "flag"
  10. "fmt"
  11. "go/ast"
  12. "go/parser"
  13. "go/printer"
  14. "go/token"
  15. "io"
  16. "os"
  17. "path/filepath"
  18. "reflect"
  19. "strconv"
  20. "strings"
  21. "unicode/utf8"
  22. )
  23. var verbose = flag.Bool("v", false, "verbose")
  24. var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
  25. var exitCode = 0
  26. // setExit sets the value for os.Exit when it is called, later. It
  27. // remembers the highest value.
  28. func setExit(err int) {
  29. if err > exitCode {
  30. exitCode = err
  31. }
  32. }
  33. // Usage is a replacement usage function for the flags package.
  34. func Usage() {
  35. fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
  36. flag.PrintDefaults()
  37. os.Exit(2)
  38. }
  39. // File is a wrapper for the state of a file used in the parser.
  40. // The parse tree walkers are all methods of this type.
  41. type File struct {
  42. fset *token.FileSet
  43. file *ast.File
  44. b bytes.Buffer // for use by methods
  45. }
  46. func main() {
  47. flag.Usage = Usage
  48. flag.Parse()
  49. if *printfuncs != "" {
  50. for _, name := range strings.Split(*printfuncs, ",") {
  51. if len(name) == 0 {
  52. flag.Usage()
  53. }
  54. skip := 0
  55. if colon := strings.LastIndex(name, ":"); colon > 0 {
  56. var err error
  57. skip, err = strconv.Atoi(name[colon+1:])
  58. if err != nil {
  59. errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
  60. }
  61. name = name[:colon]
  62. }
  63. name = strings.ToLower(name)
  64. if name[len(name)-1] == 'f' {
  65. printfList[name] = skip
  66. } else {
  67. printList[name] = skip
  68. }
  69. }
  70. }
  71. if flag.NArg() == 0 {
  72. doFile("stdin", os.Stdin)
  73. } else {
  74. for _, name := range flag.Args() {
  75. // Is it a directory?
  76. if fi, err := os.Stat(name); err == nil && fi.IsDir() {
  77. walkDir(name)
  78. } else {
  79. doFile(name, nil)
  80. }
  81. }
  82. }
  83. os.Exit(exitCode)
  84. }
  85. // doFile analyzes one file. If the reader is nil, the source code is read from the
  86. // named file.
  87. func doFile(name string, reader io.Reader) {
  88. fs := token.NewFileSet()
  89. parsedFile, err := parser.ParseFile(fs, name, reader, 0)
  90. if err != nil {
  91. errorf("%s: %s", name, err)
  92. return
  93. }
  94. file := &File{fset: fs, file: parsedFile}
  95. file.checkFile(name, parsedFile)
  96. }
  97. func visit(path string, f os.FileInfo, err error) error {
  98. if err != nil {
  99. errorf("walk error: %s", err)
  100. return nil
  101. }
  102. if !f.IsDir() && strings.HasSuffix(path, ".go") {
  103. doFile(path, nil)
  104. }
  105. return nil
  106. }
  107. // walkDir recursively walks the tree looking for .go files.
  108. func walkDir(root string) {
  109. filepath.Walk(root, visit)
  110. }
  111. // error formats the error to standard error, adding program
  112. // identification and a newline
  113. func errorf(format string, args ...interface{}) {
  114. fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...)
  115. setExit(2)
  116. }
  117. // Println is fmt.Println guarded by -v.
  118. func Println(args ...interface{}) {
  119. if !*verbose {
  120. return
  121. }
  122. fmt.Println(args...)
  123. }
  124. // Printf is fmt.Printf guarded by -v.
  125. func Printf(format string, args ...interface{}) {
  126. if !*verbose {
  127. return
  128. }
  129. fmt.Printf(format+"\n", args...)
  130. }
  131. // Bad reports an error and sets the exit code..
  132. func (f *File) Bad(pos token.Pos, args ...interface{}) {
  133. f.Warn(pos, args...)
  134. setExit(1)
  135. }
  136. // Badf reports a formatted error and sets the exit code.
  137. func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
  138. f.Warnf(pos, format, args...)
  139. setExit(1)
  140. }
  141. // Warn reports an error but does not set the exit code.
  142. func (f *File) Warn(pos token.Pos, args ...interface{}) {
  143. loc := f.fset.Position(pos).String() + ": "
  144. fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...))
  145. }
  146. // Warnf reports a formatted error but does not set the exit code.
  147. func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
  148. loc := f.fset.Position(pos).String() + ": "
  149. fmt.Fprintf(os.Stderr, loc+format+"\n", args...)
  150. }
  151. // checkFile checks all the top-level declarations in a file.
  152. func (f *File) checkFile(name string, file *ast.File) {
  153. Println("Checking file", name)
  154. ast.Walk(f, file)
  155. }
  156. // Visit implements the ast.Visitor interface.
  157. func (f *File) Visit(node ast.Node) ast.Visitor {
  158. switch n := node.(type) {
  159. case *ast.CallExpr:
  160. f.checkCallExpr(n)
  161. case *ast.Field:
  162. f.checkFieldTag(n)
  163. case *ast.FuncDecl:
  164. f.checkMethodDecl(n)
  165. case *ast.InterfaceType:
  166. f.checkInterfaceType(n)
  167. }
  168. return f
  169. }
  170. // checkMethodDecl checks for canonical method signatures
  171. // in method declarations.
  172. func (f *File) checkMethodDecl(d *ast.FuncDecl) {
  173. if d.Recv == nil {
  174. // not a method
  175. return
  176. }
  177. f.checkMethod(d.Name, d.Type)
  178. }
  179. // checkInterfaceType checks for canonical method signatures
  180. // in interface definitions.
  181. func (f *File) checkInterfaceType(t *ast.InterfaceType) {
  182. for _, field := range t.Methods.List {
  183. for _, id := range field.Names {
  184. f.checkMethod(id, field.Type.(*ast.FuncType))
  185. }
  186. }
  187. }
  188. type MethodSig struct {
  189. args []string
  190. results []string
  191. }
  192. // canonicalMethods lists the input and output types for Go methods
  193. // that are checked using dynamic interface checks. Because the
  194. // checks are dynamic, such methods would not cause a compile error
  195. // if they have the wrong signature: instead the dynamic check would
  196. // fail, sometimes mysteriously. If a method is found with a name listed
  197. // here but not the input/output types listed here, govet complains.
  198. //
  199. // A few of the canonical methods have very common names.
  200. // For example, a type might implement a Scan method that
  201. // has nothing to do with fmt.Scanner, but we still want to check
  202. // the methods that are intended to implement fmt.Scanner.
  203. // To do that, the arguments that have a + prefix are treated as
  204. // signals that the canonical meaning is intended: if a Scan
  205. // method doesn't have a fmt.ScanState as its first argument,
  206. // we let it go. But if it does have a fmt.ScanState, then the
  207. // rest has to match.
  208. var canonicalMethods = map[string]MethodSig{
  209. // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict
  210. "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter
  211. "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder
  212. "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder
  213. "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler
  214. "MarshalXML": {[]string{}, []string{"[]byte", "error"}}, // xml.Marshaler
  215. "Peek": {[]string{"=int"}, []string{"[]byte", "error"}}, // image.reader (matching bufio.Reader)
  216. "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader
  217. "ReadFrom": {[]string{"=io.Reader"}, []string{"int64", "error"}}, // io.ReaderFrom
  218. "ReadRune": {[]string{}, []string{"rune", "int", "error"}}, // io.RuneReader
  219. "Scan": {[]string{"=fmt.ScanState", "rune"}, []string{"error"}}, // fmt.Scanner
  220. "Seek": {[]string{"=int64", "int"}, []string{"int64", "error"}}, // io.Seeker
  221. "UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}}, // json.Unmarshaler
  222. "UnreadByte": {[]string{}, []string{"error"}},
  223. "UnreadRune": {[]string{}, []string{"error"}},
  224. "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer)
  225. "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo
  226. }
  227. func (f *File) checkMethod(id *ast.Ident, t *ast.FuncType) {
  228. // Expected input/output.
  229. expect, ok := canonicalMethods[id.Name]
  230. if !ok {
  231. return
  232. }
  233. // Actual input/output
  234. args := typeFlatten(t.Params.List)
  235. var results []ast.Expr
  236. if t.Results != nil {
  237. results = typeFlatten(t.Results.List)
  238. }
  239. // Do the =s (if any) all match?
  240. if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") {
  241. return
  242. }
  243. // Everything must match.
  244. if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") {
  245. expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
  246. if len(expect.results) == 1 {
  247. expectFmt += " " + argjoin(expect.results)
  248. } else if len(expect.results) > 1 {
  249. expectFmt += " (" + argjoin(expect.results) + ")"
  250. }
  251. f.b.Reset()
  252. if err := printer.Fprint(&f.b, f.fset, t); err != nil {
  253. fmt.Fprintf(&f.b, "<%s>", err)
  254. }
  255. actual := f.b.String()
  256. if strings.HasPrefix(actual, "func(") {
  257. actual = actual[4:]
  258. }
  259. actual = id.Name + actual
  260. f.Warnf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
  261. }
  262. }
  263. func argjoin(x []string) string {
  264. y := make([]string, len(x))
  265. for i, s := range x {
  266. if s[0] == '=' {
  267. s = s[1:]
  268. }
  269. y[i] = s
  270. }
  271. return strings.Join(y, ", ")
  272. }
  273. // Turn parameter list into slice of types
  274. // (in the ast, types are Exprs).
  275. // Have to handle f(int, bool) and f(x, y, z int)
  276. // so not a simple 1-to-1 conversion.
  277. func typeFlatten(l []*ast.Field) []ast.Expr {
  278. var t []ast.Expr
  279. for _, f := range l {
  280. if len(f.Names) == 0 {
  281. t = append(t, f.Type)
  282. continue
  283. }
  284. for _ = range f.Names {
  285. t = append(t, f.Type)
  286. }
  287. }
  288. return t
  289. }
  290. // Does each type in expect with the given prefix match the corresponding type in actual?
  291. func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bool {
  292. for i, x := range expect {
  293. if !strings.HasPrefix(x, prefix) {
  294. continue
  295. }
  296. if i >= len(actual) {
  297. return false
  298. }
  299. if !f.matchParamType(x, actual[i]) {
  300. return false
  301. }
  302. }
  303. if prefix == "" && len(actual) > len(expect) {
  304. return false
  305. }
  306. return true
  307. }
  308. // Does this one type match?
  309. func (f *File) matchParamType(expect string, actual ast.Expr) bool {
  310. if strings.HasPrefix(expect, "=") {
  311. expect = expect[1:]
  312. }
  313. // Strip package name if we're in that package.
  314. if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' {
  315. expect = expect[n+1:]
  316. }
  317. // Overkill but easy.
  318. f.b.Reset()
  319. printer.Fprint(&f.b, f.fset, actual)
  320. return f.b.String() == expect
  321. }
  322. // checkField checks a struct field tag.
  323. func (f *File) checkFieldTag(field *ast.Field) {
  324. if field.Tag == nil {
  325. return
  326. }
  327. tag, err := strconv.Unquote(field.Tag.Value)
  328. if err != nil {
  329. f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
  330. return
  331. }
  332. // Check tag for validity by appending
  333. // new key:value to end and checking that
  334. // the tag parsing code can find it.
  335. if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
  336. f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
  337. return
  338. }
  339. }
  340. // checkCallExpr checks a call expression.
  341. func (f *File) checkCallExpr(call *ast.CallExpr) {
  342. switch x := call.Fun.(type) {
  343. case *ast.Ident:
  344. f.checkCall(call, x.Name)
  345. case *ast.SelectorExpr:
  346. f.checkCall(call, x.Sel.Name)
  347. }
  348. }
  349. // printfList records the formatted-print functions. The value is the location
  350. // of the format parameter. Names are lower-cased so the lookup is
  351. // case insensitive.
  352. var printfList = map[string]int{
  353. "errorf": 0,
  354. "fatalf": 0,
  355. "fprintf": 1,
  356. "panicf": 0,
  357. "printf": 0,
  358. "sprintf": 0,
  359. }
  360. // printList records the unformatted-print functions. The value is the location
  361. // of the first parameter to be printed. Names are lower-cased so the lookup is
  362. // case insensitive.
  363. var printList = map[string]int{
  364. "error": 0,
  365. "fatal": 0,
  366. "fprint": 1, "fprintln": 1,
  367. "panic": 0, "panicln": 0,
  368. "print": 0, "println": 0,
  369. "sprint": 0, "sprintln": 0,
  370. }
  371. // checkCall triggers the print-specific checks if the call invokes a print function.
  372. func (f *File) checkCall(call *ast.CallExpr, Name string) {
  373. name := strings.ToLower(Name)
  374. if skip, ok := printfList[name]; ok {
  375. f.checkPrintf(call, Name, skip)
  376. return
  377. }
  378. if skip, ok := printList[name]; ok {
  379. f.checkPrint(call, Name, skip)
  380. return
  381. }
  382. }
  383. // checkPrintf checks a call to a formatted print routine such as Printf.
  384. // The skip argument records how many arguments to ignore; that is,
  385. // call.Args[skip] is (well, should be) the format argument.
  386. func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
  387. if len(call.Args) <= skip {
  388. return
  389. }
  390. // Common case: literal is first argument.
  391. arg := call.Args[skip]
  392. lit, ok := arg.(*ast.BasicLit)
  393. if !ok {
  394. // Too hard to check.
  395. if *verbose {
  396. f.Warn(call.Pos(), "can't check args for call to", name)
  397. }
  398. return
  399. }
  400. if lit.Kind == token.STRING {
  401. if !strings.Contains(lit.Value, "%") {
  402. if len(call.Args) > skip+1 {
  403. f.Badf(call.Pos(), "no formatting directive in %s call", name)
  404. }
  405. return
  406. }
  407. }
  408. // Hard part: check formats against args.
  409. // Trivial but useful test: count.
  410. numArgs := 0
  411. for i, w := 0, 0; i < len(lit.Value); i += w {
  412. w = 1
  413. if lit.Value[i] == '%' {
  414. nbytes, nargs := parsePrintfVerb(lit.Value[i:])
  415. w = nbytes
  416. numArgs += nargs
  417. }
  418. }
  419. expect := len(call.Args) - (skip + 1)
  420. if numArgs != expect {
  421. f.Badf(call.Pos(), "wrong number of args in %s call: %d needed but %d args", name, numArgs, expect)
  422. }
  423. }
  424. // parsePrintfVerb returns the number of bytes and number of arguments
  425. // consumed by the Printf directive that begins s, including its percent sign
  426. // and verb.
  427. func parsePrintfVerb(s string) (nbytes, nargs int) {
  428. // There's guaranteed a percent sign.
  429. nbytes = 1
  430. end := len(s)
  431. // There may be flags.
  432. FlagLoop:
  433. for nbytes < end {
  434. switch s[nbytes] {
  435. case '#', '0', '+', '-', ' ':
  436. nbytes++
  437. default:
  438. break FlagLoop
  439. }
  440. }
  441. getNum := func() {
  442. if nbytes < end && s[nbytes] == '*' {
  443. nbytes++
  444. nargs++
  445. } else {
  446. for nbytes < end && '0' <= s[nbytes] && s[nbytes] <= '9' {
  447. nbytes++
  448. }
  449. }
  450. }
  451. // There may be a width.
  452. getNum()
  453. // If there's a period, there may be a precision.
  454. if nbytes < end && s[nbytes] == '.' {
  455. nbytes++
  456. getNum()
  457. }
  458. // Now a verb.
  459. c, w := utf8.DecodeRuneInString(s[nbytes:])
  460. nbytes += w
  461. if c != '%' {
  462. nargs++
  463. }
  464. return
  465. }
  466. // checkPrint checks a call to an unformatted print routine such as Println.
  467. // The skip argument records how many arguments to ignore; that is,
  468. // call.Args[skip] is the first argument to be printed.
  469. func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
  470. isLn := strings.HasSuffix(name, "ln")
  471. args := call.Args
  472. if len(args) <= skip {
  473. if *verbose && !isLn {
  474. f.Badf(call.Pos(), "no args in %s call", name)
  475. }
  476. return
  477. }
  478. arg := args[skip]
  479. if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
  480. if strings.Contains(lit.Value, "%") {
  481. f.Badf(call.Pos(), "possible formatting directive in %s call", name)
  482. }
  483. }
  484. if isLn {
  485. // The last item, if a string, should not have a newline.
  486. arg = args[len(call.Args)-1]
  487. if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
  488. if strings.HasSuffix(lit.Value, `\n"`) {
  489. f.Badf(call.Pos(), "%s call ends with newline", name)
  490. }
  491. }
  492. }
  493. }
  494. // This function never executes, but it serves as a simple test for the program.
  495. // Test with make test.
  496. func BadFunctionUsedInTests() {
  497. fmt.Println() // not an error
  498. fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
  499. fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args in Printf call"
  500. fmt.Printf("%s%%%d", "hi", 3) // correct
  501. fmt.Printf("%.*d", 3, 3) // correct
  502. fmt.Printf("%.*d", 3, 3, 3) // ERROR "wrong number of args in Printf call"
  503. printf("now is the time", "buddy") // ERROR "no formatting directive"
  504. Printf("now is the time", "buddy") // ERROR "no formatting directive"
  505. Printf("hi") // ok
  506. f := new(File)
  507. f.Warn(0, "%s", "hello", 3) // ERROR "possible formatting directive in Warn call"
  508. f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
  509. }
  510. type BadTypeUsedInTests struct {
  511. X int "hello" // ERROR "struct field tag"
  512. }
  513. func (t *BadTypeUsedInTests) Scan(x fmt.ScanState, c byte) { // ERROR "method Scan[(]x fmt.ScanState, c byte[)] should have signature Scan[(]fmt.ScanState, rune[)] error"
  514. }
  515. type BadInterfaceUsedInTests interface {
  516. ReadByte() byte // ERROR "method ReadByte[(][)] byte should have signature ReadByte[(][)] [(]byte, error[)]"
  517. }
  518. // printf is used by the test.
  519. func printf(format string, args ...interface{}) {
  520. panic("don't call - testing only")
  521. }