Rust Style Formatting and Static Analysis
Based on the rustfmt Book, Clippy Book, Edition Guide, and Error Code Index.
Capability Boundaries
✅ Strengths
- Stable rustfmt configuration (edition, maxwidth, tabspaces, usefieldinit_shorthand, etc.)
- Clippy lint system — all 10 lint groups: correctness, suspicious, style, complexity, perf, pedantic, restriction, cargo, nursery, internal
clippy.toml configuration (msrv, arithmetic-side, cognitive-complexity-threshold, avoid-breaking-exported-api, etc.)
#[expect(...)] attribute (Rust 1.81+) for CI-enforced lint expectations
- Lint
priority ordering for layered policy
- Production CI lint policy (deny/warn/allow decisions per group)
- Edition migration (2015→2018→2021→2024, key changes per edition and cargo fix commands)
- Compiler error code interpretation (rustc --explain, common error codes reference table)
⚠️ Prerequisites
- Rust toolchain installed and configured
❌ Out of Scope
- Rust syntax basics → Use
rust-stable skill
- Code review → Use
rust-code-review skill
- API shape design (naming, type/trait design, module layout) and the full ~100 C- API Guidelines checklist → Use the
rust-api-design skill. This skill only maps the ~25 C- rules that Clippy can mechanically enforce; the rest are design decisions.
When to Use
- "Format Rust code"
- "Run Clippy"
- "Migrate to a new Edition"
- "What does compiler error E0xxx mean?"
I. rustfmt Configuration
# .rustfmt.toml
max_width = 100 # Line width (default: 100)
tab_spaces = 4 # Indentation spaces
edition = "2024" # Rust edition
merge_derives = true # Merge derives
use_field_init_shorthand = true # Field initialization shorthand
use_try_shorthand = true # Use ? shorthand
cargo fmt # Format all files
cargo fmt --check # Check formatting (CI usage)
cargo fmt -- --config max_width=80 # Apply specific configuration
Options such as importsgranularity, groupimports, and reorderimplitems may still require nightly rustfmt; do not include them in default configurations that must pass stable CI.
II. Clippy
cargo clippy # Default: correctness, suspicious, style, complexity, perf
cargo clippy -- -W clippy::pedantic # Enable pedantic group
cargo clippy --fix # Auto-fix MachineApplicable lints
cargo clippy -- -A clippy::module_inception # Allow a specific lint
All 10 lint groups
| Group |
Default level |
Description |
High-leverage lints |
correctness |
deny (effectively) |
Code that is wrong — broken semantics |
almostswap, dropnondrop, ifsamethenelse, outofboundslooping, ptroffsetwithcast |
suspicious |
warn |
Likely-buggy code that compiles but smells off |
mutablekeytype, assignoppattern, blqcklistedname, castlossless, cloneonref_ptr |
style |
warn (default group) |
Idiomatic Rust stylistic preferences |
enumvariantnames, newwithoutdefault, wrongselfconvention, needlessreturn, moduleinception |
complexity |
warn |
Code that could be simpler |
toomanyarguments, cognitive-complexity, manualflatten, optionoption |
perf |
warn |
Performance hints (allocations, copies) |
largeenumvariant, singlecharpattern, manualmemcpy, vecbox, derivable_impls |
pedantic |
allow (opt-in) |
Opinionated style — stricter than style |
castpossibletruncation, fnparamsexcessivebools, mustusecandidate, missingerrorsdoc, modulename_repetitions |
restriction |
allow (opt-in) |
Forbid patterns that may be intentional but risky |
unwrapused, expectused, panic, indexingslicing, dbgmacro, printstdout, floatarithmetic |
cargo |
warn |
Cargo.toml quality |
cargocommonmetadata, negativefeaturenames, redundantfeaturenames, wildcard_dependencies |
nursery |
allow (experimental) |
Lints under development |
useself, fallibleimplfrom, missingconstforfn |
internal |
allow |
For Clippy's own development |
(rarely used by users) |
#[expect] attribute (Rust 1.81+) — better than #[allow]
// ✅ #[expect] — CI fails if the lint stops firing, surfacing dead expectations
#[expect(clippy::too_many_arguments, reason = "configurable builder has many options")]
fn build(name: &str, retries: u32, timeout: u32, /* 5 more */) { /* */ }
// ❌ #[allow] — silently becomes dead code if the lint stops firing
#[allow(clippy::too_many_arguments)]
fn build(/* */) { /* */ }
Prefer #[expect] for intentional suppressions; reserve #[allow] for transient reasons.
Lint priority — layering
// Higher priority wins. Use for layered policy.
#![warn(clippy::pedantic)] // enable pedantic (priority 0)
#![warn(priority = 1, clippy::module_name_repetitions)] // re-enable a specific lint
clippy.toml configuration
# clippy.toml at workspace root
msrv = "1.85" # Don't suggest APIs newer than MSRV
avoid-breaking-exported-api = false # Suggest fixes that change public API
cognitive-complexity-threshold = 25 # Function complexity limit
arithmetic-side = "checked" # Prefer checked_* arithmetic
enum-variant-name-threshold = 1 # Trigger variant_name lint
single-char-binding-names-threshold = 3 # Allow `_a`, `_b`, but not 4+
too-many-arguments-threshold = 7
type-complexity-threshold = 250
disallowed-methods = [
{ path = "std::env::var", reason = "use our config::get instead" },
]
disallowed-types = [
{ path = "std::collections::LinkedList", reason = "almost never the right choice" },
]
disallowed-macros = [
{ path = "std::println", reason = "use tracing in libraries" },
]
See references/clippy-lint-policy.md for the full clippy.toml reference and production policies.
Production CI lint policy
Different projects need different strictness. See references/clippy-lint-policy.md for ready-to-paste configurations.
| Project type |
Pedantic |
Restriction |
Recommended |
| Library (published) |
warn |
allow |
clippy::all + clippy::pedantic warn + cargo::cargocommonmetadata deny |
| Application / binary |
warn |
warn (unwrap_used) |
Add restriction::unwrapused, panic, indexingslicing |
| Embedded / safety-critical |
warn |
deny |
All restriction lints deny; add float_arithmetic deny |
| Internal tool |
allow |
allow |
Just clippy::all (default groups) |
III. Edition Migration
# Check current edition
cargo metadata --format-version 1 | jq '.packages[0].edition'
# Migration steps (example: 2021 → 2024)
cargo fix --edition # Auto-migrate code
cargo build # Verify compilation
cargo test # Validate functionality
# Update Cargo.toml
# edition = "2024"
Key changes per edition:
| Edition |
Key Changes |
| 2015→2018 |
Path and module import changes, dyn Trait, NLL, anonymous lifetimes and keywords changed |
| 2018→2021 |
Precise closure capture, array IntoIterator, panic macro consistency, prelude and reserved syntax changes |
| 2021→2024 |
RPIT lifetime capture, match ergonomics adjustment, temporary value scope, unsafe extern/unsafe attributes, gen keyword, etc. |
IV. Compiler Error Code Quick Reference
# View error details
rustc --explain E0277
| Error Code |
Meaning |
Typical Scenario |
| E0277 |
Trait not implemented |
T: Trait bound is unsatisfied |
| E0308 |
Type mismatch |
Expected type A, but B provided |
| E0502 |
Borrow conflict |
Cannot have mutable borrow and immutable borrow simultaneously |
| E0597 |
Insufficient lifetimes |
Reference goes out of scope beyond its lifetime value |
| E0432 |
Import not found |
use path is incorrect |
| E0061 |
Parameter count mismatch |
Function call has wrong number of parameters |
| E0106 |
Missing lifetimes |
Function signature requires explicit lifetimes |
| E0382 |
Use moved value |
Ownership already transferred |
| E0499 |
Simultaneous mutable borrow |
Only one &mut allowed per expression |
| E0716 |
Insufficient lifetime for temporary values |
Reference on temporary exceeds its scope |
V. API Guidelines ↔ Clippy Lints
The Rust API Guidelines checklist uses C-* rules (about 100 total). Clippy mechanically enforces roughly 25 of them; the remaining ~75 are design judgments (naming, type/trait shape, module layout) that belong to the rust-api-design skill, or require cargo-semver-checks for breaking-change detection. The table below lists the 12 highest-leverage mappings reviewers ask about most. The full crosswalk, including "lints not yet covered" guidance, lives in [references/api-guidelines-to-clippy.md](references/api-guidelines-to-clippy.md).
| C-* Rule |
Clippy Lint |
Group |
Effect |
| C-UNWRAP |
clippy::unwrap_used |
restriction |
Flags unwrap() calls |
| C-UNWRAP |
clippy::expect_used |
restriction |
Flags expect() calls |
| C-PANIC |
clippy::panic |
restriction |
Flags panic!() |
| C-INDEXING |
clippy::indexing_slicing |
restriction |
Flags [i] indexing (panics) |
| C-BOOL-ARG |
clippy::fnparamsexcessive_bools |
pedantic |
Functions with ≥3 bool params |
| C-NEWTYPE |
clippy::newwithoutdefault |
style |
new() exists but no Default |
| C-NEWTYPE |
clippy::newretno_self |
style |
new() returns non-Self |
| C-CONV / C-WRONG-SELF |
clippy::wrongselfconvention |
style |
asX(self) taking &self, or toX(&self) consuming self |
| C-STRING-PATTERNS |
clippy::singlecharpattern |
perf |
.contains("a") → .contains('a') |
| C-COMMON-TRAITS |
clippy::derivable_impls |
perf |
Manual impl that could be derived |
| C-LARGE-NUMERIC |
clippy::unreadable_literal |
style |
1000000 should be 1000000 |
| C-MUTABLE-KEY |
clippy::mutablekeytype |
suspicious |
HashMap key type is mutable |
| C-CLONE-ON-REF |
clippy::cloneonref_ptr |
restriction |
.clone() on Rc/Arc |
Many restriction and pedantic lints are off by default — enable them explicitly via #![warn(clippy::unwrap_used)] or in clippy.toml when enforcing a guideline in CI.
Workflow
- Format code —
cargo fmt ensures consistent style
- Run Clippy —
cargo clippy runs the 5 default groups (correctness, suspicious, style, complexity, perf); add -W clippy::pedantic for stricter
- Decide policy — pick pedantic/restriction level by project type (see table above); paste the matching config from
references/clippy-lint-policy.md
- Configure
clippy.toml — set msrv, disallowed-methods, and any project-specific thresholds
- Use
#[expect] for intentional suppressions — keeps CI honest about dead expectations
- Check Edition — Confirm edition in Cargo.toml is up-to-date
- CI integration —
cargo fmt --check + cargo clippy -- -D warnings + cargo audit in CI
Gotchas
cargo clippy --fix only fixes lints at MachineApplicable level
- rustfmt config file is named
.rustfmt.toml, not rustfmt.toml
- After edition migration, new warnings may appear — especially around unsafeopinunsafefn in 2024
cargo fix --edition does not fix all issues; manual review required after migration
- Prefer
let ... else for early exits and issomeand/then_some for simple boolean mapping; avoid compressing complex control flows just to use modern syntax
saturating, checked, and regular arithmetic expressions have different business semantics regarding overflow strategy — decide first, then select API
On-Demand Resources
- [Format and Clippy Examples](examples/examples.md)
- [Lint Group Quick Reference](references/references.md)
- [Clippy Lint Policy](references/clippy-lint-policy.md): Full
clippy.toml reference, all 10 lint groups in depth, #[expect] patterns, priority layering, and ready-to-paste production CI configurations by project type.
- [Production Rust Idioms](references/production-rust-idioms.md): Review let-else, Option combinators, newtype patterns, non-exhaustive APIs, lock scopes, and overflow strategies when reviewing production code.
- [API Guidelines ↔ Clippy Lints Crosswalk](references/api-guidelines-to-clippy.md): Full mapping from Rust API Guidelines
C-* rules to the Clippy lints that enforce them, plus the ~75 rules Clippy does not cover and where to review them.
examples/golden-style/: Golden examples for CI passing rustfmt and Clippy
Official References