From 8570af1d9691d7cb59c4b91876fa0f608c7a9eb3 Mon Sep 17 00:00:00 2001 From: Cyrill Schenkel Date: Tue, 11 Mar 2025 20:35:48 +0100 Subject: [PATCH] Add `print_stdout` and `print_stderr` lints (#17446) (#18233) # Objective - Prevent usage of `println!`, `eprintln!` and the like because they require `std` - Fixes #17446 ## Solution - Enable the `print_stdout` and `print_stderr` clippy lints - Replace all `println!` and `eprintln!` occurrences with `log::*` where applicable or alternatively ignore the warnings ## Testing - Run `cargo clippy --workspace` to ensure that there are no warnings relating to printing to `stdout` or `stderr` --- Cargo.toml | 2 ++ crates/bevy_asset/src/asset_changed.rs | 1 + crates/bevy_ecs/examples/change_detection.rs | 1 + crates/bevy_ecs/examples/events.rs | 2 ++ crates/bevy_ecs/examples/resources.rs | 1 + crates/bevy_ecs/src/error/bevy_error.rs | 1 + crates/bevy_ecs/src/query/iter.rs | 1 + crates/bevy_ecs/src/query/mod.rs | 1 + .../src/schedule/executor/multi_threaded.rs | 25 ++++++++++++------- .../bevy_ecs/src/schedule/executor/simple.rs | 1 + .../src/schedule/executor/single_threaded.rs | 1 + crates/bevy_ecs/src/schedule/stepping.rs | 1 + crates/bevy_ecs/src/system/mod.rs | 1 + crates/bevy_ecs/src/world/mod.rs | 1 + crates/bevy_log/src/lib.rs | 1 + .../src/bounding/bounded2d/primitive_impls.rs | 1 + crates/bevy_math/src/direction.rs | 11 +++++--- crates/bevy_mikktspace/examples/generate.rs | 1 + crates/bevy_reflect/examples/reflect_docs.rs | 2 ++ crates/bevy_remote/src/builtin_methods.rs | 1 + crates/bevy_tasks/examples/busy_behavior.rs | 2 ++ crates/bevy_tasks/examples/idle_behavior.rs | 2 ++ crates/bevy_time/src/lib.rs | 1 + .../src/components/transform.rs | 5 +++- tools/build-easefunction-graphs/src/main.rs | 3 +++ tools/example-showcase/src/main.rs | 2 ++ 26 files changed, 58 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e37832e3b4..130eafda2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,8 @@ unwrap_or_default = "warn" needless_lifetimes = "allow" too_many_arguments = "allow" nonstandard_macro_braces = "warn" +print_stdout = "warn" +print_stderr = "warn" ptr_as_ptr = "warn" ptr_cast_constness = "warn" diff --git a/crates/bevy_asset/src/asset_changed.rs b/crates/bevy_asset/src/asset_changed.rs index 5fc959eada..8e3005a360 100644 --- a/crates/bevy_asset/src/asset_changed.rs +++ b/crates/bevy_asset/src/asset_changed.rs @@ -281,6 +281,7 @@ unsafe impl QueryFilter for AssetChanged { } #[cfg(test)] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { use crate::{AssetEvents, AssetPlugin, Handle}; use alloc::{vec, vec::Vec}; diff --git a/crates/bevy_ecs/examples/change_detection.rs b/crates/bevy_ecs/examples/change_detection.rs index 23420b5e88..1b101b4033 100644 --- a/crates/bevy_ecs/examples/change_detection.rs +++ b/crates/bevy_ecs/examples/change_detection.rs @@ -8,6 +8,7 @@ #![expect( clippy::std_instead_of_core, + clippy::print_stdout, reason = "Examples should not follow this lint" )] diff --git a/crates/bevy_ecs/examples/events.rs b/crates/bevy_ecs/examples/events.rs index 711ba57e1a..70efa9b471 100644 --- a/crates/bevy_ecs/examples/events.rs +++ b/crates/bevy_ecs/examples/events.rs @@ -1,6 +1,8 @@ //! In this example a system sends a custom event with a 50/50 chance during any frame. //! If an event was send, it will be printed by the console in a receiving system. +#![expect(clippy::print_stdout, reason = "Allowed in examples.")] + use bevy_ecs::{event::EventRegistry, prelude::*}; fn main() { diff --git a/crates/bevy_ecs/examples/resources.rs b/crates/bevy_ecs/examples/resources.rs index 43eddf7ce2..bb079d249d 100644 --- a/crates/bevy_ecs/examples/resources.rs +++ b/crates/bevy_ecs/examples/resources.rs @@ -3,6 +3,7 @@ #![expect( clippy::std_instead_of_core, + clippy::print_stdout, reason = "Examples should not follow this lint" )] diff --git a/crates/bevy_ecs/src/error/bevy_error.rs b/crates/bevy_ecs/src/error/bevy_error.rs index 9632d89bc7..4c5c2d89b4 100644 --- a/crates/bevy_ecs/src/error/bevy_error.rs +++ b/crates/bevy_ecs/src/error/bevy_error.rs @@ -139,6 +139,7 @@ std::thread_local! { /// When called, this will skip the currently configured panic hook when a [`BevyError`] backtrace has already been printed. #[cfg(feature = "backtrace")] +#[expect(clippy::print_stdout, reason = "Allowed behind `std` feature gate.")] pub fn bevy_error_panic_hook( current_hook: impl Fn(&std::panic::PanicHookInfo), ) -> impl Fn(&std::panic::PanicHookInfo) { diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 58034618cb..1e5dca4fb1 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -2585,6 +2585,7 @@ impl Ord for NeutralOrd { } #[cfg(test)] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { use alloc::vec::Vec; use std::println; diff --git a/crates/bevy_ecs/src/query/mod.rs b/crates/bevy_ecs/src/query/mod.rs index e9578ed902..fbf55909dd 100644 --- a/crates/bevy_ecs/src/query/mod.rs +++ b/crates/bevy_ecs/src/query/mod.rs @@ -102,6 +102,7 @@ impl DebugCheckedUnwrap for Option { } #[cfg(test)] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { use crate::{ archetype::Archetype, diff --git a/crates/bevy_ecs/src/schedule/executor/multi_threaded.rs b/crates/bevy_ecs/src/schedule/executor/multi_threaded.rs index 7ab6f1a392..a8974682da 100644 --- a/crates/bevy_ecs/src/schedule/executor/multi_threaded.rs +++ b/crates/bevy_ecs/src/schedule/executor/multi_threaded.rs @@ -5,10 +5,9 @@ use bevy_utils::{default, syncunsafecell::SyncUnsafeCell}; use concurrent_queue::ConcurrentQueue; use core::{any::Any, panic::AssertUnwindSafe}; use fixedbitset::FixedBitSet; -use std::{ - eprintln, - sync::{Mutex, MutexGuard}, -}; +#[cfg(feature = "std")] +use std::eprintln; +use std::sync::{Mutex, MutexGuard}; #[cfg(feature = "trace")] use tracing::{info_span, Span}; @@ -283,7 +282,11 @@ impl<'scope, 'env: 'scope, 'sys> Context<'scope, 'env, 'sys> { .push(SystemResult { system_index }) .unwrap_or_else(|error| unreachable!("{}", error)); if let Err(payload) = res { - eprintln!("Encountered a panic in system `{}`!", &*system.name()); + #[cfg(feature = "std")] + #[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")] + { + eprintln!("Encountered a panic in system `{}`!", &*system.name()); + } // set the payload to propagate the error { let mut panic_payload = self.environment.executor.panic_payload.lock().unwrap(); @@ -741,10 +744,14 @@ fn apply_deferred( system.apply_deferred(world); })); if let Err(payload) = res { - eprintln!( - "Encountered a panic when applying buffers for system `{}`!", - &*system.name() - ); + #[cfg(feature = "std")] + #[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")] + { + eprintln!( + "Encountered a panic when applying buffers for system `{}`!", + &*system.name() + ); + } return Err(payload); } } diff --git a/crates/bevy_ecs/src/schedule/executor/simple.rs b/crates/bevy_ecs/src/schedule/executor/simple.rs index a295919690..9570e98d09 100644 --- a/crates/bevy_ecs/src/schedule/executor/simple.rs +++ b/crates/bevy_ecs/src/schedule/executor/simple.rs @@ -118,6 +118,7 @@ impl SystemExecutor for SimpleExecutor { }); #[cfg(feature = "std")] + #[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")] { if let Err(payload) = std::panic::catch_unwind(f) { eprintln!("Encountered a panic in system `{}`!", &*system.name()); diff --git a/crates/bevy_ecs/src/schedule/executor/single_threaded.rs b/crates/bevy_ecs/src/schedule/executor/single_threaded.rs index 277d41eb0b..3f3d579cc2 100644 --- a/crates/bevy_ecs/src/schedule/executor/single_threaded.rs +++ b/crates/bevy_ecs/src/schedule/executor/single_threaded.rs @@ -144,6 +144,7 @@ impl SystemExecutor for SingleThreadedExecutor { }); #[cfg(feature = "std")] + #[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")] { if let Err(payload) = std::panic::catch_unwind(f) { eprintln!("Encountered a panic in system `{}`!", &*system.name()); diff --git a/crates/bevy_ecs/src/schedule/stepping.rs b/crates/bevy_ecs/src/schedule/stepping.rs index 7902460da3..d8a33159a0 100644 --- a/crates/bevy_ecs/src/schedule/stepping.rs +++ b/crates/bevy_ecs/src/schedule/stepping.rs @@ -823,6 +823,7 @@ impl ScheduleState { } #[cfg(all(test, feature = "bevy_debug_stepping"))] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { use super::*; use crate::{prelude::*, schedule::ScheduleLabel}; diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index 9be853bf12..9f408968a9 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -323,6 +323,7 @@ pub fn assert_system_does_not_conflict FromWorld for T { } #[cfg(test)] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { use super::{FromWorld, World}; use crate::{ diff --git a/crates/bevy_log/src/lib.rs b/crates/bevy_log/src/lib.rs index 0a4db7fb8b..055395bad7 100644 --- a/crates/bevy_log/src/lib.rs +++ b/crates/bevy_log/src/lib.rs @@ -259,6 +259,7 @@ impl Default for LogPlugin { } impl Plugin for LogPlugin { + #[expect(clippy::print_stderr, reason = "Allowed during logger setup")] fn build(&self, app: &mut App) { #[cfg(feature = "trace")] { diff --git a/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs index 202b125588..766249b7ca 100644 --- a/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs @@ -438,6 +438,7 @@ impl Bounded2d for Capsule2d { } #[cfg(test)] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { use core::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_4, FRAC_PI_6, TAU}; use std::println; diff --git a/crates/bevy_math/src/direction.rs b/crates/bevy_math/src/direction.rs index 78eb7cc359..f9b98021d3 100644 --- a/crates/bevy_math/src/direction.rs +++ b/crates/bevy_math/src/direction.rs @@ -69,10 +69,13 @@ fn assert_is_normalized(message: &str, length_squared: f32) { } else if length_error_squared > 2e-4 { // Length error is approximately 1e-4 or more. #[cfg(feature = "std")] - eprintln!( - "Warning: {message} The length is {}.", - ops::sqrt(length_squared) - ); + #[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")] + { + eprintln!( + "Warning: {message} The length is {}.", + ops::sqrt(length_squared) + ); + } } } diff --git a/crates/bevy_mikktspace/examples/generate.rs b/crates/bevy_mikktspace/examples/generate.rs index 764d070850..62f6f10bfa 100644 --- a/crates/bevy_mikktspace/examples/generate.rs +++ b/crates/bevy_mikktspace/examples/generate.rs @@ -5,6 +5,7 @@ clippy::useless_conversion, reason = "Crate auto-generated with many non-idiomatic decisions. See #7372 for details." )] +#![expect(clippy::print_stdout, reason = "Allowed in examples.")] use glam::{Vec2, Vec3}; diff --git a/crates/bevy_reflect/examples/reflect_docs.rs b/crates/bevy_reflect/examples/reflect_docs.rs index 10852185c0..d52589cc1d 100644 --- a/crates/bevy_reflect/examples/reflect_docs.rs +++ b/crates/bevy_reflect/examples/reflect_docs.rs @@ -6,6 +6,8 @@ //! //! These scenarios can readily be achieved by using `bevy_reflect` with the `documentation` feature. +#![expect(clippy::print_stdout, reason = "Allowed in examples.")] + use bevy_reflect::{Reflect, TypeInfo, Typed}; fn main() { diff --git a/crates/bevy_remote/src/builtin_methods.rs b/crates/bevy_remote/src/builtin_methods.rs index f75e4d4da3..83a0bbe9da 100644 --- a/crates/bevy_remote/src/builtin_methods.rs +++ b/crates/bevy_remote/src/builtin_methods.rs @@ -1758,6 +1758,7 @@ fn get_resource_type_registration<'r>( } #[cfg(test)] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { /// A generic function that tests serialization and deserialization of any type /// implementing Serialize and Deserialize traits. diff --git a/crates/bevy_tasks/examples/busy_behavior.rs b/crates/bevy_tasks/examples/busy_behavior.rs index 808940ab9f..c560e58b91 100644 --- a/crates/bevy_tasks/examples/busy_behavior.rs +++ b/crates/bevy_tasks/examples/busy_behavior.rs @@ -2,6 +2,8 @@ //! for 100ms. It's expected to take about a second to run (assuming the machine has >= 4 logical //! cores) +#![expect(clippy::print_stdout, reason = "Allowed in examples.")] + use bevy_platform_support::time::Instant; use bevy_tasks::TaskPoolBuilder; use core::time::Duration; diff --git a/crates/bevy_tasks/examples/idle_behavior.rs b/crates/bevy_tasks/examples/idle_behavior.rs index 3de9388fd2..c68e399a89 100644 --- a/crates/bevy_tasks/examples/idle_behavior.rs +++ b/crates/bevy_tasks/examples/idle_behavior.rs @@ -2,6 +2,8 @@ //! spinning. Other than the one thread, the system should remain idle, demonstrating good behavior //! for small workloads. +#![expect(clippy::print_stdout, reason = "Allowed in examples.")] + use bevy_platform_support::time::Instant; use bevy_tasks::TaskPoolBuilder; use core::time::Duration; diff --git a/crates/bevy_time/src/lib.rs b/crates/bevy_time/src/lib.rs index 2f37ead16a..db39a41929 100644 --- a/crates/bevy_time/src/lib.rs +++ b/crates/bevy_time/src/lib.rs @@ -175,6 +175,7 @@ pub fn time_system( } #[cfg(test)] +#[expect(clippy::print_stdout, reason = "Allowed in tests.")] mod tests { use crate::{Fixed, Time, TimePlugin, TimeUpdateStrategy, Virtual}; use bevy_app::{App, FixedUpdate, Startup, Update}; diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index ba4328becb..f37c981663 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -27,7 +27,10 @@ fn assert_is_normalized(message: &str, length_squared: f32) { } else if length_error_squared > 2e-4 { // Length error is approximately 1e-4 or more. #[cfg(feature = "std")] - eprintln!("Warning: {message}",); + #[expect(clippy::print_stderr, reason = "Allowed behind `std` feature gate.")] + { + eprintln!("Warning: {message}",); + } } } diff --git a/tools/build-easefunction-graphs/src/main.rs b/tools/build-easefunction-graphs/src/main.rs index 5034251ab2..2408987bd2 100644 --- a/tools/build-easefunction-graphs/src/main.rs +++ b/tools/build-easefunction-graphs/src/main.rs @@ -1,4 +1,7 @@ //! Generates graphs for the `EaseFunction` docs. + +#![expect(clippy::print_stdout, reason = "Allowed in tools.")] + use std::path::PathBuf; use bevy_math::curve::{CurveExt, EaseFunction, EasingCurve, JumpAt}; diff --git a/tools/example-showcase/src/main.rs b/tools/example-showcase/src/main.rs index 49afb15c20..4cdf3b0412 100644 --- a/tools/example-showcase/src/main.rs +++ b/tools/example-showcase/src/main.rs @@ -1,5 +1,7 @@ //! Tool to run all examples or generate a showcase page for the Bevy website. +#![expect(clippy::print_stdout, reason = "Allowed in tools.")] + use core::{ fmt::Display, hash::{Hash, Hasher},