blob: 5066bc2e4df76cf347f71758ca6e03de684b3f51 [file] [view]
# Clippy in Chromium
## How to run Clippy lints against Rust code in Chromium
When building locally, Clippy is disabled by default to avoid adding build
overhead to Chromium engineers primarily working with C, C++, or Java.
However, Clippy warnings are enforced by the CQ. Therefore, it is strongly
recommended that engineers working with Rust code enable Clippy warnings by
setting `enable_rust_clippy = true` in their `args.gn`.
Doing so allows you to fix Clippy warnings as they occur, rather than waiting to
discover them until after uploading a CL and running it through the CQ. It also
lets you verify that you've fixed all the problems when rebuilding locally.
## Chromium policy
Chromium has a relaxed, non-strict Clippy policy.
Clippy is a tool that hopefully helps to improve the quality of Chromium code,
but ultimately we trust the judgement of Chromium engineers.
* We hope that *most* Clippy violations
point out actual opportunities for improving the code
(e.g. catching common mistakes, teaching idiomatic Rust patterns, etc.).
* If a Clippy lint doesn’t seem useful in a certain scenario,
then use your best judgement
and feel free to suppress the lint using the `#[allow(...)]` macro.
- We recommend leaving a short comment
that will help future readers understand
why the lint was suppressed.
- We recommend consulting with the
[@security team](https://groups.google.com/u/1/a/chromium.org/g/security)
before suppressing `unsafe`-related lints like
[`clippy::missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html?search=safe#missing_safety_doc)
or
[`clippy::clippy::undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html?search=safe#undocumented_unsafe_blocks).
- We recommend applying suppression to a single item,
but it is okay to suppress at a module, or crate level if it makes sense
(e.g. if all functions in a given test module
have to violate a certain lint)
* If a Clippy lint is frequently suppressed, then
one option on the table is
disabling the lint globally in Chromium - please talk with
[@chrome-rust](https://groups.google.com/a/google.com/g/chrome-rust)
if you find yourself oftentimes disabling a particular lint.
For a list of Clippy lints that apply by default to Chromium targets please
see the `//build/config/compiler:default_clippy_lints` target.
## Known issues
* https://crbug.com/472338477: Can't invoke Clippy on a proc-macro crate
* https://github.com/rust-lang/rust-clippy/issues/16317:
`clippy::missing_safety_doc` triggers on `cxx::bridge`-generated code
([Example `#[allow(...)]` used as a workaround](https://source.chromium.org/chromium/chromium/src/+/main:mojo/public/rust/sequences/cxx.rs;l=24-25;drc=3abf739f4b711e4339c793af95ab482ca3a6c7fc))
## Clippy coverage in Chromium CQ/CI
Clippy is enabled on a subset of CQ bots:
`android-arm64-rel`,
`linux-chromeos-rel`,
`linux-rel`,
`mac-rel`,
`win-rel`.
TODO(https://crbug.com/41484295): Add other bots and target platforms
if additional code needs to be covered by Clippy (`ios-simulator`?).
## Future work
Next steps:
* Figure out how Chromium-specific lints can be added
* Consider opting into additional lints. Examples:
- [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks)
- [`multiple_unsafe_ops_per_block`](https://rust-lang.github.io/rust-clippy/master/index.html?groups=restriction#multiple_unsafe_ops_per_block)
## Automatically applying fix suggestions
### IDE integration
TODO: See if/how this works + write this section.
### Command-line
When build fails because of Clippy, then
a note toward the end spells out a command
for using `build/rust/apply_fixes.py`
to apply machine-applicable fix suggestions
from this particular Clippy invocation.
Example:
```
$ autoninja -C out/rel ...
...
error: this expression creates a reference which is immediately dereferenced by the compiler
--> ../../third_party/blink/renderer/core/xml/parser/xml_ffi.rs:271:33
|
271 | q_name.push_str(&pref);
| ^^^^^ help: change this to: `pref`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
= note: `-D clippy::needless-borrow` implied by `-D clippy::style`
= help: to override `-D clippy::style` add `#[allow(clippy::needless_borrow)]`
error: aborting due to 1 previous error
NOTE: See `//docs/rust/clippy.md` for more Clippy info.
NOTE: To apply machine-applicable fix suggestions (if any) run: build/rust/apply_fixes.py out/rel clippy-driver obj/third_party/blink/renderer/core/xml_ffi.rustflags.json
...
$ build/rust/apply_fixes.py out/rel clippy-driver obj/third_party/blink/renderer/core/xml_ffi.rustflags.json
Invoking clippy-driver to repro the build problem...
Looking for machine-applicable fixes...
Applying fixes to `../../third_party/blink/renderer/core/xml/parser/xml_ffi.rs`...
Applying a fix on line 271...
$ git diff
diff --git a/third_party/blink/renderer/core/xml/parser/xml_ffi.rs b/third_party/blink/renderer/core/xml/parser/xml_ffi.rs
index 707c74bf87784..b02eaf1266d2c 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_ffi.rs
+++ b/third_party/blink/renderer/core/xml/parser/xml_ffi.rs
@@ -268,7 +268,7 @@ fn attributes_next<'a>(
match &name.prefix {
Some(pref) => {
let mut q_name = String::with_capacity(pref.len() + 1 + name.local_name.len());
- q_name.push_str(&pref);
+ q_name.push_str(pref);
q_name.push(':');
q_name.push_str(&name.local_name);
attribute_view.as_mut().Populate(
```
## Implementation detail: When exactly does Clippy run?
When `enable_rust_clippy = true` then by default each Rust target
(e.g. `rust_static_library("foo")`) will have a
[`validations`](https://gn.googlesource.com/gn/+/main/docs/reference.md#var_validations)
dependency edge to an `action("foo_clippy")` target.
This means that `foo_clippy` will be invoked whenever `foo` is built (when
`ninja` is asked to build `foo` directly or when `foo` is transitively needed).
OTOH, targets that depend on `foo` will not be blocked waiting for completion
of `foo_clippy`.
If you want to minimize overhead of Clippy even further, you can consider
setting `enable_rust_clippy_eager = false`. This removes the `validations`
dependency edge described above, so that building `foo` no longer triggers
`foo_clippy`. This mode is discouraged, because it means that Clippy failures
will go undetected until a full build (e.g. until CQ). Nevertheless, this mode
may be useful when wanting to quickly iterate on code.
## References
* Tracking bug: https://crbug.com/41484295/dependencies
* Initial design doc:
["Clippy in Chromium"](https://docs.google.com/document/d/1waxby3UnWPhU_CjKFQlQGUTMmkb0qTZK2gYwqo4KPd0/edit?usp=sharing)
* Technical deep dive:
["Clippy in Chromium: dep edge"](https://docs.google.com/document/d/1Ki9gwPv43p4G65cYoaPOdv3GIqHNpYHAPsXNp0Zdmjk/edit?usp=sharing)