You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

linter.go 2.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package lint
  2. import (
  3. "bufio"
  4. "bytes"
  5. "fmt"
  6. "go/token"
  7. "os"
  8. "sync"
  9. )
  10. // ReadFile defines an abstraction for reading files.
  11. type ReadFile func(path string) (result []byte, err error)
  12. type disabledIntervalsMap = map[string][]DisabledInterval
  13. // Linter is used for linting set of files.
  14. type Linter struct {
  15. reader ReadFile
  16. }
  17. // New creates a new Linter
  18. func New(reader ReadFile) Linter {
  19. return Linter{reader: reader}
  20. }
  21. var (
  22. genHdr = []byte("// Code generated ")
  23. genFtr = []byte(" DO NOT EDIT.")
  24. )
  25. // Lint lints a set of files with the specified rule.
  26. func (l *Linter) Lint(packages [][]string, ruleSet []Rule, config Config) (<-chan Failure, error) {
  27. failures := make(chan Failure)
  28. var wg sync.WaitGroup
  29. for _, pkg := range packages {
  30. wg.Add(1)
  31. go func(pkg []string) {
  32. if err := l.lintPackage(pkg, ruleSet, config, failures); err != nil {
  33. fmt.Fprintln(os.Stderr, err)
  34. os.Exit(1)
  35. }
  36. defer wg.Done()
  37. }(pkg)
  38. }
  39. go func() {
  40. wg.Wait()
  41. close(failures)
  42. }()
  43. return failures, nil
  44. }
  45. func (l *Linter) lintPackage(filenames []string, ruleSet []Rule, config Config, failures chan Failure) error {
  46. pkg := &Package{
  47. fset: token.NewFileSet(),
  48. files: map[string]*File{},
  49. mu: sync.Mutex{},
  50. }
  51. for _, filename := range filenames {
  52. content, err := l.reader(filename)
  53. if err != nil {
  54. return err
  55. }
  56. if isGenerated(content) && !config.IgnoreGeneratedHeader {
  57. continue
  58. }
  59. file, err := NewFile(filename, content, pkg)
  60. if err != nil {
  61. return err
  62. }
  63. pkg.files[filename] = file
  64. }
  65. if len(pkg.files) == 0 {
  66. return nil
  67. }
  68. pkg.lint(ruleSet, config, failures)
  69. return nil
  70. }
  71. // isGenerated reports whether the source file is generated code
  72. // according the rules from https://golang.org/s/generatedcode.
  73. // This is inherited from the original go lint.
  74. func isGenerated(src []byte) bool {
  75. sc := bufio.NewScanner(bytes.NewReader(src))
  76. for sc.Scan() {
  77. b := sc.Bytes()
  78. if bytes.HasPrefix(b, genHdr) && bytes.HasSuffix(b, genFtr) && len(b) >= len(genHdr)+len(genFtr) {
  79. return true
  80. }
  81. }
  82. return false
  83. }