validate.go 3.1 KB

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