1
16
17
18
19 package warn
20
21 import (
22 "fmt"
23 "strings"
24
25 "github.com/bazelbuild/buildtools/build"
26 )
27
28 var functionsWithPositionalArguments = map[string]bool{
29 "distribs": true,
30 "exports_files": true,
31 "licenses": true,
32 "print": true,
33 "register_toolchains": true,
34 "vardef": true,
35 }
36
37 func constantGlobWarning(f *build.File) []*LinterFinding {
38 switch f.Type {
39 case build.TypeBuild, build.TypeWorkspace, build.TypeBzl:
40 default:
41
42 return nil
43 }
44
45 findings := []*LinterFinding{}
46 build.Walk(f, func(expr build.Expr, stack []build.Expr) {
47 call, ok := expr.(*build.CallExpr)
48 if !ok || len(call.List) == 0 {
49 return
50 }
51 ident, ok := (call.X).(*build.Ident)
52 if !ok || ident.Name != "glob" {
53 return
54 }
55 patterns, ok := call.List[0].(*build.ListExpr)
56 if !ok {
57 return
58 }
59 for _, expr := range patterns.List {
60 str, ok := expr.(*build.StringExpr)
61 if !ok {
62 continue
63 }
64 if !strings.Contains(str.Value, "*") {
65 message := fmt.Sprintf(
66 `Glob pattern %q has no wildcard ('*'). Constant patterns can be error-prone, move the file outside the glob.`, str.Value)
67 findings = append(findings, makeLinterFinding(expr, message))
68 return
69 }
70 }
71 })
72 return findings
73 }
74
75 func nativeInBuildFilesWarning(f *build.File) []*LinterFinding {
76 if f.Type != build.TypeBuild {
77 return nil
78 }
79
80 findings := []*LinterFinding{}
81 build.WalkPointers(f, func(expr *build.Expr, stack []build.Expr) {
82
83 dot, ok := (*expr).(*build.DotExpr)
84 if !ok {
85 return
86 }
87 ident, ok := dot.X.(*build.Ident)
88 if !ok || ident.Name != "native" {
89 return
90 }
91
92 findings = append(findings,
93 makeLinterFinding(ident,
94 `The "native" module shouldn't be used in BUILD files, its members are available as global symbols.`,
95 LinterReplacement{expr, &build.Ident{Name: dot.Name}}))
96 })
97 return findings
98 }
99
100 func nativePackageWarning(f *build.File) []*LinterFinding {
101 if f.Type != build.TypeBzl {
102 return nil
103 }
104
105 findings := []*LinterFinding{}
106 build.Walk(f, func(expr build.Expr, stack []build.Expr) {
107
108 call, ok := expr.(*build.CallExpr)
109 if !ok {
110 return
111 }
112 dot, ok := call.X.(*build.DotExpr)
113 if !ok || dot.Name != "package" {
114 return
115 }
116 ident, ok := dot.X.(*build.Ident)
117 if !ok || ident.Name != "native" {
118 return
119 }
120
121 findings = append(findings,
122 makeLinterFinding(call, `"native.package()" shouldn't be used in .bzl files.`))
123 })
124 return findings
125 }
126
127 func duplicatedNameWarning(f *build.File) []*LinterFinding {
128 if f.Type != build.TypeBuild && f.Type != build.TypeWorkspace {
129
130 return nil
131 }
132
133 findings := []*LinterFinding{}
134 names := make(map[string]int)
135 msg := `A rule with name %q was already found on line %d. ` +
136 `Even if it's valid for Blaze, this may confuse other tools. ` +
137 `Please rename it and use different names.`
138
139 for _, rule := range f.Rules("") {
140 name := rule.ExplicitName()
141 if name == "" {
142 continue
143 }
144 start, _ := rule.Call.Span()
145 if line, ok := names[name]; ok {
146 finding := makeLinterFinding(rule.Call, fmt.Sprintf(msg, name, line))
147 if nameNode := rule.Attr("name"); nameNode != nil {
148 finding.Start, finding.End = nameNode.Span()
149 start = finding.Start
150 }
151 findings = append(findings, finding)
152 } else {
153 names[name] = start.Line
154 }
155 }
156 return findings
157 }
158
159 func positionalArgumentsWarning(call *build.CallExpr, pkg string) *LinterFinding {
160 if id, ok := call.X.(*build.Ident); !ok || functionsWithPositionalArguments[id.Name] {
161 return nil
162 }
163 for _, arg := range call.List {
164 if _, ok := arg.(*build.AssignExpr); ok || arg == nil {
165 continue
166 }
167 return makeLinterFinding(arg, "All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.")
168 }
169 return nil
170 }
171
172 func argsKwargsInBuildFilesWarning(f *build.File) []*LinterFinding {
173 if f.Type != build.TypeBuild {
174 return nil
175 }
176
177 findings := []*LinterFinding{}
178 build.Walk(f, func(expr build.Expr, stack []build.Expr) {
179
180 call, ok := expr.(*build.CallExpr)
181 if !ok {
182 return
183 }
184 for _, param := range call.List {
185 unary, ok := param.(*build.UnaryExpr)
186 if !ok {
187 continue
188 }
189 switch unary.Op {
190 case "*":
191 findings = append(findings,
192 makeLinterFinding(param, `*args are not allowed in BUILD files.`))
193 case "**":
194 findings = append(findings,
195 makeLinterFinding(param, `**kwargs are not allowed in BUILD files.`))
196 }
197 }
198 })
199 return findings
200 }
201
202 func printWarning(f *build.File) []*LinterFinding {
203 if f.Type == build.TypeDefault {
204
205 return nil
206 }
207
208 findings := []*LinterFinding{}
209 build.Walk(f, func(expr build.Expr, stack []build.Expr) {
210 call, ok := expr.(*build.CallExpr)
211 if !ok {
212 return
213 }
214 ident, ok := (call.X).(*build.Ident)
215 if !ok || ident.Name != "print" {
216 return
217 }
218 findings = append(findings,
219 makeLinterFinding(expr, `"print()" is a debug function and shouldn't be submitted.`))
220 })
221 return findings
222 }
223
View as plain text