GoPLS Viewer

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