From 68772252b931d67545d3277e46b475ce4ed9cb56 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:18:30 -0500 Subject: [PATCH 1/6] feat: create `declare_bevy_lint_pass!` macro --- bevy_lint/src/lib.rs | 1 + bevy_lint/src/lint.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 7b9f0398..c282b8fb 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -21,6 +21,7 @@ extern crate rustc_hir; extern crate rustc_hir_analysis; extern crate rustc_interface; extern crate rustc_lint; +extern crate rustc_lint_defs; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; diff --git a/bevy_lint/src/lint.rs b/bevy_lint/src/lint.rs index 3b8bfcf0..8b6e517a 100644 --- a/bevy_lint/src/lint.rs +++ b/bevy_lint/src/lint.rs @@ -101,3 +101,33 @@ macro_rules! declare_bevy_lint { }; }; } + +#[macro_export] +#[doc(hidden)] +macro_rules! declare_bevy_lint_pass { + ( + $(#[$attr:meta])* + $vis:vis $name:ident => [$($lint:expr),* $(,)?], + + $( + @default = { + $($default_field:ident: $default_ty:ty = $default_value:expr)*, + }, + )? + ) => { + $(#[$attr])* + $vis struct $name { + $($($default_field: $default_ty)*,)? + } + + impl ::std::default::Default for $name { + fn default() -> Self { + Self { + $($($default_field: $default_value)*,)? + } + } + } + + ::rustc_lint_defs::impl_lint_pass!($name => [$($lint),*]); + }; +} From 6579112cc05c3d64fc29f7b6de8dc48a8fd96efe Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:22:14 -0500 Subject: [PATCH 2/6] chore: migrate all lint passes to `declare_bevy_lint_pass!` --- bevy_lint/src/lints/borrowed_reborrowable.rs | 7 +++---- bevy_lint/src/lints/insert_event_resource.rs | 7 +++---- .../src/lints/main_return_without_appexit.rs | 7 +++---- bevy_lint/src/lints/missing_reflect.rs | 7 +++---- bevy_lint/src/lints/mod.rs | 18 +++++++++++------- bevy_lint/src/lints/panicking_methods.rs | 7 +++---- .../src/lints/plugin_not_ending_in_plugin.rs | 7 +++---- bevy_lint/src/lints/zst_query.rs | 7 +++---- 8 files changed, 32 insertions(+), 35 deletions(-) diff --git a/bevy_lint/src/lints/borrowed_reborrowable.rs b/bevy_lint/src/lints/borrowed_reborrowable.rs index 6c2a3606..891cf2c6 100644 --- a/bevy_lint/src/lints/borrowed_reborrowable.rs +++ b/bevy_lint/src/lints/borrowed_reborrowable.rs @@ -78,13 +78,12 @@ use std::ops::ControlFlow; -use crate::declare_bevy_lint; +use crate::{declare_bevy_lint, declare_bevy_lint_pass}; use clippy_utils::{diagnostics::span_lint_and_sugg, ty::match_type}; use rustc_errors::Applicability; use rustc_hir::{intravisit::FnKind, Body, FnDecl, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Interner, Ty, TyKind, TypeVisitable, TypeVisitor}; -use rustc_session::declare_lint_pass; use rustc_span::{ def_id::LocalDefId, symbol::{kw, Ident}, @@ -97,8 +96,8 @@ declare_bevy_lint! { "parameter takes a mutable reference to a re-borrowable type", } -declare_lint_pass! { - BorrowedReborrowable => [BORROWED_REBORROWABLE.lint] +declare_bevy_lint_pass! { + pub BorrowedReborrowable => [BORROWED_REBORROWABLE.lint], } impl<'tcx> LateLintPass<'tcx> for BorrowedReborrowable { diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index d94abaa9..22e4c839 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -35,7 +35,7 @@ //! App::new().add_event::().run(); //! ``` -use crate::declare_bevy_lint; +use crate::{declare_bevy_lint, declare_bevy_lint_pass}; use clippy_utils::{ diagnostics::span_lint_and_sugg, source::snippet_with_applicability, sym, ty::match_type, }; @@ -43,7 +43,6 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TyKind}; -use rustc_session::declare_lint_pass; use rustc_span::Span; use std::borrow::Cow; @@ -53,8 +52,8 @@ declare_bevy_lint! { "called `App::insert_resource(Events)` or `App::init_resource::>()` instead of `App::add_event::()`", } -declare_lint_pass! { - InsertEventResource => [INSERT_EVENT_RESOURCE.lint] +declare_bevy_lint_pass! { + pub InsertEventResource => [INSERT_EVENT_RESOURCE.lint], } impl<'tcx> LateLintPass<'tcx> for InsertEventResource { diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index 1072b1ec..e050f4b6 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -30,7 +30,7 @@ //! } //! ``` -use crate::declare_bevy_lint; +use crate::{declare_bevy_lint, declare_bevy_lint_pass}; use clippy_utils::{ diagnostics::span_lint_hir_and_then, is_entrypoint_fn, sym, ty::match_type, visitors::for_each_expr, @@ -40,7 +40,6 @@ use rustc_hir::{ def_id::LocalDefId, intravisit::FnKind, Body, ExprKind, FnDecl, FnRetTy, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; use rustc_span::Span; use std::ops::ControlFlow; @@ -50,8 +49,8 @@ declare_bevy_lint! { "an entrypoint that calls `App::run()` does not return `AppExit`", } -declare_lint_pass! { - MainReturnWithoutAppExit => [MAIN_RETURN_WITHOUT_APPEXIT.lint] +declare_bevy_lint_pass! { + pub MainReturnWithoutAppExit => [MAIN_RETURN_WITHOUT_APPEXIT.lint], } impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { diff --git a/bevy_lint/src/lints/missing_reflect.rs b/bevy_lint/src/lints/missing_reflect.rs index a3c7aa2d..bd8fe3c4 100644 --- a/bevy_lint/src/lints/missing_reflect.rs +++ b/bevy_lint/src/lints/missing_reflect.rs @@ -31,7 +31,7 @@ //! struct MyComponent; //! ``` -use crate::declare_bevy_lint; +use crate::{declare_bevy_lint, declare_bevy_lint_pass}; use clippy_utils::{def_path_res, diagnostics::span_lint_hir_and_then, sugg::DiagExt}; use rustc_errors::Applicability; use rustc_hir::{ @@ -40,7 +40,6 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_session::declare_lint_pass; use rustc_span::Span; declare_bevy_lint! { @@ -51,8 +50,8 @@ declare_bevy_lint! { @crate_level_only = true, } -declare_lint_pass! { - MissingReflect => [MISSING_REFLECT.lint] +declare_bevy_lint_pass! { + pub MissingReflect => [MISSING_REFLECT.lint], } impl<'tcx> LateLintPass<'tcx> for MissingReflect { diff --git a/bevy_lint/src/lints/mod.rs b/bevy_lint/src/lints/mod.rs index 02e26ef9..73756378 100644 --- a/bevy_lint/src/lints/mod.rs +++ b/bevy_lint/src/lints/mod.rs @@ -32,11 +32,15 @@ pub(crate) fn register_lints(store: &mut LintStore) { } pub(crate) fn register_passes(store: &mut LintStore) { - store.register_late_pass(|_| Box::new(borrowed_reborrowable::BorrowedReborrowable)); - store.register_late_pass(|_| Box::new(insert_event_resource::InsertEventResource)); - store.register_late_pass(|_| Box::new(main_return_without_appexit::MainReturnWithoutAppExit)); - store.register_late_pass(|_| Box::new(missing_reflect::MissingReflect)); - store.register_late_pass(|_| Box::new(panicking_methods::PanickingMethods)); - store.register_late_pass(|_| Box::new(plugin_not_ending_in_plugin::PluginNotEndingInPlugin)); - store.register_late_pass(|_| Box::new(zst_query::ZstQuery)); + store.register_late_pass(|_| Box::new(borrowed_reborrowable::BorrowedReborrowable::default())); + store.register_late_pass(|_| Box::new(insert_event_resource::InsertEventResource::default())); + store.register_late_pass(|_| { + Box::new(main_return_without_appexit::MainReturnWithoutAppExit::default()) + }); + store.register_late_pass(|_| Box::new(missing_reflect::MissingReflect::default())); + store.register_late_pass(|_| Box::new(panicking_methods::PanickingMethods::default())); + store.register_late_pass(|_| { + Box::new(plugin_not_ending_in_plugin::PluginNotEndingInPlugin::default()) + }); + store.register_late_pass(|_| Box::new(zst_query::ZstQuery::default())); } diff --git a/bevy_lint/src/lints/panicking_methods.rs b/bevy_lint/src/lints/panicking_methods.rs index bdc2525f..0c300936 100644 --- a/bevy_lint/src/lints/panicking_methods.rs +++ b/bevy_lint/src/lints/panicking_methods.rs @@ -76,7 +76,7 @@ //! # bevy::ecs::system::assert_is_system(graceful_world); //! ``` -use crate::declare_bevy_lint; +use crate::{declare_bevy_lint, declare_bevy_lint_pass}; use clippy_utils::{ diagnostics::span_lint_and_help, source::{snippet, snippet_opt}, @@ -85,7 +85,6 @@ use clippy_utils::{ use rustc_hir::{Expr, ExprKind, GenericArgs}; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::Ty; -use rustc_session::declare_lint_pass; use rustc_span::{Span, Symbol}; declare_bevy_lint! { @@ -100,8 +99,8 @@ declare_bevy_lint! { "called a `World` method that can panic when a non-panicking alternative exists", } -declare_lint_pass! { - PanickingMethods => [PANICKING_QUERY_METHODS.lint, PANICKING_WORLD_METHODS.lint] +declare_bevy_lint_pass! { + pub PanickingMethods => [PANICKING_QUERY_METHODS.lint, PANICKING_WORLD_METHODS.lint], } impl<'tcx> LateLintPass<'tcx> for PanickingMethods { diff --git a/bevy_lint/src/lints/plugin_not_ending_in_plugin.rs b/bevy_lint/src/lints/plugin_not_ending_in_plugin.rs index 0e7bbd32..98b73f2a 100644 --- a/bevy_lint/src/lints/plugin_not_ending_in_plugin.rs +++ b/bevy_lint/src/lints/plugin_not_ending_in_plugin.rs @@ -37,12 +37,11 @@ //! } //! ``` -use crate::declare_bevy_lint; +use crate::{declare_bevy_lint, declare_bevy_lint_pass}; use clippy_utils::{diagnostics::span_lint_hir_and_then, match_def_path, path_res}; use rustc_errors::Applicability; use rustc_hir::{def::Res, HirId, Item, ItemKind, OwnerId}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; declare_bevy_lint! { @@ -51,8 +50,8 @@ declare_bevy_lint! { "implemented `Plugin` for a structure whose name does not end in \"Plugin\"", } -declare_lint_pass! { - PluginNotEndingInPlugin => [PLUGIN_NOT_ENDING_IN_PLUGIN.lint] +declare_bevy_lint_pass! { + pub PluginNotEndingInPlugin => [PLUGIN_NOT_ENDING_IN_PLUGIN.lint], } impl<'tcx> LateLintPass<'tcx> for PluginNotEndingInPlugin { diff --git a/bevy_lint/src/lints/zst_query.rs b/bevy_lint/src/lints/zst_query.rs index 2ed90f5e..19195f8b 100644 --- a/bevy_lint/src/lints/zst_query.rs +++ b/bevy_lint/src/lints/zst_query.rs @@ -32,7 +32,7 @@ //! ``` use crate::{ - declare_bevy_lint, + declare_bevy_lint, declare_bevy_lint_pass, utils::hir_parse::{detuple, generic_type_at}, }; use clippy_utils::{ @@ -46,7 +46,6 @@ use rustc_middle::ty::{ layout::{LayoutOf, TyAndLayout}, Ty, }; -use rustc_session::declare_lint_pass; declare_bevy_lint! { pub ZST_QUERY, @@ -54,8 +53,8 @@ declare_bevy_lint! { "query for a zero-sized type", } -declare_lint_pass! { - ZstQuery => [ZST_QUERY.lint] +declare_bevy_lint_pass! { + pub ZstQuery => [ZST_QUERY.lint], } impl<'tcx> LateLintPass<'tcx> for ZstQuery { From 95a715cfc6eb53e09d2a8b63c9c2677529e3db3e Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:55:42 -0500 Subject: [PATCH 3/6] feat: write docs for macro --- bevy_lint/src/lint.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bevy_lint/src/lint.rs b/bevy_lint/src/lint.rs index 8b6e517a..3c968dd7 100644 --- a/bevy_lint/src/lint.rs +++ b/bevy_lint/src/lint.rs @@ -102,6 +102,26 @@ macro_rules! declare_bevy_lint { }; } +/// Creates a new [`LintPass`](rustc_lint::LintPass). +/// +/// This is based on [`declare_lint_pass!`](rustc_lint_defs::declare_lint_pass), but supports more +/// options. +/// +/// # Example +/// +/// ```ignore +/// declare_bevy_lint_pass! { +/// // Declares which lints are emitted by this lint pass. +/// pub LintPassName => [LINT_NAME.lint], +/// +/// // The following are optional fields, and may be excluded. +/// // +/// // Declares fields of the lint pass that are set when `LintPassName::default()` is called. +/// @default = { +/// component_sym: Symbol = Symbol::intern("component"), +/// }, +/// } +/// ``` #[macro_export] #[doc(hidden)] macro_rules! declare_bevy_lint_pass { From 8363cb9cd6bd8db4bbffd587b48fcfe636c4e3b0 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:12:23 -0500 Subject: [PATCH 4/6] fix: allow multiple default fields --- bevy_lint/src/lint.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bevy_lint/src/lint.rs b/bevy_lint/src/lint.rs index 3c968dd7..219deac4 100644 --- a/bevy_lint/src/lint.rs +++ b/bevy_lint/src/lint.rs @@ -131,19 +131,19 @@ macro_rules! declare_bevy_lint_pass { $( @default = { - $($default_field:ident: $default_ty:ty = $default_value:expr)*, + $($default_field:ident: $default_ty:ty = $default_value:expr),* $(,)? }, )? ) => { $(#[$attr])* $vis struct $name { - $($($default_field: $default_ty)*,)? + $($($default_field: $default_ty),*)? } impl ::std::default::Default for $name { fn default() -> Self { Self { - $($($default_field: $default_value)*,)? + $($($default_field: $default_value),*)? } } } From d19957610b87c9184bbc422d44cbb39e5cfe634a Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:15:35 -0500 Subject: [PATCH 5/6] refactor: replace existing `sym!` calls with caching --- bevy_lint/src/lint.rs | 2 +- bevy_lint/src/lints/insert_event_resource.rs | 10 +++++++--- bevy_lint/src/lints/main_return_without_appexit.rs | 7 +++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/bevy_lint/src/lint.rs b/bevy_lint/src/lint.rs index 219deac4..d2d65e10 100644 --- a/bevy_lint/src/lint.rs +++ b/bevy_lint/src/lint.rs @@ -118,7 +118,7 @@ macro_rules! declare_bevy_lint { /// // /// // Declares fields of the lint pass that are set when `LintPassName::default()` is called. /// @default = { -/// component_sym: Symbol = Symbol::intern("component"), +/// component: Symbol = Symbol::intern("component"), /// }, /// } /// ``` diff --git a/bevy_lint/src/lints/insert_event_resource.rs b/bevy_lint/src/lints/insert_event_resource.rs index 22e4c839..8295099f 100644 --- a/bevy_lint/src/lints/insert_event_resource.rs +++ b/bevy_lint/src/lints/insert_event_resource.rs @@ -43,7 +43,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TyKind}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::borrow::Cow; declare_bevy_lint! { @@ -54,6 +54,10 @@ declare_bevy_lint! { declare_bevy_lint_pass! { pub InsertEventResource => [INSERT_EVENT_RESOURCE.lint], + @default = { + insert_resource: Symbol = sym!(insert_resource), + init_resource: Symbol = sym!(init_resource), + }, } impl<'tcx> LateLintPass<'tcx> for InsertEventResource { @@ -72,10 +76,10 @@ impl<'tcx> LateLintPass<'tcx> for InsertEventResource { // If the method is `App::insert_resource()` or `App::init_resource()`, check it with // its corresponding function. match path.ident.name { - symbol if symbol == sym!(insert_resource) => { + symbol if symbol == self.insert_resource => { check_insert_resource(cx, args, method_span) } - symbol if symbol == sym!(init_resource) => { + symbol if symbol == self.init_resource => { check_init_resource(cx, path, method_span) } _ => {} diff --git a/bevy_lint/src/lints/main_return_without_appexit.rs b/bevy_lint/src/lints/main_return_without_appexit.rs index e050f4b6..ec5e5db0 100644 --- a/bevy_lint/src/lints/main_return_without_appexit.rs +++ b/bevy_lint/src/lints/main_return_without_appexit.rs @@ -40,7 +40,7 @@ use rustc_hir::{ def_id::LocalDefId, intravisit::FnKind, Body, ExprKind, FnDecl, FnRetTy, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use std::ops::ControlFlow; declare_bevy_lint! { @@ -51,6 +51,9 @@ declare_bevy_lint! { declare_bevy_lint_pass! { pub MainReturnWithoutAppExit => [MAIN_RETURN_WITHOUT_APPEXIT.lint], + @default = { + run: Symbol = sym!(run), + }, } impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { @@ -80,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit { for_each_expr(cx, body, |expr| { // Find a method call that matches `.run()`. if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind - && path.ident.name == sym!(run) + && path.ident.name == self.run { // Get the type of `src` for `src.run()`. We peel away all references because // both `App` and `&mut App` are allowed. From e4996f5a6713ac3f9a000d2eec60cf00e8f0f6ba Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Wed, 15 Jan 2025 08:06:09 -0500 Subject: [PATCH 6/6] feat: rephrase comment "excluded" -> "omitted" Co-authored-by: TimJentzsch --- bevy_lint/src/lint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bevy_lint/src/lint.rs b/bevy_lint/src/lint.rs index d2d65e10..eac1fba4 100644 --- a/bevy_lint/src/lint.rs +++ b/bevy_lint/src/lint.rs @@ -114,7 +114,7 @@ macro_rules! declare_bevy_lint { /// // Declares which lints are emitted by this lint pass. /// pub LintPassName => [LINT_NAME.lint], /// -/// // The following are optional fields, and may be excluded. +/// // The following are optional fields, and may be omitted. /// // /// // Declares fields of the lint pass that are set when `LintPassName::default()` is called. /// @default = {