Ha eddig csak a cargo build-re és a cargo test-re támaszkodtál, itt az ideje, hogy megismerkedj a Clippy-vel. A Rust fordító már önmagában is szigorú, de a Clippy egy szinttel feljebb viszi a dolgot: olyan mintázatokat is felismer, amik technikailag helyesek, de nem idiomatikusak, feleslegesen lassúak, vagy egyszerűen csak zavaróak egy másik fejlesztő számára.
Miért van szükséged a Clippyre?
A Rust compiler feladata, hogy a memóriabiztonságot és a típusbiztonságot garantálja. Ez viszont nem jelenti azt, hogy a kódod jó is. Gondolj bele: egy if x == true { ... } szintaktikailag tökéletes, de senki sem írna ilyet, ha tudná, hogy elég annyi, hogy if x { ... }. A Clippy pontosan ezeket a mintázatokat kapja el, mielőtt code review-ban valaki más venné észre.
A Clippy nevét a paperclip-ből (gemkapocs) kapta, utalva a régi Microsoft Office segédre — csak itt a segéd tényleg hasznos tanácsokat ad.
Telepítés és első futtatás
Ha rustup-ot használsz (és valószínűleg igen), a Clippy telepítése egyetlen parancs:
rustup component add clippy
Ezután bármelyik projekted gyökerében lefuttathatod:
cargo clippy
Ez alapból minden targetet átvizsgál a jelenlegi feature-flag konfigurációval. Ha teljesebb lefedettséget szeretnél (tesztek, példák, benchmarkok is), érdemes ezt használni:
cargo clippy --all-targets --all-features
Nézzünk egy egyszerű példát, amit a Clippy azonnal kiszúr:
fn calculate_area(width: f64, height: f64) -> f64 {
let result = width * height;
return result;
}
fn main() {
let area = calculate_area(3.0, 4.0);
if area == 12.0 {
println!("Pontosan 12!");
}
}
Ennél a kódnál a Clippy két dolgot is jelezni fog: a felesleges return-t a függvény végén (clippy::needless_return), illetve azt, hogy lebegőpontos számokat egyenlőségre hasonlítasz, ami hibás eredményekhez vezethet (clippy::float_cmp). Ez utóbbi egy klasszikus kezdő hiba — a lebegőpontos aritmetika pontatlanságai miatt ritkán van értelme ==-t használni két f64 érték között.
Lint kategóriák: correctness, style, complexity, pedantic
A Clippy lintek nincsenek egy kalap alatt — csoportokba vannak rendezve, és ez nagyon fontos, mert eltérő a szigorúságuk és a hamis pozitív arányuk:
- correctness: ezek szinte biztosan hibák. A
cargo clippyalapbóldenyszinten futtatja őket, tehát build hibát is okozhatnak. - suspicious: gyanús minták, amik gyakran hibára utalnak, de nem mindig.
- style: idiomatikus Rust írásmódra vonatkozó javaslatok — pl. a fenti
needless_return. - complexity: feleslegesen bonyolult kódra figyelmeztet, amit egyszerűbben is meg lehetne írni.
- perf: teljesítmény szempontból szuboptimális mintázatok, pl. felesleges klónozás.
- pedantic: extra szigorú, stílusfüggő szabályok, amiket alapból NEM futtat a Clippy, mert sok projektben túl zajosak lennének.
- nursery: kísérleti lintek, amik még fejlesztés alatt állnak, instabilak lehetnek.
- restriction: erősen szubjektív, projekt-specifikus tiltások (pl.
unwraptiltása), ezeket sosem kapcsolod be csoportosan.
Alapból a cargo clippy a correctness, suspicious, style, complexity és perf csoportokat futtatja (ez a clippy::all csoport). Ha szeretnéd bekapcsolni a pedantic szabályokat is, ezt explicit meg kell tenned:
cargo clippy -- -W clippy::pedantic
A pedantic csoport tényleg pedáns. Ha egy nagyobb, régebbi kódbázison kapcsolod be először, könnyen kaphatsz több száz figyelmeztetést. Ne ess pánikba — fokozatosan vezesd be, modulonként.
Finomhangolás projekt szinten: clippy.toml és lint attribútumok
A legtöbb csapatnál a lint szabályokat nem a parancssorban akarod tartani, hanem a kódban, verziókövetve. Erre két eszközöd van: a lint attribútumok a kódban, és a clippy.toml konfigurációs fájl a projekt gyökerében.
A src/lib.rs vagy src/main.rs tetején beállíthatod, mely csoportokat szeretnéd figyelmeztetésként vagy hibaként kezelni:
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
#![deny(clippy::correctness)]
fn divide(a: i32, b: i32) -> i32 {
a / b
}
Ez a beállítás azt jelenti, hogy a correctness kategóriájú lintek hibát dobnak (a build megbukik), míg a pedantic és nursery csak figyelmeztetést ad. Ez egy jó kompromisszum: a valódi hibákat kizárod a build-ből, de a stilisztikai javaslatokat nem kényszeríted ki azonnal.
A clippy.toml fájllal pedig egyes lintek viselkedését testre szabhatod. Például, ha nem szeretnéd, hogy a too_many_arguments lint már 5 paraméternél panaszkodjon:
# clippy.toml
too-many-arguments-threshold = 8
cognitive-complexity-threshold = 25
Ez különösen hasznos, ha a csapatod más konvenciókat követ, mint a Clippy alapértelmezett feltételezései.
A clippy.toml csak bizonyos lintek paramétereit tudja hangolni, nem kapcsol be vagy ki l797kombinációkat — arra a #![warn(...)] / #![allow(...)] attribútumok valók.
Clippy a CI pipeline-ban
Ha a Clippy futtatása csak a fejlesztők jóindulatán múlik, előbb-utóbb valaki simán elfelejti lefuttatni. Éppen ezért érdemes a CI pipeline-ba beépíteni, hogy a pull request-ek automatikusan ellenőrizve legyenek.
GitHub Actions esetén egy egyszerű job így nézhet ki:
name: CI
on: [push, pull_request]
jobs:
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: clippy
override: true
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
A -D warnings kapcsoló kulcsfontosságú: ez minden figyelmeztetést hibává alakít, így a build megbukik, ha bármilyen lint triggerelődik. Ez elsőre ijesztőnek tűnhet, de hosszú távon garantálja, hogy a kódbázisod tiszta marad.
Ha csapatban dolgozol, célszerű a -D warnings-t csak a clippy::all csoportra alkalmazni, és a pedantic/nursery figyelmeztetéseket külön, nem blokkoló lépésként futtatni. Így nem állítod meg a fejlesztést minden apró stilisztikai észrevétel miatt.
Hamis pozitívok kezelése
Előbb-utóbb találkozol olyan esettel, amikor a Clippy hibásan jelez valamit — vagy technikailag igaza van, de a te konkrét helyzetedben a javaslata nem alkalmazható. Ilyenkor az #[allow(...)] attribútum a barátod, de érdemes minél szűkebb hatókörben használni.
#[allow(clippy::too_many_arguments)]
fn create_report(
title: &str,
author: &str,
date: &str,
department: &str,
priority: u8,
tags: &[&str],
body: &str,
footer: &str,
) -> String {
format!("{title} - {author} ({date})")
}
Itt tudatosan elfogadjuk, hogy a függvénynek sok paramétere van (esetleg egy builder pattern-re való átállás később megéri, de most nem). A kulcs, hogy ne a fájl tetején, hanem közvetlenül a releváns kód fölött helyezd el az allow-t — így bárki, aki később olvassa a kódot, pontosan látja, mi és miért van kikapcsolva.
Kerüld a #![allow(clippy::all)] használatát a fájl vagy a crate tetején! Ez gyakorlatilag kikapcsolja a teljes Clippy-t az adott hatókörben, és elveszíted az összes hasznos figyelmeztetést is, nem csak azt az egyet, ami zavart.
Ha egy adott lintet a teljes projektben szeretnél letiltani (mert pl. nem illik a csapat konvenciójához), azt is megteheted a lib.rs-ben:
#![allow(clippy::module_name_repetitions)]
Ez a lint pl. azt jelzi, ha egy modulban lévő típus neve megismétli a modul nevét (pl. report::Report), ami sok esetben teljesen ésszerű elnevezési konvenció, csak a Clippy pedantic csoportja szigorúan veszi.
Összefoglalás
A Clippy nem egy plusz teher, hanem egy ingyenes senior code reviewer, aki sosem fárad el, és mindig ugyanazokkal a szemüvegekkel néz a kódra. Kezdd az alapokkal (cargo clippy), ismerkedj meg a lint kategóriákkal, majd fokozatosan vezesd be a pedantic szabályokat is, ahol értelmes. Építsd be a CI-ba, hogy senki ne tudja megkerülni, és tanuld meg tudatosan, célzottan használni az #[allow(...)] attribútumot azokra az esetekre, ahol a Clippy javaslata nem illik a helyzetedhez. Ezekkel a lépésekkel a kódbázisod nemcsak fordítani fog, hanem valódi, idiomatikus Rust kód lesz — amit bárki könnyen olvashat és karbantarthat utánad.