blob: dc3a4d1d953e78cf11c9241459ae3a10b5a1142e [file]
/*
Copyright 2020 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package warn
import "testing"
func TestConstantGlob(t *testing.T) {
checkFindings(t, "constant-glob", `
cc_library(srcs = glob(["foo.cc"]))
cc_library(srcs = glob(include = ["foo.cc"]))
cc_library(srcs = glob(include = ["foo.cc"], exclude = ["bar.cc"]))
cc_library(srcs = glob(exclude = ["bar.cc"], include = ["foo.cc"]))
cc_library(srcs =
["constant"] + glob([
"*.cc",
"test.cpp",
])
)
cc_library(srcs = glob(["*.cc"]))
cc_library(srcs = glob(["*.cc"], exclude = ["bar.cc"]))
cc_library(srcs = glob(include = ["*.cc"], exclude = ["bar.cc"]))
cc_library(srcs = glob(exclude = ["bar.cc"], include = ["*.cc"]))`,
[]string{`:1: Glob pattern "foo.cc" has no wildcard`,
`:2: Glob pattern "foo.cc" has no wildcard`,
`:3: Glob pattern "foo.cc" has no wildcard`,
`:4: Glob pattern "foo.cc" has no wildcard`,
`:8: Glob pattern "test.cpp" has no wildcard`},
scopeBuild|scopeBzl|scopeWorkspace)
}
func TestNativeInBuildFiles(t *testing.T) {
checkFindingsAndFix(t, "native-build", `
native.package("foo")
native.cc_library(name = "lib")
`, `
package("foo")
cc_library(name = "lib")
`, []string{
`:1: The "native" module shouldn't be used in BUILD files, its members are available as global symbols.`,
`:3: The "native" module shouldn't be used in BUILD files, its members are available as global symbols.`,
}, scopeBuild)
}
func TestNativePackage(t *testing.T) {
checkFindings(t, "native-package", `
native.package("foo")
native.cc_library(name = "lib")
`, []string{
`:1: "native.package()" shouldn't be used in .bzl files.`,
}, scopeBzl)
}
func TestDuplicatedName(t *testing.T) {
checkFindings(t, "duplicated-name", `
cc_library(name = "x")
cc_library(name = "y")
py_library(name = "x")
py_library(name = "z")
php_library(name = "x")`,
[]string{
`:3: A rule with name "x" was already found on line 1`,
`:5: A rule with name "x" was already found on line 1`,
}, scopeBuild|scopeWorkspace)
checkFindings(t, "duplicated-name", `
exports_files(["foo.txt"])
[macro(name = "bar_%s" % i) for i in ii]
`,
[]string{},
scopeBuild|scopeWorkspace)
}
func TestPositionalArgumentsDoesNotWarnForNamedArguments(t *testing.T) {
checkFindings(t, "positional-args", `
my_macro = macro()
my_rule = rule()
def my_function(foo):
pass
my_macro(foo = "bar")
my_rule(foo = "bar")
my_function(foo = "bar")
`,
[]string{},
scopeBuild)
}
func TestPositionalArgumentsDoesNotWarnForAllowlistedFunctions(t *testing.T) {
checkFindings(t, "positional-args", `
register_toolchains(
"//foo",
"//bar",
)`,
[]string{},
scopeBuild)
}
func TestPositionalArgumentsWarnsForPositionalMacrosOrRuleCalls(t *testing.T) {
checkFindings(t, "positional-args", `
my_macro = macro()
my_rule = rule()
def my_function(foo):
pass
my_macro("foo", "bar")
my_rule("foo", "bar")
my_function("foo", "bar")
`,
[]string{
`6: All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.
Found call to rule or macro "my_macro" with positional arguments.`,
`7: All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.
Found call to rule or macro "my_rule" with positional arguments.`,
},
scopeBuild)
}
func TestPositionalArgumentsWarnsWhenCalledInNestedContexts(t *testing.T) {
checkFindings(t, "positional-args", `
my_macro = macro()
my_rule = rule()
def my_function(foo):
pass
other_function(foo = my_macro(x))
other_function(foo = my_rule(x))
other_function(foo = my_function(x))
[my_macro(foo) for foo in bar]
[my_rule(foo) for foo in bar]
[my_function(foo) for foo in bar]
`,
[]string{
`6: All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.
Found call to rule or macro "my_macro" with positional arguments.`,
`7: All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.
Found call to rule or macro "my_rule" with positional arguments.`,
`10: All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.
Found call to rule or macro "my_macro" with positional arguments.`,
`11: All calls to rules or macros should pass arguments by keyword (arg_name=value) syntax.
Found call to rule or macro "my_rule" with positional arguments.`,
},
scopeBuild)
}
func TestKwargsInBuildFilesWarning(t *testing.T) {
checkFindings(t, "build-args-kwargs", `
cc_library(
name = "foo",
*args,
**kwargs,
)
foo(*bar(**kgs))`,
[]string{
":3: *args are not allowed in BUILD files.",
":4: **kwargs are not allowed in BUILD files.",
":7: *args are not allowed in BUILD files.",
":7: **kwargs are not allowed in BUILD files.",
},
scopeBuild)
checkFindings(t, "build-args-kwargs", `
cc_library(
name = "foo",
-args,
)
foo(not bar(-kgs))`,
[]string{},
scopeBuild)
}
func TestPrintWarning(t *testing.T) {
checkFindings(t, "print", `
foo()
print("foo")
def f(x):
print(x)
g(x) or print("not g")
`,
[]string{
`:3: "print()" is a debug function and shouldn't be submitted.`,
`:6: "print()" is a debug function and shouldn't be submitted.`,
`:8: "print()" is a debug function and shouldn't be submitted.`,
},
scopeBazel)
}
func TestMakeLocationVariable(t *testing.T) {
checkFindings(t, "make-location", `
genrule(
name = "a",
srcs = [":foo"],
outs = ["out"],
cmd = "cp $(location :foo) $@",
)
genrule(
name = "b",
srcs = [":a", ":b"],
outs = ["out"],
cmd = "cat $(locations :a :b) > $@",
)
genrule(
name = "c",
srcs = [":foo"],
outs = ["out"],
cmd = "cp $$(location :foo) $$@",
)
cc_test(
name = "d",
args = ["--config=$(execpath :cfg)"],
)
load("location", "symbol")
`,
[]string{
`:5: The "$(location)" and "$(locations)" make variables are deprecated. Use "$(execpath ...)" or "$(rootpath ...)" instead.`,
`:12: The "$(location)" and "$(locations)" make variables are deprecated. Use "$(execpath ...)" or "$(rootpath ...)" instead.`,
`:19: The "$(location)" and "$(locations)" make variables are deprecated. Use "$(execpath ...)" or "$(rootpath ...)" instead.`,
},
scopeBuild)
}
func TestPathMapping(t *testing.T) {
checkFindingsAndFix(t, "path-mapping", `
load("@bazel_skylib//lib:paths.bzl", "paths")
def _dirname(file):
return file.dirname
def _add_srcs(args, srcs):
args.add_all([src.path for src in srcs])
def _impl(ctx):
args = ctx.actions.args()
actions = ctx.actions
out_dir = ctx.actions.declare_directory("out")
# Compatible with path mapping
args.add(src)
args.add("--out", out)
args.add_all(dirs, expand_directories = False)
args.add_all([src], map_each = _dirname)
args.add_all(srcs, format_each = "--src=%s")
args.add(src.short_path)
args.add(src.basename)
args.add(paths.dirname(src.short_path))
ctx.actions.run(
outputs = [out],
executable = ctx.executable._tool,
arguments = [args],
)
ctx.actions.run_shell(
outputs = [out],
command = "cp $1 $2",
arguments = [args],
)
# Incompatible with path mapping, fixed automatically
args.add(src.path)
args.add("--out", out.path)
args.add(src.path, format = "--src=%s")
args.add("--src=%s" % src.path)
args.add("--src=" + src.path)
args.add(src.path + ".d")
args.add("-I" + src.path + "/include")
args.add("--src={}".format(src.path))
args.add(out_dir.path)
args.add("--out", out_dir.path)
args.add_all([src.path, out.path])
args.add_all([src.path for src in srcs])
args.add_all([src.path for src in srcs], format_each = "-I%s")
args.add_all(["-I" + inc.path for inc in incs])
args.add_joined([src.path for src in srcs], join_with = ",")
args.add_all([src.path, out_dir.path])
ctx.actions.run(
outputs = [out],
executable = tool.path,
arguments = [args],
)
# Incompatible with path mapping, not fixed automatically
args.add(src.dirname)
args.add("--bin=%s" % ctx.bin_dir.path)
args.add("--gen={}".format(ctx.genfiles_dir.path))
args.add("--root=" + src.root.path)
args.add(paths.join(ctx.bin_dir.path, "include"))
args.add(src.path if src else out.path)
args.add("--src=%s" % src.path, format = "%s")
args.add("%s=%s" % (name, src.path))
args.add(out_dir.path, format = "--out=%s")
args.add_all([src.path for src in srcs if src])
args.add_all([src.path for src in srcs], map_each = _dirname)
args.add_all(["-I" + inc.path for inc in incs], format_each = "%s")
ctx.actions.run(
outputs = [out],
executable = tool.path,
arguments = [src.path, "--out", out.path],
)
ctx.actions.run_shell(
outputs = [out],
command = "cp %s %s" % (src.path, out.path),
)
actions.run_shell(
outputs = [out],
command = "cp $1 " + out.dirname,
arguments = [src.path],
)
# Unrelated
other.add(src.path)
ctx.actions.other(arguments = [src.path])
ctx.actions.run(
outputs = [out],
executable = ctx.executable._tool,
arguments = [args],
progress_message = "Building %s" % out.path,
)
`, `
load("@bazel_skylib//lib:paths.bzl", "paths")
def _dirname(file):
return file.dirname
def _add_srcs(args, srcs):
args.add_all(srcs)
def _impl(ctx):
args = ctx.actions.args()
actions = ctx.actions
out_dir = ctx.actions.declare_directory("out")
# Compatible with path mapping
args.add(src)
args.add("--out", out)
args.add_all(dirs, expand_directories = False)
args.add_all([src], map_each = _dirname)
args.add_all(srcs, format_each = "--src=%s")
args.add(src.short_path)
args.add(src.basename)
args.add(paths.dirname(src.short_path))
ctx.actions.run(
outputs = [out],
executable = ctx.executable._tool,
arguments = [args],
)
ctx.actions.run_shell(
outputs = [out],
command = "cp $1 $2",
arguments = [args],
)
# Incompatible with path mapping, fixed automatically
args.add(src)
args.add("--out", out)
args.add(src, format = "--src=%s")
args.add(src, format = "--src=%s")
args.add(src, format = "--src=%s")
args.add(src, format = "%s.d")
args.add(src, format = "-I%s/include")
args.add(src, format = "--src=%s")
args.add_all([out_dir], expand_directories = False)
args.add_all(["--out", out_dir], expand_directories = False)
args.add_all([src, out])
args.add_all(srcs)
args.add_all(srcs, format_each = "-I%s")
args.add_all(incs, format_each = "-I%s")
args.add_joined(srcs, join_with = ",")
args.add_all([src, out_dir], expand_directories = False)
ctx.actions.run(
outputs = [out],
executable = tool,
arguments = [args],
)
# Incompatible with path mapping, not fixed automatically
args.add(src.dirname)
args.add("--bin=%s" % ctx.bin_dir.path)
args.add("--gen={}".format(ctx.genfiles_dir.path))
args.add("--root=" + src.root.path)
args.add(paths.join(ctx.bin_dir.path, "include"))
args.add(src.path if src else out.path)
args.add("--src=%s" % src.path, format = "%s")
args.add("%s=%s" % (name, src.path))
args.add(out_dir.path, format = "--out=%s")
args.add_all([src.path for src in srcs if src])
args.add_all([src.path for src in srcs], map_each = _dirname)
args.add_all(["-I" + inc.path for inc in incs], format_each = "%s")
ctx.actions.run(
outputs = [out],
executable = tool,
arguments = [src.path, "--out", out.path],
)
ctx.actions.run_shell(
outputs = [out],
command = "cp %s %s" % (src.path, out.path),
)
actions.run_shell(
outputs = [out],
command = "cp $1 " + out.dirname,
arguments = [src.path],
)
# Unrelated
other.add(src.path)
ctx.actions.other(arguments = [src.path])
ctx.actions.run(
outputs = [out],
executable = ctx.executable._tool,
arguments = [args],
progress_message = "Building %s" % out.path,
)
`,
[]string{
`:7: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:35: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:36: "out.path" is not rewritten by path mapping. Pass "out" to "args.add()" instead, or use "args.add_all([out], expand_directories = False)" if it is a directory.`,
`:37: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:38: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:39: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:40: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:41: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:42: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:43: "out_dir.path" is not rewritten by path mapping. Pass "out_dir" to "args.add()" instead, or use "args.add_all([out_dir], expand_directories = False)" if it is a directory.`,
`:44: "out_dir.path" is not rewritten by path mapping. Pass "out_dir" to "args.add()" instead, or use "args.add_all([out_dir], expand_directories = False)" if it is a directory.`,
`:45: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:45: "out.path" is not rewritten by path mapping. Pass "out" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:46: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:47: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:48: "inc.path" is not rewritten by path mapping. Pass "inc" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:49: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_joined()" instead (with "expand_directories = False" if it is a directory).`,
`:50: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:50: "out_dir.path" is not rewritten by path mapping. Pass "out_dir" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:53: "tool.path" is not rewritten by path mapping. Pass "tool" as "executable" instead.`,
`:58: "src.dirname" is not rewritten by path mapping. Add "src" to "ctx.actions.args()" with a "map_each" callback that returns "file.dirname" instead.`,
`:59: "ctx.bin_dir.path" is not rewritten by path mapping. Compute it from an output "File" in a "map_each" callback via "file.root.path" instead.`,
`:60: "ctx.genfiles_dir.path" is not rewritten by path mapping. Compute it from an output "File" in a "map_each" callback via "file.root.path" instead.`,
`:61: "src.root.path" is not rewritten by path mapping. Add "src" to "ctx.actions.args()" with a "map_each" callback that returns "file.root.path" instead.`,
`:62: "ctx.bin_dir.path" is not rewritten by path mapping. Compute it from an output "File" in a "map_each" callback via "file.root.path" instead.`,
`:63: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:63: "out.path" is not rewritten by path mapping. Pass "out" to "args.add()" instead, or use "args.add_all([out], expand_directories = False)" if it is a directory.`,
`:64: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:65: "src.path" is not rewritten by path mapping. Pass "src" to "args.add()" instead, or use "args.add_all([src], expand_directories = False)" if it is a directory.`,
`:66: "out_dir.path" is not rewritten by path mapping. Pass "out_dir" to "args.add()" instead, or use "args.add_all([out_dir], expand_directories = False)" if it is a directory.`,
`:67: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:68: "src.path" is not rewritten by path mapping. Pass "src" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:69: "inc.path" is not rewritten by path mapping. Pass "inc" to "args.add_all()" instead (with "expand_directories = False" if it is a directory).`,
`:72: "tool.path" is not rewritten by path mapping. Pass "tool" as "executable" instead.`,
`:73: "src.path" is not rewritten by path mapping. Add "src" to "ctx.actions.args()" and pass the "Args" object in "arguments" instead.`,
`:73: "out.path" is not rewritten by path mapping. Add "out" to "ctx.actions.args()" and pass the "Args" object in "arguments" instead.`,
`:77: "src.path" is not rewritten by path mapping. Add "src" to "ctx.actions.args()", pass the "Args" object in "arguments" and refer to it as "$1", "$2", ... in "command" instead.`,
`:77: "out.path" is not rewritten by path mapping. Add "out" to "ctx.actions.args()", pass the "Args" object in "arguments" and refer to it as "$1", "$2", ... in "command" instead.`,
`:81: "out.dirname" is not rewritten by path mapping. Add "out" to "ctx.actions.args()" with a "map_each" callback that returns "file.dirname" instead.`,
`:82: "src.path" is not rewritten by path mapping. Add "src" to "ctx.actions.args()" and pass the "Args" object in "arguments" instead.`,
},
scopeBzl)
}