@@ -433,6 +433,32 @@ declare_clippy_lint! {
433433 "prevent from misusing the wrong attr name"
434434}
435435
436+ declare_clippy_lint ! {
437+ /// ### What it does
438+ /// Checks for `#[cfg_attr(feature = "cargo-clippy", ...)]` and for
439+ /// `#[cfg(feature = "cargo-clippy")]` and suggests to replace it with
440+ /// `#[cfg_attr(clippy, ...)]` or `#[cfg(clippy)]`.
441+ ///
442+ /// ### Why is this bad?
443+ /// This feature has been deprecated for years and shouldn't be used anymore.
444+ ///
445+ /// ### Example
446+ /// ```no_run
447+ /// #[cfg(feature = "cargo-clippy")]
448+ /// struct Bar;
449+ /// ```
450+ ///
451+ /// Use instead:
452+ /// ```no_run
453+ /// #[cfg(clippy)]
454+ /// struct Bar;
455+ /// ```
456+ #[ clippy:: version = "1.78.0" ]
457+ pub DEPRECATED_CLIPPY_CFG_ATTR ,
458+ suspicious,
459+ "usage of `cfg(feature = \" cargo-clippy\" )` instead of `cfg(clippy)`"
460+ }
461+
436462declare_lint_pass ! ( Attributes => [
437463 ALLOW_ATTRIBUTES_WITHOUT_REASON ,
438464 INLINE_ALWAYS ,
@@ -794,6 +820,7 @@ impl_lint_pass!(EarlyAttributes => [
794820 EMPTY_LINE_AFTER_DOC_COMMENTS ,
795821 NON_MINIMAL_CFG ,
796822 MAYBE_MISUSED_CFG ,
823+ DEPRECATED_CLIPPY_CFG_ATTR ,
797824] ) ;
798825
799826impl EarlyLintPass for EarlyAttributes {
@@ -803,6 +830,7 @@ impl EarlyLintPass for EarlyAttributes {
803830
804831 fn check_attribute ( & mut self , cx : & EarlyContext < ' _ > , attr : & Attribute ) {
805832 check_deprecated_cfg_attr ( cx, attr, & self . msrv ) ;
833+ check_deprecated_cfg ( cx, attr) ;
806834 check_mismatched_target_os ( cx, attr) ;
807835 check_minimal_cfg_condition ( cx, attr) ;
808836 check_misused_cfg ( cx, attr) ;
@@ -857,39 +885,80 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
857885 }
858886}
859887
888+ fn check_cargo_clippy_attr ( cx : & EarlyContext < ' _ > , item : & rustc_ast:: MetaItem ) {
889+ if item. has_name ( sym:: feature) && item. value_str ( ) . is_some_and ( |v| v. as_str ( ) == "cargo-clippy" ) {
890+ span_lint_and_sugg (
891+ cx,
892+ DEPRECATED_CLIPPY_CFG_ATTR ,
893+ item. span ,
894+ "`feature = \" cargo-clippy\" ` was replaced by `clippy`" ,
895+ "replace with" ,
896+ "clippy" . to_string ( ) ,
897+ Applicability :: MachineApplicable ,
898+ ) ;
899+ }
900+ }
901+
902+ fn check_deprecated_cfg_recursively ( cx : & EarlyContext < ' _ > , attr : & rustc_ast:: MetaItem ) {
903+ if let Some ( ident) = attr. ident ( ) {
904+ if [ "any" , "all" , "not" ] . contains ( & ident. name . as_str ( ) ) {
905+ let Some ( list) = attr. meta_item_list ( ) else { return } ;
906+ for item in list. iter ( ) . filter_map ( |item| item. meta_item ( ) ) {
907+ check_deprecated_cfg_recursively ( cx, item) ;
908+ }
909+ } else {
910+ check_cargo_clippy_attr ( cx, attr) ;
911+ }
912+ }
913+ }
914+
915+ fn check_deprecated_cfg ( cx : & EarlyContext < ' _ > , attr : & Attribute ) {
916+ if attr. has_name ( sym:: cfg)
917+ && let Some ( list) = attr. meta_item_list ( )
918+ {
919+ for item in list. iter ( ) . filter_map ( |item| item. meta_item ( ) ) {
920+ check_deprecated_cfg_recursively ( cx, item) ;
921+ }
922+ }
923+ }
924+
860925fn check_deprecated_cfg_attr ( cx : & EarlyContext < ' _ > , attr : & Attribute , msrv : & Msrv ) {
861- if msrv. meets ( msrvs:: TOOL_ATTRIBUTES )
862- // check cfg_attr
863- && attr. has_name ( sym:: cfg_attr)
926+ // check cfg_attr
927+ if attr. has_name ( sym:: cfg_attr)
864928 && let Some ( items) = attr. meta_item_list ( )
865929 && items. len ( ) == 2
866- // check for `rustfmt`
867930 && let Some ( feature_item) = items[ 0 ] . meta_item ( )
868- && feature_item. has_name ( sym:: rustfmt)
869- // check for `rustfmt_skip` and `rustfmt::skip`
870- && let Some ( skip_item) = & items[ 1 ] . meta_item ( )
871- && ( skip_item. has_name ( sym ! ( rustfmt_skip) )
872- || skip_item
873- . path
874- . segments
875- . last ( )
876- . expect ( "empty path in attribute" )
877- . ident
878- . name
879- == sym:: skip)
880- // Only lint outer attributes, because custom inner attributes are unstable
881- // Tracking issue: https://github.com/rust-lang/rust/issues/54726
882- && attr. style == AttrStyle :: Outer
883931 {
884- span_lint_and_sugg (
885- cx,
886- DEPRECATED_CFG_ATTR ,
887- attr. span ,
888- "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes" ,
889- "use" ,
890- "#[rustfmt::skip]" . to_string ( ) ,
891- Applicability :: MachineApplicable ,
892- ) ;
932+ // check for `rustfmt`
933+ if feature_item. has_name ( sym:: rustfmt)
934+ && msrv. meets ( msrvs:: TOOL_ATTRIBUTES )
935+ // check for `rustfmt_skip` and `rustfmt::skip`
936+ && let Some ( skip_item) = & items[ 1 ] . meta_item ( )
937+ && ( skip_item. has_name ( sym ! ( rustfmt_skip) )
938+ || skip_item
939+ . path
940+ . segments
941+ . last ( )
942+ . expect ( "empty path in attribute" )
943+ . ident
944+ . name
945+ == sym:: skip)
946+ // Only lint outer attributes, because custom inner attributes are unstable
947+ // Tracking issue: https://github.com/rust-lang/rust/issues/54726
948+ && attr. style == AttrStyle :: Outer
949+ {
950+ span_lint_and_sugg (
951+ cx,
952+ DEPRECATED_CFG_ATTR ,
953+ attr. span ,
954+ "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes" ,
955+ "use" ,
956+ "#[rustfmt::skip]" . to_string ( ) ,
957+ Applicability :: MachineApplicable ,
958+ ) ;
959+ } else {
960+ check_deprecated_cfg_recursively ( cx, feature_item) ;
961+ }
893962 }
894963}
895964
0 commit comments