@@ -20,30 +20,28 @@ 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 ] = & [
23
+ static UNIX_SYSTEMS : & [ & str ] = & [
25
24
"android" ,
26
- "cloudabi" ,
27
25
"dragonfly" ,
28
26
"emscripten" ,
29
27
"freebsd" ,
30
28
"fuchsia" ,
31
29
"haiku" ,
32
- "hermit" ,
33
30
"illumos" ,
34
31
"ios" ,
35
32
"l4re" ,
36
33
"linux" ,
37
34
"macos" ,
38
35
"netbsd" ,
39
- "none" ,
40
36
"openbsd" ,
41
37
"redox" ,
42
38
"solaris" ,
43
39
"vxworks" ,
44
- "wasi" ,
45
40
] ;
46
41
42
+ // NOTE: windows is excluded from the list because it's also a valid target family.
43
+ static NON_UNIX_SYSTEMS : & [ & str ] = & [ "cloudabi" , "hermit" , "none" , "wasi" ] ;
44
+
47
45
declare_clippy_lint ! {
48
46
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
49
47
/// unless the annotated function is empty or simply panics.
@@ -592,18 +590,32 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) {
592
590
}
593
591
594
592
fn check_mismatched_target_os ( cx : & EarlyContext < ' _ > , attr : & Attribute ) {
593
+ fn find_os ( name : & str ) -> Option < & ' static str > {
594
+ UNIX_SYSTEMS
595
+ . iter ( )
596
+ . chain ( NON_UNIX_SYSTEMS . iter ( ) )
597
+ . find ( |& & os| os == name)
598
+ . copied ( )
599
+ }
600
+
601
+ fn is_unix ( name : & str ) -> bool {
602
+ UNIX_SYSTEMS . iter ( ) . any ( |& os| os == name)
603
+ }
604
+
595
605
fn find_mismatched_target_os ( items : & [ NestedMetaItem ] ) -> Vec < ( & str , Span ) > {
596
606
let mut mismatched = Vec :: new ( ) ;
607
+
597
608
for item in items {
598
609
if let NestedMetaItem :: MetaItem ( meta) = item {
599
610
match & meta. kind {
600
611
MetaItemKind :: List ( list) => {
601
612
mismatched. extend ( find_mismatched_target_os ( & list) ) ;
602
613
} ,
603
614
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) {
615
+ if_chain ! {
616
+ if let Some ( ident) = meta. ident( ) ;
617
+ if let Some ( os) = find_os( & * ident. name. as_str( ) ) ;
618
+ then {
607
619
mismatched. push( ( os, ident. span) ) ;
608
620
}
609
621
}
@@ -612,23 +624,33 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
612
624
}
613
625
}
614
626
}
627
+
615
628
mismatched
616
629
}
617
630
618
631
if_chain ! {
619
632
if attr. check_name( sym!( cfg) ) ;
620
633
if let Some ( list) = attr. meta_item_list( ) ;
634
+ let mismatched = find_mismatched_target_os( & list) ;
635
+ if let Some ( ( _, span) ) = mismatched. iter( ) . peekable( ) . peek( ) ;
621
636
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) ;
637
+ let mess = "operating system used in target family position" ;
626
638
627
- span_lint_and_then( cx, MISMATCHED_TARGET_OS , span, & mess, |diag| {
639
+ span_lint_and_then( cx, MISMATCHED_TARGET_OS , * span, & mess, |diag| {
640
+ // Avoid showing the unix suggestion multiple times in case
641
+ // we have more than one mismatch for unix-like systems
642
+ let mut unix_suggested = false ;
643
+
644
+ for ( os, span) in mismatched {
645
+ let sugg = format!( "target_os = \" {}\" " , os) ;
628
646
diag. span_suggestion( span, "try" , sugg, Applicability :: MaybeIncorrect ) ;
629
- diag. help( "Did you mean `unix`?" ) ;
630
- } ) ;
631
- }
647
+
648
+ if !unix_suggested && is_unix( os) {
649
+ diag. help( "Did you mean `unix`?" ) ;
650
+ unix_suggested = true ;
651
+ }
652
+ }
653
+ } ) ;
632
654
}
633
655
}
634
656
}
0 commit comments