Skip to content

Commit 12635b7

Browse files
BD103TimJentzsch
andauthored
Extend declare_lint_pass! macro (#228)
Often lints need to compare [`Symbol`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html)s. Some lints take the inefficient route by interning the string each time: ```rust if ident.name == Symbol::intern("component") { // ... } // Also seen as... if ident.name == sym!(component) { // ... } ``` This is bad because interning a string is quite expensive. To avoid this, lint passes cache the `Symbol`: ```rust struct MyLintPass { component_sym: Symbol, } impl Default for MyLintPass { fn default() -> Self { Self { component_sym: Symbol::intern("component") } } } impl<'tcx> LateLintPass<'tcx> for MyLintPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { // ... if ident.name == self.component_sym { // ... } } } ``` This requires a lot of boilerplate. To shorten this, this PR introduces a custom `declare_bevy_lint_pass!` macro that supports cached values: ```rust declare_bevy_lint_pass! { MyLintPass => [MY_LINT.lint], @default = { component: Symbol = sym!("component"), }, } ``` Eventually this macro will be used to declare custom lint config, but for now it just supports default values. I've migrated all existing lints to use `declare_bevy_lint_pass!`. --------- Co-authored-by: TimJentzsch <commits@timjen.net>
1 parent c91a3a0 commit 12635b7

File tree

10 files changed

+95
-40
lines changed

10 files changed

+95
-40
lines changed

bevy_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern crate rustc_hir;
2121
extern crate rustc_hir_analysis;
2222
extern crate rustc_interface;
2323
extern crate rustc_lint;
24+
extern crate rustc_lint_defs;
2425
extern crate rustc_middle;
2526
extern crate rustc_session;
2627
extern crate rustc_span;

bevy_lint/src/lint.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,53 @@ macro_rules! declare_bevy_lint {
101101
};
102102
};
103103
}
104+
105+
/// Creates a new [`LintPass`](rustc_lint::LintPass).
106+
///
107+
/// This is based on [`declare_lint_pass!`](rustc_lint_defs::declare_lint_pass), but supports more
108+
/// options.
109+
///
110+
/// # Example
111+
///
112+
/// ```ignore
113+
/// declare_bevy_lint_pass! {
114+
/// // Declares which lints are emitted by this lint pass.
115+
/// pub LintPassName => [LINT_NAME.lint],
116+
///
117+
/// // The following are optional fields, and may be omitted.
118+
/// //
119+
/// // Declares fields of the lint pass that are set when `LintPassName::default()` is called.
120+
/// @default = {
121+
/// component: Symbol = Symbol::intern("component"),
122+
/// },
123+
/// }
124+
/// ```
125+
#[macro_export]
126+
#[doc(hidden)]
127+
macro_rules! declare_bevy_lint_pass {
128+
(
129+
$(#[$attr:meta])*
130+
$vis:vis $name:ident => [$($lint:expr),* $(,)?],
131+
132+
$(
133+
@default = {
134+
$($default_field:ident: $default_ty:ty = $default_value:expr),* $(,)?
135+
},
136+
)?
137+
) => {
138+
$(#[$attr])*
139+
$vis struct $name {
140+
$($($default_field: $default_ty),*)?
141+
}
142+
143+
impl ::std::default::Default for $name {
144+
fn default() -> Self {
145+
Self {
146+
$($($default_field: $default_value),*)?
147+
}
148+
}
149+
}
150+
151+
::rustc_lint_defs::impl_lint_pass!($name => [$($lint),*]);
152+
};
153+
}

bevy_lint/src/lints/borrowed_reborrowable.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,12 @@
7878
7979
use std::ops::ControlFlow;
8080

81-
use crate::declare_bevy_lint;
81+
use crate::{declare_bevy_lint, declare_bevy_lint_pass};
8282
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::match_type};
8383
use rustc_errors::Applicability;
8484
use rustc_hir::{intravisit::FnKind, Body, FnDecl, Mutability};
8585
use rustc_lint::{LateContext, LateLintPass};
8686
use rustc_middle::ty::{Interner, Ty, TyKind, TypeVisitable, TypeVisitor};
87-
use rustc_session::declare_lint_pass;
8887
use rustc_span::{
8988
def_id::LocalDefId,
9089
symbol::{kw, Ident},
@@ -97,8 +96,8 @@ declare_bevy_lint! {
9796
"parameter takes a mutable reference to a re-borrowable type",
9897
}
9998

100-
declare_lint_pass! {
101-
BorrowedReborrowable => [BORROWED_REBORROWABLE.lint]
99+
declare_bevy_lint_pass! {
100+
pub BorrowedReborrowable => [BORROWED_REBORROWABLE.lint],
102101
}
103102

104103
impl<'tcx> LateLintPass<'tcx> for BorrowedReborrowable {

bevy_lint/src/lints/insert_event_resource.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,15 @@
3535
//! App::new().add_event::<MyEvent>().run();
3636
//! ```
3737
38-
use crate::declare_bevy_lint;
38+
use crate::{declare_bevy_lint, declare_bevy_lint_pass};
3939
use clippy_utils::{
4040
diagnostics::span_lint_and_sugg, source::snippet_with_applicability, sym, ty::match_type,
4141
};
4242
use rustc_errors::Applicability;
4343
use rustc_hir::{Expr, ExprKind, GenericArg, GenericArgs, Path, PathSegment, QPath};
4444
use rustc_lint::{LateContext, LateLintPass};
4545
use rustc_middle::ty::{Ty, TyKind};
46-
use rustc_session::declare_lint_pass;
47-
use rustc_span::Span;
46+
use rustc_span::{Span, Symbol};
4847
use std::borrow::Cow;
4948

5049
declare_bevy_lint! {
@@ -53,8 +52,12 @@ declare_bevy_lint! {
5352
"called `App::insert_resource(Events<T>)` or `App::init_resource::<Events<T>>()` instead of `App::add_event::<T>()`",
5453
}
5554

56-
declare_lint_pass! {
57-
InsertEventResource => [INSERT_EVENT_RESOURCE.lint]
55+
declare_bevy_lint_pass! {
56+
pub InsertEventResource => [INSERT_EVENT_RESOURCE.lint],
57+
@default = {
58+
insert_resource: Symbol = sym!(insert_resource),
59+
init_resource: Symbol = sym!(init_resource),
60+
},
5861
}
5962

6063
impl<'tcx> LateLintPass<'tcx> for InsertEventResource {
@@ -73,10 +76,10 @@ impl<'tcx> LateLintPass<'tcx> for InsertEventResource {
7376
// If the method is `App::insert_resource()` or `App::init_resource()`, check it with
7477
// its corresponding function.
7578
match path.ident.name {
76-
symbol if symbol == sym!(insert_resource) => {
79+
symbol if symbol == self.insert_resource => {
7780
check_insert_resource(cx, args, method_span)
7881
}
79-
symbol if symbol == sym!(init_resource) => {
82+
symbol if symbol == self.init_resource => {
8083
check_init_resource(cx, path, method_span)
8184
}
8285
_ => {}

bevy_lint/src/lints/main_return_without_appexit.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//! }
3131
//! ```
3232
33-
use crate::declare_bevy_lint;
33+
use crate::{declare_bevy_lint, declare_bevy_lint_pass};
3434
use clippy_utils::{
3535
diagnostics::span_lint_hir_and_then, is_entrypoint_fn, sym, ty::match_type,
3636
visitors::for_each_expr,
@@ -40,8 +40,7 @@ use rustc_hir::{
4040
def_id::LocalDefId, intravisit::FnKind, Body, ExprKind, FnDecl, FnRetTy, Ty, TyKind,
4141
};
4242
use rustc_lint::{LateContext, LateLintPass};
43-
use rustc_session::declare_lint_pass;
44-
use rustc_span::Span;
43+
use rustc_span::{Span, Symbol};
4544
use std::ops::ControlFlow;
4645

4746
declare_bevy_lint! {
@@ -50,8 +49,11 @@ declare_bevy_lint! {
5049
"an entrypoint that calls `App::run()` does not return `AppExit`",
5150
}
5251

53-
declare_lint_pass! {
54-
MainReturnWithoutAppExit => [MAIN_RETURN_WITHOUT_APPEXIT.lint]
52+
declare_bevy_lint_pass! {
53+
pub MainReturnWithoutAppExit => [MAIN_RETURN_WITHOUT_APPEXIT.lint],
54+
@default = {
55+
run: Symbol = sym!(run),
56+
},
5557
}
5658

5759
impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit {
@@ -81,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MainReturnWithoutAppExit {
8183
for_each_expr(cx, body, |expr| {
8284
// Find a method call that matches `.run()`.
8385
if let ExprKind::MethodCall(path, src, _, method_span) = expr.kind
84-
&& path.ident.name == sym!(run)
86+
&& path.ident.name == self.run
8587
{
8688
// Get the type of `src` for `src.run()`. We peel away all references because
8789
// both `App` and `&mut App` are allowed.

bevy_lint/src/lints/missing_reflect.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
//! struct MyComponent;
3232
//! ```
3333
34-
use crate::declare_bevy_lint;
34+
use crate::{declare_bevy_lint, declare_bevy_lint_pass};
3535
use clippy_utils::{def_path_res, diagnostics::span_lint_hir_and_then, sugg::DiagExt};
3636
use rustc_errors::Applicability;
3737
use rustc_hir::{
@@ -40,7 +40,6 @@ use rustc_hir::{
4040
};
4141
use rustc_lint::{LateContext, LateLintPass};
4242
use rustc_middle::ty::TyCtxt;
43-
use rustc_session::declare_lint_pass;
4443
use rustc_span::Span;
4544

4645
declare_bevy_lint! {
@@ -51,8 +50,8 @@ declare_bevy_lint! {
5150
@crate_level_only = true,
5251
}
5352

54-
declare_lint_pass! {
55-
MissingReflect => [MISSING_REFLECT.lint]
53+
declare_bevy_lint_pass! {
54+
pub MissingReflect => [MISSING_REFLECT.lint],
5655
}
5756

5857
impl<'tcx> LateLintPass<'tcx> for MissingReflect {

bevy_lint/src/lints/mod.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ pub(crate) fn register_lints(store: &mut LintStore) {
3232
}
3333

3434
pub(crate) fn register_passes(store: &mut LintStore) {
35-
store.register_late_pass(|_| Box::new(borrowed_reborrowable::BorrowedReborrowable));
36-
store.register_late_pass(|_| Box::new(insert_event_resource::InsertEventResource));
37-
store.register_late_pass(|_| Box::new(main_return_without_appexit::MainReturnWithoutAppExit));
38-
store.register_late_pass(|_| Box::new(missing_reflect::MissingReflect));
39-
store.register_late_pass(|_| Box::new(panicking_methods::PanickingMethods));
40-
store.register_late_pass(|_| Box::new(plugin_not_ending_in_plugin::PluginNotEndingInPlugin));
41-
store.register_late_pass(|_| Box::new(zst_query::ZstQuery));
35+
store.register_late_pass(|_| Box::new(borrowed_reborrowable::BorrowedReborrowable::default()));
36+
store.register_late_pass(|_| Box::new(insert_event_resource::InsertEventResource::default()));
37+
store.register_late_pass(|_| {
38+
Box::new(main_return_without_appexit::MainReturnWithoutAppExit::default())
39+
});
40+
store.register_late_pass(|_| Box::new(missing_reflect::MissingReflect::default()));
41+
store.register_late_pass(|_| Box::new(panicking_methods::PanickingMethods::default()));
42+
store.register_late_pass(|_| {
43+
Box::new(plugin_not_ending_in_plugin::PluginNotEndingInPlugin::default())
44+
});
45+
store.register_late_pass(|_| Box::new(zst_query::ZstQuery::default()));
4246
}

bevy_lint/src/lints/panicking_methods.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
//! # bevy::ecs::system::assert_is_system(graceful_world);
7777
//! ```
7878
79-
use crate::declare_bevy_lint;
79+
use crate::{declare_bevy_lint, declare_bevy_lint_pass};
8080
use clippy_utils::{
8181
diagnostics::span_lint_and_help,
8282
source::{snippet, snippet_opt},
@@ -85,7 +85,6 @@ use clippy_utils::{
8585
use rustc_hir::{Expr, ExprKind, GenericArgs};
8686
use rustc_lint::{LateContext, LateLintPass, Lint};
8787
use rustc_middle::ty::Ty;
88-
use rustc_session::declare_lint_pass;
8988
use rustc_span::{Span, Symbol};
9089

9190
declare_bevy_lint! {
@@ -100,8 +99,8 @@ declare_bevy_lint! {
10099
"called a `World` method that can panic when a non-panicking alternative exists",
101100
}
102101

103-
declare_lint_pass! {
104-
PanickingMethods => [PANICKING_QUERY_METHODS.lint, PANICKING_WORLD_METHODS.lint]
102+
declare_bevy_lint_pass! {
103+
pub PanickingMethods => [PANICKING_QUERY_METHODS.lint, PANICKING_WORLD_METHODS.lint],
105104
}
106105

107106
impl<'tcx> LateLintPass<'tcx> for PanickingMethods {

bevy_lint/src/lints/plugin_not_ending_in_plugin.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,11 @@
3737
//! }
3838
//! ```
3939
40-
use crate::declare_bevy_lint;
40+
use crate::{declare_bevy_lint, declare_bevy_lint_pass};
4141
use clippy_utils::{diagnostics::span_lint_hir_and_then, match_def_path, path_res};
4242
use rustc_errors::Applicability;
4343
use rustc_hir::{def::Res, HirId, Item, ItemKind, OwnerId};
4444
use rustc_lint::{LateContext, LateLintPass};
45-
use rustc_session::declare_lint_pass;
4645
use rustc_span::symbol::Ident;
4746

4847
declare_bevy_lint! {
@@ -51,8 +50,8 @@ declare_bevy_lint! {
5150
"implemented `Plugin` for a structure whose name does not end in \"Plugin\"",
5251
}
5352

54-
declare_lint_pass! {
55-
PluginNotEndingInPlugin => [PLUGIN_NOT_ENDING_IN_PLUGIN.lint]
53+
declare_bevy_lint_pass! {
54+
pub PluginNotEndingInPlugin => [PLUGIN_NOT_ENDING_IN_PLUGIN.lint],
5655
}
5756

5857
impl<'tcx> LateLintPass<'tcx> for PluginNotEndingInPlugin {

bevy_lint/src/lints/zst_query.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
//! ```
3333
3434
use crate::{
35-
declare_bevy_lint,
35+
declare_bevy_lint, declare_bevy_lint_pass,
3636
utils::hir_parse::{detuple, generic_type_at},
3737
};
3838
use clippy_utils::{
@@ -46,16 +46,15 @@ use rustc_middle::ty::{
4646
layout::{LayoutOf, TyAndLayout},
4747
Ty,
4848
};
49-
use rustc_session::declare_lint_pass;
5049

5150
declare_bevy_lint! {
5251
pub ZST_QUERY,
5352
RESTRICTION,
5453
"query for a zero-sized type",
5554
}
5655

57-
declare_lint_pass! {
58-
ZstQuery => [ZST_QUERY.lint]
56+
declare_bevy_lint_pass! {
57+
pub ZstQuery => [ZST_QUERY.lint],
5958
}
6059

6160
impl<'tcx> LateLintPass<'tcx> for ZstQuery {

0 commit comments

Comments
 (0)