@@ -3,9 +3,11 @@ use clippy_utils::get_parent_expr;
33use clippy_utils:: source:: snippet_with_context;
44use clippy_utils:: ty:: { is_type_lang_item, peel_mid_ty_refs} ;
55use if_chain:: if_chain;
6+ use rustc_ast:: util:: parser:: PREC_PREFIX ;
67use rustc_errors:: Applicability ;
78use rustc_hir:: { BorrowKind , Expr , ExprKind , LangItem , Mutability } ;
89use rustc_lint:: { LateContext , LateLintPass } ;
10+ use rustc_middle:: ty:: adjustment:: { Adjust , AutoBorrow , AutoBorrowMutability } ;
911use rustc_middle:: ty:: subst:: GenericArg ;
1012use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1113
@@ -57,44 +59,64 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
5759 then {
5860 let ( expr_ty, expr_ref_count) = peel_mid_ty_refs( cx. typeck_results( ) . expr_ty( expr) ) ;
5961 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+ } ) ;
6066 let mut app = Applicability :: MachineApplicable ;
6167
6268 let ( help, sugg) = if expr_ty == indexed_ty {
6369 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.
6475 return ;
6576 }
77+ let deref_count = indexed_ref_count - expr_ref_count;
6678
6779 let ( reborrow_str, help_str) = if mutability == Mutability :: Mut {
6880 // The slice was used to reborrow the mutable reference.
6981 ( "&mut *" , "reborrow the original value instead" )
7082 } else if matches!(
71- get_parent_expr ( cx , expr ) ,
83+ parent_expr ,
7284 Some ( Expr {
7385 kind: ExprKind :: AddrOf ( BorrowKind :: Ref , Mutability :: Mut , _) ,
7486 ..
7587 } )
76- ) {
88+ ) || cx. typeck_results( ) . expr_adjustments( expr) . first( ) . map_or( false , |a| {
89+ matches!( a. kind, Adjust :: Borrow ( AutoBorrow :: Ref ( _, AutoBorrowMutability :: Mut { .. } ) ) )
90+ } ) {
7791 // The slice was used to make a temporary reference.
7892 ( "&*" , "reborrow the original value instead" )
79- } else if expr_ref_count != indexed_ref_count {
93+ } else if deref_count != 0 {
8094 ( "" , "dereference the original value instead" )
8195 } else {
8296 ( "" , "use the original value instead" )
8397 } ;
8498
8599 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)
87107 } else if let Some ( target_id) = cx. tcx. lang_items( ) . deref_target( ) {
88108 if let Ok ( deref_ty) = cx. tcx. try_normalize_erasing_regions(
89109 cx. param_env,
90110 cx. tcx. mk_projection( target_id, cx. tcx. mk_substs( [ GenericArg :: from( indexed_ty) ] . into_iter( ) ) ) ,
91111 ) {
92112 if deref_ty == expr_ty {
93113 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)
98120 } else {
99121 return ;
100122 }
0 commit comments