|
1 | 1 | //! checks for attributes
|
2 | 2 |
|
3 | 3 | use clippy_config::msrvs::{self, Msrv};
|
4 |
| -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; |
| 4 | +use clippy_utils::diagnostics::{ |
| 5 | + span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, |
| 6 | +}; |
5 | 7 | use clippy_utils::is_from_proc_macro;
|
6 | 8 | use clippy_utils::macros::{is_panic, macro_backtrace};
|
7 | 9 | use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
|
@@ -459,6 +461,30 @@ declare_clippy_lint! {
|
459 | 461 | "usage of `cfg(feature = \"cargo-clippy\")` instead of `cfg(clippy)`"
|
460 | 462 | }
|
461 | 463 |
|
| 464 | +declare_clippy_lint! { |
| 465 | + /// ### What it does |
| 466 | + /// Checks for `#[cfg_attr(clippy, allow(clippy::lint))]` |
| 467 | + /// and suggests to replace it with `#[allow(clippy::lint)]`. |
| 468 | + /// |
| 469 | + /// ### Why is this bad? |
| 470 | + /// There is no reason to put clippy attributes behind a clippy `cfg` as they are not |
| 471 | + /// run by anything else than clippy. |
| 472 | + /// |
| 473 | + /// ### Example |
| 474 | + /// ```no_run |
| 475 | + /// #![cfg_attr(clippy, allow(clippy::deprecated_cfg_attr))] |
| 476 | + /// ``` |
| 477 | + /// |
| 478 | + /// Use instead: |
| 479 | + /// ```no_run |
| 480 | + /// #![allow(clippy::deprecated_cfg_attr)] |
| 481 | + /// ``` |
| 482 | + #[clippy::version = "1.78.0"] |
| 483 | + pub UNNECESSARY_CLIPPY_CFG, |
| 484 | + suspicious, |
| 485 | + "usage of `cfg_attr(clippy, allow(clippy::lint))` instead of `allow(clippy::lint)`" |
| 486 | +} |
| 487 | + |
462 | 488 | declare_lint_pass!(Attributes => [
|
463 | 489 | ALLOW_ATTRIBUTES_WITHOUT_REASON,
|
464 | 490 | INLINE_ALWAYS,
|
@@ -821,6 +847,7 @@ impl_lint_pass!(EarlyAttributes => [
|
821 | 847 | NON_MINIMAL_CFG,
|
822 | 848 | MAYBE_MISUSED_CFG,
|
823 | 849 | DEPRECATED_CLIPPY_CFG_ATTR,
|
| 850 | + UNNECESSARY_CLIPPY_CFG, |
824 | 851 | ]);
|
825 | 852 |
|
826 | 853 | impl EarlyLintPass for EarlyAttributes {
|
@@ -958,6 +985,74 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr
|
958 | 985 | );
|
959 | 986 | } else {
|
960 | 987 | check_deprecated_cfg_recursively(cx, feature_item);
|
| 988 | + if let Some(behind_cfg_attr) = items[1].meta_item() { |
| 989 | + check_clippy_cfg_attr(cx, feature_item, behind_cfg_attr, attr); |
| 990 | + } |
| 991 | + } |
| 992 | + } |
| 993 | +} |
| 994 | + |
| 995 | +fn check_clippy_cfg_attr( |
| 996 | + cx: &EarlyContext<'_>, |
| 997 | + cfg_attr: &rustc_ast::MetaItem, |
| 998 | + behind_cfg_attr: &rustc_ast::MetaItem, |
| 999 | + attr: &Attribute, |
| 1000 | +) { |
| 1001 | + if cfg_attr.has_name(sym::clippy) |
| 1002 | + && let Some(ident) = behind_cfg_attr.ident() |
| 1003 | + // FIXME: replace with `from_symbol` once https://github.com/rust-lang/rust/pull/121230 |
| 1004 | + // is merged. |
| 1005 | + && Level::from_str(ident.name.as_str()).is_some() |
| 1006 | + && let Some(items) = behind_cfg_attr.meta_item_list() |
| 1007 | + { |
| 1008 | + let nb_items = items.len(); |
| 1009 | + let mut clippy_lints = Vec::with_capacity(items.len()); |
| 1010 | + for item in items { |
| 1011 | + if let Some(meta_item) = item.meta_item() |
| 1012 | + && let [part1, _] = meta_item.path.segments.as_slice() |
| 1013 | + && part1.ident.name == sym::clippy |
| 1014 | + { |
| 1015 | + clippy_lints.push(item.span()); |
| 1016 | + } |
| 1017 | + } |
| 1018 | + if clippy_lints.is_empty() { |
| 1019 | + return; |
| 1020 | + } |
| 1021 | + if nb_items == clippy_lints.len() { |
| 1022 | + if let Some(snippet) = snippet_opt(cx, behind_cfg_attr.span) { |
| 1023 | + span_lint_and_sugg( |
| 1024 | + cx, |
| 1025 | + UNNECESSARY_CLIPPY_CFG, |
| 1026 | + attr.span, |
| 1027 | + "no need to put clippy lints behind a `clippy` cfg", |
| 1028 | + "replace with", |
| 1029 | + format!( |
| 1030 | + "#{}[{}]", |
| 1031 | + if attr.style == AttrStyle::Inner { "!" } else { "" }, |
| 1032 | + snippet |
| 1033 | + ), |
| 1034 | + Applicability::MachineApplicable, |
| 1035 | + ); |
| 1036 | + } |
| 1037 | + } else { |
| 1038 | + let snippet = clippy_lints |
| 1039 | + .iter() |
| 1040 | + .filter_map(|sp| snippet_opt(cx, *sp)) |
| 1041 | + .collect::<Vec<_>>() |
| 1042 | + .join(","); |
| 1043 | + span_lint_and_note( |
| 1044 | + cx, |
| 1045 | + UNNECESSARY_CLIPPY_CFG, |
| 1046 | + clippy_lints, |
| 1047 | + "no need to put clippy lints behind a `clippy` cfg", |
| 1048 | + None, |
| 1049 | + &format!( |
| 1050 | + "write instead: `#{}[{}({})]`", |
| 1051 | + if attr.style == AttrStyle::Inner { "!" } else { "" }, |
| 1052 | + ident.name, |
| 1053 | + snippet |
| 1054 | + ), |
| 1055 | + ); |
961 | 1056 | }
|
962 | 1057 | }
|
963 | 1058 | }
|
|
0 commit comments