Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand mismatched_target_os lint to check macro position usage #8192

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 0 additions & 123 deletions clippy_lints/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,6 @@ use rustc_span::sym;
use rustc_span::symbol::{Symbol, SymbolStr};
use semver::Version;

static UNIX_SYSTEMS: &[&str] = &[
"android",
"dragonfly",
"emscripten",
"freebsd",
"fuchsia",
"haiku",
"illumos",
"ios",
"l4re",
"linux",
"macos",
"netbsd",
"openbsd",
"redox",
"solaris",
"vxworks",
];

// NOTE: windows is excluded from the list because it's also a valid target family.
static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"];

declare_clippy_lint! {
/// ### What it does
/// Checks for items annotated with `#[inline(always)]`,
Expand Down Expand Up @@ -221,39 +199,6 @@ declare_clippy_lint! {
"usage of `cfg_attr(rustfmt)` instead of tool attributes"
}

declare_clippy_lint! {
/// ### What it does
/// Checks for cfg attributes having operating systems used in target family position.
///
/// ### Why is this bad?
/// The configuration option will not be recognised and the related item will not be included
/// by the conditional compilation engine.
///
/// ### Example
/// Bad:
/// ```rust
/// #[cfg(linux)]
/// fn conditional() { }
/// ```
///
/// Good:
/// ```rust
/// #[cfg(target_os = "linux")]
/// fn conditional() { }
/// ```
///
/// Or:
/// ```rust
/// #[cfg(unix)]
/// fn conditional() { }
/// ```
/// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details.
#[clippy::version = "1.45.0"]
pub MISMATCHED_TARGET_OS,
correctness,
"usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`"
}

declare_lint_pass!(Attributes => [
INLINE_ALWAYS,
DEPRECATED_SEMVER,
Expand Down Expand Up @@ -512,7 +457,6 @@ pub struct EarlyAttributes {

impl_lint_pass!(EarlyAttributes => [
DEPRECATED_CFG_ATTR,
MISMATCHED_TARGET_OS,
EMPTY_LINE_AFTER_OUTER_ATTR,
]);

Expand All @@ -523,7 +467,6 @@ impl EarlyLintPass for EarlyAttributes {

fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
check_deprecated_cfg_attr(cx, attr, self.msrv);
check_mismatched_target_os(cx, attr);
}

extract_msrv_attr!(EarlyContext);
Expand Down Expand Up @@ -594,72 +537,6 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Opti
}
}

fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
fn find_os(name: &str) -> Option<&'static str> {
UNIX_SYSTEMS
.iter()
.chain(NON_UNIX_SYSTEMS.iter())
.find(|&&os| os == name)
.copied()
}

fn is_unix(name: &str) -> bool {
UNIX_SYSTEMS.iter().any(|&os| os == name)
}

fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> {
let mut mismatched = Vec::new();

for item in items {
if let NestedMetaItem::MetaItem(meta) = item {
match &meta.kind {
MetaItemKind::List(list) => {
mismatched.extend(find_mismatched_target_os(list));
},
MetaItemKind::Word => {
if_chain! {
if let Some(ident) = meta.ident();
if let Some(os) = find_os(&*ident.name.as_str());
then {
mismatched.push((os, ident.span));
}
}
},
MetaItemKind::NameValue(..) => {},
}
}
}

mismatched
}

if_chain! {
if attr.has_name(sym::cfg);
if let Some(list) = attr.meta_item_list();
let mismatched = find_mismatched_target_os(&list);
if !mismatched.is_empty();
then {
let mess = "operating system used in target family position";

span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| {
// Avoid showing the unix suggestion multiple times in case
// we have more than one mismatch for unix-like systems
let mut unix_suggested = false;

for (os, span) in mismatched {
let sugg = format!("target_os = \"{}\"", os);
diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);

if !unix_suggested && is_unix(os) {
diag.help("did you mean `unix`?");
unix_suggested = true;
}
}
});
}
}
}

fn is_lint_level(symbol: Symbol) -> bool {
matches!(symbol, sym::allow | sym::warn | sym::deny | sym::forbid)
}
178 changes: 178 additions & 0 deletions clippy_lints/src/cfg_target_os.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
//! checks for cfg `target_os` usages

use clippy_utils::diagnostics::span_lint_and_then;
use if_chain::if_chain;
use rustc_ast::{Attribute, MacCall, MetaItemKind, NestedMetaItem};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_parse::parser;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::sym;

static UNIX_SYSTEMS: &[&str] = &[
"android",
"dragonfly",
"emscripten",
"freebsd",
"fuchsia",
"haiku",
"illumos",
"ios",
"l4re",
"linux",
"macos",
"netbsd",
"openbsd",
"redox",
"solaris",
"vxworks",
];

// NOTE: windows is excluded from the list because it's also a valid target family.
static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"];

declare_clippy_lint! {
/// ### What it does
/// Checks for cfg attributes having operating systems used in target family position.
///
/// ### Why is this bad?
/// The configuration option will not be recognised and the related item will not be included
/// by the conditional compilation engine.
///
/// ### Example
/// Bad:
/// ```rust
/// #[cfg(linux)]
/// fn conditional() { }
/// ```
///
/// Good:
/// ```rust
/// #[cfg(target_os = "linux")]
/// fn conditional() { }
/// ```
///
/// Or:
/// ```rust
/// #[cfg(unix)]
/// fn conditional() { }
/// ```
/// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details.
#[clippy::version = "1.45.0"]
pub MISMATCHED_TARGET_OS,
correctness,
"usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`"
}

declare_lint_pass!(CfgTargetOs => [MISMATCHED_TARGET_OS]);

