Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lint: Res<Events<T>> #262

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 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 main_return_without_appexit;
pub mod missing_reflect;
pub mod panicking_methods;
pub mod plugin_not_ending_in_plugin;
pub mod sus_resource;
pub mod zst_query;

pub(crate) static LINTS: &[&BevyLint] = &[
Expand All @@ -26,6 +27,7 @@ pub(crate) static LINTS: &[&BevyLint] = &[
panicking_methods::PANICKING_WORLD_METHODS,
plugin_not_ending_in_plugin::PLUGIN_NOT_ENDING_IN_PLUGIN,
zst_query::ZST_QUERY,
sus_resource::EVENTS_RESOURCE_SYSTEM_PARAM,
];

pub(crate) fn register_lints(store: &mut LintStore) {
Expand All @@ -46,4 +48,6 @@ pub(crate) fn register_passes(store: &mut LintStore) {
});
store.register_late_pass(|_| Box::new(zst_query::ZstQuery::default()));
store.register_late_pass(|_| Box::new(insert_unit_bundle::InsertUnitBundle::default()));

store.register_late_pass(|_| Box::new(sus_resource::EventsResourceSystemParam::default()));
}
72 changes: 72 additions & 0 deletions bevy_lint/src/lints/sus_resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::{
declare_bevy_lint, declare_bevy_lint_pass,
utils::hir_parse::{detuple, generic_type_at},
};
use clippy_utils::{
diagnostics::span_lint_and_help,
ty::match_type,
};
use rustc_hir_analysis::collect::ItemCtxt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;

declare_bevy_lint! {
pub EVENTS_RESOURCE_SYSTEM_PARAM,
RESTRICTION,
// FIXME: Better note.
"use of bad system parameter",
}

declare_bevy_lint_pass! {
pub EventsResourceSystemParam => [EVENTS_RESOURCE_SYSTEM_PARAM.lint],
}

impl<'tcx> LateLintPass<'tcx> for EventsResourceSystemParam {
fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &'tcx rustc_hir::Ty<'tcx>) {
let item_cx = ItemCtxt::new(cx.tcx, hir_ty.hir_id.owner.def_id);
let ty = item_cx.lower_ty(hir_ty);

let Some(res_kind) = ResKind::try_from_ty(cx, ty) else {
return;
};

let Some(res_data_ty) = generic_type_at(cx, hir_ty, 1) else {
return;
};

// FIXME: Is detuple necessary ? Or will `T` in `Res<T>` always be a single type ?
detuple(*res_data_ty)
.iter()
.filter(|&hir_ty| match_type(cx, item_cx.lower_ty(hir_ty), &crate::paths::EVENTS))
.for_each(|hir_ty| {
span_lint_and_help(
cx,
EVENTS_RESOURCE_SYSTEM_PARAM.lint,
hir_ty.span,
EVENTS_RESOURCE_SYSTEM_PARAM.lint.desc,
None,
res_kind.help(None),
)
});
}
}

enum ResKind {
Res,
}

impl ResKind {
fn try_from_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Self> {
if match_type(cx, ty, &crate::paths::RES) {
Some(Self::Res)
} else {
None
}
}

fn help(&self, o_ty: Option<&Ty<'_>>) -> String {
match self {
Self::Res => format!("events Resource footgun"),
}
}
}
1 change: 1 addition & 0 deletions bevy_lint/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub const PTR_MUT: [&str; 2] = ["bevy_ptr", "PtrMut"];
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: [&str; 3] = ["bevy_ecs", "change_detection", "Res"];
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"];
13 changes: 13 additions & 0 deletions bevy_lint/tests/ui/sus_resource/my_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::events_resource_system_param)]

use bevy::prelude::*;

fn main() {
App::new().add_systems(Startup, (bad_system,)).run();
}

//~| HELP: events Resource footgun
//~v ERROR: use of bad system parameter
fn bad_system(_resource_events: Res<Events<AppExit>>) {}
15 changes: 15 additions & 0 deletions bevy_lint/tests/ui/sus_resource/my_test.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error: use of bad system parameter
--> tests/ui/sus_resource/my_test.rs:13:37
|
13 | fn bad_system(_resource_events: Res<Events<AppExit>>) {}
| ^^^^^^^^^^^^^^^
|
= help: events Resource footgun
note: the lint level is defined here
--> tests/ui/sus_resource/my_test.rs:3:9
|
3 | #![deny(bevy::events_resource_system_param)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error