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