1
16
17 package warn
18
19 import (
20 "fmt"
21 "testing"
22
23 "github.com/bazelbuild/buildtools/tables"
24 )
25
26 func TestAttrDataConfigurationWarning(t *testing.T) {
27 checkFindingsAndFix(t, "attr-cfg", `
28 rule(
29 attrs = {
30 "foo": attr.label_list(mandatory = True, cfg = "data"),
31 }
32 )
33
34 attr.label_list(mandatory = True, cfg = "exec")`, `
35 rule(
36 attrs = {
37 "foo": attr.label_list(mandatory = True),
38 }
39 )
40
41 attr.label_list(mandatory = True, cfg = "exec")`,
42 []string{`:3: cfg = "data" for attr definitions has no effect and should be removed.`},
43 scopeBzl)
44 }
45
46 func TestAttrHostConfigurationWarning(t *testing.T) {
47 checkFindingsAndFix(t, "attr-cfg", `
48 rule(
49 attrs = {
50 "foo": attr.label_list(mandatory = True, cfg = "host"),
51 }
52 )
53
54 attr.label_list(mandatory = True, cfg = "exec")`, `
55 rule(
56 attrs = {
57 "foo": attr.label_list(mandatory = True, cfg = "exec"),
58 }
59 )
60
61 attr.label_list(mandatory = True, cfg = "exec")`,
62 []string{`:3: cfg = "host" for attr definitions should be replaced by cfg = "exec".`},
63 scopeBzl)
64 }
65
66 func TestDepsetItemsWarning(t *testing.T) {
67 checkFindings(t, "depset-items", `
68 def f():
69 depset(items=foo)
70 a = depset()
71 depset(a)
72 `, []string{
73 `:2: Parameter "items" is deprecated, use "direct" and/or "transitive" instead.`,
74 `:4: Giving a depset as first unnamed parameter to depset() is deprecated, use the "transitive" parameter instead.`,
75 },
76 scopeEverywhere)
77 }
78
79 func TestAttrNonEmptyWarning(t *testing.T) {
80 checkFindingsAndFix(t, "attr-non-empty", `
81 rule(
82 attrs = {
83 "foo": attr.label_list(mandatory = True, non_empty = True),
84 "bar": attr.label_list(mandatory = True, non_empty = False),
85 "baz": attr.label_list(mandatory = True, non_empty = foo.bar()),
86 "qux": attr.label_list(mandatory = True, non_empty = not foo.bar()),
87 "aaa": attr.label_list(mandatory = True, non_empty = (foo.bar())),
88 "bbb": attr.label_list(mandatory = True, non_empty = (
89 not foo.bar()
90 )),
91 }
92 )`, `
93 rule(
94 attrs = {
95 "foo": attr.label_list(mandatory = True, allow_empty = False),
96 "bar": attr.label_list(mandatory = True, allow_empty = True),
97 "baz": attr.label_list(mandatory = True, allow_empty = not foo.bar()),
98 "qux": attr.label_list(mandatory = True, allow_empty = foo.bar()),
99 "aaa": attr.label_list(mandatory = True, allow_empty = (not foo.bar())),
100 "bbb": attr.label_list(mandatory = True, allow_empty = (
101 foo.bar()
102 )),
103 }
104 )`,
105 []string{
106 ":3: non_empty attributes for attr definitions are deprecated in favor of allow_empty.",
107 ":4: non_empty attributes for attr definitions are deprecated in favor of allow_empty.",
108 ":5: non_empty attributes for attr definitions are deprecated in favor of allow_empty.",
109 ":6: non_empty attributes for attr definitions are deprecated in favor of allow_empty.",
110 ":7: non_empty attributes for attr definitions are deprecated in favor of allow_empty.",
111 ":8: non_empty attributes for attr definitions are deprecated in favor of allow_empty.",
112 },
113 scopeBzl)
114 }
115
116 func TestAttrSingleFileWarning(t *testing.T) {
117 checkFindingsAndFix(t, "attr-single-file", `
118 rule(
119 attrs = {
120 "foo": attr.label_list(single_file = True, allow_files = [".cc"], mandatory = True),
121 "bar": attr.label_list(single_file = True, mandatory = True),
122 "baz": attr.label_list(single_file = False, mandatory = True),
123 }
124 )`, `
125 rule(
126 attrs = {
127 "foo": attr.label_list(allow_single_file = [".cc"], mandatory = True),
128 "bar": attr.label_list(allow_single_file = True, mandatory = True),
129 "baz": attr.label_list(mandatory = True),
130 }
131 )`,
132 []string{
133 ":3: single_file is deprecated in favor of allow_single_file.",
134 ":4: single_file is deprecated in favor of allow_single_file.",
135 ":5: single_file is deprecated in favor of allow_single_file.",
136 },
137 scopeBzl)
138 }
139
140 func TestCtxActionsWarning(t *testing.T) {
141 checkFindingsAndFix(t, "ctx-actions", `
142 def impl(ctx):
143 ctx.new_file(foo)
144 ctx.new_file(foo, "foo %s " % bar)
145 ctx.new_file(foo, name = bar)
146 ctx.new_file(foo, bar, baz)
147 ctx.experimental_new_directory(foo, bar)
148 ctx.file_action(foo, bar)
149 ctx.file_action(foo, bar, executable = True)
150 ctx.action(foo, bar, command = "foo")
151 ctx.action(foo, bar, executable = "bar")
152 ctx.empty_action(foo, bar)
153 ctx.template_action(foo, bar)
154 ctx.template_action(foo, bar, executable = True)
155 ctx.foobar(foo, bar)
156 `, `
157 def impl(ctx):
158 ctx.actions.declare_file(foo)
159 ctx.actions.declare_file("foo %s " % bar, sibling = foo)
160 ctx.actions.declare_file(bar, sibling = foo)
161 ctx.new_file(foo, bar, baz)
162 ctx.actions.declare_directory(foo, bar)
163 ctx.actions.write(foo, bar)
164 ctx.actions.write(foo, bar, is_executable = True)
165 ctx.actions.run_shell(foo, bar, command = "foo")
166 ctx.actions.run(foo, bar, executable = "bar")
167 ctx.actions.do_nothing(foo, bar)
168 ctx.actions.expand_template(foo, bar)
169 ctx.actions.expand_template(foo, bar, is_executable = True)
170 ctx.foobar(foo, bar)
171 `,
172 []string{
173 `:2: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`,
174 `:3: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`,
175 `:4: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`,
176 `:5: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`,
177 `:6: "ctx.experimental_new_directory" is deprecated in favor of "ctx.actions.declare_directory".`,
178 `:7: "ctx.file_action" is deprecated in favor of "ctx.actions.write".`,
179 `:8: "ctx.file_action" is deprecated in favor of "ctx.actions.write".`,
180 `:9: "ctx.action" is deprecated in favor of "ctx.actions.run_shell".`,
181 `:10: "ctx.action" is deprecated in favor of "ctx.actions.run".`,
182 `:11: "ctx.empty_action" is deprecated in favor of "ctx.actions.do_nothing".`,
183 `:12: "ctx.template_action" is deprecated in favor of "ctx.actions.expand_template".`,
184 `:13: "ctx.template_action" is deprecated in favor of "ctx.actions.expand_template".`,
185 },
186 scopeBzl)
187
188 checkFindings(t, "ctx-actions", `
189 def impl(ctx):
190 ctx.new_file(foo, bar, baz)
191 `, []string{
192 `:2: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`,
193 }, scopeBzl)
194 }
195
196 func TestPackageNameWarning(t *testing.T) {
197 checkFindingsAndFix(t, "package-name", `
198 foo(a = PACKAGE_NAME)
199
200 def f(PACKAGE_NAME):
201 foo(a = PACKAGE_NAME)
202
203 def g():
204 foo(a = PACKAGE_NAME)
205 `, `
206 foo(a = native.package_name())
207
208 def f(PACKAGE_NAME):
209 foo(a = PACKAGE_NAME)
210
211 def g():
212 foo(a = native.package_name())
213 `,
214 []string{
215 `:1: Global variable "PACKAGE_NAME" is deprecated in favor of "native.package_name()". Please rename it.`,
216 `:7: Global variable "PACKAGE_NAME" is deprecated in favor of "native.package_name()". Please rename it.`,
217 },
218 scopeBzl)
219
220 checkFindings(t, "package-name", `
221 PACKAGE_NAME = "foo"
222 foo(a = PACKAGE_NAME)
223 `, []string{}, scopeBzl)
224
225 checkFindings(t, "package-name", `
226 load(":foo.bzl", "PACKAGE_NAME")
227 foo(a = PACKAGE_NAME)
228 `, []string{}, scopeBzl)
229 }
230
231 func TestRepositoryNameWarning(t *testing.T) {
232 checkFindingsAndFix(t, "repository-name", `
233 foo(a = REPOSITORY_NAME)
234
235 def f(REPOSITORY_NAME):
236 foo(a = REPOSITORY_NAME)
237
238 def g():
239 foo(a = REPOSITORY_NAME)
240 `, `
241 foo(a = native.repository_name())
242
243 def f(REPOSITORY_NAME):
244 foo(a = REPOSITORY_NAME)
245
246 def g():
247 foo(a = native.repository_name())
248 `,
249 []string{
250 `:1: Global variable "REPOSITORY_NAME" is deprecated in favor of "native.repository_name()". Please rename it.`,
251 `:7: Global variable "REPOSITORY_NAME" is deprecated in favor of "native.repository_name()". Please rename it.`,
252 }, scopeBzl)
253
254 checkFindings(t, "repository-name", `
255 REPOSITORY_NAME = "foo"
256 foo(a = REPOSITORY_NAME)
257 `, []string{}, scopeBzl)
258
259 checkFindings(t, "repository-name", `
260 load(":foo.bzl", "REPOSITORY_NAME")
261 foo(a = REPOSITORY_NAME)
262 `, []string{}, scopeBzl)
263 }
264
265 func TestFileTypeNameWarning(t *testing.T) {
266 checkFindings(t, "filetype", `
267 rule1(types=FileType([".cc", ".h"]))
268 rule2(types=FileType(types=[".cc", ".h"]))
269
270 FileType(foobar)
271
272 def macro1():
273 a = FileType([".py"])
274
275 def macro2():
276 FileType = foo
277 b = FileType([".java"])
278 `, []string{
279 ":1: The FileType function is deprecated.",
280 ":2: The FileType function is deprecated.",
281 ":4: The FileType function is deprecated.",
282 ":7: The FileType function is deprecated.",
283 }, scopeBzl)
284
285 checkFindings(t, "filetype", `
286 FileType = foo
287
288 rule1(types=FileType([".cc", ".h"]))
289 rule2(types=FileType(types=[".cc", ".h"]))
290 `, []string{}, scopeBzl)
291 }
292
293 func TestOutputGroupWarning(t *testing.T) {
294 checkFindingsAndFix(t, "output-group", `
295 def _impl(ctx):
296 bin = ctx.attr.my_dep.output_group.bin
297 `, `
298 def _impl(ctx):
299 bin = ctx.attr.my_dep[OutputGroupInfo].bin
300 `,
301 []string{
302 `:2: "ctx.attr.dep.output_group" is deprecated in favor of "ctx.attr.dep[OutputGroupInfo]".`,
303 },
304 scopeBzl)
305 }
306
307 func TestNativeGitRepositoryWarning(t *testing.T) {
308 checkFindingsAndFix(t, "git-repository", `
309 """My file"""
310
311 def macro():
312 git_repository(foo, bar)
313 `, `
314 """My file"""
315
316 load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
317
318 def macro():
319 git_repository(foo, bar)
320 `,
321 []string{
322 `:4: Function "git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`,
323 },
324 scopeBzl)
325
326 checkFindingsAndFix(t, "git-repository", `
327 """My file"""
328
329 def macro():
330 git_repository(foo, bar)
331 new_git_repository(foo, bar)
332 `, `
333 """My file"""
334
335 load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
336
337 def macro():
338 git_repository(foo, bar)
339 new_git_repository(foo, bar)
340 `,
341 []string{
342 `:4: Function "git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`,
343 `:5: Function "new_git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`,
344 },
345 scopeBzl)
346
347 checkFindingsAndFix(t, "git-repository", `
348 """My file"""
349
350 load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
351
352 def macro():
353 git_repository(foo, bar)
354 new_git_repository(foo, bar)
355 `, `
356 """My file"""
357
358 load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
359
360 def macro():
361 git_repository(foo, bar)
362 new_git_repository(foo, bar)
363 `,
364 []string{
365 `:7: Function "new_git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`,
366 },
367 scopeBzl)
368 }
369
370 func TestNativeHttpArchiveWarning(t *testing.T) {
371 checkFindingsAndFix(t, "http-archive", `
372 """My file"""
373
374 def macro():
375 http_archive(foo, bar)
376 `, `
377 """My file"""
378
379 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
380
381 def macro():
382 http_archive(foo, bar)
383 `,
384 []string{
385 `:4: Function "http_archive" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:http.bzl".`,
386 },
387 scopeBzl)
388 }
389
390 func TestContextArgsAPIWarning(t *testing.T) {
391 checkFindingsAndFix(t, "ctx-args", `
392 def impl(ctx):
393 args = ctx.actions.args()
394 args.add(foo, bar)
395 args.add(foo, bar, before_each = aaa)
396 args.add(foo, bar, join_with = bbb)
397 args.add(foo, bar, before_each = ccc, join_with = ddd)
398 args.add(foo, bar, map_fn = eee)
399 args.add(foo, bar, map_fn = fff, before_each = ggg)
400 args.add(foo, bar, map_fn = hhh, join_with = iii)
401 args.add(foo, bar, map_fn = jjj, before_each = kkk, join_with = lll)
402 `, `
403 def impl(ctx):
404 args = ctx.actions.args()
405 args.add(foo, bar)
406 args.add_all(foo, bar, before_each = aaa)
407 args.add_joined(foo, bar, join_with = bbb)
408 args.add_joined(foo, bar, format_each = ccc + "%s", join_with = ddd)
409 args.add_all(foo, bar, map_each = eee)
410 args.add_all(foo, bar, map_each = fff, before_each = ggg)
411 args.add_joined(foo, bar, map_each = hhh, join_with = iii)
412 args.add_joined(foo, bar, map_each = jjj, format_each = kkk + "%s", join_with = lll)
413 `,
414 []string{
415 `:4: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`,
416 `:5: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`,
417 `:6: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`,
418 `:7: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`,
419 `:8: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`,
420 `:9: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`,
421 `:10: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`,
422 },
423 scopeBzl)
424 }
425
426 func TestAttrOutputDefault(t *testing.T) {
427 checkFindings(t, "attr-output-default", `
428 rule(
429 attrs = {
430 "foo": attr.output(default="foo"),
431 "bar": attr.output(not_default="foo"),
432 "baz": attr.string(default="foo"),
433 }
434 )
435 `,
436 []string{
437 `:3: The "default" parameter for attr.output() is deprecated.`,
438 },
439 scopeBzl)
440 }
441
442 func TestAttrLicense(t *testing.T) {
443 checkFindings(t, "attr-license", `
444 rule(
445 attrs = {
446 "foo": attr.license(foo),
447 "bar": attr.license(),
448 "baz": attr.no_license(),
449 }
450 )
451 `, []string{
452 `:3: "attr.license()" is deprecated and shouldn't be used.`,
453 `:4: "attr.license()" is deprecated and shouldn't be used.`,
454 }, scopeBzl)
455 }
456
457 func TestRuleImplReturn(t *testing.T) {
458 checkFindings(t, "rule-impl-return", `
459 def _impl(ctx):
460 return struct()
461
462 rule(implementation=_impl)
463 `, []string{
464 `:2: Avoid using the legacy provider syntax.`,
465 }, scopeBzl)
466
467 checkFindings(t, "rule-impl-return", `
468 def _impl(ctx):
469 if True:
470 return struct()
471 return
472
473 x = rule(_impl, attrs = {})
474 `, []string{
475 `:3: Avoid using the legacy provider syntax.`,
476 }, scopeBzl)
477
478 checkFindings(t, "rule-impl-return", `
479 def _impl(ctx):
480 pass # no return statements
481
482 x = rule(_impl, attrs = {})
483 `, []string{}, scopeBzl)
484
485 checkFindings(t, "rule-impl-return", `
486 def _impl1(): # not used as a rule implementation function
487 return struct()
488
489 def _impl2(): # no structs returned
490 if x:
491 return []
492 elif y:
493 return foo()
494 return
495
496 x = rule(
497 implementation=_impl2,
498 )
499
500 rule(
501 _impl3, # not defined here
502 )
503
504 rule(
505 _impl1(), # not an identifier
506 )
507
508 rule() # no parameters
509 rule(foo = bar) # no matching parameters
510 `, []string{}, scopeBzl)
511 }
512
513 func TestNativeAndroidWarning(t *testing.T) {
514 checkFindingsAndFix(t, "native-android", `
515 """My file"""
516
517 def macro():
518 aar_import()
519 android_library()
520 native.android_library()
521 native.android_local_test()
522
523 android_binary()
524 `, fmt.Sprintf(`
525 """My file"""
526
527 load(%q, "aar_import", "android_binary", "android_library", "android_local_test")
528
529 def macro():
530 aar_import()
531 android_library()
532 android_library()
533 android_local_test()
534
535 android_binary()
536 `, tables.AndroidLoadPath),
537 []string{
538 fmt.Sprintf(`:4: Function "aar_import" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath),
539 fmt.Sprintf(`:5: Function "android_library" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath),
540 fmt.Sprintf(`:6: Function "android_library" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath),
541 fmt.Sprintf(`:7: Function "android_local_test" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath),
542 fmt.Sprintf(`:9: Function "android_binary" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath),
543 },
544 scopeBzl|scopeBuild)
545 }
546
547 func TestNativeCcWarning(t *testing.T) {
548 checkFindingsAndFix(t, "native-cc", `
549 """My file"""
550
551 def macro():
552 cc_library()
553 native.cc_binary()
554 cc_test()
555 cc_proto_library()
556 native.fdo_prefetch_hints()
557 native.objc_library()
558 objc_import()
559 cc_toolchain()
560 native.cc_toolchain_suite()
561
562 fdo_profile()
563 cc_import()
564 `, fmt.Sprintf(`
565 """My file"""
566
567 load(%q, "cc_binary", "cc_import", "cc_library", "cc_proto_library", "cc_test", "cc_toolchain", "cc_toolchain_suite", "fdo_prefetch_hints", "fdo_profile", "objc_import", "objc_library")
568
569 def macro():
570 cc_library()
571 cc_binary()
572 cc_test()
573 cc_proto_library()
574 fdo_prefetch_hints()
575 objc_library()
576 objc_import()
577 cc_toolchain()
578 cc_toolchain_suite()
579
580 fdo_profile()
581 cc_import()
582 `, tables.CcLoadPath),
583 []string{
584 fmt.Sprintf(`:4: Function "cc_library" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
585 fmt.Sprintf(`:5: Function "cc_binary" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
586 fmt.Sprintf(`:6: Function "cc_test" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
587 fmt.Sprintf(`:7: Function "cc_proto_library" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
588 fmt.Sprintf(`:8: Function "fdo_prefetch_hints" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
589 fmt.Sprintf(`:9: Function "objc_library" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
590 fmt.Sprintf(`:10: Function "objc_import" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
591 fmt.Sprintf(`:11: Function "cc_toolchain" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
592 fmt.Sprintf(`:12: Function "cc_toolchain_suite" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
593 fmt.Sprintf(`:14: Function "fdo_profile" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
594 fmt.Sprintf(`:15: Function "cc_import" is not global anymore and needs to be loaded from "%s".`, tables.CcLoadPath),
595 },
596 scopeBzl|scopeBuild)
597 }
598
599 func TestNativeJavaWarning(t *testing.T) {
600 checkFindingsAndFix(t, "native-java", `
601 """My file"""
602
603 def macro():
604 java_import()
605 java_library()
606 native.java_library()
607 native.java_binary()
608
609 java_test()
610 `, fmt.Sprintf(`
611 """My file"""
612
613 load(%q, "java_binary", "java_import", "java_library", "java_test")
614
615 def macro():
616 java_import()
617 java_library()
618 java_library()
619 java_binary()
620
621 java_test()
622 `, tables.JavaLoadPath),
623 []string{
624 fmt.Sprintf(`:4: Function "java_import" is not global anymore and needs to be loaded from "%s".`, tables.JavaLoadPath),
625 fmt.Sprintf(`:5: Function "java_library" is not global anymore and needs to be loaded from "%s".`, tables.JavaLoadPath),
626 fmt.Sprintf(`:6: Function "java_library" is not global anymore and needs to be loaded from "%s".`, tables.JavaLoadPath),
627 fmt.Sprintf(`:7: Function "java_binary" is not global anymore and needs to be loaded from "%s".`, tables.JavaLoadPath),
628 fmt.Sprintf(`:9: Function "java_test" is not global anymore and needs to be loaded from "%s".`, tables.JavaLoadPath),
629 },
630 scopeBzl|scopeBuild)
631 }
632
633 func TestNativePyWarning(t *testing.T) {
634 checkFindingsAndFix(t, "native-py", `
635 """My file"""
636
637 def macro():
638 py_library()
639 py_binary()
640 native.py_test()
641 native.py_runtime()
642
643 py_test()
644 `, fmt.Sprintf(`
645 """My file"""
646
647 load(%q, "py_binary", "py_library", "py_runtime", "py_test")
648
649 def macro():
650 py_library()
651 py_binary()
652 py_test()
653 py_runtime()
654
655 py_test()
656 `, tables.PyLoadPath),
657 []string{
658 fmt.Sprintf(`:4: Function "py_library" is not global anymore and needs to be loaded from "%s".`, tables.PyLoadPath),
659 fmt.Sprintf(`:5: Function "py_binary" is not global anymore and needs to be loaded from "%s".`, tables.PyLoadPath),
660 fmt.Sprintf(`:6: Function "py_test" is not global anymore and needs to be loaded from "%s".`, tables.PyLoadPath),
661 fmt.Sprintf(`:7: Function "py_runtime" is not global anymore and needs to be loaded from "%s".`, tables.PyLoadPath),
662 fmt.Sprintf(`:9: Function "py_test" is not global anymore and needs to be loaded from "%s".`, tables.PyLoadPath),
663 },
664 scopeBzl|scopeBuild)
665 }
666
667 func TestNativeProtoWarning(t *testing.T) {
668 checkFindingsAndFix(t, "native-proto", `
669 """My file"""
670
671 def macro():
672 proto_library()
673 proto_lang_toolchain()
674 native.proto_lang_toolchain()
675 native.proto_library()
676
677 ProtoInfo
678 proto_common
679 `, fmt.Sprintf(`
680 """My file"""
681
682 load(%q, "ProtoInfo", "proto_common", "proto_lang_toolchain", "proto_library")
683
684 def macro():
685 proto_library()
686 proto_lang_toolchain()
687 proto_lang_toolchain()
688 proto_library()
689
690 ProtoInfo
691 proto_common
692 `, tables.ProtoLoadPath),
693 []string{
694 fmt.Sprintf(`:4: Function "proto_library" is not global anymore and needs to be loaded from "%s".`, tables.ProtoLoadPath),
695 fmt.Sprintf(`:5: Function "proto_lang_toolchain" is not global anymore and needs to be loaded from "%s".`, tables.ProtoLoadPath),
696 fmt.Sprintf(`:6: Function "proto_lang_toolchain" is not global anymore and needs to be loaded from "%s".`, tables.ProtoLoadPath),
697 fmt.Sprintf(`:7: Function "proto_library" is not global anymore and needs to be loaded from "%s".`, tables.ProtoLoadPath),
698 fmt.Sprintf(`:9: Symbol "ProtoInfo" is not global anymore and needs to be loaded from "%s".`, tables.ProtoLoadPath),
699 fmt.Sprintf(`:10: Symbol "proto_common" is not global anymore and needs to be loaded from "%s".`, tables.ProtoLoadPath),
700 },
701 scopeBzl|scopeBuild)
702 }
703
704 func TestKeywordParameters(t *testing.T) {
705 checkFindingsAndFix(t, "keyword-positional-params", `
706 foo(key = value)
707 all(elements = [True, False])
708 any(elements = [True, False])
709 tuple(x = [1, 2, 3])
710 list(x = [1, 2, 3])
711 len(x = [1, 2, 3])
712 str(x = foo)
713 repr(x = foo)
714 bool(x = 3)
715 int(x = "3")
716 int(x = "13", base = 8)
717 dir(x = foo)
718 type(x = foo)
719 select(x = {})
720 `, `
721 foo(key = value)
722 all([True, False])
723 any([True, False])
724 tuple([1, 2, 3])
725 list([1, 2, 3])
726 len([1, 2, 3])
727 str(foo)
728 repr(foo)
729 bool(3)
730 int("3")
731 int("13", base = 8)
732 dir(foo)
733 type(foo)
734 select({})
735 `, []string{
736 `:2: Keyword parameter "elements" for "all" should be positional.`,
737 `:3: Keyword parameter "elements" for "any" should be positional.`,
738 `:4: Keyword parameter "x" for "tuple" should be positional.`,
739 `:5: Keyword parameter "x" for "list" should be positional.`,
740 `:6: Keyword parameter "x" for "len" should be positional.`,
741 `:7: Keyword parameter "x" for "str" should be positional.`,
742 `:8: Keyword parameter "x" for "repr" should be positional.`,
743 `:9: Keyword parameter "x" for "bool" should be positional.`,
744 `:10: Keyword parameter "x" for "int" should be positional.`,
745 `:11: Keyword parameter "x" for "int" should be positional.`,
746 `:12: Keyword parameter "x" for "dir" should be positional.`,
747 `:13: Keyword parameter "x" for "type" should be positional.`,
748 `:14: Keyword parameter "x" for "select" should be positional.`,
749 }, scopeEverywhere)
750
751 checkFindingsAndFix(t, "keyword-positional-params", `
752 hasattr(
753 x = foo,
754 name = "bar",
755 )
756 getattr(
757 x = foo,
758 name = "bar",
759 )
760 getattr(
761 x = foo,
762 name = "bar",
763 default = "baz",
764 )
765 `, `
766 hasattr(
767 foo,
768 "bar",
769 )
770 getattr(
771 foo,
772 "bar",
773 )
774 getattr(
775 foo,
776 "bar",
777 "baz",
778 )
779 `, []string{
780 `:2: Keyword parameter "x" for "hasattr" should be positional.`,
781 `:3: Keyword parameter "name" for "hasattr" should be positional.`,
782 `:6: Keyword parameter "x" for "getattr" should be positional.`,
783 `:7: Keyword parameter "name" for "getattr" should be positional.`,
784 `:10: Keyword parameter "x" for "getattr" should be positional.`,
785 `:11: Keyword parameter "name" for "getattr" should be positional.`,
786 `:12: Keyword parameter "default" for "getattr" should be positional.`,
787 }, scopeEverywhere)
788 }
789
790 func TestProvider(t *testing.T) {
791 checkFindings(t, "provider-params", `provider(doc = "doc", fields = [])`, []string{}, scopeBzl)
792 checkFindings(t, "provider-params", `provider("doc", fields = [])`, []string{}, scopeBzl)
793 checkFindings(t, "provider-params", `provider(fields = None, doc = "doc")`, []string{}, scopeBzl)
794
795 checkFindings(t, "provider-params", `provider(fields = [])`,
796 []string{`1: Calls to 'provider' should provide a documentation`}, scopeBzl)
797 checkFindings(t, "provider-params", `provider(doc = "doc")`,
798 []string{`1: Calls to 'provider' should provide a list of fields:`}, scopeBzl)
799 checkFindings(t, "provider-params", `p = provider()`,
800 []string{`1: Calls to 'provider' should provide a list of fields and a documentation:`}, scopeBzl)
801 }
802
803 func TestAttributeNameWarning(t *testing.T) {
804 checkFindings(t, "attr-licenses", `
805 def _impl(ctx):
806 pass
807
808 foo = rule(
809 implementation = _impl,
810 attrs = {
811 "license": attr.string(),
812 "licenses": attr.string(),
813 },
814 )
815 `, []string{
816 ":6: Do not use 'licenses' as an attribute name. It may cause unexpected behavior.",
817 }, scopeBzl)
818
819 checkFindings(t, "attr-applicable_licenses", `
820 def _impl(ctx):
821 pass
822
823 foo = rule(
824 implementation = _impl,
825 attrs = {
826 "applicable_licenses": attr.string(),
827 "package_metadata": attr.string(),
828 },
829 )
830 `, []string{
831 ":6: Do not use 'applicable_licenses' as an attribute name. It may cause unexpected behavior.",
832 ":6: Do not use 'package_metadata' as an attribute name. It may cause unexpected behavior.",
833 }, scopeBzl)
834 }
835
View as plain text