Skip to content

Commit 7c448a6

Browse files
committed
Auto merge of #10860 - ihciah:master, r=Manishearth
add checking for cfg(features = ...) *Please write a short comment explaining your change (or "none" for internal only changes)* changelog: [`maybe_misused_cfg`]: check if `#[cfg(feature = "...")]` misused as `#[cfg(features = "...")]` I've found that there is no indication when `#[cfg(features = "...")]` is used incorrectly, which can easily make mistakes hard to spot. When I searched for this code on github, I also found many misuse cases([link](https://github.com/search?q=%23%5Bcfg%28features+language%3ARust&type=code)). PS: This clippy name is just a temporary name, it can be replaced with a better name.
2 parents 30448e8 + ad76687 commit 7c448a6

File tree

5 files changed

+99
-0
lines changed

5 files changed

+99
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4947,6 +4947,7 @@ Released 2018-09-13
49474947
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
49484948
[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
49494949
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
4950+
[`maybe_misused_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_misused_cfg
49504951
[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
49514952
[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
49524953
[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none

clippy_lints/src/attrs.rs

+57
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,32 @@ declare_clippy_lint! {
362362
"ensure that all `cfg(any())` and `cfg(all())` have more than one condition"
363363
}
364364

365+
declare_clippy_lint! {
366+
/// ### What it does
367+
/// Checks for `#[cfg(features = "...")]` and suggests to replace it with
368+
/// `#[cfg(feature = "...")]`.
369+
///
370+
/// ### Why is this bad?
371+
/// Misspelling `feature` as `features` can be sometimes hard to spot. It
372+
/// may cause conditional compilation not work quitely.
373+
///
374+
/// ### Example
375+
/// ```rust
376+
/// #[cfg(features = "some-feature")]
377+
/// fn conditional() { }
378+
/// ```
379+
///
380+
/// Use instead:
381+
/// ```rust
382+
/// #[cfg(feature = "some-feature")]
383+
/// fn conditional() { }
384+
/// ```
385+
#[clippy::version = "1.69.0"]
386+
pub MAYBE_MISUSED_CFG,
387+
suspicious,
388+
"prevent from misusing the wrong attr name"
389+
}
390+
365391
declare_lint_pass!(Attributes => [
366392
ALLOW_ATTRIBUTES_WITHOUT_REASON,
367393
INLINE_ALWAYS,
@@ -676,6 +702,7 @@ impl_lint_pass!(EarlyAttributes => [
676702
EMPTY_LINE_AFTER_OUTER_ATTR,
677703
EMPTY_LINE_AFTER_DOC_COMMENTS,
678704
NON_MINIMAL_CFG,
705+
MAYBE_MISUSED_CFG,
679706
]);
680707

681708
impl EarlyLintPass for EarlyAttributes {
@@ -687,6 +714,7 @@ impl EarlyLintPass for EarlyAttributes {
687714
check_deprecated_cfg_attr(cx, attr, &self.msrv);
688715
check_mismatched_target_os(cx, attr);
689716
check_minimal_cfg_condition(cx, attr);
717+
check_misused_cfg(cx, attr);
690718
}
691719

692720
extract_msrv_attr!(EarlyContext);
@@ -810,6 +838,27 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
810838
}
811839
}
812840

841+
fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
842+
for item in items.iter() {
843+
if let NestedMetaItem::MetaItem(meta) = item {
844+
if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() {
845+
span_lint_and_sugg(
846+
cx,
847+
MAYBE_MISUSED_CFG,
848+
meta.span,
849+
"feature may misspelled as features",
850+
"use",
851+
format!("feature = \"{val}\""),
852+
Applicability::MaybeIncorrect,
853+
);
854+
}
855+
if let MetaItemKind::List(list) = &meta.kind {
856+
check_nested_misused_cfg(cx, list);
857+
}
858+
}
859+
}
860+
}
861+
813862
fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) {
814863
if attr.has_name(sym::cfg) &&
815864
let Some(items) = attr.meta_item_list()
@@ -818,6 +867,14 @@ fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) {
818867
}
819868
}
820869

870+
fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) {
871+
if attr.has_name(sym::cfg) &&
872+
let Some(items) = attr.meta_item_list()
873+
{
874+
check_nested_misused_cfg(cx, &items);
875+
}
876+
}
877+
821878
fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
822879
fn find_os(name: &str) -> Option<&'static str> {
823880
UNIX_SYSTEMS

clippy_lints/src/declared_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
5151
crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
5252
crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
5353
crate::attrs::INLINE_ALWAYS_INFO,
54+
crate::attrs::MAYBE_MISUSED_CFG_INFO,
5455
crate::attrs::MISMATCHED_TARGET_OS_INFO,
5556
crate::attrs::NON_MINIMAL_CFG_INFO,
5657
crate::attrs::USELESS_ATTRIBUTE_INFO,

tests/ui/cfg_features.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![warn(clippy::maybe_misused_cfg)]
2+
3+
fn main() {
4+
#[cfg(features = "not-really-a-feature")]
5+
let _ = 1 + 2;
6+
7+
#[cfg(all(feature = "right", features = "wrong"))]
8+
let _ = 1 + 2;
9+
10+
#[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))]
11+
let _ = 1 + 2;
12+
}

tests/ui/cfg_features.stderr

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: feature may misspelled as features
2+
--> $DIR/cfg_features.rs:4:11
3+
|
4+
LL | #[cfg(features = "not-really-a-feature")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `feature = "not-really-a-feature"`
6+
|
7+
= note: `-D clippy::maybe-misused-cfg` implied by `-D warnings`
8+
9+
error: feature may misspelled as features
10+
--> $DIR/cfg_features.rs:7:34
11+
|
12+
LL | #[cfg(all(feature = "right", features = "wrong"))]
13+
| ^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong"`
14+
15+
error: feature may misspelled as features
16+
--> $DIR/cfg_features.rs:10:15
17+
|
18+
LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))]
19+
| ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong1"`
20+
21+
error: feature may misspelled as features
22+
--> $DIR/cfg_features.rs:10:59
23+
|
24+
LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))]
25+
| ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong2"`
26+
27+
error: aborting due to 4 previous errors
28+

0 commit comments

Comments
 (0)