Warning categories supported by buildifier's linter:
attr-cfg
attr-license
attr-non-empty
attr-output-default
attr-single-file
build-args-kwargs
bzl-visibility
confusing-name
constant-glob
ctx-actions
ctx-args
depset-iteration
depset-union
dict-concatenation
duplicated-name
filetype
function-docstring
function-docstring-header
function-docstring-args
function-docstring-return
git-repository
http-archive
integer-division
keyword-positional-params
list-append
load
load-on-top
module-docstring
name-conventions
native-android
native-build
native-cc
native-java
native-package
native-proto
native-py
no-effect
out-of-order-load
output-group
overly-nested-depset
package-name
package-on-top
positional-args
print
redefined-variable
repository-name
return-value
rule-impl-return
same-origin-load
string-escape
string-iteration
uninitialized
unreachable
unsorted-dict-items
unused-variable
All warnings can be disabled / suppressed / ignored by adding a special comment # buildifier: disable=<category_name>
to the expression that causes the warning. Historically comments with buildozer
instead of buildifier
are also supported, they are equivalent.
# buildifier: disable=no-effect """ A multiline comment as a string literal. Docstrings don't trigger the warning if they are first statements of a file or a function. """ if debug: print("Debug information:", foo) # buildifier: disable=print
cfg = "data"
for attr definitions has no effectattr-cfg
--incompatible_disallow_data_transition
The Configuration cfg = "data"
is deprecated and has no effect. Consider removing it.
attr.license()
is deprecated and shouldn't be usedattr-license
--incompatible_no_attr_license
The attr.license()
method is almost never used and being deprecated.
non_empty
attribute for attr definitions are deprecatedattr-non-empty
--incompatible_disable_deprecated_attr_params
The non_empty
attribute for attr definitions is deprecated, please use allow_empty
with an opposite value instead.
default
parameter for attr.output()
is deprecatedattr-output-default
--incompatible_no_output_attr_default
The default
parameter of attr.output()
is bug-prone, as two targets of the same rule would be unable to exist in the same package under default behavior. Use Starlark macros to specify defaults for these attributes instead.
single_file
is deprecatedattr-single-file
--incompatible_disable_deprecated_attr_params
The single_file
attribute is deprecated, please use allow_single_file
instead.
*args
and **kwargs
are not allowed in BUILD filesbuild-args-kwargs
--incompatible_no_kwargs_in_build_files
Having *args
or **kwargs
makes BUILD files hard to read and manipulate. The list of arguments should be explicit.
bzl-visibility
If a directory foo
contains a subdirectory internal
or private
, only files located under foo
can access it.
For example, dir/rules_mockascript/private/foo.bzl
can be loaded from dir/rules_mockascript/private/bar.bzl
or dir/rules_mockascript/sub/public.bzl
, but not from dir/other_rule/file.bzl
.
l
, I
, or O
as namesconfusing-name
The names l
, I
, or O
can be easily confused with I
, l
, or 0
correspondingly.
constant-glob
Glob function is used to get a list of files from the depot. The patterns (the first argument) typically include a wildcard (* character). A pattern without a wildcard is often useless and sometimes harmful.
To fix the warning, move the string out of the glob:
- glob(["*.cc", "test.cpp"]) + glob(["*.cc"]) + ["test.cpp"]
There’s one important difference: before the change, Bazel would silently ignore test.cpp if file is missing; after the change, Bazel will throw an error if file is missing.
If test.cpp
doesn’t exist, the fix becomes:
- glob(["*.cc", "test.cpp"]) + glob(["*.cc"])
which improves maintenance and readability.
If no pattern has a wildcard, just remove the glob. It will also improve build performance (glob can be relatively slow):
- glob(["test.cpp"]) + ["test.cpp"]
ctx.{action_name}
is deprecatedctx-actions
--incompatible_new_actions_api
The following actions are deprecated, please use the new API:
ctx.new_file
→ ctx.actions.declare_file
ctx.experimental_new_directory
→ ctx.actions.declare_directory
ctx.file_action
→ ctx.actions.write
ctx.action(command = "...")
→ ctx.actions.run_shell
ctx.action(executable = "...")
→ ctx.actions.run
ctx.empty_action
→ ctx.actions.do_nothing
ctx.template_action
→ ctx.actions.expand_template
ctx.actions.args().add()
for multiple arguments is deprecatedctx-args
--incompatible_disallow_old_style_args_add
It's deprecated to use the add
method of ctx.actions.args()
to add a list (or a depset) of variables. Please use either add_all
or add_joined
, depending on the desired behavior.
depset-iteration
--incompatible_depset_is_not_iterable
Depsets are complex structures, iterations over them and lookups require flattening them to a list which may be a heavy operation. To make it more obvious it's now required to call the .to_list()
method on them in order to be able to iterate their items:
deps = depset() [x.path for x in deps] # deprecated [x.path for x in deps.to_list()] # recommended
depset-union
--incompatible_depset_union
The following ways to merge two depsets are deprecated:
depset1 + depset2 depset1 | depset2 depset1.union(depset2)
Please use the depset constructor instead:
depset(transitive = [depset1, depset2])
When fixing this issue, make sure you understand depsets and try to reduce the number of calls to depset.
dict-concatenation
--incompatible_disallow_dict_plus
The +
operator to concatenate dicts is deprecated. The operator used to create a new dict and copy the data to it. There are several ways to avoid it, for example, instead of d = d1 + d2 + d3
you can use one of the following:
Use Skylib:
load("@bazel_skylib//lib:dicts.bzl", "dicts") d = dicts.add(d1, d2, d3)
The same if you don't want to use Skylib:
d = dict(d1.items() + d2.items() + d3.items())
The same in several steps:
d = dict(d1) # If you don't want `d1` to be mutated d.update(d2) d.update(d3)
foo
was already found on lineduplicated-name
Each label in Bazel has a unique name, and Bazel doesn’t allow two rules to have the same name. With macros, this may be accepted by Bazel (if each macro generates different rules):
my_first_macro(name = "foo") my_other_macro(name = "foo")
Although the build may work, this code can be very confusing. It can confuse users reading a BUILD file (if they look for the rule “foo”, they may read see only one of the macros). It will also confuse tools that edit BUILD files.
Just change the name attribute of one rule/macro.
FileType
function is deprecatedfiletype
--incompatible_disallow_filetype
The function FileType
is deprecated. Instead of using it as an argument to the rule
function just use a list of strings.
function-docstring
function-docstring-header
function-docstring-args
function-docstring-return
Public functions should have docstrings describing functions and their signatures. A docstring is a string literal (not a comment) which should be the first statement of a function (it may follow comment lines). Function docstrings are expected to be formatted in the following way:
"""One-line summary: must be followed and may be preceded by a blank line. Optional additional description like this. If it's a function docstring and the function has more than one argument, the docstring has to document these parameters as follows: Args: parameter1: description of the first parameter. Each parameter line should be indented by one, preferably two, spaces (as here). parameter2: description of the second parameter that spans two lines. Each additional line should have a hanging indentation of at least one, preferably two, additional spaces (as here). another_parameter (unused, mutable): a parameter may be followed by additional attributes in parentheses Returns: Description of the return value. Should be indented by at least one, preferably two spaces (as here) Can span multiple lines. """
Docstrings are required for all public functions with at least 5 statements. If a docstring exists it should start with a one-line summary line followed by an empty line. If a docsrting is required or it describe some of the arguments, it should describe all of them. If a docstring is required and the function returns a value, it should be described.
git_repository
is not global anymoregit-repository
--incompatible_remove_native_git_repository
Native git_repository
and new_git_repository
functions are removed. Please use the Starlark versions instead:
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository")
http_archive
is not global anymorehttp-archive
--incompatible_remove_native_http_archive
Native http_archive
function are removed. Please use the Starlark versions instead:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
/
operator for integer division is deprecatedinteger-division
--incompatible_disallow_slash_operator
The /
operator is deprecated in favor of //
, please use the latter for integer division:
a = b // c d //= e
keyword-positional-params
Some parameters for builtin functions in Starlark are keyword for legacy reasons; their names are not meaningful (e.g. x
). Making them positional-only will improve the readability.
list-append
Transforming x += [expr]
to x.append(expr)
avoids a list allocation.
load
load is used to import definitions in a BUILD file. If the definition is not used in the file, the load can be safely removed. If a symbol is loaded two times, you will get a warning on the second occurrence.
Delete the line. When load is used to import multiple symbols, you can remove the unused symbols from the list. To fix your BUILD files automatically, try this command:
$ buildozer 'fix unusedLoads' path/to/BUILD
If you want to keep the load, you can disable the warning by adding a comment # @unused
.
load-on-top
--incompatible_bzl_disallow_load_after_statement
Load statements should be first statements (with the exception of WORKSPACE
files), they can follow only comments and docstrings.
module-docstring
.bzl
files should have docstrings on top of them. A docstring is a string literal (not a comment) which should be the first statement of the file (it may follow comment lines). For example:
""" This module contains build rules for my project. """ ...
name-conventions
By convention, all variables should be lower_snake_case, constant should be UPPER_SNAKE_CASE, and providers should be UpperCamelCase ending with Info
.
native-android
The Android build rules should be loaded from Starlark. The native rules will be disabled.
native
module shouldn't be used in BUILD filesnative-build
There's no need in using native.
in BUILD files, its members are available as global symbols there.
native-cc
--incompatible_load_cc_rules_from_bzl
The C++ build rules should be loaded from Starlark. The native rules will be disabled.
native-java
--incompatible_load_java_rules_from_bzl
The Java build rules should be loaded from Starlark. The native rules will be disabled.
native.package()
shouldn't be used in .bzl filesnative-package
It's discouraged and will be disallowed to use native.package()
in .bzl files. It can silently modify the semantics of a BUILD file and makes it hard to maintain.
native-proto
--incompatible_load_proto_rules_from_bzl
The Proto build rules and symbols should be loaded from Starlark. The native rules will be disabled.
native-py
--incompatible_load_python_rules_from_bzl
The Python build rules should be loaded from Starlark. The native rules will be disabled.
no-effect
The statement has no effect. Consider removing it or storing its result in a variable.
out-of-order-load
Load statements should be ordered by their first argument - extension file label. This makes it easier to developers to locate loads of interest and reduces chances for conflicts when performing large-scale automated refactoring.
When applying automated fixes, it's highly recommended to also use load-on-top
fixes, since otherwise the relative order of a symbol load and its usage can change resulting in runtime error.
ctx.attr.dep.output_group
is deprecatedoutput-group
--incompatible_no_target_output_group
The output_group
field of a target is deprecated in favor of the OutputGroupInfo
provider.
overly-nested-depset
If a depset is iteratively chained in a for loop, e.g. the following pattern is used:
for ...: x = depset(..., transitive = [..., x, ...])
this can result in an overly nested depset with a long chain of transitive elements. Such patterns can lead to performance problems, consider refactoring the code to create a flat list of transitive elements and call the depset constructor just once:
transitive = [] for ...: transitive += ... x = depset(..., transitive = transitive)
Or in simple cases you can use list comprehensions instead:
x = depset(..., transitive = [y.deps for y in ...])
For more information, read Bazel documentation about depsets and reducing the number of calls to depset.
PACKAGE_NAME
is deprecatedpackage-name
--incompatible_package_name_is_a_function
The global variable PACKAGE_NAME
is deprecated, please use native.package_name()
instead.
package-on-top
Here is a typical structure of a BUILD file:
load()
statementspackage()
Instantiating a rule and setting the package defaults later can be very confusing, and has been a source of bugs (tools and humans sometimes believe package applies to everything in a BUILD file). This might become an error in the future (but it requires large-scale changes in google3).
The linter allows the following to be before package()
:
load()
package_group()
licenses()
positional-args
All top level calls (except for some built-ins) should use keyword args over positional arguments. Positional arguments can cause subtle errors if the order is switched or if an argument is removed. Keyword args also greatly improve readability.
- my_macro("foo", "bar") + my_macro(name = "foo", env = "bar")
The linter allows the following functions to be called with positional arguments:
load()
vardef()
export_files()
licenses()
print()
print()
is a debug function and shouldn't be submittedprint
Using the print()
function for warnings is discouraged: they are often spammy and non actionable, the people who see the warning are usually not the people who can fix the code to make the warning disappear, and the actual maintainers of the code may never see the warning.
redefined-variable
In .bzl files, redefining a global variable is already forbidden. This helps both humans and tools reason about the code. For consistency, we want to bring this restriction also to BUILD files.
Rename one of the variables.
Note that the content of lists and dictionaries can still be modified. We will forbid reassignment, but not every side-effect.
REPOSITORY_NAME
is deprecatedrepository-name
--incompatible_package_name_is_a_function
The global variable REPOSITORY_NAME
is deprecated, please use native.repository_name()
instead.
return-value
Some but not all execution paths of a function return a value. Either there's an explicit empty return
statement, or an implcit return in the end of a function. If it is intentional, make it explicit using return None
. If you know certain parts of the code cannot be reached, add the statement fail("unreachable")
to them.
rule-impl-return
Returning structs from rule implementation functions is deprecated, consider using providers or lists of providers instead.
same-origin-load
load is used to import definitions in a BUILD file. If the same label is used for loading symbols more the ones, all such loads can be merged into a single one.
Merge all loads into a single one. For example,
load(":f.bzl", "s1") load(":f.bzl", "s2")
can be written more compactly as
load(":f.bzl", "s1", "s2")
string-escape
--incompatible_restrict_string_escapes
Unrecognized escape sequences in string literals (e.g. "\a \b"
is error-prone and shouldn't be used. If you need the backslash symbol, escape it explicitly: "\\a \\b"
.
string-iteration
--incompatible_string_is_not_iterable
Iteration over strings often leads to confusion with iteration over a sequence of strings, therefore strings won't be recognized as sequences of 1-element strings (like in Python). Use string indexing and len
instead:
my_string = "hello world" for i in range(len(my_string)): char = my_string[i] # do something with char
uninitialized
The local value can be not initialized at the time of execution. It may happen if it's initialized in one of the if-else clauses but not in all of them, or in a for-loop which can potentially be empty.
unreachable
The statement is unreachable because it follows a return
, break
, continue
, or fail()
statement.
unsorted-dict-items
Dictionary items should be sorted lexicagraphically by their keys. This makes it easier to find the item of interest and reduces chances of conflicts when performing large-scale automated refactoring.
The order is affected by NamePriority
dictionary passed using -tables
or -add_tables
flags.
If you want to preserve the original dictionary items order, you can disable the warning by adding a comment # @unsorted-dict-items
to the dictionary expression or any of its enclosing expressins (binary, if etc). For example,
# @unsorted-dict-items d = { "b": "bvalue", "a": "avalue", }
will not be reported as an issue because the assignment operation that uses the dictionary with unsorted items has a comment disabling this warning.
unused-variable
This happens when a variable is set but not used in the file, e.g.
x = [1, 2]
The line can often be safely removed.
If you want to keep the variable, you can disable the warning by adding a comment # @unused
.
x = [1, 2] # @unused