1
1
//! checks for attributes
2
2
3
3
mod allow_attributes_without_reason;
4
+ mod allow_attributes;
4
5
mod blanket_clippy_restriction_lints;
5
6
mod deprecated_cfg_attr;
6
7
mod deprecated_semver;
@@ -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
@@ -272,23 +273,17 @@ declare_clippy_lint! {
272
273
/// ### What it does
273
274
/// Checks for attributes that allow lints without a reason.
274
275
///
275
- /// (This requires the `lint_reasons` feature)
276
- ///
277
276
/// ### Why restrict this?
278
277
/// Justifying each `allow` helps readers understand the reasoning,
279
278
/// and may allow removing `allow` attributes if their purpose is obsolete.
280
279
///
281
280
/// ### Example
282
281
/// ```no_run
283
- /// #![feature(lint_reasons)]
284
- ///
285
282
/// #![allow(clippy::some_lint)]
286
283
/// ```
287
284
///
288
285
/// Use instead:
289
286
/// ```no_run
290
- /// #![feature(lint_reasons)]
291
- ///
292
287
/// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
293
288
/// ```
294
289
#[ clippy:: version = "1.61.0" ]
@@ -297,6 +292,41 @@ declare_clippy_lint! {
297
292
"ensures that all `allow` and `expect` attributes have a reason"
298
293
}
299
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
+
300
330
declare_clippy_lint ! {
301
331
/// ### What it does
302
332
/// Checks for `#[should_panic]` attributes without specifying the expected panic message.
@@ -469,7 +499,12 @@ declare_clippy_lint! {
469
499
"duplicated attribute"
470
500
}
471
501
472
- declare_lint_pass ! ( Attributes => [
502
+ #[ derive( Clone ) ]
503
+ pub struct Attributes {
504
+ msrv : Msrv ,
505
+ }
506
+
507
+ impl_lint_pass ! ( Attributes => [
473
508
ALLOW_ATTRIBUTES_WITHOUT_REASON ,
474
509
INLINE_ALWAYS ,
475
510
DEPRECATED_SEMVER ,
@@ -480,6 +515,13 @@ declare_lint_pass!(Attributes => [
480
515
DUPLICATED_ATTRIBUTES ,
481
516
] ) ;
482
517
518
+ impl Attributes {
519
+ #[ must_use]
520
+ pub fn new ( msrv : Msrv ) -> Self {
521
+ Self { msrv }
522
+ }
523
+ }
524
+
483
525
impl < ' tcx > LateLintPass < ' tcx > for Attributes {
484
526
fn check_crate ( & mut self , cx : & LateContext < ' tcx > ) {
485
527
blanket_clippy_restriction_lints:: check_command_line ( cx) ;
@@ -492,8 +534,15 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
492
534
if is_lint_level ( ident. name , attr. id ) {
493
535
blanket_clippy_restriction_lints:: check ( cx, ident. name , items) ;
494
536
}
537
+ if matches ! ( ident. name, sym:: allow) {
538
+ if self . msrv . meets ( msrvs:: LINT_REASONS_STABILIZATION ) {
539
+ allow_attributes:: check ( cx, attr) ;
540
+ }
541
+ }
495
542
if matches ! ( ident. name, sym:: allow | sym:: expect) {
496
- allow_attributes_without_reason:: check ( cx, ident. name , items, attr) ;
543
+ if self . msrv . meets ( msrvs:: LINT_REASONS_STABILIZATION ) {
544
+ allow_attributes_without_reason:: check ( cx, ident. name , items, attr) ;
545
+ }
497
546
}
498
547
if items. is_empty ( ) || !attr. has_name ( sym:: deprecated) {
499
548
return ;
@@ -537,6 +586,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
537
586
inline_always:: check ( cx, item. span , item. ident . name , cx. tcx . hir ( ) . attrs ( item. hir_id ( ) ) ) ;
538
587
}
539
588
}
589
+
590
+ extract_msrv_attr ! ( LateContext ) ;
540
591
}
541
592
542
593
pub struct EarlyAttributes {
0 commit comments