.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / go / analysis / validate.go
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
5 package analysis
6
7 import (
8         "fmt"
9         "reflect"
10         "strings"
11         "unicode"
12 )
13
14 // Validate reports an error if any of the analyzers are misconfigured.
15 // Checks include:
16 // that the name is a valid identifier;
17 // that the Requires graph is acyclic;
18 // that analyzer fact types are unique;
19 // that each fact type is a pointer.
20 func Validate(analyzers []*Analyzer) error {
21         // Map each fact type to its sole generating analyzer.
22         factTypes := make(map[reflect.Type]*Analyzer)
23
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
40                         // names
41                         if !validIdent(a.Name) {
42                                 return fmt.Errorf("invalid analyzer name %q", a)
43                         }
44
45                         if a.Doc == "" {
46                                 return fmt.Errorf("analyzer %q is undocumented", a)
47                         }
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.Ptr {
60                                         return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
61                                 }
62                                 factTypes[t] = a
63                         }
64
65                         // recursion
66                         for _, req := range a.Requires {
67                                 if err := visit(req); err != nil {
68                                         return err
69                                 }
70                         }
71                         color[a] = black
72                 }
73
74                 if color[a] == grey {
75                         stack := []*Analyzer{a}
76                         inCycle := map[string]bool{}
77                         for len(stack) > 0 {
78                                 current := stack[len(stack)-1]
79                                 stack = stack[:len(stack)-1]
80                                 if color[current] == grey && !inCycle[current.Name] {
81                                         inCycle[current.Name] = true
82                                         stack = append(stack, current.Requires...)
83                                 }
84                         }
85                         return &CycleInRequiresGraphError{AnalyzerNames: inCycle}
86                 }
87
88                 return nil
89         }
90         for _, a := range analyzers {
91                 if err := visit(a); err != nil {
92                         return err
93                 }
94         }
95
96         // Reject duplicates among analyzers.
97         // Precondition:  color[a] == black.
98         // Postcondition: color[a] == finished.
99         for _, a := range analyzers {
100                 if color[a] == finished {
101                         return fmt.Errorf("duplicate analyzer: %s", a.Name)
102                 }
103                 color[a] = finished
104         }
105
106         return nil
107 }
108
109 func validIdent(name string) bool {
110         for i, r := range name {
111                 if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
112                         return false
113                 }
114         }
115         return name != ""
116 }
117
118 type CycleInRequiresGraphError struct {
119         AnalyzerNames map[string]bool
120 }
121
122 func (e *CycleInRequiresGraphError) Error() string {
123         var b strings.Builder
124         b.WriteString("cycle detected involving the following analyzers:")
125         for n := range e.AnalyzerNames {
126                 b.WriteByte(' ')
127                 b.WriteString(n)
128         }
129         return b.String()
130 }