From 8bfabafe8a2f752715fdfa73fef0d11352a875c9 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Fri, 6 Nov 2026 20:06:56 +0800 Subject: [PATCH] =?UTF-8?q?fix(app-iced):=20M147=20=E4=BF=AE=E6=8E=89=20Li?= =?UTF-8?q?nux=20=E4=BE=A7=20clippy=20=E7=9A=84=2014=20=E6=9D=A1=E9=94=99?= =?UTF-8?q?=E4=B8=8E=E5=86=99=E6=AD=BB=E5=B9=B3=E5=8F=B0=E7=9A=84=20=CE=B1?= =?UTF-8?q?=20=E6=96=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两条红的成因都是「Windows-only 的东西没有平台门」:Linux + `--all-targets` + `-D warnings` 三件事凑齐时,Windows 专有的 DWM/穿透代码在 Linux 上变成未用导入 + 死代码。 clippy(14 条错,docker 内 exit 101 → 0): - dwm.rs `set_preference` 的 `#[cfg(not(windows))]` 分支以 `return` 结尾 ⇒ needless_return; 那个块本来就是该 cfg 下函数体的尾巴,去掉 `return`。 - dwm.rs 三常量 + 四读函数在非 Windows 上没有使用者(唯一调用方 `probe::run_one` 的 Windows 版被门着,`transparency.rs` 只 re-export 三项)⇒ dead_code。用**模块级** `#![cfg_attr(not(target_os = "windows"), allow(dead_code))]`: · 逐项 `cfg(target_os = "windows")` 会把它们从 Linux 构建里删掉,本文件那几条与平台 无关的单测(属性号照 Win32 头文件、无效句柄不许表现成成功)就连编译都过不了; · 逐项 `cfg_attr` 要多 7 行,本文件 394 行 → 会顶破 guards.yml 的 400 行红线(现 398 行)。 代价写明在文件头:非 Windows 上本模块的 dead_code 不再报。 - exstyle.rs `use super::raw_ex_style`:唯一使用者 `click_through` 自己按平台门着 ⇒ 补 cfg。 - probe.rs 的 `use super::dwm::{…}`:`CornerOutcome` 与平台无关(`ProbeRow` 字段 + 非 Windows 的 `empty_row`),其余九个符号只服务于 Windows 的 `run_one` ⇒ 拆成两条 use。 - window_alpha.rs `use …RawWindowHandle`:只有 `RawWindowHandle::Win32` 那条臂用它 ⇒ 补 cfg。 test(docker 内 622 passed / 1 failed → 623 passed / 0 failed): `opaque_or_refused_alpha_never_touches_the_window_style` 里「无效句柄 ⇒ Failed」是按 Windows 语义写死的;非 Windows 走 `transparency::set_layered` 的空实现,如实返回 `Unsupported`。 按平台拆成两条断言(Windows 断 `Failed`,其它断 `Unsupported`),两边都不许表现成 `Applied`/`Opaque`。顺带说明:`dispatch` 的 `layered=false` 那半条断言与平台无关,保留在 两条之外照跑。 验证(本机 Windows + Docker Debian 12,命令与 ci.yml 逐字一致): - docker `cargo clippy --workspace --all-targets -- -D warnings` → exit 0 - docker `cargo test -p unlucky-app-iced --lib` → 623 passed / 0 failed - Windows `cargo check -p unlucky-app-iced --all-targets` → 无 error/warning - Windows `cargo test -p unlucky-app-iced --lib` → 624 passed / 0 failed / 2 ignored --- crates/app-iced/src/app/window_alpha.rs | 13 +++++++++++++ .../app-iced/src/platform/win32/transparency/dwm.rs | 6 +++++- .../src/platform/win32/transparency/exstyle.rs | 3 +++ .../src/platform/win32/transparency/probe.rs | 7 ++++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/crates/app-iced/src/app/window_alpha.rs b/crates/app-iced/src/app/window_alpha.rs index e3366d9..7ece895 100644 --- a/crates/app-iced/src/app/window_alpha.rs +++ b/crates/app-iced/src/app/window_alpha.rs @@ -52,6 +52,9 @@ impl Dispatch { /// 把 iced 的窗口句柄翻成 Win32 的 `HWND`(`isize`)。非 Windows 平台返回 `None`。 pub(super) fn probe_hwnd(handle: &dyn window::Window) -> Option { + // 只有 `RawWindowHandle::Win32` 那条臂用到它,其余平台只剩 `_ => None` + // ⇒ 无条件导入在非 Windows 上是 `unused_imports`(M147)。 + #[cfg(target_os = "windows")] use window::raw_window_handle::RawWindowHandle; let handle = handle.window_handle().ok()?; @@ -99,11 +102,21 @@ mod tests { // 无效句柄 + 合法 α:样式补不上(layered=false),FFI 也不会成功——两层都如实报告。 let invalid = dispatch(1, Some(0.5)); assert!(!invalid.layered, "无效句柄补不上 WS_EX_LAYERED"); + // 「做不到」的语义随平台不同(M147 实证:这条断言原先按 Windows 写死,Ubuntu 上 + // 622 passed / 1 failed):Windows 上 FFI 真被调用并失败 ⇒ `Failed`;非 Windows 走 + // `transparency.rs` 的空实现 ⇒ `Unsupported`。两边都不许表现成 `Applied` / `Opaque`。 + #[cfg(target_os = "windows")] assert!( matches!(invalid.alpha, AlphaOutcome::Failed { .. }), "{:?}", invalid.alpha ); + #[cfg(not(target_os = "windows"))] + assert_eq!( + invalid.alpha, + AlphaOutcome::Unsupported, + "非 Windows 的空实现必须如实说「这个平台不支持」,不许冒充成功" + ); } /// 本机真窗口的取证由 `App` 启动日志给(见 `app::appearance::log_appearance`), diff --git a/crates/app-iced/src/platform/win32/transparency/dwm.rs b/crates/app-iced/src/platform/win32/transparency/dwm.rs index 3990bae..a8707b2 100644 --- a/crates/app-iced/src/platform/win32/transparency/dwm.rs +++ b/crates/app-iced/src/platform/win32/transparency/dwm.rs @@ -18,6 +18,10 @@ //! 回读拿到的是 **DWM 侧的当前值**——它能抓住「设了 A 属性、读回还是旧值」这类事 //! (比如把 `DWMWA_WINDOW_CORNER_PREFERENCE` 写成别的号,回读会给出 `None` 或旧值)。 +// M147:本模块七项(三个属性号 + 四个读函数)只在 Windows 上有使用者——唯一调用方 `probe::run_one` +// 的 Windows 版被门着,Linux + `-D warnings` 下就是 dead_code 错。用模块级 `cfg_attr` 而不是 +// 逐项 `cfg`:`cfg` 会把这些项连同本文件那几条与平台无关的单测一起门掉(逐项 `cfg_attr` 多 7 行,顶破红线)。 +#![cfg_attr(not(target_os = "windows"), allow(dead_code))] /// `DWMWA_WINDOW_CORNER_PREFERENCE`:窗口圆角偏好的属性号(Win11 / Server 2025,build ≥ 22000)。 pub const DWMWA_WINDOW_CORNER_PREFERENCE: u32 = 34; /// `DWMWCP_DONOTROUND`:显式直角。 @@ -120,7 +124,7 @@ pub fn set_preference(hwnd: isize, preference: u32) -> CornerOutcome { #[cfg(not(target_os = "windows"))] { let _ = (hwnd, preference); - return CornerOutcome::UnsupportedPlatform; + CornerOutcome::UnsupportedPlatform } #[cfg(target_os = "windows")] { diff --git a/crates/app-iced/src/platform/win32/transparency/exstyle.rs b/crates/app-iced/src/platform/win32/transparency/exstyle.rs index 82c8ab4..ec1ce34 100644 --- a/crates/app-iced/src/platform/win32/transparency/exstyle.rs +++ b/crates/app-iced/src/platform/win32/transparency/exstyle.rs @@ -19,6 +19,9 @@ //! 「取证窗口真的把命中测试关掉了」的 OS 侧证据——比「出图 hash 不变」有判别力得多 //! (实测:同 argv 开/关穿透,hash 完全相同)。 +// 唯一使用者是下面的 `click_through`(它自己按平台门禁),非 Windows 上这个导入没人用 +// ⇒ `unused_imports` 在 `-D warnings` 下升成错(M147)。 +#[cfg(target_os = "windows")] use super::raw_ex_style; /// `WS_EX_TRANSPARENT`:**点击穿透**位(`0x0000_0020`)。 diff --git a/crates/app-iced/src/platform/win32/transparency/probe.rs b/crates/app-iced/src/platform/win32/transparency/probe.rs index 2a307ac..05ce55d 100644 --- a/crates/app-iced/src/platform/win32/transparency/probe.rs +++ b/crates/app-iced/src/platform/win32/transparency/probe.rs @@ -39,9 +39,14 @@ #[cfg(target_os = "windows")] use super::alpha::{apply_window_alpha, ensure_layered}; +// `CornerOutcome` 与平台无关(`ProbeRow` 的字段类型、非 Windows 的 `empty_row` 都用它), +// 其余九个符号只服务于 Windows 的 `run_one` —— 分开写,否则非 Windows 上整条导入无人使用 +// (`unused_imports`,M147)。 +use super::dwm::CornerOutcome; +#[cfg(target_os = "windows")] use super::dwm::{ corner_preference_hr, extended_frame_bounds, set_preference, visible_border_thickness, - window_rect, window_style, CornerOutcome, DWMWCP_DONOTROUND, DWMWCP_ROUND, + window_rect, window_style, DWMWCP_DONOTROUND, DWMWCP_ROUND, }; /// `WS_POPUP`(`0x8000_0000`):**带 owner 的弹出窗**才用它;产品主窗口没有 owner,不用。