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