1
1
mod let_unit_value;
2
+ mod unit_arg;
2
3
mod unit_cmp;
3
4
mod utils;
4
5
5
- use rustc_errors:: Applicability ;
6
- use rustc_hir as hir;
7
- use rustc_hir:: { Block , Expr , ExprKind , MatchSource , Node , Stmt , StmtKind } ;
6
+ use rustc_hir:: { Expr , Stmt } ;
8
7
use rustc_lint:: { LateContext , LateLintPass } ;
9
8
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10
9
11
- use if_chain:: if_chain;
12
-
13
- use crate :: utils:: { indent_of, reindent_multiline, snippet_opt, span_lint_and_then} ;
14
-
15
- use utils:: { is_unit, is_unit_literal} ;
16
-
17
10
declare_clippy_lint ! {
18
11
/// **What it does:** Checks for binding a unit value.
19
12
///
@@ -80,18 +73,6 @@ declare_clippy_lint! {
80
73
"comparing unit values"
81
74
}
82
75
83
- declare_lint_pass ! ( UnitTypes => [ LET_UNIT_VALUE , UNIT_CMP ] ) ;
84
-
85
- impl LateLintPass < ' _ > for UnitTypes {
86
- fn check_stmt ( & mut self , cx : & LateContext < ' _ > , stmt : & Stmt < ' _ > ) {
87
- let_unit_value:: check ( cx, stmt) ;
88
- }
89
-
90
- fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
91
- unit_cmp:: check ( cx, expr) ;
92
- }
93
- }
94
-
95
76
declare_clippy_lint ! {
96
77
/// **What it does:** Checks for passing a unit value as an argument to a function without using a
97
78
/// unit literal (`()`).
@@ -112,205 +93,15 @@ declare_clippy_lint! {
112
93
"passing unit to a function"
113
94
}
114
95
115
- declare_lint_pass ! ( UnitArg => [ UNIT_ARG ] ) ;
116
-
117
- impl < ' tcx > LateLintPass < ' tcx > for UnitArg {
118
- fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
119
- if expr. span . from_expansion ( ) {
120
- return ;
121
- }
122
-
123
- // apparently stuff in the desugaring of `?` can trigger this
124
- // so check for that here
125
- // only the calls to `Try::from_error` is marked as desugared,
126
- // so we need to check both the current Expr and its parent.
127
- if is_questionmark_desugar_marked_call ( expr) {
128
- return ;
129
- }
130
- if_chain ! {
131
- let map = & cx. tcx. hir( ) ;
132
- let opt_parent_node = map. find( map. get_parent_node( expr. hir_id) ) ;
133
- if let Some ( hir:: Node :: Expr ( parent_expr) ) = opt_parent_node;
134
- if is_questionmark_desugar_marked_call( parent_expr) ;
135
- then {
136
- return ;
137
- }
138
- }
139
-
140
- match expr. kind {
141
- ExprKind :: Call ( _, args) | ExprKind :: MethodCall ( _, _, args, _) => {
142
- let args_to_recover = args
143
- . iter ( )
144
- . filter ( |arg| {
145
- if is_unit ( cx. typeck_results ( ) . expr_ty ( arg) ) && !is_unit_literal ( arg) {
146
- !matches ! (
147
- & arg. kind,
148
- ExprKind :: Match ( .., MatchSource :: TryDesugar ) | ExprKind :: Path ( ..)
149
- )
150
- } else {
151
- false
152
- }
153
- } )
154
- . collect :: < Vec < _ > > ( ) ;
155
- if !args_to_recover. is_empty ( ) {
156
- lint_unit_args ( cx, expr, & args_to_recover) ;
157
- }
158
- } ,
159
- _ => ( ) ,
160
- }
161
- }
162
- }
96
+ declare_lint_pass ! ( UnitTypes => [ LET_UNIT_VALUE , UNIT_CMP , UNIT_ARG ] ) ;
163
97
164
- fn is_questionmark_desugar_marked_call ( expr : & Expr < ' _ > ) -> bool {
165
- use rustc_span:: hygiene:: DesugaringKind ;
166
- if let ExprKind :: Call ( ref callee, _) = expr. kind {
167
- callee. span . is_desugaring ( DesugaringKind :: QuestionMark )
168
- } else {
169
- false
98
+ impl LateLintPass < ' _ > for UnitTypes {
99
+ fn check_stmt ( & mut self , cx : & LateContext < ' _ > , stmt : & Stmt < ' _ > ) {
100
+ let_unit_value:: check ( cx, stmt) ;
170
101
}
171
- }
172
-
173
- fn lint_unit_args ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , args_to_recover : & [ & Expr < ' _ > ] ) {
174
- let mut applicability = Applicability :: MachineApplicable ;
175
- let ( singular, plural) = if args_to_recover. len ( ) > 1 {
176
- ( "" , "s" )
177
- } else {
178
- ( "a " , "" )
179
- } ;
180
- span_lint_and_then (
181
- cx,
182
- UNIT_ARG ,
183
- expr. span ,
184
- & format ! ( "passing {}unit value{} to a function" , singular, plural) ,
185
- |db| {
186
- let mut or = "" ;
187
- args_to_recover
188
- . iter ( )
189
- . filter_map ( |arg| {
190
- if_chain ! {
191
- if let ExprKind :: Block ( block, _) = arg. kind;
192
- if block. expr. is_none( ) ;
193
- if let Some ( last_stmt) = block. stmts. iter( ) . last( ) ;
194
- if let StmtKind :: Semi ( last_expr) = last_stmt. kind;
195
- if let Some ( snip) = snippet_opt( cx, last_expr. span) ;
196
- then {
197
- Some ( (
198
- last_stmt. span,
199
- snip,
200
- ) )
201
- }
202
- else {
203
- None
204
- }
205
- }
206
- } )
207
- . for_each ( |( span, sugg) | {
208
- db. span_suggestion (
209
- span,
210
- "remove the semicolon from the last statement in the block" ,
211
- sugg,
212
- Applicability :: MaybeIncorrect ,
213
- ) ;
214
- or = "or " ;
215
- applicability = Applicability :: MaybeIncorrect ;
216
- } ) ;
217
-
218
- let arg_snippets: Vec < String > = args_to_recover
219
- . iter ( )
220
- . filter_map ( |arg| snippet_opt ( cx, arg. span ) )
221
- . collect ( ) ;
222
- let arg_snippets_without_empty_blocks: Vec < String > = args_to_recover
223
- . iter ( )
224
- . filter ( |arg| !is_empty_block ( arg) )
225
- . filter_map ( |arg| snippet_opt ( cx, arg. span ) )
226
- . collect ( ) ;
227
-
228
- if let Some ( call_snippet) = snippet_opt ( cx, expr. span ) {
229
- let sugg = fmt_stmts_and_call (
230
- cx,
231
- expr,
232
- & call_snippet,
233
- & arg_snippets,
234
- & arg_snippets_without_empty_blocks,
235
- ) ;
236
102
237
- if arg_snippets_without_empty_blocks. is_empty ( ) {
238
- db. multipart_suggestion (
239
- & format ! ( "use {}unit literal{} instead" , singular, plural) ,
240
- args_to_recover
241
- . iter ( )
242
- . map ( |arg| ( arg. span , "()" . to_string ( ) ) )
243
- . collect :: < Vec < _ > > ( ) ,
244
- applicability,
245
- ) ;
246
- } else {
247
- let plural = arg_snippets_without_empty_blocks. len ( ) > 1 ;
248
- let empty_or_s = if plural { "s" } else { "" } ;
249
- let it_or_them = if plural { "them" } else { "it" } ;
250
- db. span_suggestion (
251
- expr. span ,
252
- & format ! (
253
- "{}move the expression{} in front of the call and replace {} with the unit literal `()`" ,
254
- or, empty_or_s, it_or_them
255
- ) ,
256
- sugg,
257
- applicability,
258
- ) ;
259
- }
260
- }
261
- } ,
262
- ) ;
263
- }
264
-
265
- fn is_empty_block ( expr : & Expr < ' _ > ) -> bool {
266
- matches ! (
267
- expr. kind,
268
- ExprKind :: Block (
269
- Block {
270
- stmts: & [ ] ,
271
- expr: None ,
272
- ..
273
- } ,
274
- _,
275
- )
276
- )
277
- }
278
-
279
- fn fmt_stmts_and_call (
280
- cx : & LateContext < ' _ > ,
281
- call_expr : & Expr < ' _ > ,
282
- call_snippet : & str ,
283
- args_snippets : & [ impl AsRef < str > ] ,
284
- non_empty_block_args_snippets : & [ impl AsRef < str > ] ,
285
- ) -> String {
286
- let call_expr_indent = indent_of ( cx, call_expr. span ) . unwrap_or ( 0 ) ;
287
- let call_snippet_with_replacements = args_snippets
288
- . iter ( )
289
- . fold ( call_snippet. to_owned ( ) , |acc, arg| acc. replacen ( arg. as_ref ( ) , "()" , 1 ) ) ;
290
-
291
- let mut stmts_and_call = non_empty_block_args_snippets
292
- . iter ( )
293
- . map ( |it| it. as_ref ( ) . to_owned ( ) )
294
- . collect :: < Vec < _ > > ( ) ;
295
- stmts_and_call. push ( call_snippet_with_replacements) ;
296
- stmts_and_call = stmts_and_call
297
- . into_iter ( )
298
- . map ( |v| reindent_multiline ( v. into ( ) , true , Some ( call_expr_indent) ) . into_owned ( ) )
299
- . collect ( ) ;
300
-
301
- let mut stmts_and_call_snippet = stmts_and_call. join ( & format ! ( "{}{}" , ";\n " , " " . repeat( call_expr_indent) ) ) ;
302
- // expr is not in a block statement or result expression position, wrap in a block
303
- let parent_node = cx. tcx . hir ( ) . find ( cx. tcx . hir ( ) . get_parent_node ( call_expr. hir_id ) ) ;
304
- if !matches ! ( parent_node, Some ( Node :: Block ( _) ) ) && !matches ! ( parent_node, Some ( Node :: Stmt ( _) ) ) {
305
- let block_indent = call_expr_indent + 4 ;
306
- stmts_and_call_snippet =
307
- reindent_multiline ( stmts_and_call_snippet. into ( ) , true , Some ( block_indent) ) . into_owned ( ) ;
308
- stmts_and_call_snippet = format ! (
309
- "{{\n {}{}\n {}}}" ,
310
- " " . repeat( block_indent) ,
311
- & stmts_and_call_snippet,
312
- " " . repeat( call_expr_indent)
313
- ) ;
103
+ fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
104
+ unit_cmp:: check ( cx, expr) ;
105
+ unit_arg:: check ( cx, expr) ;
314
106
}
315
- stmts_and_call_snippet
316
107
}
0 commit comments