chore(infra): prune the tree's lint suppressions and make the survivors expect - #720
Merged
Conversation
Collaborator
Greptile SummaryThis PR audits workspace lint suppressions, removes obsolete exemptions, and converts most surviving
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| Cargo.toml | Enables Clippy checks that require suppression reasons and prefer checked expectations. |
| clippy.toml | Centralizes unwrap and expect exemptions for recognized test contexts. |
| crates/openlogi-desktop/src/features/camera/controls.rs | Consolidates repeated camera slider conversions into narrowly suppressed helpers. |
| crates/openlogi-hook/src/windows.rs | Replaces reference-to-pointer coercions and signed casts with explicit raw-pointer and bit-preserving forms. |
| .claude/rules/rust.md | Documents expectation-first lint suppression policy, exceptions, scoping, and audit steps. |
Reviews (2): Last reviewed commit: "fix(camera): drop unfulfilled linux cast..." | Re-trigger Greptile
Collaborator
The workspace table keeps `unwrap_used`/`expect_used` at warn so production code has to state its panics, but every test module then re-stated the same exemption by hand — 78 copies of `#[allow(…, reason = "idiomatic in tests")]`, roughly 40% of every lint suppression in the tree. Clippy has a config for exactly this; a two-line `clippy.toml` replaces all of them. Three build scripts and the `openlogi-ipc` wire-format test keep a suppression, because neither is a test in clippy's sense: a build script fails by panicking, and the golden-bytes fixtures sit in free helpers outside any `#[test]` fn — the one test shape `allow-expect-in-tests` cannot see. Those four are now `expect`, so they warn if they ever stop being needed.
`#[allow]` is silent when it stops suppressing anything, so suppressions rot
in place: nothing tells you the cast it covered was deleted three refactors
ago. `#[expect]` warns instead. Converting the 77 non-`cfg_attr` suppressions
surfaced 20 that no longer suppress anything, all removed here:
- `openlogi-assets` {index,manifest,metadata}: three module-wide `dead_code`
blankets that have been inert since the modules became `pub mod` — public
items are reachable, so the lint could never fire. The dangerous kind: had
those modules gone private again, the blanket would have hidden real dead
code forever.
- `LightCapabilities` is down to three bools, under `struct_excessive_bools`.
- `InstanceGuard._handle` and `CGEventTapInformation` are exempt from
`dead_code` on their own (leading underscore / all fields now read).
- Nine GUI `dead_code` and cast suppressions, and the surplus lint names in
six multi-lint blankets that only ever needed one or two of them.
Four suppressions stay `allow` on purpose, each with a comment saying why
`expect` is wrong there:
- `platform::os_version` — the lint only fires on the macOS arm; off macOS the
expectation would go unfulfilled and redden the Linux/Windows lanes.
- `function_row`'s `float_cmp` — rustc does not credit an expectation with a
lint raised inside a macro expansion (`assert_eq!` here), so `expect` would
suppress the warning and then report itself unfulfilled: unfixable under
`-D warnings`.
- The four `cfg_attr`-wrapped ones, whose fulfilment differs between the lib
and test targets of the same crate.
Also drops `_silence_pickfn`, a dead function that existed only to keep an
unused `PickFn` import "used" — a hand-rolled lint workaround; the import goes
with it. And gives the tree's one reason-less suppression a reason.
Verified on the macOS and windows-gnu lanes; the Linux lane is CI's.
Seven files silenced `cast_possible_truncation` / `cast_sign_loss` / `cast_possible_wrap` (and in the hook's Win32 backend `borrow_as_ptr` and `needless_pass_by_value`) for their entire contents. Between them they covered 50 real sites — and every future cast anyone adds to those files, unchecked. Most of the sites did not need a suppression at all: - `capture_windows` and the hook's Win32 backend now use `cast_signed()` / `cast_unsigned()`, which say "reinterpret the bits" instead of "trust me". That is the whole file-level blanket gone from `capture_windows`. - The hook's six `borrow_as_ptr` sites become `&raw mut` / `&raw const`, the edition-2024 spelling — and the better one at an FFI boundary, since it never materializes the intermediate reference. - `uvc`'s descriptor fixture builds its two bytes with `to_le_bytes`. - `camera/controls` funnelled eleven ad-hoc `i32 as f32` / `f32 as i32` conversions through `to_slider`/`from_slider`, so the UVC-range argument is made once where it belongs rather than eleven times by omission. What genuinely needs a cast keeps one, scoped to the function that does it and with a reason naming the bound that makes it safe. `capture_linux` keeps its file-level blanket: `v4l2-sys-mit` runs bindgen, so that backend cannot be cross-linted from macOS and narrowing it would be blind work. Tracked separately. Verified on all three lint lanes: macOS native, x86_64-pc-windows-gnu, and aarch64-unknown-linux-musl (everything but the GPUI crates and the v4l2 backend, neither of which cross-compiles).
`.claude/rules/rust.md` still told agents to hand-write an `#[allow(clippy::expect_used)]` on every test module — now `clippy.toml`'s job — and still described `openlogi-hidpp` as sitting outside the workspace lint table, which its own AGENTS.md retired some time ago. Replaces both, and adds the rule the sweep produced: `expect` by default, with the three cases where it provably cannot work (cfg-conditional lints, fulfilment differing between a crate's lib and test targets, and lints raised inside a macro expansion), plus the scoping rule for cast suppressions and the mechanical recipe for re-running the sweep across all three lint lanes. Logged in `docs/DECISIONS.md` with the numbers behind it.
Several of the new suppression rationales argued the case instead of stating it. A `reason` earns its keep by naming the bound; the surrounding prose was restating what the attribute already says.
`allow_attributes` and `allow_attributes_without_reason` turn the two rules the sweep just wrote down into build failures instead of review notes: reach for `expect`, and say why. Adopting them cost three annotated exceptions and nothing else — the sweep had already left the tree compliant, and `allow_attributes_without_reason` found zero violations on any lane. The three sites where `expect` provably cannot work keep their `allow` behind an `#[expect(clippy::allow_attributes)]`, which is a better home for the "why not expect" note than a bare comment: it fails the build if the exception ever stops being one. Two useful things fell out: - The first pass ruled that a `cfg_attr`-wrapped suppression always needs `allow`. Two of the four turned out to work fine as `expect` — the rule was too coarse, and the lint is what surfaced it. `state.rs` and the permissions page are now `expect`. - `allow_attributes` only sees outer `#[allow]`. A module-wide `#![allow(…)]` is invisible to it — precisely the shape that had rotted in `openlogi-assets`. Recorded in the lint table and in the rules so nobody reads a green build as full coverage.
davidbudnick
force-pushed
the
chore/prune-clippy-suppressions
branch
from
August 20, 2026 20:10
5961e89 to
d3452c4
Compare
|
Too many files changed for review (118 files, 100 file limit). Bypass the limit by tagging |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
An audit of every lint suppression in the tree — 207 attributes carrying 247 lints — found that most of them were not carrying information. 78 were test modules restating the same
unwrap/expectexemption by hand, 20 no longer suppressed anything at all, and seven files silencedcast_*for their entire contents. This prunes the tree to 130 attributes / 140 lints and changes the default form fromallow(silent when it goes stale) toexpect(fails the build when it does): theallow:expectratio goes from 159:48 to 6:124.The mechanism is worth keeping: rewriting every non-
cfg_attrallow(toexpect(and running clippy turns each dead suppression into an "unfulfilled lint expectation" warning. That is how the 20 below were found, and.claude/rules/rust.mdnow documents the recipe so the sweep can be repeated.Notable finds:
openlogi-assets's three module-wide#![allow(dead_code)]blankets have been inert since those modules becamepub mod— public items are reachable, so the lint could never fire. They would have silently hidden real dead code the moment a module went private again.LightCapabilitiesis down to three bools, understruct_excessive_bools.InstanceGuard._handleandCGEventTapInformationare exempt fromdead_codeon their own._silence_pickfnwas a dead function whose only job was keeping an unusedPickFnimport "used" — a hand-rolled way aroundunused_imports. Both are gone.Three cases where
expectprovably cannot work keepallow, each with a comment naming which case applies:platform::os_versionreturnsSome(…)on macOS (sounnecessary_wrapsfires) andNoneelsewhere (so it does not) — anexpectthere is green on macOS and red on the other two lanes.expectsuppresses the warning and reports itself unfulfilled — unfixable under-D warnings.function_row'sfloat_cmpon floats compared insideassert_eq!is the case here.dead_codesuppression on a helper only the tests call is fulfilled in the--libbuild and unfulfilled in the--testbuild. These were alreadycfg_attr-wrapped.Changes
clippy.tomlwithallow-unwrap-in-tests/allow-expect-in-tests. Clippy's exemption covers#[cfg(test)]modules and#[test]functions; a free helper in atests/integration file is the one shape it cannot see, soopenlogi-ipc's wire-format test keeps a file-level suppression, as do the three build scripts (a build script is not a test — it fails by panicking).capture_windows's file-wide cast blanket is gone entirely — its five sites arecast_signed()/cast_unsigned(), which say "reinterpret the bits" rather than "trust me".uvcbuilds its descriptor fixture withto_le_bytesand keeps two narrowly scoped suppressions;capturekeeps one on the statement that stores frame dimensions.capture_linuxkeeps its blanket:v4l2-sys-mitruns bindgen, so that backend cannot be cross-linted from macOS and narrowing it would be blind work.&raw mut/&raw constat its six FFI pointer coercions (the edition-2024 spelling, and the better one at an FFI boundary since it never materializes the intermediate reference),cast_signed()at three sites, and four function-scopedexpects for what is genuinely left.tray_windows's blanket narrowed to the five functions that need it; the three build scripts'expect_usedrestated asexpect.camera/controlsfunnelled eleven ad-hoci32 as f32/f32 as i32conversions through ato_slider/from_sliderpair, so the UVC-range argument is made once where it belongs instead of eleven times by omission.function_row's cast blanket narrowed to four functions. Nine deaddead_code/cast suppressions removed.expect..claude/rules/rust.mdno longer tells agents to hand-write a test-module#[allow], no longer describesopenlogi-hidppas sitting outside the workspace lint table (its own AGENTS.md retired that), and gains theexpect-by-default rule plus the scoping rule for cast suppressions.docs/DECISIONS.mdrecords the decision with the numbers behind it.Testing
Full local gate on the final tree:
Because a platform-gated suppression is only ever evaluated on its own platform, and because an
expectthat goes unfulfilled is a hard error under-D warnings, the sweep was verified on all three lint lanes rather than just the local one:Both clean. Not covered locally: the GPUI crates off macOS (no cross build) and
openlogi-camera's v4l2 backend (bindgen) — CI'sclippyandclippy (windows)jobs own those.This is a lint-hygiene change with no behavioural surface, so there is nothing to verify on hardware. The three code rewrites that are not pure attribute edits —
cast_signed/cast_unsigned,&raw mut/&raw const, and theto_slider/from_sliderpair — are each exactly equivalent to what they replace, and all of them are on Windows or in the camera panel; not runtime-tested on hardware.Follow-ups
capture_linux's file-level cast blanket stays until the v4l2 backend can be linted somewhere other than a Linux box.#[cfg(target_os = "macos")]suppression — the ObjC FFI surface inopenlogi-inject,openlogi-hook,openlogi-camera,openlogi-permissions, and both GPUI apps — is checked only by the maintainer's local gate. That gap predates this PR, butexpectmakes it more valuable to close.