1
- use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
- use clippy_utils:: source:: { indent_of, reindent_multiline, snippet_with_applicability} ;
3
- use clippy_utils:: ty:: is_type_diagnostic_item;
4
- use clippy_utils:: { is_expr_final_block_expr, is_expr_used_or_unified, peel_blocks} ;
5
1
use rustc_errors:: Applicability ;
6
2
use rustc_hir as hir;
7
3
use rustc_lint:: LateContext ;
4
+ use rustc_middle:: ty:: { self , GenericArg , Ty } ;
8
5
use rustc_span:: sym;
6
+ use std:: ops:: ControlFlow ;
9
7
10
- use super :: RETURN_AND_THEN ;
8
+ use clippy_utils:: diagnostics:: span_lint_and_sugg;
9
+ use clippy_utils:: source:: { indent_of, reindent_multiline, snippet_with_applicability} ;
10
+ use clippy_utils:: ty:: get_type_diagnostic_name;
11
+ use clippy_utils:: visitors:: for_each_unconsumed_temporary;
12
+ use clippy_utils:: { is_expr_final_block_expr, peel_blocks} ;
11
13
12
- fn is_final_call ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
13
- if !is_expr_used_or_unified ( cx. tcx , expr) {
14
- return false ;
15
- }
16
- is_expr_final_block_expr ( cx. tcx , expr)
17
- }
14
+ use super :: RETURN_AND_THEN ;
18
15
19
- /// lint if `and_then` is the last call in the function
16
+ /// lint if `and_then` is the last expression in a block and
17
+ /// there are no temporaries in the receiver
20
18
pub ( super ) fn check < ' tcx > (
21
- cx : & LateContext < ' _ > ,
19
+ cx : & LateContext < ' tcx > ,
22
20
expr : & hir:: Expr < ' _ > ,
23
- recv : & ' tcx hir:: Expr < ' _ > ,
21
+ recv : & ' tcx hir:: Expr < ' tcx > ,
24
22
arg : & ' tcx hir:: Expr < ' _ > ,
25
23
) {
26
- if !is_final_call ( cx, expr) {
24
+ if !is_expr_final_block_expr ( cx. tcx , expr) {
27
25
return ;
28
26
}
29
27
30
28
let recv_type = cx. typeck_results ( ) . expr_ty ( recv) ;
31
- let is_option = is_type_diagnostic_item ( cx, recv_type, sym:: Option ) ;
32
- let is_result = is_type_diagnostic_item ( cx, recv_type, sym:: Result ) ;
29
+ if !matches ! ( get_type_diagnostic_name( cx, recv_type) , Some ( sym:: Option | sym:: Result ) ) {
30
+ return ;
31
+ }
33
32
34
- if !is_option && !is_result {
33
+ let has_ref_type = matches ! ( recv_type. kind( ) , ty:: Adt ( _, args) if args
34
+ . first( )
35
+ . and_then( |arg0: & GenericArg <' tcx>| GenericArg :: as_type( * arg0) )
36
+ . is_some_and( Ty :: is_ref) ) ;
37
+ let has_temporaries = for_each_unconsumed_temporary ( cx, recv, |_| ControlFlow :: Break ( ( ) ) ) . is_break ( ) ;
38
+ if has_ref_type && has_temporaries {
35
39
return ;
36
40
}
37
41
@@ -44,7 +48,7 @@ pub(super) fn check<'tcx>(
44
48
45
49
let mut applicability = Applicability :: MachineApplicable ;
46
50
let arg_snip = snippet_with_applicability ( cx, closure_arg. span , "_" , & mut applicability) ;
47
- let recv_snip = snippet_with_applicability ( cx, recv. span , ".. " , & mut applicability) ;
51
+ let recv_snip = snippet_with_applicability ( cx, recv. span , "_ " , & mut applicability) ;
48
52
let body_snip = snippet_with_applicability ( cx, closure_expr. span , ".." , & mut applicability) ;
49
53
let inner = match body_snip. strip_prefix ( '{' ) . and_then ( |s| s. strip_suffix ( '}' ) ) {
50
54
Some ( s) => s. trim_start_matches ( '\n' ) . trim_end ( ) ,
0 commit comments