1- use clippy_utils:: diagnostics:: span_lint_and_sugg;
1+ use clippy_utils:: { diagnostics:: span_lint_and_sugg, source :: snippet_opt } ;
22use rustc_ast:: ast:: { Item , ItemKind , VariantData } ;
33use rustc_errors:: Applicability ;
4+ use rustc_lexer:: TokenKind ;
45use rustc_lint:: { EarlyContext , EarlyLintPass } ;
56use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
7+ use rustc_span:: Span ;
68
79declare_clippy_lint ! {
810 /// ### What it does
@@ -28,9 +30,9 @@ declare_lint_pass!(UnitLikeStructBrackets => [UNIT_LIKE_STRUCT_BRACKETS]);
2830
2931impl 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}
0 commit comments