@@ -20,30 +20,28 @@ use rustc_span::source_map::Span;
2020use rustc_span:: symbol:: Symbol ;
2121use semver:: Version ;
2222
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 ] = & [
2524 "android" ,
26- "cloudabi" ,
2725 "dragonfly" ,
2826 "emscripten" ,
2927 "freebsd" ,
3028 "fuchsia" ,
3129 "haiku" ,
32- "hermit" ,
3330 "illumos" ,
3431 "ios" ,
3532 "l4re" ,
3633 "linux" ,
3734 "macos" ,
3835 "netbsd" ,
39- "none" ,
4036 "openbsd" ,
4137 "redox" ,
4238 "solaris" ,
4339 "vxworks" ,
44- "wasi" ,
4540] ;
4641
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+
4745declare_clippy_lint ! {
4846 /// **What it does:** Checks for items annotated with `#[inline(always)]`,
4947 /// unless the annotated function is empty or simply panics.
@@ -592,18 +590,32 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) {
592590}
593591
594592fn 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+
595605 fn find_mismatched_target_os ( items : & [ NestedMetaItem ] ) -> Vec < ( & str , Span ) > {
596606 let mut mismatched = Vec :: new ( ) ;
607+
597608 for item in items {
598609 if let NestedMetaItem :: MetaItem ( meta) = item {
599610 match & meta. kind {
600611 MetaItemKind :: List ( list) => {
601612 mismatched. extend ( find_mismatched_target_os ( & list) ) ;
602613 } ,
603614 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 {
607619 mismatched. push( ( os, ident. span) ) ;
608620 }
609621 }
@@ -612,23 +624,33 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
612624 }
613625 }
614626 }
627+
615628 mismatched
616629 }
617630
618631 if_chain ! {
619632 if attr. check_name( sym!( cfg) ) ;
620633 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( ) ;
621636 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" ;
626638
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) ;
628646 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+ } ) ;
632654 }
633655 }
634656}
0 commit comments