1
- use clippy_utils:: diagnostics:: span_lint_and_sugg;
1
+ use clippy_utils:: { diagnostics:: span_lint_and_sugg, source :: snippet_opt } ;
2
2
use rustc_ast:: ast:: { Item , ItemKind , VariantData } ;
3
3
use rustc_errors:: Applicability ;
4
+ use rustc_lexer:: TokenKind ;
4
5
use rustc_lint:: { EarlyContext , EarlyLintPass } ;
5
6
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
7
+ use rustc_span:: Span ;
6
8
7
9
declare_clippy_lint ! {
8
10
/// ### What it does
@@ -28,9 +30,9 @@ declare_lint_pass!(UnitLikeStructBrackets => [UNIT_LIKE_STRUCT_BRACKETS]);
28
30
29
31
impl EarlyLintPass for UnitLikeStructBrackets {
30
32
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 ( ) ) ;
33
34
35
+ if let ItemKind :: Struct ( var_data, _) = & item. kind && has_no_fields ( cx, var_data, span_after_ident) {
34
36
span_lint_and_sugg (
35
37
cx,
36
38
UNIT_LIKE_STRUCT_BRACKETS ,
@@ -44,9 +46,51 @@ impl EarlyLintPass for UnitLikeStructBrackets {
44
46
}
45
47
}
46
48
47
- fn has_no_fields ( var_data : & VariantData ) -> bool {
49
+ fn has_fields_in_hir ( var_data : & VariantData ) -> bool {
48
50
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) ) ;
51
95
}
52
96
}
0 commit comments