Skip to content

Commit 85a3fa0

Browse files
committed
Implement mismatched_target_os lint
1 parent 6ffe725 commit 85a3fa0

File tree

7 files changed

+307
-28
lines changed

7 files changed

+307
-28
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,7 @@ Released 2018-09-13
14441444
[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
14451445
[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
14461446
[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
1447+
[`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
14471448
[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
14481449
[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
14491450
[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items

clippy_lints/src/attrs.rs

+130-27
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,30 @@ use rustc_span::source_map::Span;
2020
use rustc_span::symbol::Symbol;
2121
use semver::Version;
2222

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+
2347
declare_clippy_lint! {
2448
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
2549
/// unless the annotated function is empty or simply panics.
@@ -189,6 +213,38 @@ declare_clippy_lint! {
189213
"usage of `cfg_attr(rustfmt)` instead of tool attributes"
190214
}
191215

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+
192248
declare_lint_pass!(Attributes => [
193249
INLINE_ALWAYS,
194250
DEPRECATED_SEMVER,
@@ -496,35 +552,82 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
496552
}
497553
}
498554

499-
declare_lint_pass!(DeprecatedCfgAttribute => [DEPRECATED_CFG_ATTR]);
555+
declare_lint_pass!(EarlyAttributes => [DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS]);
500556

501-
impl EarlyLintPass for DeprecatedCfgAttribute {
557+
impl EarlyLintPass for EarlyAttributes {
502558
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+
});
528631
}
529632
}
530633
}

clippy_lints/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &Co
350350
store.register_pre_expansion_pass(move || box non_expressive_names::NonExpressiveNames {
351351
single_char_binding_names_threshold,
352352
});
353-
store.register_pre_expansion_pass(|| box attrs::DeprecatedCfgAttribute);
353+
store.register_pre_expansion_pass(|| box attrs::EarlyAttributes);
354354
store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro);
355355
}
356356

@@ -496,6 +496,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
496496
&attrs::DEPRECATED_SEMVER,
497497
&attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
498498
&attrs::INLINE_ALWAYS,
499+
&attrs::MISMATCHED_TARGET_OS,
499500
&attrs::UNKNOWN_CLIPPY_LINTS,
500501
&attrs::USELESS_ATTRIBUTE,
501502
&await_holding_lock::AWAIT_HOLDING_LOCK,
@@ -1189,6 +1190,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11891190
LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
11901191
LintId::of(&attrs::DEPRECATED_CFG_ATTR),
11911192
LintId::of(&attrs::DEPRECATED_SEMVER),
1193+
LintId::of(&attrs::MISMATCHED_TARGET_OS),
11921194
LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
11931195
LintId::of(&attrs::USELESS_ATTRIBUTE),
11941196
LintId::of(&bit_mask::BAD_BIT_MASK),
@@ -1611,6 +1613,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16111613
LintId::of(&approx_const::APPROX_CONSTANT),
16121614
LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
16131615
LintId::of(&attrs::DEPRECATED_SEMVER),
1616+
LintId::of(&attrs::MISMATCHED_TARGET_OS),
16141617
LintId::of(&attrs::USELESS_ATTRIBUTE),
16151618
LintId::of(&bit_mask::BAD_BIT_MASK),
16161619
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),

src/lintlist/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
12281228
deprecation: None,
12291229
module: "minmax",
12301230
},
1231+
Lint {
1232+
name: "mismatched_target_os",
1233+
group: "correctness",
1234+
desc: "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`",
1235+
deprecation: None,
1236+
module: "attrs",
1237+
},
12311238
Lint {
12321239
name: "misrefactored_assign_op",
12331240
group: "complexity",

tests/ui/mismatched_target_os.fixed

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::mismatched_target_os)]
4+
#![allow(unused)]
5+
6+
#[cfg(target_os = "linux")]
7+
fn linux() {}
8+
9+
#[cfg(target_os = "freebsd")]
10+
fn freebsd() {}
11+
12+
#[cfg(target_os = "dragonfly")]
13+
fn dragonfly() {}
14+
15+
#[cfg(target_os = "openbsd")]
16+
fn openbsd() {}
17+
18+
#[cfg(target_os = "netbsd")]
19+
fn netbsd() {}
20+
21+
#[cfg(target_os = "macos")]
22+
fn macos() {}
23+
24+
#[cfg(target_os = "ios")]
25+
fn ios() {}
26+
27+
#[cfg(target_os = "android")]
28+
fn android() {}
29+
30+
#[cfg(all(not(any(windows, target_os = "linux")), target_os = "freebsd"))]
31+
fn list() {}
32+
33+
// windows is a valid target family, should be ignored
34+
#[cfg(windows)]
35+
fn windows() {}
36+
37+
// correct use, should be ignored
38+
#[cfg(target_os = "freebsd")]
39+
fn freebsd() {}
40+
41+
fn main() {}

tests/ui/mismatched_target_os.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::mismatched_target_os)]
4+
#![allow(unused)]
5+
6+
#[cfg(linux)]
7+
fn linux() {}
8+
9+
#[cfg(freebsd)]
10+
fn freebsd() {}
11+
12+
#[cfg(dragonfly)]
13+
fn dragonfly() {}
14+
15+
#[cfg(openbsd)]
16+
fn openbsd() {}
17+
18+
#[cfg(netbsd)]
19+
fn netbsd() {}
20+
21+
#[cfg(macos)]
22+
fn macos() {}
23+
24+
#[cfg(ios)]
25+
fn ios() {}
26+
27+
#[cfg(android)]
28+
fn android() {}
29+
30+
#[cfg(all(not(any(windows, linux)), freebsd))]
31+
fn list() {}
32+
33+
// windows is a valid target family, should be ignored
34+
#[cfg(windows)]
35+
fn windows() {}
36+
37+
// correct use, should be ignored
38+
#[cfg(target_os = "freebsd")]
39+
fn freebsd() {}
40+
41+
fn main() {}

0 commit comments

Comments
 (0)