@@ -485,6 +485,33 @@ declare_clippy_lint! {
485
485
"usage of `cfg_attr(clippy, allow(clippy::lint))` instead of `allow(clippy::lint)`"
486
486
}
487
487
488
+ declare_clippy_lint ! {
489
+ /// ### What it does
490
+ /// Checks that an item has only one kind of attributes.
491
+ ///
492
+ /// ### Why is this bad?
493
+ /// Having both kinds of attributes makes it more complicated to read code.
494
+ ///
495
+ /// ### Example
496
+ /// ```no_run
497
+ /// #[cfg(linux)]
498
+ /// pub fn foo() {
499
+ /// #![cfg(windows)]
500
+ /// }
501
+ /// ```
502
+ /// Use instead:
503
+ /// ```no_run
504
+ /// #[cfg(linux)]
505
+ /// #[cfg(windows)]
506
+ /// pub fn foo() {
507
+ /// }
508
+ /// ```
509
+ #[ clippy:: version = "1.78.0" ]
510
+ pub MIXED_ATTRIBUTES_STYLE ,
511
+ suspicious,
512
+ "item has both inner and outer attributes"
513
+ }
514
+
488
515
declare_lint_pass ! ( Attributes => [
489
516
ALLOW_ATTRIBUTES_WITHOUT_REASON ,
490
517
INLINE_ALWAYS ,
@@ -849,11 +876,13 @@ impl_lint_pass!(EarlyAttributes => [
849
876
MAYBE_MISUSED_CFG ,
850
877
DEPRECATED_CLIPPY_CFG_ATTR ,
851
878
UNNECESSARY_CLIPPY_CFG ,
879
+ MIXED_ATTRIBUTES_STYLE ,
852
880
] ) ;
853
881
854
882
impl EarlyLintPass for EarlyAttributes {
855
883
fn check_item ( & mut self , cx : & EarlyContext < ' _ > , item : & rustc_ast:: Item ) {
856
884
check_empty_line_after_outer_attr ( cx, item) ;
885
+ check_mixed_attributes ( cx, item) ;
857
886
}
858
887
859
888
fn check_attribute ( & mut self , cx : & EarlyContext < ' _ > , attr : & Attribute ) {
@@ -867,6 +896,32 @@ impl EarlyLintPass for EarlyAttributes {
867
896
extract_msrv_attr ! ( EarlyContext ) ;
868
897
}
869
898
899
+ fn check_mixed_attributes ( cx : & EarlyContext < ' _ > , item : & rustc_ast:: Item ) {
900
+ let mut has_outer = false ;
901
+ let mut has_inner = false ;
902
+
903
+ for attr in & item. attrs {
904
+ if attr. span . from_expansion ( ) {
905
+ continue ;
906
+ }
907
+ match attr. style {
908
+ AttrStyle :: Inner => has_inner = true ,
909
+ AttrStyle :: Outer => has_outer = true ,
910
+ }
911
+ }
912
+ if !has_outer || !has_inner {
913
+ return ;
914
+ }
915
+ let mut attrs_iter = item. attrs . iter ( ) . filter ( |attr| !attr. span . from_expansion ( ) ) ;
916
+ let span = attrs_iter. next ( ) . unwrap ( ) . span ;
917
+ span_lint (
918
+ cx,
919
+ MIXED_ATTRIBUTES_STYLE ,
920
+ span. with_hi ( attrs_iter. last ( ) . unwrap ( ) . span . hi ( ) ) ,
921
+ "item has both inner and outer attributes" ,
922
+ ) ;
923
+ }
924
+
870
925
/// Check for empty lines after outer attributes.
871
926
///
872
927
/// Attributes and documentation comments are both considered outer attributes
0 commit comments