cargo-cars is a cargo extension that enforces code compliance with the
Canonical Rust best practices.
It implements all 11 disciplines as modular checkers with auto-fix support, inline suppression via comments, and UK spelling validation via hunspell.
Requires Rust >= 1.85.0, libclang, and libhunspell-dev at build time.
For UK spelling checks at runtime (optional), you will also need
hunspell-en-gb. If not installed, spelling checks fall back to a built-in
US/UK word map.
installing dependencies:
sudo apt install libclang-dev libhunspell-dev hunspell-en-gb
Then, install cargo-cars:
cargo install --path .
cargo cars # analyze current project
cargo cars src/main.rs src/lib.rs # specific files
cargo cars src/ # directory
cargo cars --disciplines cosmetic,naming # select disciplines
cargo cars --exclude-disciplines comment # exclude disciplines
cargo cars --format json # json | sarif | console (default)
cargo cars --fix # apply auto-fixes
cargo cars --fixable-only # show only fixable violations
cargo cars --config .cars.toml # custom config file
cargo cars --quiet # errors only| # | ID | Description |
|---|---|---|
| 1 | cosmetic |
Hex literal case, semantic blank line spacing |
| 2 | naming |
Generic/lifetime naming, UK spelling, pattern match variables |
| 3 | import |
No wildcard imports, import grouping order |
| 4 | pattern_matching |
No ref patterns, no tuple indexing, no param patterns |
| 5 | code |
Empty vec macro, explicit drop, from_iter, Self usage |
| 6 | error_panic |
Unwrap usage, error message format |
| 7 | function |
Single-use generics, unused parameters |
| 8 | ordering |
Derive order, field visibility order, definition order |
| 9 | unsafe_code |
SAFETY comments, unsafe fn docs, block size |
| 10 | structural |
mod.rs structure, Error/Result placement |
| 11 | comment |
Doc comment length, article usage |
These rules provide automatic fixes via --fix:
cosmetic::hex_case- lowercase hex literalscode::empty_vec- replacevec![]withVec::new()code::self_usage- replace concrete type withSelfin impl blockserror_panic::unwrap_usage- replace.unwrap()with.expect("TODO: add reason")ordering::derive_order- reorder derive attributes (Copy first, alphabetical)
Suppress violations on the next line with a comment:
// cars:disable cosmetic::hex_case
let x = 0xABCD; // no violation reported
// cars:disable cosmetic
let y = 0xEF01; // suppresses all cosmetic rules
// cars:disable
let z = 0xFF; // suppresses all rulescargo-cars looks for a .cars.toml file starting from the current working
directory and searching upward through parent directories until one is found.
You can override this with --config <path>.
CLI arguments always take precedence over the config file.
The simplest configuration uses top-level keys:
disciplines = ["cosmetic", "naming", "import", "pattern_matching",
"code", "error_panic", "function", "ordering",
"unsafe_code", "structural", "comment"]
exclude_disciplines = []The structured format uses a [cars] section and optional [disciplines.<name>]
tables for per-discipline key/value options:
[cars]
disciplines = ["cosmetic", "naming", "code", "error_panic"]
exclude_disciplines = ["comment"]
[disciplines.cosmetic]
hex_case = "lower" # "lower" (default), "upper", or "any"
[disciplines.error_panic]
allow_unwrap_in_tests = "true" # "true" (default) or "false"| Key | Type | Default | Description |
|---|---|---|---|
disciplines |
array of strings | All 11 disciplines | Which disciplines to enable |
exclude_disciplines |
array of strings | [] |
Disciplines to skip (applied after disciplines) |
[disciplines.<name>] |
table of key/value strings | {} |
Per-discipline options passed to the checker |
| Discipline | Key | Values | Default | Description |
|---|---|---|---|---|
cosmetic |
hex_case |
lower, upper, any |
lower |
Required case for hex literals |
error_panic |
allow_unwrap_in_tests |
true, false |
true |
Whether .unwrap() is allowed in test code |
cosmetic, naming, import, pattern_matching, code, error_panic,
function, ordering, unsafe_code, structural, comment
Console (default):
error[cosmetic::hex_case]: use lowercase for hex literals
--> src/main.rs:42:13
= help: use 0xabcd instead
JSON: structured output with violations, locations, and summary.
SARIF: SARIF 2.1.0 for IDE integration.
| Code | Meaning |
|---|---|
| 0 | No violations |
| 1 | Violations found |
| 2 | Tool error (parse failure, config error) |
cargo test # all tests
cargo test --lib # unit tests only
cargo test --test '*' # integration tests only
cargo test cosmetic # single discipline
cargo test -- --nocapture # with stdoutEach discipline has inline unit tests. Integration tests cover CLI flags,
output formats, auto-fix, and configuration loading. Fixtures under
tests/fixtures/pass/ and tests/fixtures/fail/ provide per-discipline
sample code.
To add a discipline:
- Create
src/disciplines/your_discipline.rsimplementingDiscipline - Register it in
src/disciplines/mod.rs - Add pass/fail fixtures in
tests/fixtures/ - Add inline unit tests with
#[cfg(test)]
The Discipline trait:
pub trait Discipline {
fn id(&self) -> &'static str;
fn check(&self, file: &ParsedFile) -> Vec<Violation>;
}MIT OR Apache-2.0