Skip to content
Draft
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
37 changes: 36 additions & 1 deletion bevy_lint/src/lints/nursery/zst_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -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();

Expand Down
2 changes: 2 additions & 0 deletions bevy_lint/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ pub static PLUGIN: PathLookup = type_path!(bevy_app::plugin::Plugin);
pub static PTR_MUT: PathLookup = type_path!(bevy_ptr::PtrMut);
/// <https://github.com/bevyengine/bevy/blob/v0.17.0-rc.1/crates/bevy_ecs/src/system/query.rs#L485>
pub static QUERY: PathLookup = type_path!(bevy_ecs::system::query::Query);
/// <https://github.com/bevyengine/bevy/blob/v0.17.2/crates/bevy_ecs/src/query/fetch.rs#L283>
pub static QUERYDATA: PathLookup = type_path!(bevy_ecs::query::QueryData);
/// <https://github.com/bevyengine/bevy/blob/v0.17.0-rc.1/crates/bevy_reflect/src/reflect.rs#L415>
pub static REFLECT: PathLookup = type_path!(bevy_reflect::reflect::Reflect);
/// <https://github.com/bevyengine/bevy/blob/v0.17.0-rc.1/crates/bevy_ecs/src/relationship/related_methods.rs#L565>
Expand Down
3 changes: 2 additions & 1 deletion bevy_lint/src/sym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -157,6 +157,7 @@ declare_bevy_symbols! {
PtrMut,
query,
Query,
QueryData,
Reflect,
related_methods,
RelatedSpawner,
Expand Down
Loading