Skip to content

Commit 2c9f3c6

Browse files
committed
chore(deps): upgrade perfectionist to 0.0.0-rc.9
The new rule `macro_argument_binding` flags 25 sites across the codebase. Investigation showed every single one to be a false positive belonging to one of five upstream bug classes, filed as #415, #416, #417, #418, and #419. None of the suggested "bind to a `let` first" fixes are correct here: - The 13 `debug_assert_op!` / `debug_assert_op_expr!` sites would have their arguments forced to run in release builds (#415), defeating the entire point of `debug_assert_*`. - The `make_const!` and `bump!` matchers (#416) use definition / compound-assignment shapes that have no `let`-binding form. - `app::App::run` passes the unit literal `()`, which the rule's grammar fails to recognise as trivial (#417). - `debug_assert_op_expr!`'s middle operator argument (`==`, `>`) is a bare token, not an expression at all (#418). - The late pass anchors item-position macro violations at the crate root (#419), which is why module-scope `#[expect]` cannot suppress them and `proportion_bar.rs`'s `make_const!` macro had to be expanded into five `pub const` lines by hand. Apply `#[cfg_attr(dylint_lib = "perfectionist", expect(...))]` at the smallest scope each false positive permits (function scope where the macro call is statement-position, crate root in `tests/bytes_format.rs` where the call is item-position). Rewrite the `link!` / `symlink!` macros in `tests/_utils.rs` as closures so the test-utility module needs no suppression. https://claude.ai/code/session_01CoRidYHvni9nKNgxMPXmfQ
1 parent 0d3465c commit 2c9f3c6

10 files changed

Lines changed: 97 additions & 41 deletions

File tree

dylint.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[workspace.metadata.dylint]
22
libraries = [
3-
{ git = "https://github.com/KSXGitHub/perfectionist", rev = "a21a146eff0ff5b61571160d287fec100879046d" },
3+
{ git = "https://github.com/KSXGitHub/perfectionist", tag = "0.0.0-rc.9" },
44
]
55

66
["perfectionist::single_letter_names"]

src/app.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ impl App {
3939
}
4040

4141
/// Run the application.
42+
#[cfg_attr(
43+
dylint_lib = "perfectionist",
44+
expect(
45+
perfectionist::macro_argument_binding,
46+
reason = "the unit literal `()` is the canonical trivial value, but the rule's trivial-expression grammar does not yet accept parenthesised forms; see #417",
47+
)
48+
)]
4249
pub fn run(mut self) -> Result<(), RuntimeError> {
4350
// DYNAMIC DISPATCH POLICY:
4451
//

src/data_tree/hardlink.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ where
1212
{
1313
/// Reduce the size of the directories that have hardlinks.
1414
#[cfg_attr(not(unix), expect(unused))]
15+
#[cfg_attr(
16+
dylint_lib = "perfectionist",
17+
expect(
18+
perfectionist::macro_argument_binding,
19+
reason = "binding a `debug_assert_op!` argument to a `let` forces it to run in release builds, which defeats the entire point of `debug_assert_*`; see #415",
20+
)
21+
)]
1522
pub(crate) fn par_deduplicate_hardlinks(&mut self, hardlink_info: &[(Size, Vec<&Path>)]) {
1623
if hardlink_info.is_empty() {
1724
return;

src/reporter/progress_and_error_reporter.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ where
7979
ReportError: Fn(ErrorReport) + Sync,
8080
u64: Into<Size>,
8181
{
82+
#[cfg_attr(
83+
dylint_lib = "perfectionist",
84+
expect(
85+
perfectionist::macro_argument_binding,
86+
reason = "the `bump!` macro's `($field:ident += $delta:expr)` matcher uses structural assignment syntax rather than a single expression, so binding the argument to a `let` is not even syntactically possible; see #416",
87+
)
88+
)]
8289
fn report(&self, event: Event<Size>) {
8390
use Event::*;
8491
let ProgressAndErrorReporter {

src/visualizer/methods/bar_table.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ pub(super) struct BarRow<Name, NodeData> {
1212
pub(super) proportion_bar: ProportionBar,
1313
}
1414

15+
#[cfg_attr(
16+
dylint_lib = "perfectionist",
17+
expect(
18+
perfectionist::macro_argument_binding,
19+
reason = "the flagged sites are all `debug_assert_op!` / `debug_assert_op_expr!` calls on side-effect-free locals; binding to a `let` would defeat the debug-only contract (see #415), and the rule also miscategorises bare operator tokens like `==` as expressions (see #418)",
20+
)
21+
)]
1522
pub(super) fn render_bars<'a, Name, Size>(
1623
tree_table: TreeTable<&'a Name, Size>,
1724
total: u64,

src/visualizer/methods/initial_table.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ impl InitialColumnWidth {
3737
pub(super) type InitialTable<Name, NodeData> =
3838
Table<InitialRow<Name, NodeData>, InitialColumnWidth>;
3939

40+
#[cfg_attr(
41+
dylint_lib = "perfectionist",
42+
expect(
43+
perfectionist::macro_argument_binding,
44+
reason = "the flagged sites are `debug_assert_op!` calls on side-effect-free locals; binding to a `let` would defeat the debug-only contract. See #415",
45+
)
46+
)]
4047
pub(super) fn render_initial<Name, Size>(
4148
visualizer: Visualizer<'_, Name, Size>,
4249
) -> InitialTable<&'_ Name, Size>

