| # 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) |