diff --git a/bevy_lint/src/lints/zst_query.rs b/bevy_lint/src/lints/zst_query.rs index 267ffd80..4741f374 100644 --- a/bevy_lint/src/lints/zst_query.rs +++ b/bevy_lint/src/lints/zst_query.rs @@ -129,13 +129,17 @@ impl QueryKind { /// - `Some(false)` if the type is most likely not a ZST /// - `None` if we cannot determine the size (e.g., type is not normalizable) fn is_zero_sized<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { + // `cx.layout_of()` panics if the type is not normalizable. if !is_normalizable(cx, cx.param_env, ty) { return None; } - let Ok(TyAndLayout { layout, .. }) = cx.layout_of(ty) else { - return None; - }; - - Some(layout.size() == Size::ZERO) + // Note: we don't use `approx_ty_size` from `clippy_utils` here + // because it will return `0` as the default value if the type is not + // normalizable, which will put us at risk of emitting more false positives. + if let Ok(TyAndLayout { layout, .. }) = cx.layout_of(ty) { + Some(layout.size() == Size::ZERO) + } else { + None + } } diff --git a/bevy_lint/src/utils/hir_parse.rs b/bevy_lint/src/utils/hir_parse.rs index 2d1fbd67..b93aaa20 100644 --- a/bevy_lint/src/utils/hir_parse.rs +++ b/bevy_lint/src/utils/hir_parse.rs @@ -6,7 +6,10 @@ use rustc_lint::LateContext; /// Returns the list of types inside a tuple type. /// /// If the type is not a tuple, returns a list containing the type itself. -pub(crate) fn detuple(ty: Ty<'_>) -> Vec> { +/// +/// This function will work for both tuples and references to tuples, +/// such as `(f32, &str)` and `&(f32, &str)`. +pub fn detuple(ty: Ty<'_>) -> Vec> { if let TyKind::Tup(items) = ty.peel_refs().kind { items.to_vec() } else { @@ -17,7 +20,7 @@ pub(crate) fn detuple(ty: Ty<'_>) -> Vec> { /// Gets the [`Ty`] for a generic argument at the specified index. /// /// If the generic argument is not a type, returns `None`. -pub(crate) fn generic_type_at<'tcx>( +pub fn generic_type_at<'tcx>( cx: &LateContext<'tcx>, hir_ty: &'tcx Ty<'tcx>, index: usize, @@ -32,10 +35,7 @@ pub(crate) fn generic_type_at<'tcx>( } } /// Returns the [`GenericArg`] at the given index. -pub(crate) fn generic_at<'hir>( - hir_ty: &'hir Ty<'hir>, - index: usize, -) -> Option<&'hir GenericArg<'hir>> { +pub fn generic_at<'hir>(hir_ty: &'hir Ty<'hir>, index: usize) -> Option<&'hir GenericArg<'hir>> { let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind else { return None; }; diff --git a/bevy_lint/src/utils/mod.rs b/bevy_lint/src/utils/mod.rs index 8a76bd1a..94a682b0 100644 --- a/bevy_lint/src/utils/mod.rs +++ b/bevy_lint/src/utils/mod.rs @@ -1 +1 @@ -pub(crate) mod hir_parse; +pub mod hir_parse; diff --git a/bevy_lint/tests/ui/zst_query/query.rs b/bevy_lint/tests/ui/zst_query/query.rs index 7b244ae2..f0567264 100644 --- a/bevy_lint/tests/ui/zst_query/query.rs +++ b/bevy_lint/tests/ui/zst_query/query.rs @@ -8,15 +8,15 @@ use bevy::prelude::*; use std::marker::PhantomData; #[derive(Component)] -struct Foo; +struct ZST; #[derive(Component)] #[allow(dead_code)] -struct Bar(u32); +struct NonZST(u32); #[derive(Component)] #[allow(dead_code)] -struct Baz(T); +struct Generic(T); #[derive(Component)] #[allow(dead_code)] @@ -35,6 +35,8 @@ fn main() { immutable_query, mutable_query, generic_immutable_query::, + generic_immutable_zst, + generic_mutable_zst, generic_mutable_query::, immutable_query_tuple, mutable_query_tuple, @@ -46,34 +48,42 @@ fn main() { fn unit_query(_query: Query<()>) {} -//~| HELP: consider using a filter instead: `With` +//~| HELP: consider using a filter instead: `With` //~v ERROR: query for a zero-sized type -fn immutable_zst(_query: Query<&Foo>) {} +fn immutable_zst(_query: Query<&ZST>) {} -//~| HELP: consider using a filter instead: `With` +//~| HELP: consider using a filter instead: `With` //~v ERROR: query for a zero-sized type -fn mutable_zst(_query: Query<&mut Foo>) {} +fn mutable_zst(_query: Query<&mut ZST>) {} -//~| HELP: consider using a filter instead: `With` +//~| HELP: consider using a filter instead: `With` //~v ERROR: query for a zero-sized type -fn immutable_zst_tuple(_query: Query<(Entity, &Foo)>) {} +fn immutable_zst_tuple(_query: Query<(Entity, &ZST)>) {} -//~| HELP: consider using a filter instead: `With` +//~| HELP: consider using a filter instead: `With` //~v ERROR: query for a zero-sized type -fn mutable_zst_tuple(_query: Query<(Entity, &mut Foo)>) {} +fn mutable_zst_tuple(_query: Query<(Entity, &mut ZST)>) {} -fn immutable_query(_query: Query<&Bar>) {} +fn immutable_query(_query: Query<&NonZST>) {} -fn mutable_query(_query: Query<&mut Bar>) {} +fn mutable_query(_query: Query<&mut NonZST>) {} -fn generic_immutable_query(_query: Query<&Baz>) {} +fn generic_immutable_query(_query: Query<&Generic>) {} -fn generic_mutable_query(_query: Query<&mut Baz>) {} +fn generic_mutable_query(_query: Query<&mut Generic>) {} -fn immutable_query_tuple(_query: Query<(Entity, &Bar)>) {} +//~| HELP: consider using a filter instead: `With>` +//~v ERROR: query for a zero-sized type +fn generic_immutable_zst(_query: Query<&Generic>) {} + +//~| HELP: consider using a filter instead: `With>` +//~v ERROR: query for a zero-sized type +fn generic_mutable_zst(_query: Query<&mut Generic>) {} + +fn immutable_query_tuple(_query: Query<(Entity, &NonZST)>) {} -fn mutable_query_tuple(_query: Query<(Entity, &mut Bar)>) {} +fn mutable_query_tuple(_query: Query<(Entity, &mut NonZST)>) {} -//~| HELP: consider using a filter instead: `With>` +//~| HELP: consider using a filter instead: `With>` //~v ERROR: query for a zero-sized type -fn phantom_data_query(_query: Query<&Phantom>) {} +fn phantom_data_query(_query: Query<&Phantom>) {} diff --git a/bevy_lint/tests/ui/zst_query/query.stderr b/bevy_lint/tests/ui/zst_query/query.stderr index bf0515d4..b3291dd1 100644 --- a/bevy_lint/tests/ui/zst_query/query.stderr +++ b/bevy_lint/tests/ui/zst_query/query.stderr @@ -1,10 +1,10 @@ error: query for a zero-sized type - --> tests/ui/zst_query/query.rs:51:32 + --> tests/ui/zst_query/query.rs:53:32 | -51 | fn immutable_zst(_query: Query<&Foo>) {} +53 | fn immutable_zst(_query: Query<&ZST>) {} | ^^^^ | - = help: consider using a filter instead: `With` + = help: consider using a filter instead: `With` note: the lint level is defined here --> tests/ui/zst_query/query.rs:5:9 | @@ -12,36 +12,52 @@ note: the lint level is defined here | ^^^^^^^^^^^^^^^ error: query for a zero-sized type - --> tests/ui/zst_query/query.rs:55:30 + --> tests/ui/zst_query/query.rs:57:30 | -55 | fn mutable_zst(_query: Query<&mut Foo>) {} +57 | fn mutable_zst(_query: Query<&mut ZST>) {} | ^^^^^^^^ | - = help: consider using a filter instead: `With` + = help: consider using a filter instead: `With` error: query for a zero-sized type - --> tests/ui/zst_query/query.rs:59:47 + --> tests/ui/zst_query/query.rs:61:47 | -59 | fn immutable_zst_tuple(_query: Query<(Entity, &Foo)>) {} +61 | fn immutable_zst_tuple(_query: Query<(Entity, &ZST)>) {} | ^^^^ | - = help: consider using a filter instead: `With` + = help: consider using a filter instead: `With` error: query for a zero-sized type - --> tests/ui/zst_query/query.rs:63:45 + --> tests/ui/zst_query/query.rs:65:45 | -63 | fn mutable_zst_tuple(_query: Query<(Entity, &mut Foo)>) {} +65 | fn mutable_zst_tuple(_query: Query<(Entity, &mut ZST)>) {} | ^^^^^^^^ | - = help: consider using a filter instead: `With` + = help: consider using a filter instead: `With` error: query for a zero-sized type - --> tests/ui/zst_query/query.rs:79:37 + --> tests/ui/zst_query/query.rs:77:40 | -79 | fn phantom_data_query(_query: Query<&Phantom>) {} - | ^^^^^^^^^^^^^ +77 | fn generic_immutable_zst(_query: Query<&Generic>) {} + | ^^^^^^^^^^^^^ | - = help: consider using a filter instead: `With>` + = help: consider using a filter instead: `With>` -error: aborting due to 5 previous errors +error: query for a zero-sized type + --> tests/ui/zst_query/query.rs:81:38 + | +81 | fn generic_mutable_zst(_query: Query<&mut Generic>) {} + | ^^^^^^^^^^^^^^^^^ + | + = help: consider using a filter instead: `With>` + +error: query for a zero-sized type + --> tests/ui/zst_query/query.rs:89:37 + | +89 | fn phantom_data_query(_query: Query<&Phantom>) {} + | ^^^^^^^^^^^^^^^^ + | + = help: consider using a filter instead: `With>` + +error: aborting due to 7 previous errors