generated.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package facts
  2. import (
  3. "bufio"
  4. "bytes"
  5. "io"
  6. "os"
  7. "reflect"
  8. "strings"
  9. "golang.org/x/tools/go/analysis"
  10. )
  11. type Generator int
  12. // A list of known generators we can detect
  13. const (
  14. Unknown Generator = iota
  15. Goyacc
  16. Cgo
  17. Stringer
  18. )
  19. var (
  20. // used by cgo before Go 1.11
  21. oldCgo = []byte("// Created by cgo - DO NOT EDIT")
  22. prefix = []byte("// Code generated ")
  23. suffix = []byte(" DO NOT EDIT.")
  24. nl = []byte("\n")
  25. crnl = []byte("\r\n")
  26. )
  27. func isGenerated(path string) (Generator, bool) {
  28. f, err := os.Open(path)
  29. if err != nil {
  30. return 0, false
  31. }
  32. defer f.Close()
  33. br := bufio.NewReader(f)
  34. for {
  35. s, err := br.ReadBytes('\n')
  36. if err != nil && err != io.EOF {
  37. return 0, false
  38. }
  39. s = bytes.TrimSuffix(s, crnl)
  40. s = bytes.TrimSuffix(s, nl)
  41. if bytes.HasPrefix(s, prefix) && bytes.HasSuffix(s, suffix) {
  42. text := string(s[len(prefix) : len(s)-len(suffix)])
  43. switch text {
  44. case "by goyacc.":
  45. return Goyacc, true
  46. case "by cmd/cgo;":
  47. return Cgo, true
  48. }
  49. if strings.HasPrefix(text, `by "stringer `) {
  50. return Stringer, true
  51. }
  52. return Unknown, true
  53. }
  54. if bytes.Equal(s, oldCgo) {
  55. return Cgo, true
  56. }
  57. if err == io.EOF {
  58. break
  59. }
  60. }
  61. return 0, false
  62. }
  63. var Generated = &analysis.Analyzer{
  64. Name: "isgenerated",
  65. Doc: "annotate file names that have been code generated",
  66. Run: func(pass *analysis.Pass) (interface{}, error) {
  67. m := map[string]Generator{}
  68. for _, f := range pass.Files {
  69. path := pass.Fset.PositionFor(f.Pos(), false).Filename
  70. g, ok := isGenerated(path)
  71. if ok {
  72. m[path] = g
  73. }
  74. }
  75. return m, nil
  76. },
  77. RunDespiteErrors: true,
  78. ResultType: reflect.TypeOf(map[string]Generator{}),
  79. }