validate.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package analysis
  2. import (
  3. "fmt"
  4. "reflect"
  5. "unicode"
  6. )
  7. // Validate reports an error if any of the analyzers are misconfigured.
  8. // Checks include:
  9. // that the name is a valid identifier;
  10. // that analyzer names are unique;
  11. // that the Requires graph is acylic;
  12. // that analyzer fact types are unique;
  13. // that each fact type is a pointer.
  14. func Validate(analyzers []*Analyzer) error {
  15. names := make(map[string]bool)
  16. // Map each fact type to its sole generating analyzer.
  17. factTypes := make(map[reflect.Type]*Analyzer)
  18. // Traverse the Requires graph, depth first.
  19. const (
  20. white = iota
  21. grey
  22. black
  23. finished
  24. )
  25. color := make(map[*Analyzer]uint8)
  26. var visit func(a *Analyzer) error
  27. visit = func(a *Analyzer) error {
  28. if a == nil {
  29. return fmt.Errorf("nil *Analyzer")
  30. }
  31. if color[a] == white {
  32. color[a] = grey
  33. // names
  34. if !validIdent(a.Name) {
  35. return fmt.Errorf("invalid analyzer name %q", a)
  36. }
  37. if names[a.Name] {
  38. return fmt.Errorf("duplicate analyzer name %q", a)
  39. }
  40. names[a.Name] = true
  41. if a.Doc == "" {
  42. return fmt.Errorf("analyzer %q is undocumented", a)
  43. }
  44. // fact types
  45. for _, f := range a.FactTypes {
  46. if f == nil {
  47. return fmt.Errorf("analyzer %s has nil FactType", a)
  48. }
  49. t := reflect.TypeOf(f)
  50. if prev := factTypes[t]; prev != nil {
  51. return fmt.Errorf("fact type %s registered by two analyzers: %v, %v",
  52. t, a, prev)
  53. }
  54. if t.Kind() != reflect.Ptr {
  55. return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
  56. }
  57. factTypes[t] = a
  58. }
  59. // recursion
  60. for i, req := range a.Requires {
  61. if err := visit(req); err != nil {
  62. return fmt.Errorf("%s.Requires[%d]: %v", a.Name, i, err)
  63. }
  64. }
  65. color[a] = black
  66. }
  67. return nil
  68. }
  69. for _, a := range analyzers {
  70. if err := visit(a); err != nil {
  71. return err
  72. }
  73. }
  74. // Reject duplicates among analyzers.
  75. // Precondition: color[a] == black.
  76. // Postcondition: color[a] == finished.
  77. for _, a := range analyzers {
  78. if color[a] == finished {
  79. return fmt.Errorf("duplicate analyzer: %s", a.Name)
  80. }
  81. color[a] = finished
  82. }
  83. return nil
  84. }
  85. func validIdent(name string) bool {
  86. for i, r := range name {
  87. if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
  88. return false
  89. }
  90. }
  91. return name != ""
  92. }