impl EarlyLintPass for CfgTargetOs {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
check_mismatched_target_os(cx, attr);
}

fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
check_mismatched_target_os_mac(cx, mac);
}
}

fn find_os(name: &str) -> Option<&'static str> {
UNIX_SYSTEMS
.iter()
.chain(NON_UNIX_SYSTEMS.iter())
.find(|&&os| os == name)
.copied()
}

fn is_unix(name: &str) -> bool {
UNIX_SYSTEMS.iter().any(|&os| os == name)
}

fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> {
let mut mismatched = Vec::new();

for item in items {
if let NestedMetaItem::MetaItem(meta) = item {
match &meta.kind {
MetaItemKind::List(list) => {
mismatched.extend(find_mismatched_target_os(list));
},
MetaItemKind::Word => {
if_chain! {
if let Some(ident) = meta.ident();
if let Some(os) = find_os(&*ident.name.as_str());
then {
mismatched.push((os, ident.span));
}
}
},
MetaItemKind::NameValue(..) => {},
}
}
}

mismatched
}

fn write_diagnoses(cx: &EarlyContext<'_>, mismatched: Vec<(&str, Span)>, span: Span) {
if !mismatched.is_empty() {
let mess = "operating system used in target family position";

span_lint_and_then(cx, MISMATCHED_TARGET_OS, span, mess, |diag| {
// Avoid showing the unix suggestion multiple times in case
// we have more than one mismatch for unix-like systems
let mut unix_suggested = false;

for (os, span) in mismatched {
let sugg = format!("target_os = \"{}\"", os);
diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);

if !unix_suggested && is_unix(os) {
diag.help("did you mean `unix`?");
unix_suggested = true;
}
}
});
}
}

fn check_mismatched_target_os_mac(cx: &EarlyContext<'_>, mac: &MacCall) {
let args = &mac.args;
let inner = args.inner_tokens();
let mut parser = parser::Parser::new(&cx.sess.parse_sess, inner, false, None);
let meta = parser.parse_meta_item().unwrap();

let mismatched = if let Some(items) = meta.meta_item_list() {
find_mismatched_target_os(items)
} else {
match &meta.kind {
MetaItemKind::List(list) => find_mismatched_target_os(list),
MetaItemKind::Word => {
if_chain! {
if let Some(ident) = meta.ident();
if let Some(os) = find_os(&*ident.name.as_str());
then {
vec![(os, ident.span)]
} else {
Vec::new()
}
}
},
MetaItemKind::NameValue(..) => Vec::new(),
}
};

write_diagnoses(cx, mismatched, mac.span());
}

fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
if_chain! {
if attr.has_name(sym::cfg);
if let Some(list) = attr.meta_item_list();
let mismatched = find_mismatched_target_os(&list);
then {
write_diagnoses(cx, mismatched, attr.span);
}
}
}
2 changes: 1 addition & 1 deletion clippy_lints/src/lib.register_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
LintId::of(attrs::DEPRECATED_CFG_ATTR),
LintId::of(attrs::DEPRECATED_SEMVER),
LintId::of(attrs::MISMATCHED_TARGET_OS),
LintId::of(attrs::USELESS_ATTRIBUTE),
LintId::of(bit_mask::BAD_BIT_MASK),
LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
Expand All @@ -26,6 +25,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(casts::FN_TO_NUMERIC_CAST),
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
LintId::of(casts::UNNECESSARY_CAST),
LintId::of(cfg_target_os::MISMATCHED_TARGET_OS),
LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
LintId::of(collapsible_if::COLLAPSIBLE_IF),
LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/lib.register_correctness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
LintId::of(approx_const::APPROX_CONSTANT),
LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
LintId::of(attrs::DEPRECATED_SEMVER),
LintId::of(attrs::MISMATCHED_TARGET_OS),
LintId::of(attrs::USELESS_ATTRIBUTE),
LintId::of(bit_mask::BAD_BIT_MASK),
LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
LintId::of(booleans::LOGIC_BUG),
LintId::of(casts::CAST_REF_TO_MUT),
LintId::of(cfg_target_os::MISMATCHED_TARGET_OS),
LintId::of(copies::IFS_SAME_COND),
LintId::of(copies::IF_SAME_THEN_ELSE),
LintId::of(derive::DERIVE_HASH_XOR_EQ),
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/lib.register_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ store.register_lints(&[
attrs::DEPRECATED_SEMVER,
attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
attrs::INLINE_ALWAYS,
attrs::MISMATCHED_TARGET_OS,
attrs::USELESS_ATTRIBUTE,
await_holding_invalid::AWAIT_HOLDING_LOCK,
await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
Expand Down Expand Up @@ -75,6 +74,7 @@ store.register_lints(&[
casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
casts::PTR_AS_PTR,
casts::UNNECESSARY_CAST,
cfg_target_os::MISMATCHED_TARGET_OS,
checked_conversions::CHECKED_CONVERSIONS,
cognitive_complexity::COGNITIVE_COMPLEXITY,
collapsible_if::COLLAPSIBLE_ELSE_IF,
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ mod bytecount;
mod cargo_common_metadata;
mod case_sensitive_file_extension_comparisons;
mod casts;
mod cfg_target_os;
mod checked_conversions;
mod cognitive_complexity;
mod collapsible_if;
Expand Down Expand Up @@ -427,6 +428,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se

store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
store.register_pre_expansion_pass(|| Box::new(cfg_target_os::CfgTargetOs));
store.register_pre_expansion_pass(|| Box::new(dbg_macro::DbgMacro));
}

Expand Down
Loading