src/visualizer/methods/tree_table.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ impl TreeColumnWidth {
4141

4242
pub(super) type TreeTable<Name, NodeData> = Table<TreeRow<Name, NodeData>, TreeColumnWidth>;
4343

44+
#[cfg_attr(
45+
dylint_lib = "perfectionist",
46+
expect(
47+
perfectionist::macro_argument_binding,
48+
reason = "the flagged sites are `debug_assert_op!` / `debug_assert_op_expr!` calls; binding to a `let` would defeat the debug-only contract (see #415), and the rule miscategorises bare operator tokens like `==` and `>` as expressions (see #418)",
49+
)
50+
)]
4451
pub(super) fn render_tree<'a, Name, Size>(
4552
visualizer: Visualizer<'a, Name, Size>,
4653
initial_table: InitialTable<&'a Name, Size>,

src/visualizer/proportion_bar.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,11 @@ use std::fmt::{Display, Error, Formatter};
77
#[derive(Debug, Clone, Copy, PartialEq, Eq, AsRef, Deref, Display, Into)]
88
pub struct ProportionBarBlock(char);
99

10-
macro_rules! make_const {
11-
($name:ident = $content:literal) => {
12-
pub const $name: ProportionBarBlock = ProportionBarBlock($content);
13-
};
14-
}
15-
16-
make_const!(LEVEL0_BLOCK = '█');
17-
make_const!(LEVEL1_BLOCK = '▓');
18-
make_const!(LEVEL2_BLOCK = '▒');
19-
make_const!(LEVEL3_BLOCK = '░');
20-
make_const!(LEVEL4_BLOCK = ' ');
10+
pub const LEVEL0_BLOCK: ProportionBarBlock = ProportionBarBlock('█');
11+
pub const LEVEL1_BLOCK: ProportionBarBlock = ProportionBarBlock('▓');
12+
pub const LEVEL2_BLOCK: ProportionBarBlock = ProportionBarBlock('▒');
13+
pub const LEVEL3_BLOCK: ProportionBarBlock = ProportionBarBlock('░');
14+
pub const LEVEL4_BLOCK: ProportionBarBlock = ProportionBarBlock(' ');
2115

2216
/// Proportion bar.
2317
#[derive(Debug, Clone, Copy, PartialEq, Eq, From, Into)]

