diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 555fafc6..5c3334a2 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -9,6 +9,11 @@ //! it from `main()` will set the exit code, which allows external processes to detect whether there //! was an error. //! +//! # Known issues +//! +//! If you wish to silence this lint, you must add `#[allow(bevy::main_return_without_appexit)]` to +//! `fn main()`, not the line that calls `App::run()`. +//! //! # Example //! //! ``` diff --git a/bevy_lint/tests/ui/insert_event_resource/bug_94.rs b/bevy_lint/tests/ui/insert_event_resource/bug_94.rs new file mode 100644 index 00000000..17e4e987 --- /dev/null +++ b/bevy_lint/tests/ui/insert_event_resource/bug_94.rs @@ -0,0 +1,22 @@ +//! This test tracks the bug reported in [#94]. When this starts failing, the bug has been fixed. +//! +//! [#94]: https://github.com/TheBevyFlock/bevy_cli/issues/94 + +//@check-pass + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::insert_event_resource)] + +use bevy::prelude::*; + +#[derive(Event)] +struct Foo; + +fn main() { + let mut app = App::new(); + + // These both should error, but currently do not. + App::init_resource::>(&mut app); + App::insert_resource::>(&mut app, Default::default()); +} diff --git a/bevy_lint/tests/ui/insert_event_resource/main.fixed b/bevy_lint/tests/ui/insert_event_resource/main.fixed new file mode 100644 index 00000000..2b1265c7 --- /dev/null +++ b/bevy_lint/tests/ui/insert_event_resource/main.fixed @@ -0,0 +1,26 @@ +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::insert_event_resource)] + +use bevy::prelude::*; + +#[derive(Event)] +struct Foo; + +fn main() { + App::new().add_event::(); + //~^ ERROR: called `App::init_resource::>()` instead of `App::add_event::()` + + App::new().add_event::(); + //~^ ERROR: called `App::insert_resource(Events)` instead of `App::add_event::()` + + // Make sure the correct type is detected, even when not explicitly passed to + // `insert_resource()`. + let implied_event: Events = Default::default(); + App::new().add_event::(); + //~^ ERROR: called `App::insert_resource(Events)` instead of `App::add_event::()` + + // Ensure the lint can be muted by annotating the expression. + #[allow(bevy::insert_event_resource)] + App::new().init_resource::>(); +} diff --git a/bevy_lint/tests/ui/insert_event_resource/main.rs b/bevy_lint/tests/ui/insert_event_resource/main.rs new file mode 100644 index 00000000..b48959c8 --- /dev/null +++ b/bevy_lint/tests/ui/insert_event_resource/main.rs @@ -0,0 +1,26 @@ +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::insert_event_resource)] + +use bevy::prelude::*; + +#[derive(Event)] +struct Foo; + +fn main() { + App::new().init_resource::>(); + //~^ ERROR: called `App::init_resource::>()` instead of `App::add_event::()` + + App::new().insert_resource::>(Default::default()); + //~^ ERROR: called `App::insert_resource(Events)` instead of `App::add_event::()` + + // Make sure the correct type is detected, even when not explicitly passed to + // `insert_resource()`. + let implied_event: Events = Default::default(); + App::new().insert_resource(implied_event); + //~^ ERROR: called `App::insert_resource(Events)` instead of `App::add_event::()` + + // Ensure the lint can be muted by annotating the expression. + #[allow(bevy::insert_event_resource)] + App::new().init_resource::>(); +} diff --git a/bevy_lint/tests/ui/insert_event_resource/main.stderr b/bevy_lint/tests/ui/insert_event_resource/main.stderr new file mode 100644 index 00000000..0211c215 --- /dev/null +++ b/bevy_lint/tests/ui/insert_event_resource/main.stderr @@ -0,0 +1,40 @@ +error: called `App::init_resource::>()` instead of `App::add_event::()` + --> tests/ui/insert_event_resource/main.rs:11:16 + | +11 | App::new().init_resource::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/insert_event_resource/main.rs:3:9 + | +3 | #![deny(bevy::insert_event_resource)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: inserting an `Events` resource does not fully setup that event + | +11 | App::new().add_event::(); + | ~~~~~~~~~~~~~~~~~~ + +error: called `App::insert_resource(Events)` instead of `App::add_event::()` + --> tests/ui/insert_event_resource/main.rs:14:16 + | +14 | App::new().insert_resource::>(Default::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: inserting an `Events` resource does not fully setup that event + | +14 | App::new().add_event::(); + | ~~~~~~~~~~~~~~~~~~ + +error: called `App::insert_resource(Events)` instead of `App::add_event::()` + --> tests/ui/insert_event_resource/main.rs:20:16 + | +20 | App::new().insert_resource(implied_event); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: inserting an `Events` resource does not fully setup that event + | +20 | App::new().add_event::(); + | ~~~~~~~~~~~~~~~~~~ + +error: aborting due to 3 previous errors + diff --git a/bevy_lint/tests/ui/main_return_without_appexit/bug_132.rs b/bevy_lint/tests/ui/main_return_without_appexit/bug_132.rs new file mode 100644 index 00000000..0572a7b3 --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/bug_132.rs @@ -0,0 +1,20 @@ +//! A version of `main.rs` where the lint is muted on the expression. Since this lint is run on +//! functions, it will still error. +//! +//! This test tracks the bug reported in [#132]. When this starts failing, the bug has been fixed. +//! +//! [#132]: https://github.com/TheBevyFlock/bevy_cli/issues/132 + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::main_return_without_appexit)] + +use bevy::prelude::*; + +fn main() { + //~^ HELP: try + + #[allow(bevy::main_return_without_appexit)] + App::new().run(); + //~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit` +} diff --git a/bevy_lint/tests/ui/main_return_without_appexit/bug_132.stderr b/bevy_lint/tests/ui/main_return_without_appexit/bug_132.stderr new file mode 100644 index 00000000..7b2f83b6 --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/bug_132.stderr @@ -0,0 +1,18 @@ +error: an entrypoint that calls `App::run()` does not return `AppExit` + --> tests/ui/main_return_without_appexit/bug_132.rs:18:16 + | +14 | fn main() { + | - help: try: `-> AppExit` +... +18 | App::new().run(); + | ^^^^^ + | + = note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not +note: the lint level is defined here + --> tests/ui/main_return_without_appexit/bug_132.rs:10:9 + | +10 | #![deny(bevy::main_return_without_appexit)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/bevy_lint/tests/ui/main_return_without_appexit/bug_87.rs b/bevy_lint/tests/ui/main_return_without_appexit/bug_87.rs new file mode 100644 index 00000000..ad24da6c --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/bug_87.rs @@ -0,0 +1,17 @@ +//! This test tracks the bug reported in [#87]. When this starts failing, the bug has been fixed. +//! +//! [#87]: https://github.com/TheBevyFlock/bevy_cli/issues/87 + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::main_return_without_appexit)] + +use bevy::prelude::*; + +fn main() { + // This should not raise an error, since `AppExit` is not ignored. + let app_exit = App::new().run(); + //~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit` + + println!("{app_exit:?}"); +} diff --git a/bevy_lint/tests/ui/main_return_without_appexit/bug_87.stderr b/bevy_lint/tests/ui/main_return_without_appexit/bug_87.stderr new file mode 100644 index 00000000..ae808d8a --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/bug_87.stderr @@ -0,0 +1,18 @@ +error: an entrypoint that calls `App::run()` does not return `AppExit` + --> tests/ui/main_return_without_appexit/bug_87.rs:13:31 + | +11 | fn main() { + | - help: try: `-> AppExit` +12 | // This should not raise an error, since `AppExit` is not ignored. +13 | let app_exit = App::new().run(); + | ^^^^^ + | + = note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not +note: the lint level is defined here + --> tests/ui/main_return_without_appexit/bug_87.rs:7:9 + | +7 | #![deny(bevy::main_return_without_appexit)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/bevy_lint/tests/ui/main_return_without_appexit/bug_94.rs b/bevy_lint/tests/ui/main_return_without_appexit/bug_94.rs new file mode 100644 index 00000000..eec61215 --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/bug_94.rs @@ -0,0 +1,18 @@ +//! This test tracks the bug reported in [#94]. When this starts failing, the bug has been fixed. +//! +//! [#94]: https://github.com/TheBevyFlock/bevy_cli/issues/94 + +//@check-pass + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::main_return_without_appexit)] + +use bevy::prelude::*; + +fn main() { + let mut app = App::new(); + + // This should error because the `AppExit` is not handled, but it does not. + App::run(&mut app); +} diff --git a/bevy_lint/tests/ui/main_return_without_appexit/main.rs b/bevy_lint/tests/ui/main_return_without_appexit/main.rs new file mode 100644 index 00000000..5c51dc16 --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/main.rs @@ -0,0 +1,13 @@ +//! Tests the most basic version: where `main()` returns nothing and `AppExit` is not handled. + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::main_return_without_appexit)] + +use bevy::prelude::*; + +fn main() { + //~^ HELP: try + App::new().run(); + //~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit` +} diff --git a/bevy_lint/tests/ui/main_return_without_appexit/main.stderr b/bevy_lint/tests/ui/main_return_without_appexit/main.stderr new file mode 100644 index 00000000..9f036cd9 --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/main.stderr @@ -0,0 +1,18 @@ +error: an entrypoint that calls `App::run()` does not return `AppExit` + --> tests/ui/main_return_without_appexit/main.rs:11:16 + | +9 | fn main() { + | - help: try: `-> AppExit` +10 | +11 | App::new().run(); + | ^^^^^ + | + = note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not +note: the lint level is defined here + --> tests/ui/main_return_without_appexit/main.rs:5:9 + | +5 | #![deny(bevy::main_return_without_appexit)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/bevy_lint/tests/ui/main_return_without_appexit/muted_function.rs b/bevy_lint/tests/ui/main_return_without_appexit/muted_function.rs new file mode 100644 index 00000000..49bce949 --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/muted_function.rs @@ -0,0 +1,15 @@ +//! A version of `main.rs` where the lint is muted on the function. This should pass without any +//! errors. + +//@check-pass + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::main_return_without_appexit)] + +use bevy::prelude::*; + +#[allow(bevy::main_return_without_appexit)] +fn main() { + App::new().run(); +} diff --git a/bevy_lint/tests/ui/main_return_without_appexit/return_appexit.rs b/bevy_lint/tests/ui/main_return_without_appexit/return_appexit.rs new file mode 100644 index 00000000..f289d25b --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/return_appexit.rs @@ -0,0 +1,14 @@ +//! Tests when `main()` returns `AppExit`, meaning the user has fixed the lint. No diagnostics +//! should be emitted in this case. + +//@check-pass + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::main_return_without_appexit)] + +use bevy::prelude::*; + +fn main() -> AppExit { + App::new().run() +} diff --git a/bevy_lint/tests/ui/main_return_without_appexit/return_result.rs b/bevy_lint/tests/ui/main_return_without_appexit/return_result.rs new file mode 100644 index 00000000..cafb120f --- /dev/null +++ b/bevy_lint/tests/ui/main_return_without_appexit/return_result.rs @@ -0,0 +1,16 @@ +//! Tests when `main()` returns a type other than the unit `()`. When this is done no lint is +//! emitted, since we assume the user knows what they're doing. + +//@check-pass + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::main_return_without_appexit)] + +use bevy::prelude::*; + +fn main() -> Result<(), ()> { + App::new().run(); + + Ok(()) +} diff --git a/bevy_lint/tests/ui/main_return_without_appexit.rs b/bevy_lint/tests/ui/main_return_without_appexit/return_unit.rs similarity index 85% rename from bevy_lint/tests/ui/main_return_without_appexit.rs rename to bevy_lint/tests/ui/main_return_without_appexit/return_unit.rs index 8e6cffb1..aea3087d 100644 --- a/bevy_lint/tests/ui/main_return_without_appexit.rs +++ b/bevy_lint/tests/ui/main_return_without_appexit/return_unit.rs @@ -4,7 +4,8 @@ use bevy::prelude::*; -fn main() { +fn main() -> () { + //~^ HELP: try App::new().run(); //~^ ERROR: an entrypoint that calls `App::run()` does not return `AppExit` } diff --git a/bevy_lint/tests/ui/main_return_without_appexit.stderr b/bevy_lint/tests/ui/main_return_without_appexit/return_unit.stderr similarity index 64% rename from bevy_lint/tests/ui/main_return_without_appexit.stderr rename to bevy_lint/tests/ui/main_return_without_appexit/return_unit.stderr index c5b137f0..8b3966d6 100644 --- a/bevy_lint/tests/ui/main_return_without_appexit.stderr +++ b/bevy_lint/tests/ui/main_return_without_appexit/return_unit.stderr @@ -1,14 +1,15 @@ error: an entrypoint that calls `App::run()` does not return `AppExit` - --> tests/ui/main_return_without_appexit.rs:8:16 + --> tests/ui/main_return_without_appexit/return_unit.rs:9:16 | -7 | fn main() { - | - help: try: `-> AppExit` -8 | App::new().run(); +7 | fn main() -> () { + | -- help: try: `AppExit` +8 | +9 | App::new().run(); | ^^^^^ | = note: `App::run()` returns `AppExit`, which can be used to determine whether the app exited successfully or not note: the lint level is defined here - --> tests/ui/main_return_without_appexit.rs:3:9 + --> tests/ui/main_return_without_appexit/return_unit.rs:3:9 | 3 | #![deny(bevy::main_return_without_appexit)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/bevy_lint/tests/ui/panicking_methods/query.rs b/bevy_lint/tests/ui/panicking_methods/query.rs new file mode 100644 index 00000000..fe4d128b --- /dev/null +++ b/bevy_lint/tests/ui/panicking_methods/query.rs @@ -0,0 +1,34 @@ +//! This tests the `panicking_query_methods` lint, specifically when triggered on the `Query` type. + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::panicking_query_methods)] + +use bevy::prelude::*; + +#[derive(Component)] +struct Foo; + +fn main() { + App::new().add_systems(Startup, my_system); +} + +fn my_system(mut query: Query<&mut Foo>) { + query.single(); + //~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists + //~| HELP: use `query.get_single()` + + query.single_mut(); + //~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists + //~| HELP: use `query.get_single_mut()` + + let entities = [Entity::PLACEHOLDER; 3]; + + let [_, _, _] = query.many(entities); + //~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists + //~| HELP: use `query.get_many(entities)` + + query.many_mut([]); + //~^ ERROR: called a `Query` method that can panic when a non-panicking alternative exists + //~| HELP: use `query.get_many_mut([])` +} diff --git a/bevy_lint/tests/ui/panicking_methods/query.stderr b/bevy_lint/tests/ui/panicking_methods/query.stderr new file mode 100644 index 00000000..72bb45ac --- /dev/null +++ b/bevy_lint/tests/ui/panicking_methods/query.stderr @@ -0,0 +1,39 @@ +error: called a `Query` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/query.rs:17:11 + | +17 | query.single(); + | ^^^^^^^^ + | + = help: use `query.get_single()` and handle the `Option` or `Result` +note: the lint level is defined here + --> tests/ui/panicking_methods/query.rs:5:9 + | +5 | #![deny(bevy::panicking_query_methods)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called a `Query` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/query.rs:21:11 + | +21 | query.single_mut(); + | ^^^^^^^^^^^^ + | + = help: use `query.get_single_mut()` and handle the `Option` or `Result` + +error: called a `Query` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/query.rs:27:27 + | +27 | let [_, _, _] = query.many(entities); + | ^^^^^^^^^^^^^^ + | + = help: use `query.get_many(entities)` and handle the `Option` or `Result` + +error: called a `Query` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/query.rs:31:11 + | +31 | query.many_mut([]); + | ^^^^^^^^^^^^ + | + = help: use `query.get_many_mut([])` and handle the `Option` or `Result` + +error: aborting due to 4 previous errors + diff --git a/bevy_lint/tests/ui/panicking_methods/query_state.rs b/bevy_lint/tests/ui/panicking_methods/query_state.rs new file mode 100644 index 00000000..88cb78a9 --- /dev/null +++ b/bevy_lint/tests/ui/panicking_methods/query_state.rs @@ -0,0 +1,25 @@ +//! This tests the `panicking_query_methods` lint, specifically when triggered on the `QueryState` +//! type. + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::panicking_query_methods)] + +use bevy::prelude::*; + +#[derive(Component)] +struct Foo; + +fn main() { + let mut world = World::new(); + + let mut query_state = QueryState::<&mut Foo>::new(&mut world); + + let _ = query_state.single(&world); + //~^ ERROR: called a `QueryState` method that can panic when a non-panicking alternative exists + //~| HELP: use `query_state.get_single(&world)` + + query_state.single_mut(&mut world); + //~^ ERROR: called a `QueryState` method that can panic when a non-panicking alternative exists + //~| HELP: use `query_state.get_single_mut(&mut world)` +} diff --git a/bevy_lint/tests/ui/panicking_methods/query_state.stderr b/bevy_lint/tests/ui/panicking_methods/query_state.stderr new file mode 100644 index 00000000..0096e772 --- /dev/null +++ b/bevy_lint/tests/ui/panicking_methods/query_state.stderr @@ -0,0 +1,23 @@ +error: called a `QueryState` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/query_state.rs:18:25 + | +18 | let _ = query_state.single(&world); + | ^^^^^^^^^^^^^^ + | + = help: use `query_state.get_single(&world)` and handle the `Option` or `Result` +note: the lint level is defined here + --> tests/ui/panicking_methods/query_state.rs:6:9 + | +6 | #![deny(bevy::panicking_query_methods)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called a `QueryState` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/query_state.rs:22:17 + | +22 | query_state.single_mut(&mut world); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `query_state.get_single_mut(&mut world)` and handle the `Option` or `Result` + +error: aborting due to 2 previous errors + diff --git a/bevy_lint/tests/ui/panicking_methods/world.rs b/bevy_lint/tests/ui/panicking_methods/world.rs new file mode 100644 index 00000000..a14f27e9 --- /dev/null +++ b/bevy_lint/tests/ui/panicking_methods/world.rs @@ -0,0 +1,62 @@ +//! This tests the `panicking_query_methods` lint, specifically when triggered on the `World` type. + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::panicking_world_methods)] + +use bevy::prelude::*; + +#[derive(Component)] +struct Bob; + +#[derive(Resource)] +struct Jeffrey; + +// A non-send resource. +struct Patrick; + +fn main() { + let mut world = World::new(); + + let bob = world.spawn(Bob).id(); + + world.entity(bob); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_entity(bob)` + + world.entity_mut(bob); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_entity_mut(bob)` + + world.many_entities([bob]); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_many_entities([bob])` + + world.many_entities_mut([bob]); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_many_entities_mut([bob])` + + world.resource::(); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_resource::()` + + world.resource_mut::(); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_resource_mut::()` + + world.resource_ref::(); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_resource_ref::()` + + world.non_send_resource::(); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_non_send_resource::()` + + world.non_send_resource_mut::(); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.get_non_send_resource_mut::()` + + world.schedule_scope(Update, |_world, _schedule| {}); + //~^ ERROR: called a `World` method that can panic when a non-panicking alternative exists + //~| HELP: use `world.try_schedule_scope(Update, |_world, _schedule| {})` +} diff --git a/bevy_lint/tests/ui/panicking_methods/world.stderr b/bevy_lint/tests/ui/panicking_methods/world.stderr new file mode 100644 index 00000000..dd246ff4 --- /dev/null +++ b/bevy_lint/tests/ui/panicking_methods/world.stderr @@ -0,0 +1,87 @@ +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:23:11 + | +23 | world.entity(bob); + | ^^^^^^^^^^^ + | + = help: use `world.get_entity(bob)` and handle the `Option` or `Result` +note: the lint level is defined here + --> tests/ui/panicking_methods/world.rs:5:9 + | +5 | #![deny(bevy::panicking_world_methods)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:27:11 + | +27 | world.entity_mut(bob); + | ^^^^^^^^^^^^^^^ + | + = help: use `world.get_entity_mut(bob)` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:31:11 + | +31 | world.many_entities([bob]); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.get_many_entities([bob])` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:35:11 + | +35 | world.many_entities_mut([bob]); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.get_many_entities_mut([bob])` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:39:11 + | +39 | world.resource::(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.get_resource::()` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:43:11 + | +43 | world.resource_mut::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.get_resource_mut::()` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:47:11 + | +47 | world.resource_ref::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.get_resource_ref::()` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:51:11 + | +51 | world.non_send_resource::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.get_non_send_resource::()` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:55:11 + | +55 | world.non_send_resource_mut::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.get_non_send_resource_mut::()` and handle the `Option` or `Result` + +error: called a `World` method that can panic when a non-panicking alternative exists + --> tests/ui/panicking_methods/world.rs:59:11 + | +59 | world.schedule_scope(Update, |_world, _schedule| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `world.try_schedule_scope(Update, |_world, _schedule| {})` and handle the `Option` or `Result` + +error: aborting due to 10 previous errors + diff --git a/bevy_lint/tests/ui/plugin_not_ending_in_plugin/bug_132.rs b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/bug_132.rs new file mode 100644 index 00000000..86732036 --- /dev/null +++ b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/bug_132.rs @@ -0,0 +1,26 @@ +//! A test that checks that annotating the structure definition of a plugin does not silence the +//! lint. +//! +//! This test tracks the bug reported in [#132]. When this starts failing, the bug has been fixed. +//! +//! [#132]: https://github.com/TheBevyFlock/bevy_cli/issues/132 + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::plugin_not_ending_in_plugin)] + +use bevy::prelude::*; + +// This `#[allow(...)]` does nothing. +#[allow(bevy::plugin_not_ending_in_plugin)] +struct Foo; +//~^ HELP: rename the plugin + +//~v ERROR: implemented `Plugin` for a structure whose name does not end in "Plugin" +impl Plugin for Foo { + fn build(&self, _app: &mut App) {} +} + +fn main() { + App::new().add_plugins(Foo); +} diff --git a/bevy_lint/tests/ui/plugin_not_ending_in_plugin/bug_132.stderr b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/bug_132.stderr new file mode 100644 index 00000000..d4bdd9c0 --- /dev/null +++ b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/bug_132.stderr @@ -0,0 +1,19 @@ +error: implemented `Plugin` for a structure whose name does not end in "Plugin" + --> tests/ui/plugin_not_ending_in_plugin/bug_132.rs:20:1 + | +16 | struct Foo; + | --- help: rename the plugin: `FooPlugin` +... +20 | / impl Plugin for Foo { +21 | | fn build(&self, _app: &mut App) {} +22 | | } + | |_^ + | +note: the lint level is defined here + --> tests/ui/plugin_not_ending_in_plugin/bug_132.rs:10:9 + | +10 | #![deny(bevy::plugin_not_ending_in_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/bevy_lint/tests/ui/plugin_not_ending_in_plugin/main.rs b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/main.rs new file mode 100644 index 00000000..26096e09 --- /dev/null +++ b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/main.rs @@ -0,0 +1,34 @@ +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::plugin_not_ending_in_plugin)] + +use bevy::prelude::*; + +// This should raise an error, since it does not end in "Plugin". +struct Foo; +//~^ HELP: rename the plugin + +//~v ERROR: implemented `Plugin` for a structure whose name does not end in "Plugin" +impl Plugin for Foo { + fn build(&self, _app: &mut App) {} +} + +// This should _not_ raise an error, since it ends in "Plugin". +struct BarPlugin; + +impl Plugin for BarPlugin { + fn build(&self, _app: &mut App) {} +} + +// Though this does not end in "Plugin", the lint is silenced for the `impl` blog, so no error is +// raised. +struct Baz; + +#[allow(bevy::plugin_not_ending_in_plugin)] +impl Plugin for Baz { + fn build(&self, _app: &mut App) {} +} + +fn main() { + App::new().add_plugins((Foo, BarPlugin, Baz)); +} diff --git a/bevy_lint/tests/ui/plugin_not_ending_in_plugin/main.stderr b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/main.stderr new file mode 100644 index 00000000..f41b6670 --- /dev/null +++ b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/main.stderr @@ -0,0 +1,19 @@ +error: implemented `Plugin` for a structure whose name does not end in "Plugin" + --> tests/ui/plugin_not_ending_in_plugin/main.rs:12:1 + | +8 | struct Foo; + | --- help: rename the plugin: `FooPlugin` +... +12 | / impl Plugin for Foo { +13 | | fn build(&self, _app: &mut App) {} +14 | | } + | |_^ + | +note: the lint level is defined here + --> tests/ui/plugin_not_ending_in_plugin/main.rs:3:9 + | +3 | #![deny(bevy::plugin_not_ending_in_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/bevy_lint/tests/ui/plugin_not_ending_in_plugin/spoofed_name.rs b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/spoofed_name.rs new file mode 100644 index 00000000..9a3accc0 --- /dev/null +++ b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/spoofed_name.rs @@ -0,0 +1,27 @@ +//! A test that ensures a plugin whose name is "spoofed" with `use T as F` does not sneak past the +//! lint. + +#![feature(register_tool)] +#![register_tool(bevy)] +#![deny(bevy::plugin_not_ending_in_plugin)] + +use bevy::prelude::*; + +mod bar { + pub mod baz { + pub struct Foo; + //~^ HELP: rename the plugin + } +} + +// We try to be sneaky, but it doesn't work. +use self::bar::baz::Foo as FooPlugin; + +//~v ERROR: implemented `Plugin` for a structure whose name does not end in "Plugin" +impl Plugin for FooPlugin { + fn build(&self, _app: &mut App) {} +} + +fn main() { + App::new().add_plugins(FooPlugin); +} diff --git a/bevy_lint/tests/ui/plugin_not_ending_in_plugin/spoofed_name.stderr b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/spoofed_name.stderr new file mode 100644 index 00000000..cf4100cf --- /dev/null +++ b/bevy_lint/tests/ui/plugin_not_ending_in_plugin/spoofed_name.stderr @@ -0,0 +1,19 @@ +error: implemented `Plugin` for a structure whose name does not end in "Plugin" + --> tests/ui/plugin_not_ending_in_plugin/spoofed_name.rs:21:1 + | +12 | pub struct Foo; + | --- help: rename the plugin: `FooPlugin` +... +21 | / impl Plugin for FooPlugin { +22 | | fn build(&self, _app: &mut App) {} +23 | | } + | |_^ + | +note: the lint level is defined here + --> tests/ui/plugin_not_ending_in_plugin/spoofed_name.rs:6:9 + | +6 | #![deny(bevy::plugin_not_ending_in_plugin)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +