validate.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright 2018 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. package analysis
  5. import (
  6. "fmt"
  7. "reflect"
  8. "strings"
  9. "unicode"
  10. )
  11. // Validate reports an error if any of the analyzers are misconfigured.
  12. // Checks include:
  13. // that the name is a valid identifier;
  14. // that the Requires graph is acyclic;
  15. // that analyzer fact types are unique;
  16. // that each fact type is a pointer.
  17. func Validate(analyzers []*Analyzer) error {
  18. // Map each fact type to its sole generating analyzer.
  19. factTypes := make(map[reflect.Type]*Analyzer)
  20. // Traverse the Requires graph, depth first.
  21. const (
  22. white = iota
  23. grey
  24. black
  25. finished
  26. )
  27. color := make(map[*Analyzer]uint8)
  28. var visit func(a *Analyzer) error
  29. visit = func(a *Analyzer) error {
  30. if a == nil {
  31. return fmt.Errorf("nil *Analyzer")
  32. }
  33. if color[a] == white {
  34. color[a] = grey
  35. // names
  36. if !validIdent(a.Name) {
  37. return fmt.Errorf("invalid analyzer name %q", a)
  38. }
  39. if a.Doc == "" {
  40. return fmt.Errorf("analyzer %q is undocumented", a)
  41. }
  42. // fact types
  43. for _, f := range a.FactTypes {
  44. if f == nil {
  45. return fmt.Errorf("analyzer %s has nil FactType", a)
  46. }
  47. t := reflect.TypeOf(f)
  48. if prev := factTypes[t]; prev != nil {
  49. return fmt.Errorf("fact type %s registered by two analyzers: %v, %v",
  50. t, a, prev)
  51. }
  52. if t.Kind() != reflect.Ptr {
  53. return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
  54. }
  55. factTypes[t] = a
  56. }
  57. // recursion
  58. for _, req := range a.Requires {
  59. if err := visit(req); err != nil {
  60. return err
  61. }
  62. }
  63. color[a] = black
  64. }
  65. if color[a] == grey {
  66. stack := []*Analyzer{a}
  67. inCycle := map[string]bool{}
  68. for len(stack) > 0 {
  69. current := stack[len(stack)-1]
  70. stack = stack[:len(stack)-1]
  71. if color[current] == grey && !inCycle[current.Name] {
  72. inCycle[current.Name] = true
  73. stack = append(stack, current.Requires...)
  74. }
  75. }
  76. return &CycleInRequiresGraphError{AnalyzerNames: inCycle}
  77. }
  78. return nil
  79. }
  80. for _, a := range analyzers {
  81. if err := visit(a); err != nil {
  82. return err
  83. }
  84. }
  85. // Reject duplicates among analyzers.
  86. // Precondition: color[a] == black.
  87. // Postcondition: color[a] == finished.
  88. for _, a := range analyzers {
  89. if color[a] == finished {
  90. return fmt.Errorf("duplicate analyzer: %s", a.Name)
  91. }
  92. color[a] = finished
  93. }
  94. return nil
  95. }
  96. func validIdent(name string) bool {
  97. for i, r := range name {
  98. if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
  99. return false
  100. }
  101. }
  102. return name != ""
  103. }
  104. type CycleInRequiresGraphError struct {
  105. AnalyzerNames map[string]bool
  106. }
  107. func (e *CycleInRequiresGraphError) Error() string {
  108. var b strings.Builder
  109. b.WriteString("cycle detected involving the following analyzers:")
  110. for n := range e.AnalyzerNames {
  111. b.WriteByte(' ')
  112. b.WriteString(n)
  113. }
  114. return b.String()
  115. }