diff --git a/bevy_lint/src/lints/nursery/zst_query.rs b/bevy_lint/src/lints/nursery/zst_query.rs index 21aa360b..776ac5b1 100644 --- a/bevy_lint/src/lints/nursery/zst_query.rs +++ b/bevy_lint/src/lints/nursery/zst_query.rs @@ -55,9 +55,10 @@ use rustc_abi::Size; use rustc_hir::AmbigArg; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ - Ty, + AssocTag, Ty, layout::{LayoutOf, TyAndLayout}, }; +use rustc_type_ir::fast_reject::SimplifiedType; use crate::{ declare_bevy_lint, declare_bevy_lint_pass, @@ -81,6 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for ZstQuery { if hir_ty.span.in_external_macro(cx.tcx.sess.source_map()) { return; } + let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty()); let Some(query_kind) = QueryKind::try_from_ty(cx, ty) else { @@ -94,6 +96,39 @@ impl<'tcx> LateLintPass<'tcx> for ZstQuery { for hir_ty in detuple(*query_data_ty) { let ty = ty_from_hir_ty(cx, &hir_ty); + // Get the `DefId` of the `QueryData` trait. + let Some(query_data_def_id) = crate::paths::QUERYDATA.get(cx).first() else { + return; + }; + + // We are looking for the `DefId` that matches the impl block for `QueryData` + // for our `Ty`. + let non_blanket_impls = cx.tcx.trait_impls_of(query_data_def_id).non_blanket_impls(); + + let impl_def_id = non_blanket_impls.iter().find_map(|(simplified, def_id)| { + if let SimplifiedType::Adt(simplified_adt_def_id) = simplified + && let Some(adt_def) = ty.ty_adt_def() + && *simplified_adt_def_id == adt_def.did() + { + return def_id.first(); + } + None + }); + + let ty = if let Some(impl_def_id) = impl_def_id + // Search for the associated item: `type Item<'w, 's>`. + && let Some(assoc_item) = cx + .tcx + .associated_items(impl_def_id) + .filter_by_name_unhygienic_and_kind(crate::sym::Item, AssocTag::Type) + .nth(0) + { + // If the item exists, replace the generic placeholders. + cx.tcx.type_of(assoc_item.def_id).instantiate_identity() + } else { + ty.peel_refs() + }; + // We want to make sure we're evaluating `Foo` and not `&Foo`/`&mut Foo` let peeled = ty.peel_refs(); diff --git a/bevy_lint/src/paths.rs b/bevy_lint/src/paths.rs index 9ed21c38..9dfdb601 100644 --- a/bevy_lint/src/paths.rs +++ b/bevy_lint/src/paths.rs @@ -66,6 +66,8 @@ pub static PLUGIN: PathLookup = type_path!(bevy_app::plugin::Plugin); pub static PTR_MUT: PathLookup = type_path!(bevy_ptr::PtrMut); /// pub static QUERY: PathLookup = type_path!(bevy_ecs::system::query::Query); +/// +pub static QUERYDATA: PathLookup = type_path!(bevy_ecs::query::QueryData); /// pub static REFLECT: PathLookup = type_path!(bevy_reflect::reflect::Reflect); /// diff --git a/bevy_lint/src/sym.rs b/bevy_lint/src/sym.rs index bd88efb5..dad39053 100644 --- a/bevy_lint/src/sym.rs +++ b/bevy_lint/src/sym.rs @@ -57,7 +57,7 @@ use clippy_utils::sym::EXTRA_SYMBOLS as CLIPPY_SYMBOLS; /// These are symbols that we use but are already interned by either the compiler or Clippy. pub use clippy_utils::sym::filter; -pub use rustc_span::sym::{bevy_ecs, bundle, message, plugin, reflect}; +pub use rustc_span::sym::{Item, bevy_ecs, bundle, message, plugin, reflect}; use rustc_span::{Symbol, symbol::PREDEFINED_SYMBOLS_COUNT}; /// The starting offset used for the first Bevy-specific symbol. @@ -157,6 +157,7 @@ declare_bevy_symbols! { PtrMut, query, Query, + QueryData, Reflect, related_methods, RelatedSpawner,