Skip to content

Commit f82e5d5

Browse files
committed
additional checks for conditionally compiled code
1 parent 6ed8c21 commit f82e5d5

File tree

3 files changed

+70
-8
lines changed

3 files changed

+70
-8
lines changed

clippy_lints/src/unit_like_struct_brackets.rs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
1+
use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt};
22
use rustc_ast::ast::{Item, ItemKind, VariantData};
33
use rustc_errors::Applicability;
4+
use rustc_lexer::TokenKind;
45
use rustc_lint::{EarlyContext, EarlyLintPass};
56
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
use rustc_span::Span;
68

79
declare_clippy_lint! {
810
/// ### What it does
@@ -28,9 +30,9 @@ declare_lint_pass!(UnitLikeStructBrackets => [UNIT_LIKE_STRUCT_BRACKETS]);
2830

2931
impl EarlyLintPass for UnitLikeStructBrackets {
3032
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
31-
if let ItemKind::Struct(var_data, _) = &item.kind && has_no_fields(var_data) {
32-
let span_after_ident = item.span.with_lo(item.ident.span.hi());
33+
let span_after_ident = item.span.with_lo(item.ident.span.hi());
3334

35+
if let ItemKind::Struct(var_data, _) = &item.kind && has_no_fields(cx, var_data, span_after_ident) {
3436
span_lint_and_sugg(
3537
cx,
3638
UNIT_LIKE_STRUCT_BRACKETS,
@@ -44,9 +46,51 @@ impl EarlyLintPass for UnitLikeStructBrackets {
4446
}
4547
}
4648

47-
fn has_no_fields(var_data: &VariantData) -> bool {
49+
fn has_fields_in_hir(var_data: &VariantData) -> bool {
4850
match var_data {
49-
VariantData::Struct(defs, _) | VariantData::Tuple(defs, _) => defs.is_empty(),
50-
VariantData::Unit(_) => false,
51+
VariantData::Struct(defs, _) | VariantData::Tuple(defs, _) => !defs.is_empty(),
52+
VariantData::Unit(_) => true,
53+
}
54+
}
55+
56+
fn has_no_ident_token(braces_span_str: &str) -> bool {
57+
!rustc_lexer::tokenize(braces_span_str).any(|t| t.kind == TokenKind::Ident)
58+
}
59+
60+
fn has_no_fields(cx: &EarlyContext<'_>, var_data: &VariantData, braces_span: Span) -> bool {
61+
if has_fields_in_hir(var_data) {
62+
return false;
63+
}
64+
65+
// there might still be field declarations hidden from HIR
66+
// (conditionaly compiled code using #[cfg(..)])
67+
68+
let Some(braces_span_str) = snippet_opt(cx, braces_span) else {
69+
return false;
70+
};
71+
72+
has_no_ident_token(braces_span_str.as_ref())
73+
}
74+
75+
#[cfg(test)]
76+
mod unit_test {
77+
use super::*;
78+
79+
#[test]
80+
fn test_has_no_ident_token() {
81+
let input = "{ field: u8 }";
82+
assert!(!has_no_ident_token(input));
83+
84+
let input = "(u8, String);";
85+
assert!(!has_no_ident_token(input));
86+
87+
let input = " {
88+
// test = 5
89+
}
90+
";
91+
assert!(has_no_ident_token(input));
92+
93+
let input = " ();";
94+
assert!(has_no_ident_token(input));
5195
}
5296
}

tests/ui/unit_like_struct_brackets.fixed

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@
55
pub struct MyEmptyStruct; // should trigger lint
66
struct MyEmptyTupleStruct; // should trigger lint
77

8+
// should not trigger lint
9+
struct MyCfgStruct {
10+
#[cfg(feature = "thisisneverenabled")]
11+
field: u8,
12+
}
13+
14+
// should not trigger lint
15+
struct MyCfgTupleStruct(#[cfg(feature = "thisisneverenabled")] u8);
16+
17+
// should not trigger lint
818
struct MyStruct {
9-
// should not trigger lint
1019
field: u8,
1120
}
1221
struct MyTupleStruct(usize, String); // should not trigger lint

tests/ui/unit_like_struct_brackets.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@
55
pub struct MyEmptyStruct {} // should trigger lint
66
struct MyEmptyTupleStruct(); // should trigger lint
77

8+
// should not trigger lint
9+
struct MyCfgStruct {
10+
#[cfg(feature = "thisisneverenabled")]
11+
field: u8,
12+
}
13+
14+
// should not trigger lint
15+
struct MyCfgTupleStruct(#[cfg(feature = "thisisneverenabled")] u8);
16+
17+
// should not trigger lint
818
struct MyStruct {
9-
// should not trigger lint
1019
field: u8,
1120
}
1221
struct MyTupleStruct(usize, String); // should not trigger lint

0 commit comments

Comments
 (0)