@@ -20,6 +20,30 @@ use rustc_span::source_map::Span;
20
20
use rustc_span:: symbol:: Symbol ;
21
21
use semver:: Version ;
22
22
23
+ // NOTE: windows is excluded from the list because it's also a valid target family.
24
+ static OPERATING_SYSTEMS : & [ & str ] = & [
25
+ "android" ,
26
+ "cloudabi" ,
27
+ "dragonfly" ,
28
+ "emscripten" ,
29
+ "freebsd" ,
30
+ "fuchsia" ,
31
+ "haiku" ,
32
+ "hermit" ,
33
+ "illumos" ,
34
+ "ios" ,
35
+ "l4re" ,
36
+ "linux" ,
37
+ "macos" ,
38
+ "netbsd" ,
39
+ "none" ,
40
+ "openbsd" ,
41
+ "redox" ,
42
+ "solaris" ,
43
+ "vxworks" ,
44
+ "wasi" ,
45
+ ] ;
46
+
23
47
declare_clippy_lint ! {
24
48
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
25
49
/// unless the annotated function is empty or simply panics.
@@ -189,6 +213,38 @@ declare_clippy_lint! {
189
213
"usage of `cfg_attr(rustfmt)` instead of tool attributes"
190
214
}
191
215
216
+ declare_clippy_lint ! {
217
+ /// **What it does:** Checks for cfg attributes having operating systems used in target family position.
218
+ ///
219
+ /// **Why is this bad?** The configuration option will not be recognised and the related item will not be included
220
+ /// by the conditional compilation engine.
221
+ ///
222
+ /// **Known problems:** None.
223
+ ///
224
+ /// **Example:**
225
+ ///
226
+ /// Bad:
227
+ /// ```rust
228
+ /// #[cfg(linux)]
229
+ /// fn conditional() { }
230
+ /// ```
231
+ ///
232
+ /// Good:
233
+ /// ```rust
234
+ /// #[cfg(target_os = "linux")]
235
+ /// fn conditional() { }
236
+ /// ```
237
+ ///
238
+ /// Or:
239
+ /// ```rust
240
+ /// #[cfg(unix)]
241
+ /// fn conditional() { }
242
+ /// ```
243
+ pub MISMATCHED_TARGET_OS ,
244
+ correctness,
245
+ "usage of `cfg(operating_system)` instead of `cfg(target_os = \" operating_system\" )`"
246
+ }
247
+
192
248
declare_lint_pass ! ( Attributes => [
193
249
INLINE_ALWAYS ,
194
250
DEPRECATED_SEMVER ,
@@ -496,35 +552,82 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
496
552
}
497
553
}
498
554
499
- declare_lint_pass ! ( DeprecatedCfgAttribute => [ DEPRECATED_CFG_ATTR ] ) ;
555
+ declare_lint_pass ! ( EarlyAttributes => [ DEPRECATED_CFG_ATTR , MISMATCHED_TARGET_OS ] ) ;
500
556
501
- impl EarlyLintPass for DeprecatedCfgAttribute {
557
+ impl EarlyLintPass for EarlyAttributes {
502
558
fn check_attribute ( & mut self , cx : & EarlyContext < ' _ > , attr : & Attribute ) {
503
- if_chain ! {
504
- // check cfg_attr
505
- if attr. check_name( sym!( cfg_attr) ) ;
506
- if let Some ( items) = attr. meta_item_list( ) ;
507
- if items. len( ) == 2 ;
508
- // check for `rustfmt`
509
- if let Some ( feature_item) = items[ 0 ] . meta_item( ) ;
510
- if feature_item. check_name( sym!( rustfmt) ) ;
511
- // check for `rustfmt_skip` and `rustfmt::skip`
512
- if let Some ( skip_item) = & items[ 1 ] . meta_item( ) ;
513
- if skip_item. check_name( sym!( rustfmt_skip) ) ||
514
- skip_item. path. segments. last( ) . expect( "empty path in attribute" ) . ident. name == sym!( skip) ;
515
- // Only lint outer attributes, because custom inner attributes are unstable
516
- // Tracking issue: https://github.com/rust-lang/rust/issues/54726
517
- if let AttrStyle :: Outer = attr. style;
518
- then {
519
- span_lint_and_sugg(
520
- cx,
521
- DEPRECATED_CFG_ATTR ,
522
- attr. span,
523
- "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes" ,
524
- "use" ,
525
- "#[rustfmt::skip]" . to_string( ) ,
526
- Applicability :: MachineApplicable ,
527
- ) ;
559
+ check_deprecated_cfg_attr ( cx, attr) ;
560
+ check_mismatched_target_os ( cx, attr) ;
561
+ }
562
+ }
563
+
564
+ fn check_deprecated_cfg_attr ( cx : & EarlyContext < ' _ > , attr : & Attribute ) {
565
+ if_chain ! {
566
+ // check cfg_attr
567
+ if attr. check_name( sym!( cfg_attr) ) ;
568
+ if let Some ( items) = attr. meta_item_list( ) ;
569
+ if items. len( ) == 2 ;
570
+ // check for `rustfmt`
571
+ if let Some ( feature_item) = items[ 0 ] . meta_item( ) ;
572
+ if feature_item. check_name( sym!( rustfmt) ) ;
573
+ // check for `rustfmt_skip` and `rustfmt::skip`
574
+ if let Some ( skip_item) = & items[ 1 ] . meta_item( ) ;
575
+ if skip_item. check_name( sym!( rustfmt_skip) ) ||
576
+ skip_item. path. segments. last( ) . expect( "empty path in attribute" ) . ident. name == sym!( skip) ;
577
+ // Only lint outer attributes, because custom inner attributes are unstable
578
+ // Tracking issue: https://github.com/rust-lang/rust/issues/54726
579
+ if let AttrStyle :: Outer = attr. style;
580
+ then {
581
+ span_lint_and_sugg(
582
+ cx,
583
+ DEPRECATED_CFG_ATTR ,
584
+ attr. span,
585
+ "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes" ,
586
+ "use" ,
587
+ "#[rustfmt::skip]" . to_string( ) ,
588
+ Applicability :: MachineApplicable ,
589
+ ) ;
590
+ }
591
+ }
592
+ }
593
+
594
+ fn check_mismatched_target_os ( cx : & EarlyContext < ' _ > , attr : & Attribute ) {
595
+ fn find_mismatched_target_os ( items : & [ NestedMetaItem ] ) -> Vec < ( & str , Span ) > {
596
+ let mut mismatched = Vec :: new ( ) ;
597
+ for item in items {
598
+ if let NestedMetaItem :: MetaItem ( meta) = item {
599
+ match & meta. kind {
600
+ MetaItemKind :: List ( list) => {
601
+ mismatched. extend ( find_mismatched_target_os ( & list) ) ;
602
+ } ,
603
+ MetaItemKind :: Word => {
604
+ if let Some ( ident) = meta. ident ( ) {
605
+ let name = & * ident. name . as_str ( ) ;
606
+ if let Some ( os) = OPERATING_SYSTEMS . iter ( ) . find ( |& & os| os == name) {
607
+ mismatched. push ( ( os, ident. span ) ) ;
608
+ }
609
+ }
610
+ } ,
611
+ _ => { } ,
612
+ }
613
+ }
614
+ }
615
+ mismatched
616
+ }
617
+
618
+ if_chain ! {
619
+ if attr. check_name( sym!( cfg) ) ;
620
+ if let Some ( list) = attr. meta_item_list( ) ;
621
+ then {
622
+ let mismatched = find_mismatched_target_os( & list) ;
623
+ for ( os, span) in mismatched {
624
+ let mess = format!( "`{}` is not a valid target family" , os) ;
625
+ let sugg = format!( "target_os = \" {}\" " , os) ;
626
+
627
+ span_lint_and_then( cx, MISMATCHED_TARGET_OS , span, & mess, |diag| {
628
+ diag. span_suggestion( span, "try" , sugg, Applicability :: MaybeIncorrect ) ;
629
+ diag. help( "Did you mean `unix`?" ) ;
630
+ } ) ;
528
631
}
529
632
}
530
633
}
0 commit comments