-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
rego_v1.go
126 lines (107 loc) · 3.21 KB
/
rego_v1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package ast
func checkDuplicateImports(modules []*Module) (errors Errors) {
for _, module := range modules {
processedImports := map[Var]*Import{}
for _, imp := range module.Imports {
name := imp.Name()
if processed, conflict := processedImports[name]; conflict {
errors = append(errors, NewError(CompileErr, imp.Location, "import must not shadow %v", processed))
} else {
processedImports[name] = imp
}
}
}
return
}
func checkRootDocumentOverrides(node interface{}) Errors {
errors := Errors{}
WalkRules(node, func(rule *Rule) bool {
var name string
if len(rule.Head.Reference) > 0 {
name = rule.Head.Reference[0].Value.(Var).String()
} else {
name = rule.Head.Name.String()
}
if RootDocumentRefs.Contains(RefTerm(VarTerm(name))) {
errors = append(errors, NewError(CompileErr, rule.Location, "rules must not shadow %v (use a different rule name)", name))
}
for _, arg := range rule.Head.Args {
if _, ok := arg.Value.(Ref); ok {
if RootDocumentRefs.Contains(arg) {
errors = append(errors, NewError(CompileErr, arg.Location, "args must not shadow %v (use a different variable name)", arg))
}
}
}
return true
})
WalkExprs(node, func(expr *Expr) bool {
if expr.IsAssignment() {
name := expr.Operand(0).String()
if RootDocumentRefs.Contains(RefTerm(VarTerm(name))) {
errors = append(errors, NewError(CompileErr, expr.Location, "variables must not shadow %v (use a different variable name)", name))
}
}
return false
})
return errors
}
func walkCalls(node interface{}, f func(interface{}) bool) {
vis := &GenericVisitor{func(x interface{}) bool {
switch x := x.(type) {
case Call:
return f(x)
case *Expr:
if x.IsCall() {
return f(x)
}
case *Head:
// GenericVisitor doesn't walk the rule head ref
walkCalls(x.Reference, f)
}
return false
}}
vis.Walk(node)
}
func checkDeprecatedBuiltins(deprecatedBuiltinsMap map[string]struct{}, node interface{}) Errors {
errs := make(Errors, 0)
walkCalls(node, func(x interface{}) bool {
var operator string
var loc *Location
switch x := x.(type) {
case *Expr:
operator = x.Operator().String()
loc = x.Loc()
case Call:
terms := []*Term(x)
if len(terms) > 0 {
operator = terms[0].Value.String()
loc = terms[0].Loc()
}
}
if operator != "" {
if _, ok := deprecatedBuiltinsMap[operator]; ok {
errs = append(errs, NewError(TypeErr, loc, "deprecated built-in function calls in expression: %v", operator))
}
}
return false
})
return errs
}
func checkDeprecatedBuiltinsForCurrentVersion(node interface{}) Errors {
deprecatedBuiltins := make(map[string]struct{})
capabilities := CapabilitiesForThisVersion()
for _, bi := range capabilities.Builtins {
if bi.IsDeprecated() {
deprecatedBuiltins[bi.Name] = struct{}{}
}
}
return checkDeprecatedBuiltins(deprecatedBuiltins, node)
}
// CheckRegoV1 checks the given module for errors that are specific to Rego v1
func CheckRegoV1(module *Module) Errors {
var errors Errors
errors = append(errors, checkDuplicateImports([]*Module{module})...)
errors = append(errors, checkRootDocumentOverrides(module)...)
errors = append(errors, checkDeprecatedBuiltinsForCurrentVersion(module)...)
return errors
}