Discussion: enable Clippy lints in rustfmt source tree and CI
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 7k
- Forks
- 1.1k
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 24
Description
Background
We don't currently run Clippy on rustfmt's own code. The rust-clippy job in integration.yml runs Clippy on a bunch of external crates to check that rustfmt formats them correctly; it's a formatter regression test, not a lint check on us. The only Clippy-related thing in the source is a handful of stray #[allow(clippy::*)].
If you run cargo clippy --all-targets against main today (toolchain nightly-2026-02-19), you get 269 lint hits in 50 different lints, all from Clippy's default groups. Most are warnings nobody ever sees. But src/cargo-fmt/main.rs and src/format-diff/main.rs both have #![deny(warnings)] at the top, so a Clippy warning in either of those crates becomes a compile error, and cargo clippy --all-targets doesn't actually finish cleanly. We have a Clippy gate already; it just happens to cover exactly two files by accident.
Which lints would this enable
"Default" means everything in clippy::all:
| Group | Default | What it's about |
|---|---|---|
clippy::correctness |
deny | Code that's almost certainly a bug |
clippy::suspicious |
warn | Probably wrong, occasionally intentional |
clippy::style |
warn | Idiomatic Rust style |
clippy::complexity |
warn | Has a simpler equivalent form |
clippy::perf |
warn | Avoidable performance cost |
The other groups (pedantic, nursery, restriction, cargo) are allow-by-default and would stay off. Individual lints from those can be opted into later if anyone wants.
Lint reference: https://rust-lang.github.io/rust-clippy/master/index.html
What's firing on main today
Run on nightly-2026-02-19. The four lints marked (E) are the ones currently breaking the build (they have at least one site inside cargo-fmt or format-diff and trip #![deny(warnings)]).
50 lints, 269 sites total
| Sites | Lint |
|---|---|
| 51 | clippy::bool_assert_comparison (E) |
| 41 | clippy::unnecessary_map_or |
| 26 | clippy::borrow_deref_ref |
| 14 | clippy::needless_borrow |
| 13 | clippy::explicit_auto_deref |
| 10 | clippy::too_many_arguments |
| 9 | clippy::field_reassign_with_default |
| 8 | clippy::unnecessary_lazy_evaluations |
| 7 | clippy::wrong_self_convention |
| 6 | clippy::io_other_error (E) |
| 6 | clippy::needless_borrows_for_generic_args |
| 6 | clippy::expect_fun_call |
| 6 | clippy::to_string_in_format_args |
| 6 | clippy::arc_with_non_send_sync |
| 5 | clippy::redundant_field_names |
| 5 | clippy::unnecessary_unwrap |
| 4 | clippy::needless_splitn |
| 4 | clippy::default_constructed_unit_structs |
| 3 | clippy::redundant_pattern |
| 2 | clippy::derivable_impls, clippy::useless_conversion, clippy::len_zero, clippy::manual_pattern_char_comparison, clippy::get_first, clippy::while_let_on_iterator, clippy::skip_while_next, clippy::let_unit_value |
| 1 | clippy::is_digit_ascii_radix, clippy::nonminimal_bool, clippy::needless_return, clippy::enum_variant_names, clippy::write_with_newline, clippy::needless_lifetimes, clippy::manual_inspect, clippy::ptr_arg, clippy::needless_question_mark, clippy::bind_instead_of_map, clippy::redundant_guards, clippy::clone_on_copy, clippy::collapsible_if, clippy::manual_repeat_n, clippy::borrowed_box, clippy::type_complexity, clippy::extra_unused_lifetimes, clippy::assign_op_pattern, clippy::unwrap_or_default, clippy::legacy_numeric_constants, clippy::map_flatten, clippy::non_canonical_partial_ord_impl (E), clippy::into_iter_on_ref (E) |
Suggested next step
Rather than try to agree on the whole list up front, I think the simplest start is one small PR that just lays the plumbing:
- Add a
[workspace.lints.clippy]table toCargo.tomlwithall = "allow". Nothing changes in behavior, and the twocargo-fmt/format-diffbuild failures go away because there's nothing for#![deny(warnings)]to catch anymore. - Add a
cargo clippy --all-targets -- -D warningsstep to CI. Safe to turn on immediately, since at this point nothing warns.
After that, each lint we want to actually enforce is its own small PR: flip one entry in the table from "allow" to "warn" (or "deny") and include the fixes for that lint in the same PR. The Cargo.toml ends up being the canonical record of which lints we've consciously adopted, and we never get a flood of unrelated warnings landing together.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with Cargo.toml and the rust-clippy job in integration.yml, then run cargo clippy --all-targets on the stated nightly toolchain to reproduce the current failures. Add the workspace Clippy configuration and CI step described in the issue; done means the Clippy command passes without enabling the listed lint groups.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- build-system, ci-cd, tooling
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100