Skip to content

Commit

Permalink
Add support for ResMut
Browse files Browse the repository at this point in the history
  • Loading branch information
MrGVSV committed Nov 2, 2024
1 parent 1f6a429 commit bf99294
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 2 deletions.
14 changes: 12 additions & 2 deletions bevy_lint/src/lints/borrow_of_reborrowable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,20 @@ declare_bevy_lint! {
"parameter takes `&mut Commands` instead of a re-borrowed `Commands`",
}

declare_bevy_lint! {
pub BORROW_OF_RESOURCE,
PEDANTIC,
"parameter takes `&mut ResMut` instead of a re-borrowed `ResMut`",
}

declare_bevy_lint! {
pub BORROW_OF_QUERY,
PEDANTIC,
"parameter takes `&mut Query` instead of a re-borrowed `Query`",
}

declare_lint_pass! {
BorrowOfReborrowable => [BORROW_OF_COMMANDS.lint, BORROW_OF_QUERY.lint]
BorrowOfReborrowable => [BORROW_OF_COMMANDS.lint, BORROW_OF_RESOURCE.lint, BORROW_OF_QUERY.lint]
}

impl<'tcx> LateLintPass<'tcx> for BorrowOfReborrowable {
Expand Down Expand Up @@ -147,7 +153,7 @@ enum Reborrowable {
// PtrMut,
Query,
// QueryIterationCursor,
// ResMut,
ResMut,
}

impl Reborrowable {
Expand All @@ -158,6 +164,8 @@ impl Reborrowable {
Some(Self::EntityCommands)
} else if match_type(cx, ty, &crate::paths::QUERY) {
Some(Self::Query)
} else if match_type(cx, ty, &crate::paths::RES_MUT) {
Some(Self::ResMut)
} else {
None
}
Expand All @@ -168,6 +176,7 @@ impl Reborrowable {
Self::Commands => BORROW_OF_COMMANDS.lint,
Self::EntityCommands => BORROW_OF_COMMANDS.lint,
Self::Query => BORROW_OF_QUERY.lint,
Self::ResMut => BORROW_OF_RESOURCE.lint,
}
}

Expand All @@ -181,6 +190,7 @@ impl Reborrowable {
Self::Commands => "Commands",
Self::EntityCommands => "EntityCommands",
Self::Query => "Query",
Self::ResMut => "ResMut",
}
}

Expand Down
1 change: 1 addition & 0 deletions bevy_lint/src/lints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod plugin_not_ending_in_plugin;

pub(crate) static LINTS: &[&BevyLint] = &[
borrow_of_reborrowable::BORROW_OF_COMMANDS,
borrow_of_reborrowable::BORROW_OF_RESOURCE,
borrow_of_reborrowable::BORROW_OF_QUERY,
insert_event_resource::INSERT_EVENT_RESOURCE,
main_return_without_appexit::MAIN_RETURN_WITHOUT_APPEXIT,
Expand Down
1 change: 1 addition & 0 deletions bevy_lint/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ pub const PLUGIN: [&str; 3] = ["bevy_app", "plugin", "Plugin"];
pub const QUERY: [&str; 4] = ["bevy_ecs", "system", "query", "Query"];
pub const QUERY_STATE: [&str; 4] = ["bevy_ecs", "query", "state", "QueryState"];
pub const REFLECT: [&str; 3] = ["bevy_reflect", "reflect", "Reflect"];
pub const RES_MUT: [&str; 3] = ["bevy_ecs", "change_detection", "ResMut"];
pub const RESOURCE: [&str; 4] = ["bevy_ecs", "system", "system_param", "Resource"];
pub const WORLD: [&str; 3] = ["bevy_ecs", "world", "World"];
51 changes: 51 additions & 0 deletions bevy_lint/tests/ui/borrow_of_reborrowable/resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//! This tests the `borrow_of_reborrowable` lint, specifically when triggered on the `ResMut` type.
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::borrow_of_resource)]

use bevy::prelude::*;

#[derive(Resource)]
struct Data(String);

// OK: Lint does not apply to immutable references
fn immutable_reference(_res: &ResMut<Data>) {
// ...
}

//~| HELP: use `ResMut` instead
//~v ERROR: parameter takes `&mut ResMut` instead of a re-borrowed `ResMut`
fn mutable_reference(_res: &mut ResMut<Data>) {
// ...
}

//~| HELP: use `ResMut` instead
//~v ERROR: parameter takes `&mut ResMut` instead of a re-borrowed `ResMut`
fn mutable_reference_return<'a>(_res: &'a mut ResMut<Data>) -> usize {
123
}

// OK: Lint does not apply when return type relies on reference lifetime
fn mutable_reference_bounded_return<'a>(res: &'a mut ResMut<Data>) -> &'a mut String {
&mut res.0
}

// OK: Lint does not apply when return type relies on reference lifetime
fn mutable_reference_bounded_return_complex<'a>(
res: &'a mut ResMut<Data>,
) -> Vec<(usize, &'a mut String)> {
vec![(1, &mut res.0)]
}

fn main() {
fn some_system(mut res: ResMut<Data>) {
immutable_reference(&res);
mutable_reference(&mut res);
_ = mutable_reference_return(&mut res);
_ = mutable_reference_bounded_return(&mut res);
_ = mutable_reference_bounded_return_complex(&mut res);
}

App::new().add_systems(Update, some_system).run();
}
20 changes: 20 additions & 0 deletions bevy_lint/tests/ui/borrow_of_reborrowable/resource.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: parameter takes `&mut ResMut` instead of a re-borrowed `ResMut`
--> tests/ui/borrow_of_reborrowable/resource.rs:19:22
|
19 | fn mutable_reference(_res: &mut ResMut<Data>) {
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `ResMut` instead: `mut _res: bevy::prelude::ResMut<'_, Data>`
|
note: the lint level is defined here
--> tests/ui/borrow_of_reborrowable/resource.rs:5:9
|
5 | #![deny(bevy::borrow_of_resource)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: parameter takes `&mut ResMut` instead of a re-borrowed `ResMut`
--> tests/ui/borrow_of_reborrowable/resource.rs:25:33
|
25 | fn mutable_reference_return<'a>(_res: &'a mut ResMut<Data>) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `ResMut` instead: `mut _res: bevy::prelude::ResMut<'_, Data>`

error: aborting due to 2 previous errors

0 comments on commit bf99294

Please sign in to comment.