1
1
//! checks for attributes
2
2
3
+ mod allow_attributes;
3
4
mod allow_attributes_without_reason;
4
5
mod blanket_clippy_restriction_lints;
5
6
mod deprecated_cfg_attr;
@@ -14,11 +15,11 @@ mod unnecessary_clippy_cfg;
14
15
mod useless_attribute;
15
16
mod utils;
16
17
17
- use clippy_config:: msrvs:: Msrv ;
18
+ use clippy_config:: msrvs:: { self , Msrv } ;
18
19
use rustc_ast:: { Attribute , MetaItemKind , NestedMetaItem } ;
19
20
use rustc_hir:: { ImplItem , Item , ItemKind , TraitItem } ;
20
21
use rustc_lint:: { EarlyContext , EarlyLintPass , LateContext , LateLintPass } ;
21
- use rustc_session:: { declare_lint_pass , impl_lint_pass} ;
22
+ use rustc_session:: impl_lint_pass;
22
23
use rustc_span:: sym;
23
24
use utils:: { is_lint_level, is_relevant_impl, is_relevant_item, is_relevant_trait} ;
24
25
@@ -270,26 +271,19 @@ declare_clippy_lint! {
270
271
271
272
declare_clippy_lint ! {
272
273
/// ### What it does
273
- /// Checks for attributes that allow lints without specifying the reason
274
- /// they should be allowed. (This requires the `lint_reasons` feature.)
274
+ /// Checks for attributes that allow lints without a reason.
275
275
///
276
276
/// ### Why restrict this?
277
- /// There should always be a specific reason to allow a lint. This reason
278
- /// should be documented using the `reason` parameter, so that readers can
279
- /// understand why the `allow` is required, or remove it if it's no
280
- /// longer needed.
277
+ /// Justifying each `allow` helps readers understand the reasoning,
278
+ /// and may allow removing `allow` attributes if their purpose is obsolete.
281
279
///
282
280
/// ### Example
283
281
/// ```no_run
284
- /// #![feature(lint_reasons)]
285
- ///
286
282
/// #![allow(clippy::some_lint)]
287
283
/// ```
288
284
///
289
285
/// Use instead:
290
286
/// ```no_run
291
- /// #![feature(lint_reasons)]
292
- ///
293
287
/// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
294
288
/// ```
295
289
#[ clippy:: version = "1.61.0" ]
@@ -298,6 +292,41 @@ declare_clippy_lint! {
298
292
"ensures that all `allow` and `expect` attributes have a reason"
299
293
}
300
294
295
+ declare_clippy_lint ! {
296
+ /// ### What it does
297
+ /// Checks for usage of the `#[allow]` attribute and suggests replacing it with
298
+ /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
299
+ ///
300
+ /// This lint only warns outer attributes (`#[allow]`), as inner attributes
301
+ /// (`#![allow]`) are usually used to enable or disable lints on a global scale.
302
+ ///
303
+ /// ### Why is this bad?
304
+ /// `#[expect]` attributes suppress the lint emission, but emit a warning, if
305
+ /// the expectation is unfulfilled. This can be useful to be notified when the
306
+ /// lint is no longer triggered.
307
+ ///
308
+ /// ### Example
309
+ /// ```rust,ignore
310
+ /// #[allow(unused_mut)]
311
+ /// fn foo() -> usize {
312
+ /// let mut a = Vec::new();
313
+ /// a.len()
314
+ /// }
315
+ /// ```
316
+ /// Use instead:
317
+ /// ```rust,ignore
318
+ /// #[expect(unused_mut)]
319
+ /// fn foo() -> usize {
320
+ /// let mut a = Vec::new();
321
+ /// a.len()
322
+ /// }
323
+ /// ```
324
+ #[ clippy:: version = "1.70.0" ]
325
+ pub ALLOW_ATTRIBUTES ,
326
+ restriction,
327
+ "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings."
328
+ }
329
+
301
330
declare_clippy_lint ! {
302
331
/// ### What it does
303
332
/// Checks for `#[should_panic]` attributes without specifying the expected panic message.
@@ -470,7 +499,13 @@ declare_clippy_lint! {
470
499
"duplicated attribute"
471
500
}
472
501
473
- declare_lint_pass ! ( Attributes => [
502
+ #[ derive( Clone ) ]
503
+ pub struct Attributes {
504
+ msrv : Msrv ,
505
+ }
506
+
507
+ impl_lint_pass ! ( Attributes => [
508
+ ALLOW_ATTRIBUTES ,
474
509
ALLOW_ATTRIBUTES_WITHOUT_REASON ,
475
510
INLINE_ALWAYS ,
476
511
DEPRECATED_SEMVER ,
@@ -481,6 +516,13 @@ declare_lint_pass!(Attributes => [
481
516
DUPLICATED_ATTRIBUTES ,
482
517
] ) ;
483
518
519
+ impl Attributes {
520
+ #[ must_use]
521
+ pub fn new ( msrv : Msrv ) -> Self {
522
+ Self { msrv }
523
+ }
524
+ }
525
+
484
526
impl < ' tcx > LateLintPass < ' tcx > for Attributes {
485
527
fn check_crate ( & mut self , cx : & LateContext < ' tcx > ) {
486
528
blanket_clippy_restriction_lints:: check_command_line ( cx) ;
@@ -493,7 +535,11 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
493
535
if is_lint_level ( ident. name , attr. id ) {
494
536
blanket_clippy_restriction_lints:: check ( cx, ident. name , items) ;
495
537
}
496
- if matches ! ( ident. name, sym:: allow | sym:: expect) {
538
+ if matches ! ( ident. name, sym:: allow) && self . msrv . meets ( msrvs:: LINT_REASONS_STABILIZATION ) {
539
+ allow_attributes:: check ( cx, attr) ;
540
+ }
541
+ if matches ! ( ident. name, sym:: allow | sym:: expect) && self . msrv . meets ( msrvs:: LINT_REASONS_STABILIZATION )
542
+ {
497
543
allow_attributes_without_reason:: check ( cx, ident. name , items, attr) ;
498
544
}
499
545
if items. is_empty ( ) || !attr. has_name ( sym:: deprecated) {
@@ -538,6 +584,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
538
584
inline_always:: check ( cx, item. span , item. ident . name , cx. tcx . hir ( ) . attrs ( item. hir_id ( ) ) ) ;
539
585
}
540
586
}
587
+
588
+ extract_msrv_attr ! ( LateContext ) ;
541
589
}
542
590
543
591
pub struct EarlyAttributes {
0 commit comments