Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / analysis / validate.go
1 package analysis
2
3 import (
4         "fmt"
5         "reflect"
6         "strings"
7         "unicode"
8 )
9
10 // Validate reports an error if any of the analyzers are misconfigured.
11 // Checks include:
12 // that the name is a valid identifier;
13 // that the Requires graph is acyclic;
14 // that analyzer fact types are unique;
15 // that each fact type is a pointer.
16 func Validate(analyzers []*Analyzer) error {
17         // Map each fact type to its sole generating analyzer.
18         factTypes := make(map[reflect.Type]*Analyzer)
19
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
36                         // names
37                         if !validIdent(a.Name) {
38                                 return fmt.Errorf("invalid analyzer name %q", a)
39                         }
40
41                         if a.Doc == "" {
42                                 return fmt.Errorf("analyzer %q is undocumented", a)
43                         }
44
45                         // fact types
46                         for _, f := range a.FactTypes {
47                                 if f == nil {
48                                         return fmt.Errorf("analyzer %s has nil FactType", a)
49                                 }
50                                 t := reflect.TypeOf(f)
51                                 if prev := factTypes[t]; prev != nil {
52                                         return fmt.Errorf("fact type %s registered by two analyzers: %v, %v",
53                                                 t, a, prev)
54                                 }
55                                 if t.Kind() != reflect.Ptr {
56                                         return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
57                                 }
58                                 factTypes[t] = a
59                         }
60
61                         // recursion
62                         for _, req := range a.Requires {
63                                 if err := visit(req); err != nil {
64                                         return err
65                                 }
66                         }
67                         color[a] = black
68                 }
69
70                 if color[a] == grey {
71                         stack := []*Analyzer{a}
72                         inCycle := map[string]bool{}
73                         for len(stack) > 0 {
74                                 current := stack[len(stack)-1]
75                                 stack = stack[:len(stack)-1]
76                                 if color[current] == grey && !inCycle[current.Name] {
77                                         inCycle[current.Name] = true
78                                         stack = append(stack, current.Requires...)
79                                 }
80                         }
81                         return &CycleInRequiresGraphError{AnalyzerNames: inCycle}
82                 }
83
84                 return nil
85         }
86         for _, a := range analyzers {
87                 if err := visit(a); err != nil {
88                         return err
89                 }
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
102         return nil
103 }
104
105 func validIdent(name string) bool {
106         for i, r := range name {
107                 if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
108                         return false
109                 }
110         }
111         return name != ""
112 }
113
114 type CycleInRequiresGraphError struct {
115         AnalyzerNames map[string]bool
116 }
117
118 func (e *CycleInRequiresGraphError) Error() string {
119         var b strings.Builder
120         b.WriteString("cycle detected involving the following analyzers:")
121         for n := range e.AnalyzerNames {
122                 b.WriteByte(' ')
123                 b.WriteString(n)
124         }
125         return b.String()
126 }