From 4a09782fce11c03b8afa30b8a4a5a2d0942b3303 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 4 Apr 2026 16:20:29 +0200 Subject: [PATCH] Enable a few more clippy lints (#8064) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable these new clippy lints and fix all warnings: * `format_push_string` — use `write!` instead of `s += &format!(…)` to avoid extra allocations * `ignored_unit_patterns` — use `()` instead of `_` when matching unit * `missing_fields_in_debug` — ensure manual `Debug` impls account for all fields * `needless_raw_string_hashes` — remove unnecessary `r#` on string literals * `ref_option` — prefer `Option<&T>` over `&Option` in function signatures --- Cargo.toml | 5 +++ crates/eframe/src/native/file_storage.rs | 2 +- crates/egui-wgpu/src/lib.rs | 33 ++++++++++++++----- crates/egui-wgpu/src/setup.rs | 17 +++++++--- crates/egui/src/callstack.rs | 14 +++++--- crates/egui/src/containers/window.rs | 6 ++-- crates/egui/src/context.rs | 15 ++++++--- crates/egui/src/data/input.rs | 2 ++ .../text_selection/label_text_selection.rs | 11 +++++-- crates/egui/src/widgets/drag_value.rs | 8 ++--- crates/egui_demo_app/src/main.rs | 3 +- crates/egui_demo_app/src/wrap_app.rs | 3 +- crates/egui_extras/src/table.rs | 12 +++---- crates/egui_kittest/src/snapshot.rs | 8 ++--- examples/custom_3d_glow/src/main.rs | 8 ++--- examples/file_dialog/src/main.rs | 3 +- tests/test_background_logic/src/main.rs | 3 +- 17 files changed, 100 insertions(+), 53 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c6cb0c03..d589ef954 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -218,10 +218,12 @@ flat_map_option = "warn" float_cmp_const = "warn" fn_params_excessive_bools = "warn" fn_to_numeric_cast_any = "warn" +format_push_string = "warn" from_iter_instead_of_collect = "warn" get_unwrap = "warn" if_let_mutex = "warn" ignore_without_reason = "warn" +ignored_unit_patterns = "warn" implicit_clone = "warn" implied_bounds_in_impls = "warn" imprecise_flops = "warn" @@ -270,6 +272,7 @@ mismatching_type_param_order = "warn" missing_assert_message = "warn" missing_enforced_import_renames = "warn" missing_errors_doc = "warn" +missing_fields_in_debug = "warn" missing_safety_doc = "warn" mixed_attributes_style = "warn" mut_mut = "warn" @@ -279,6 +282,7 @@ needless_continue = "warn" needless_for_each = "warn" needless_pass_by_ref_mut = "warn" needless_pass_by_value = "warn" +needless_raw_string_hashes = "warn" negative_feature_names = "warn" non_std_lazy_statics = "warn" non_zero_suggestions = "warn" @@ -299,6 +303,7 @@ rc_mutex = "warn" readonly_write_lock = "warn" redundant_type_annotations = "warn" ref_as_ptr = "warn" +ref_option = "warn" ref_option_ref = "warn" ref_patterns = "warn" rest_pat_in_fully_bound_structs = "warn" diff --git a/crates/eframe/src/native/file_storage.rs b/crates/eframe/src/native/file_storage.rs index f26a6df74..13e22fa75 100644 --- a/crates/eframe/src/native/file_storage.rs +++ b/crates/eframe/src/native/file_storage.rs @@ -207,7 +207,7 @@ fn save_to_disk(file_path: &PathBuf, kv: &HashMap) { profiling::scope!("ron::serialize"); if let Err(err) = ron::Options::default() .to_io_writer_pretty(&mut writer, &kv, config) - .and_then(|_| writer.flush().map_err(|err| err.into())) + .and_then(|()| writer.flush().map_err(|err| err.into())) { log::warn!("Failed to serialize app state: {err}"); } else { diff --git a/crates/egui-wgpu/src/lib.rs b/crates/egui-wgpu/src/lib.rs index eb04173b5..180b305be 100644 --- a/crates/egui-wgpu/src/lib.rs +++ b/crates/egui-wgpu/src/lib.rs @@ -427,37 +427,52 @@ pub fn adapter_info_summary(info: &wgpu::AdapterInfo) -> String { // > name: "Apple M1 Pro", device_type: IntegratedGpu, backend: Metal, driver: "", driver_info: "" // > name: "ANGLE (Apple, Apple M1 Pro, OpenGL 4.1)", device_type: IntegratedGpu, backend: Gl, driver: "", driver_info: "" + use std::fmt::Write as _; + let mut summary = format!("backend: {backend:?}, device_type: {device_type:?}"); if !name.is_empty() { - summary += &format!(", name: {name:?}"); + write!(summary, ", name: {name:?}").ok(); } if !driver.is_empty() { - summary += &format!(", driver: {driver:?}"); + write!(summary, ", driver: {driver:?}").ok(); } if !driver_info.is_empty() { - summary += &format!(", driver_info: {driver_info:?}"); + write!(summary, ", driver_info: {driver_info:?}").ok(); } if *vendor != 0 { #[cfg(not(target_arch = "wasm32"))] { - summary += &format!(", vendor: {} (0x{vendor:04X})", parse_vendor_id(*vendor)); + write!( + summary, + ", vendor: {} (0x{vendor:04X})", + parse_vendor_id(*vendor) + ) + .ok(); } #[cfg(target_arch = "wasm32")] { - summary += &format!(", vendor: 0x{vendor:04X}"); + write!(summary, ", vendor: 0x{vendor:04X}").ok(); } } if *device != 0 { - summary += &format!(", device: 0x{device:02X}"); + write!(summary, ", device: 0x{device:02X}").ok(); } if !device_pci_bus_id.is_empty() { - summary += &format!(", pci_bus_id: {device_pci_bus_id:?}"); + write!(summary, ", pci_bus_id: {device_pci_bus_id:?}").ok(); } if *subgroup_min_size != 0 || *subgroup_max_size != 0 { - summary += &format!(", subgroup_size: {subgroup_min_size}..={subgroup_max_size}"); + write!( + summary, + ", subgroup_size: {subgroup_min_size}..={subgroup_max_size}" + ) + .ok(); } - summary += &format!(", transient_saves_memory: {transient_saves_memory}"); + write!( + summary, + ", transient_saves_memory: {transient_saves_memory}" + ) + .ok(); summary } diff --git a/crates/egui-wgpu/src/setup.rs b/crates/egui-wgpu/src/setup.rs index c5b3f0421..cf8b652c2 100644 --- a/crates/egui-wgpu/src/setup.rs +++ b/crates/egui-wgpu/src/setup.rs @@ -296,15 +296,22 @@ impl Clone for WgpuSetupCreateNew { impl std::fmt::Debug for WgpuSetupCreateNew { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { + instance_descriptor, + display_handle, + power_preference, + native_adapter_selector, + device_descriptor: _, + } = self; f.debug_struct("WgpuSetupCreateNew") - .field("instance_descriptor", &self.instance_descriptor) - .field("display_handle", &self.display_handle) - .field("power_preference", &self.power_preference) + .field("instance_descriptor", instance_descriptor) + .field("display_handle", display_handle) + .field("power_preference", power_preference) .field( "native_adapter_selector", - &self.native_adapter_selector.is_some(), + &native_adapter_selector.is_some(), ) - .finish() + .finish_non_exhaustive() } } diff --git a/crates/egui/src/callstack.rs b/crates/egui/src/callstack.rs index fef9b2166..b1239db01 100644 --- a/crates/egui/src/callstack.rs +++ b/crates/egui/src/callstack.rs @@ -1,3 +1,5 @@ +use std::fmt::Write as _; + #[derive(Clone)] struct Frame { /// `_main` is usually as the deepest depth. @@ -23,7 +25,7 @@ pub fn capture() -> String { if let Some(file_and_line) = &mut file_and_line && let Some(line_nr) = symbol.lineno() { - file_and_line.push_str(&format!(":{line_nr}")); + write!(file_and_line, ":{line_nr}").ok(); } let file_and_line = file_and_line.unwrap_or_default(); @@ -130,12 +132,14 @@ pub fn capture() -> String { if frame.depth + 1 < last_depth || last_depth + 1 < frame.depth { // Show that some frames were elided - formatted.push_str(&format!("{:widest_depth$} …\n", "")); + writeln!(formatted, "{:widest_depth$} …", "").ok(); } - formatted.push_str(&format!( - "{depth:widest_depth$}: {file_and_line:widest_file_line$} {name}\n" - )); + writeln!( + formatted, + "{depth:widest_depth$}: {file_and_line:widest_file_line$} {name}" + ) + .ok(); last_depth = frame.depth; } diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index ae5fbfc8f..5ade37014 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -673,7 +673,7 @@ impl Window<'_> { title_bar.ui( &mut area_content_ui, - &content_response, + content_response.as_ref(), open.as_deref_mut(), &mut collapsing, collapsible, @@ -1256,7 +1256,7 @@ impl TitleBar { fn ui( self, ui: &mut Ui, - content_response: &Option, + content_response: Option<&Response>, open: Option<&mut bool>, collapsing: &mut CollapsingState, collapsible: bool, @@ -1300,7 +1300,7 @@ impl TitleBar { ui.visuals().text_color(), ); - if let Some(content_response) = &content_response { + if let Some(content_response) = content_response { // Paint separator between title and content: let content_rect = content_response.rect; if false { diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index a8751bffc..824a5318c 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -2428,6 +2428,7 @@ impl Context { #[cfg(debug_assertions)] fn debug_painting(&self) { #![expect(clippy::iter_over_hash_type)] // ok to be sloppy in debug painting + use std::fmt::Write as _; let paint_widget = |widget: &WidgetRect, text: &str, color: Color32| { let rect = widget.interact_rect; @@ -2500,13 +2501,17 @@ impl Context { for id in contains_pointer { let mut widget_text = format!("{id:?}"); if let Some(rect) = widget_rects.get(id) { - widget_text += - &format!(" {:?} {:?} {:?}", rect.layer_id, rect.rect, rect.sense); + write!( + widget_text, + " {:?} {:?} {:?}", + rect.layer_id, rect.rect, rect.sense + ) + .ok(); } if let Some(info) = widget_rects.info(id) { - widget_text += &format!(" {info:?}"); + write!(widget_text, " {info:?}").ok(); } - debug_text += &format!("{widget_text}\n"); + writeln!(debug_text, "{widget_text}").ok(); } self.debug_text(debug_text); } @@ -2571,7 +2576,7 @@ impl Context { ); self.viewport(|vp| { for reason in &vp.output.request_discard_reasons { - warning += &format!("\n {reason}"); + write!(warning, "\n {reason}").ok(); } }); diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 5e1680334..00cf59cba 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -376,12 +376,14 @@ impl ViewportInfo { ui.label(opt_as_str(&visible)); ui.end_row(); + #[expect(clippy::ref_option)] fn opt_rect_as_string(v: &Option) -> String { v.as_ref().map_or(String::new(), |r| { format!("Pos: {:?}, size: {:?}", r.min, r.size()) }) } + #[expect(clippy::ref_option)] fn opt_as_str(v: &Option) -> String { v.as_ref().map_or(String::new(), |v| format!("{v:?}")) } diff --git a/crates/egui/src/text_selection/label_text_selection.rs b/crates/egui/src/text_selection/label_text_selection.rs index 1dc825ad3..3df17d17c 100644 --- a/crates/egui/src/text_selection/label_text_selection.rs +++ b/crates/egui/src/text_selection/label_text_selection.rs @@ -49,10 +49,15 @@ fn pos_in_galley(galley: &Galley, ccursor: CCursor) -> Pos2 { impl std::fmt::Debug for WidgetTextCursor { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self { + widget_id, + ccursor, + pos: _, + } = self; f.debug_struct("WidgetTextCursor") - .field("widget_id", &self.widget_id.short_debug_format()) - .field("ccursor", &self.ccursor.index) - .finish() + .field("widget_id", &widget_id.short_debug_format()) + .field("ccursor", &ccursor.index) + .finish_non_exhaustive() } } diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 1297b614b..cca43ea2f 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -551,7 +551,7 @@ impl Widget for DragValue<'_> { if let Some(value_text) = value_text { // We were editing the value as text last frame, but lost focus. // Make sure we applied the last text value: - let parsed_value = parse(&custom_parser, &value_text); + let parsed_value = parse(custom_parser.as_ref(), &value_text); if let Some(mut parsed_value) = parsed_value { // User edits always clamps: parsed_value = clamp_value_to_range(parsed_value, range.clone()); @@ -591,7 +591,7 @@ impl Widget for DragValue<'_> { response.lost_focus() && !ui.input(|i| i.key_pressed(Key::Escape)) }; if update { - let parsed_value = parse(&custom_parser, &value_text); + let parsed_value = parse(custom_parser.as_ref(), &value_text); if let Some(mut parsed_value) = parsed_value { // User edits always clamps: parsed_value = clamp_value_to_range(parsed_value, range.clone()); @@ -733,8 +733,8 @@ impl Widget for DragValue<'_> { } } -fn parse(custom_parser: &Option>, value_text: &str) -> Option { - match &custom_parser { +fn parse(custom_parser: Option<&NumParser<'_>>, value_text: &str) -> Option { + match custom_parser { Some(parser) => parser(value_text), None => default_parser(value_text), } diff --git a/crates/egui_demo_app/src/main.rs b/crates/egui_demo_app/src/main.rs index a4ffdb5f9..38da5751d 100644 --- a/crates/egui_demo_app/src/main.rs +++ b/crates/egui_demo_app/src/main.rs @@ -38,7 +38,8 @@ fn main() { }); for loud_crate in ["naga", "wgpu_core", "wgpu_hal"] { if !rust_log.contains(&format!("{loud_crate}=")) { - rust_log += &format!(",{loud_crate}=warn"); + use std::fmt::Write as _; + write!(rust_log, ",{loud_crate}=warn").ok(); } } diff --git a/crates/egui_demo_app/src/wrap_app.rs b/crates/egui_demo_app/src/wrap_app.rs index 9f43f8624..64ecbce56 100644 --- a/crates/egui_demo_app/src/wrap_app.rs +++ b/crates/egui_demo_app/src/wrap_app.rs @@ -519,7 +519,8 @@ impl WrapApp { additional_info.push(format!("{} bytes", bytes.len())); } if !additional_info.is_empty() { - info += &format!(" ({})", additional_info.join(", ")); + use std::fmt::Write as _; + write!(info, " ({})", additional_info.join(", ")).ok(); } ui.label(info); diff --git a/crates/egui_extras/src/table.rs b/crates/egui_extras/src/table.rs index 25257421a..f62b71122 100644 --- a/crates/egui_extras/src/table.rs +++ b/crates/egui_extras/src/table.rs @@ -996,7 +996,7 @@ impl<'a> TableBody<'a> { overline: false, response: &mut response, }); - self.capture_hover_state(&response, self.row_index); + self.capture_hover_state(response.as_ref(), self.row_index); let bottom_y = self.layout.cursor.y; if Some(self.row_index) == self.scroll_to_row { @@ -1078,7 +1078,7 @@ impl<'a> TableBody<'a> { overline: false, response: &mut response, }); - self.capture_hover_state(&response, row_index); + self.capture_hover_state(response.as_ref(), row_index); } if total_rows - max_row > 0 { @@ -1160,7 +1160,7 @@ impl<'a> TableBody<'a> { overline: false, response: &mut response, }); - self.capture_hover_state(&response, row_index); + self.capture_hover_state(response.as_ref(), row_index); break; } } @@ -1183,7 +1183,7 @@ impl<'a> TableBody<'a> { selected: false, response: &mut response, }); - self.capture_hover_state(&response, row_index); + self.capture_hover_state(response.as_ref(), row_index); cursor_y += (row_height + spacing.y) as f64; if Some(row_index) == self.scroll_to_row { @@ -1234,8 +1234,8 @@ impl<'a> TableBody<'a> { // Capture the hover information for the just created row. This is used in the next render // to ensure that the entire row is highlighted. - fn capture_hover_state(&self, response: &Option, row_index: usize) { - let is_row_hovered = response.as_ref().is_some_and(|r| r.hovered()); + fn capture_hover_state(&self, response: Option<&Response>, row_index: usize) { + let is_row_hovered = response.is_some_and(|r| r.hovered()); if is_row_hovered { self.layout .ui diff --git a/crates/egui_kittest/src/snapshot.rs b/crates/egui_kittest/src/snapshot.rs index 28b5ac986..adbe32399 100644 --- a/crates/egui_kittest/src/snapshot.rs +++ b/crates/egui_kittest/src/snapshot.rs @@ -563,7 +563,7 @@ pub fn image_snapshot_options( options: &SnapshotOptions, ) { match try_image_snapshot_options(current, name, options) { - Ok(_) => {} + Ok(()) => {} Err(err) => { panic!("{err}"); } @@ -582,7 +582,7 @@ pub fn image_snapshot_options( #[track_caller] pub fn image_snapshot(current: &image::RgbaImage, name: impl Into) { match try_image_snapshot(current, name) { - Ok(_) => {} + Ok(()) => {} Err(err) => { panic!("{err}"); } @@ -884,14 +884,14 @@ impl Drop for SnapshotResults { #[expect(clippy::manual_assert)] if count >= 2 { panic!( - r#" + " Multiple SnapshotResults were dropped without being handled. In order to allow consistent snapshot updates, all snapshot results within a test should be merged in a single SnapshotResults instance. Usually this is handled internally in a harness. If you have multiple harnesses, you can merge the results using `Harness::take_snapshot_results` and `SnapshotResults::extend`. The SnapshotResult was constructed at {} - "#, + ", self.location ); } diff --git a/examples/custom_3d_glow/src/main.rs b/examples/custom_3d_glow/src/main.rs index 6b804ed1c..e0a3e3dd2 100644 --- a/examples/custom_3d_glow/src/main.rs +++ b/examples/custom_3d_glow/src/main.rs @@ -106,7 +106,7 @@ impl RotatingTriangle { let program = gl.create_program().expect("Cannot create program"); let (vertex_shader_source, fragment_shader_source) = ( - r#" + " const vec2 verts[3] = vec2[3]( vec2(0.0, 1.0), vec2(-1.0, -1.0), @@ -124,15 +124,15 @@ impl RotatingTriangle { gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0); gl_Position.x *= cos(u_angle); } - "#, - r#" + ", + " precision mediump float; in vec4 v_color; out vec4 out_color; void main() { out_color = v_color; } - "#, + ", ); let shader_sources = [ diff --git a/examples/file_dialog/src/main.rs b/examples/file_dialog/src/main.rs index 33bda7a96..a2cef84e7 100644 --- a/examples/file_dialog/src/main.rs +++ b/examples/file_dialog/src/main.rs @@ -64,7 +64,8 @@ impl eframe::App for MyApp { additional_info.push(format!("{} bytes", bytes.len())); } if !additional_info.is_empty() { - info += &format!(" ({})", additional_info.join(", ")); + use std::fmt::Write as _; + write!(info, " ({})", additional_info.join(", ")).ok(); } ui.label(info); diff --git a/tests/test_background_logic/src/main.rs b/tests/test_background_logic/src/main.rs index ea80cfa9e..b1c559916 100644 --- a/tests/test_background_logic/src/main.rs +++ b/tests/test_background_logic/src/main.rs @@ -56,7 +56,8 @@ fn viewport_info(ctx: &egui::Context) -> String { ]; for (name, value) in flags { if let Some(value) = value { - s += &format!(" {name}={value}"); + use std::fmt::Write as _; + write!(s, " {name}={value}").ok(); } } s