tests/_utils.rs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,36 @@ impl SampleWorkspace {
125125
.build(&temp)
126126
.expect("build the filesystem tree for the sample workspace");
127127

128-
macro_rules! link {
129-
($original:literal -> $link:literal) => {{
130-
let original = $original;
131-
let link = $link;
132-
if let Err(error) = hard_link(temp.join(original), temp.join(link)) {
133-
panic!("Failed to link {original} to {link}: {error}");
134-
}
135-
}};
136-
}
128+
let link = |original: &str, link: &str| {
129+
if let Err(error) = hard_link(temp.join(original), temp.join(link)) {
130+
panic!("Failed to link {original} to {link}: {error}");
131+
}
132+
};
137133

138-
link!("main/sources/one-internal-hardlink.txt" -> "main/internal-hardlinks/link-0.txt");
139-
link!("main/sources/two-internal-hardlinks.txt" -> "main/internal-hardlinks/link-1a.txt");
140-
link!("main/sources/two-internal-hardlinks.txt" -> "main/internal-hardlinks/link-1b.txt");
141-
link!("main/sources/one-external-hardlink.txt" -> "external-hardlinks/link-2.txt");
142-
link!("main/sources/one-internal-one-external-hardlinks.txt" -> "main/internal-hardlinks/link-3a.txt");
143-
link!("main/sources/one-internal-one-external-hardlinks.txt" -> "external-hardlinks/link-3b.txt");
134+
link(
135+
"main/sources/one-internal-hardlink.txt",
136+
"main/internal-hardlinks/link-0.txt",
137+
);
138+
link(
139+
"main/sources/two-internal-hardlinks.txt",
140+
"main/internal-hardlinks/link-1a.txt",
141+
);
142+
link(
143+
"main/sources/two-internal-hardlinks.txt",
144+
"main/internal-hardlinks/link-1b.txt",
145+
);
146+
link(
147+
"main/sources/one-external-hardlink.txt",
148+
"external-hardlinks/link-2.txt",
149+
);
150+
link(
151+
"main/sources/one-internal-one-external-hardlinks.txt",
152+
"main/internal-hardlinks/link-3a.txt",
153+
);
154+
link(
155+
"main/sources/one-internal-one-external-hardlinks.txt",
156+
"external-hardlinks/link-3b.txt",
157+
);
144158

145159
SampleWorkspace(temp)
146160
}
@@ -149,21 +163,17 @@ impl SampleWorkspace {
149163
use std::os::unix::fs::symlink;
150164
let workspace = SampleWorkspace::simple_tree_with_some_hardlinks(sizes);
151165

152-
macro_rules! symlink {
153-
($link_name:literal -> $target:literal) => {
154-
let link_name = $link_name;
155-
let target = $target;
156-
if let Err(error) = symlink(target, workspace.join(link_name)) {
157-
panic!("Failed create symbolic link {link_name} pointing to {target}: {error}");
158-
}
159-
};
160-
}
166+
let link = |link_name: &str, target: &str| {
167+
if let Err(error) = symlink(target, workspace.join(link_name)) {
168+
panic!("Failed create symbolic link {link_name} pointing to {target}: {error}");
169+
}
170+
};
161171

162-
symlink!("workspace-itself" -> ".");
163-
symlink!("main/main-itself" -> ".");
164-
symlink!("main/parent-of-main" -> "..");
165-
symlink!("main-mirror" -> "./main");
166-
symlink!("sources-mirror" -> "./main/sources");
172+
link("workspace-itself", ".");
173+
link("main/main-itself", ".");
174+
link("main/parent-of-main", "..");
175+
link("main-mirror", "./main");
176+
link("sources-mirror", "./main/sources");
167177

168178
workspace
169179
}

tests/bytes_format.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
#![cfg_attr(dylint_lib = "perfectionist", feature(register_tool))]
2+
#![cfg_attr(dylint_lib = "perfectionist", register_tool(perfectionist))]
3+
#![cfg_attr(
4+
dylint_lib = "perfectionist",
5+
expect(
6+
perfectionist::macro_argument_binding,
7+
reason = "the `test_case!` macro uses a `name -> value in system == expected` DSL whose separators (`->`, `in`, `==`) are matcher tokens, not expression operators; binding the argument to a `let` is not even syntactically applicable. See #416. The crate-root scope is forced by an upstream late-pass anchoring quirk: violations in module-level item-position macro expansions resolve to the crate root, where finer-scoped `#[expect]` cannot reach them.",
8+
)
9+
)]
10+
111
use parallel_disk_usage::bytes_format::BytesFormat;
212
use pretty_assertions::assert_eq;
313

0 commit comments

Comments
 (0)