1
1
use clippy_utils:: diagnostics:: span_lint_and_help;
2
- use rustc_ast:: ast:: { AssocItemKind , Extern , Fn , FnSig , Impl , Item , ItemKind , Trait , Ty , TyKind } ;
3
- use rustc_lint:: { EarlyContext , EarlyLintPass } ;
2
+ use clippy_utils:: { get_parent_node, is_bool} ;
3
+ use rustc_hir:: intravisit:: FnKind ;
4
+ use rustc_hir:: { Body , FnDecl , HirId , Item , ItemKind , Node , Ty } ;
5
+ use rustc_lint:: { LateContext , LateLintPass } ;
4
6
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
5
7
use rustc_span:: { sym, Span } ;
8
+ use rustc_target:: spec:: abi:: Abi ;
6
9
7
10
declare_clippy_lint ! {
8
11
/// ### What it does
@@ -83,6 +86,12 @@ pub struct ExcessiveBools {
83
86
max_fn_params_bools : u64 ,
84
87
}
85
88
89
+ #[ derive( Eq , PartialEq , Debug ) ]
90
+ enum Kind {
91
+ Struct ,
92
+ Fn ,
93
+ }
94
+
86
95
impl ExcessiveBools {
87
96
#[ must_use]
88
97
pub fn new ( max_struct_bools : u64 , max_fn_params_bools : u64 ) -> Self {
@@ -92,21 +101,20 @@ impl ExcessiveBools {
92
101
}
93
102
}
94
103
95
- fn check_fn_sig ( & self , cx : & EarlyContext < ' _ > , fn_sig : & FnSig , span : Span ) {
96
- match fn_sig. header . ext {
97
- Extern :: Implicit ( _) | Extern :: Explicit ( _, _) => return ,
98
- Extern :: None => ( ) ,
104
+ fn too_many_bools < ' tcx > ( & self , tys : impl Iterator < Item = & ' tcx Ty < ' tcx > > , kind : Kind ) -> bool {
105
+ if let Ok ( bools) = tys. filter ( |ty| is_bool ( ty) ) . count ( ) . try_into ( ) {
106
+ ( if Kind :: Fn == kind {
107
+ self . max_fn_params_bools
108
+ } else {
109
+ self . max_struct_bools
110
+ } ) < bools
111
+ } else {
112
+ false
99
113
}
114
+ }
100
115
101
- let fn_sig_bools = fn_sig
102
- . decl
103
- . inputs
104
- . iter ( )
105
- . filter ( |param| is_bool_ty ( & param. ty ) )
106
- . count ( )
107
- . try_into ( )
108
- . unwrap ( ) ;
109
- if self . max_fn_params_bools < fn_sig_bools {
116
+ fn check_fn_sig ( & self , cx : & LateContext < ' _ > , fn_decl : & FnDecl < ' _ > , span : Span ) {
117
+ if self . too_many_bools ( fn_decl. inputs . iter ( ) , Kind :: Fn ) {
110
118
span_lint_and_help (
111
119
cx,
112
120
FN_PARAMS_EXCESSIVE_BOOLS ,
@@ -121,55 +129,53 @@ impl ExcessiveBools {
121
129
122
130
impl_lint_pass ! ( ExcessiveBools => [ STRUCT_EXCESSIVE_BOOLS , FN_PARAMS_EXCESSIVE_BOOLS ] ) ;
123
131
124
- fn is_bool_ty ( ty : & Ty ) -> bool {
125
- if let TyKind :: Path ( None , path) = & ty. kind {
126
- if let [ name] = path. segments . as_slice ( ) {
127
- return name. ident . name == sym:: bool;
128
- }
129
- }
130
- false
131
- }
132
-
133
- impl EarlyLintPass for ExcessiveBools {
134
- fn check_item ( & mut self , cx : & EarlyContext < ' _ > , item : & Item ) {
132
+ impl < ' tcx > LateLintPass < ' tcx > for ExcessiveBools {
133
+ fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' tcx > ) {
135
134
if item. span . from_expansion ( ) {
136
135
return ;
137
136
}
138
- match & item. kind {
139
- ItemKind :: Struct ( variant_data, _) => {
140
- if item. attrs . iter ( ) . any ( |attr| attr. has_name ( sym:: repr) ) {
141
- return ;
142
- }
137
+ if let ItemKind :: Struct ( variant_data, _) = & item. kind {
138
+ if cx
139
+ . tcx
140
+ . hir ( )
141
+ . attrs ( item. hir_id ( ) )
142
+ . iter ( )
143
+ . any ( |attr| attr. has_name ( sym:: repr) )
144
+ {
145
+ return ;
146
+ }
147
+
148
+ if self . too_many_bools ( variant_data. fields ( ) . iter ( ) . map ( |field| field. ty ) , Kind :: Struct ) {
149
+ span_lint_and_help (
150
+ cx,
151
+ STRUCT_EXCESSIVE_BOOLS ,
152
+ item. span ,
153
+ & format ! ( "more than {} bools in a struct" , self . max_struct_bools) ,
154
+ None ,
155
+ "consider using a state machine or refactoring bools into two-variant enums" ,
156
+ )
157
+ }
158
+ }
159
+ }
143
160
144
- if let Ok ( struct_bools) = variant_data
145
- . fields ( )
146
- . iter ( )
147
- . filter ( |field| is_bool_ty ( & field. ty ) )
148
- . count ( )
149
- . try_into ( ) && self . max_struct_bools < struct_bools
150
- {
151
- span_lint_and_help (
152
- cx,
153
- STRUCT_EXCESSIVE_BOOLS ,
154
- item. span ,
155
- & format ! ( "more than {} bools in a struct" , self . max_struct_bools) ,
156
- None ,
157
- "consider using a state machine or refactoring bools into two-variant enums" ,
158
- )
159
- }
160
- } ,
161
- ItemKind :: Impl ( box Impl {
162
- of_trait : None , items, ..
163
- } )
164
- | ItemKind :: Trait ( box Trait { items, .. } ) => {
165
- for item in items {
166
- if let AssocItemKind :: Fn ( box Fn { sig, .. } ) = & item. kind {
167
- self . check_fn_sig ( cx, sig, item. span ) ;
168
- }
169
- }
170
- } ,
171
- ItemKind :: Fn ( box Fn { sig, .. } ) => self . check_fn_sig ( cx, sig, item. span ) ,
172
- _ => ( ) ,
161
+ fn check_fn (
162
+ & mut self ,
163
+ cx : & LateContext < ' tcx > ,
164
+ fn_kind : FnKind < ' tcx > ,
165
+ fn_decl : & ' tcx FnDecl < ' tcx > ,
166
+ _: & ' tcx Body < ' tcx > ,
167
+ span : Span ,
168
+ hir_id : HirId ,
169
+ ) {
170
+ if let Some ( fn_header) = fn_kind. header ( )
171
+ && fn_header. abi == Abi :: Rust
172
+ && if let Some ( Node :: Item ( item) ) = get_parent_node ( cx. tcx , hir_id) {
173
+ !matches ! ( item. kind, ItemKind :: ExternCrate ( ..) )
174
+ } else {
175
+ true
176
+ }
177
+ && !span. from_expansion ( ) {
178
+ self . check_fn_sig ( cx, fn_decl, span)
173
179
}
174
180
}
175
181
}
0 commit comments