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.

validate.go 2.1KB

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