@@ -3,9 +3,11 @@ use clippy_utils::get_parent_expr;
3
3
use clippy_utils:: source:: snippet_with_context;
4
4
use clippy_utils:: ty:: { is_type_lang_item, peel_mid_ty_refs} ;
5
5
use if_chain:: if_chain;
6
+ use rustc_ast:: util:: parser:: PREC_PREFIX ;
6
7
use rustc_errors:: Applicability ;
7
8
use rustc_hir:: { BorrowKind , Expr , ExprKind , LangItem , Mutability } ;
8
9
use rustc_lint:: { LateContext , LateLintPass } ;
10
+ use rustc_middle:: ty:: adjustment:: { Adjust , AutoBorrow , AutoBorrowMutability } ;
9
11
use rustc_middle:: ty:: { subst:: GenericArg , TyS } ;
10
12
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11
13
@@ -57,44 +59,64 @@ impl LateLintPass<'_> for RedundantSlicing {
57
59
then {
58
60
let ( expr_ty, expr_ref_count) = peel_mid_ty_refs( cx. typeck_results( ) . expr_ty( expr) ) ;
59
61
let ( indexed_ty, indexed_ref_count) = peel_mid_ty_refs( cx. typeck_results( ) . expr_ty( indexed) ) ;
62
+ let parent_expr = get_parent_expr( cx, expr) ;
63
+ let needs_parens_for_prefix = parent_expr. map_or( false , |parent| {
64
+ parent. precedence( ) . order( ) > PREC_PREFIX
65
+ } ) ;
60
66
let mut app = Applicability :: MachineApplicable ;
61
67
62
68
let ( help, sugg) = if TyS :: same_type( expr_ty, indexed_ty) {
63
69
if expr_ref_count > indexed_ref_count {
70
+ // Indexing takes self by reference and can't return a reference to that
71
+ // reference as it's a local variable. The only way this could happen is if
72
+ // `self` contains a reference to the `Self` type. If this occurs then the
73
+ // lint no longer applies as it's essentially a field access, which is not
74
+ // redundant.
64
75
return ;
65
76
}
77
+ let deref_count = indexed_ref_count - expr_ref_count;
66
78
67
79
let ( reborrow_str, help_str) = if mutability == Mutability :: Mut {
68
80
// The slice was used to reborrow the mutable reference.
69
81
( "&mut *" , "reborrow the original value instead" )
70
82
} else if matches!(
71
- get_parent_expr ( cx , expr ) ,
83
+ parent_expr ,
72
84
Some ( Expr {
73
85
kind: ExprKind :: AddrOf ( BorrowKind :: Ref , Mutability :: Mut , _) ,
74
86
..
75
87
} )
76
- ) {
88
+ ) || cx. typeck_results( ) . expr_adjustments( expr) . first( ) . map_or( false , |a| {
89
+ matches!( a. kind, Adjust :: Borrow ( AutoBorrow :: Ref ( _, AutoBorrowMutability :: Mut { .. } ) ) )
90
+ } ) {
77
91
// The slice was used to make a temporary reference.
78
92
( "&*" , "reborrow the original value instead" )
79
- } else if expr_ref_count != indexed_ref_count {
93
+ } else if deref_count != 0 {
80
94
( "" , "dereference the original value instead" )
81
95
} else {
82
96
( "" , "use the original value instead" )
83
97
} ;
84
98
85
99
let snip = snippet_with_context( cx, indexed. span, ctxt, ".." , & mut app) . 0 ;
86
- ( help_str, format!( "{}{}{}" , reborrow_str, "*" . repeat( indexed_ref_count - expr_ref_count) , snip) )
100
+ let sugg = if ( deref_count != 0 || !reborrow_str. is_empty( ) ) && needs_parens_for_prefix {
101
+ format!( "({}{}{})" , reborrow_str, "*" . repeat( deref_count) , snip)
102
+ } else {
103
+ format!( "{}{}{}" , reborrow_str, "*" . repeat( deref_count) , snip)
104
+ } ;
105
+
106
+ ( help_str, sugg)
87
107
} else if let Some ( target_id) = cx. tcx. lang_items( ) . deref_target( ) {
88
108
if let Ok ( deref_ty) = cx. tcx. try_normalize_erasing_regions(
89
109
cx. param_env,
90
110
cx. tcx. mk_projection( target_id, cx. tcx. mk_substs( [ GenericArg :: from( indexed_ty) ] . into_iter( ) ) ) ,
91
111
) {
92
112
if TyS :: same_type( deref_ty, expr_ty) {
93
113
let snip = snippet_with_context( cx, indexed. span, ctxt, ".." , & mut app) . 0 ;
94
- (
95
- "dereference the original value instead" ,
96
- format!( "&{}{}*{}" , mutability. prefix_str( ) , "*" . repeat( indexed_ref_count) , snip) ,
97
- )
114
+ let sugg = if needs_parens_for_prefix {
115
+ format!( "(&{}{}*{})" , mutability. prefix_str( ) , "*" . repeat( indexed_ref_count) , snip)
116
+ } else {
117
+ format!( "&{}{}*{}" , mutability. prefix_str( ) , "*" . repeat( indexed_ref_count) , snip)
118
+ } ;
119
+ ( "dereference the original value instead" , sugg)
98
120
} else {
99
121
return ;
100
122
}
0 commit comments