@@ -85,16 +85,30 @@ fn check_arguments<'tcx>(
8585 let parameters = type_definition. fn_sig ( cx. tcx ) . skip_binder ( ) . inputs ( ) ;
8686 for ( argument, parameter) in iter:: zip ( arguments, parameters) {
8787 if let ty:: Ref ( _, _, Mutability :: Not ) | ty:: RawPtr ( _, Mutability :: Not ) = parameter. kind ( )
88- && let ExprKind :: AddrOf ( BorrowKind :: Ref , Mutability :: Mut , arg) = argument. kind
88+ && let ExprKind :: AddrOf ( borrow_kind , Mutability :: Mut , arg) = argument. kind
8989 {
90- let applicability = Applicability :: MachineApplicable ;
90+ emit ( cx, name, fn_kind, argument, borrow_kind, arg) ;
91+ }
92+ }
93+ }
94+ }
95+
96+ fn emit ( cx : & LateContext < ' _ > , name : & str , fn_kind : & str , argument : & Expr < ' _ > , borrow_kind : BorrowKind , arg : & Expr < ' _ > ) {
97+ let applicability = Applicability :: MachineApplicable ;
9198
92- let span_to_remove = {
93- let span_until_arg = argument. span . until ( arg. span ) ;
94- if let Some ( Some ( ref_pos) ) = span_until_arg. with_source_text ( cx, |src| {
99+ span_lint_and_then (
100+ cx,
101+ UNNECESSARY_MUT_PASSED ,
102+ argument. span ,
103+ format ! ( "the {fn_kind} `{name}` doesn't need a mutable reference" ) ,
104+ |diag| {
105+ let span_until_arg = argument. span . until ( arg. span ) ;
106+ match borrow_kind {
107+ BorrowKind :: Ref => {
108+ let span_to_remove = if let Some ( Some ( ref_pos) ) = span_until_arg. with_source_text ( cx, |src| {
95109 src
96- // we don't use `strip_prefix` here, because `argument` might be enclosed in parens, in
97- // which case `&` is no longer the prefix
110+ // we don't use `strip_prefix` here, because `argument` might be enclosed in
111+ // parens, in which case `&` is no longer the prefix
98112 . find ( '&' )
99113 // just a sanity check, in case some proc-macro messes up the spans
100114 . filter ( |ref_pos| src[ * ref_pos..] . contains ( "mut" ) )
@@ -103,19 +117,47 @@ fn check_arguments<'tcx>(
103117 span_until_arg. split_at ( lo) . 1
104118 } else {
105119 return ;
106- }
107- } ;
120+ } ;
121+ diag. span_suggestion_verbose ( span_to_remove, "remove this `mut`" , String :: new ( ) , applicability) ;
122+ } ,
123+ BorrowKind :: Raw => {
124+ let span_to_remove =
125+ if let Some ( Some ( ref_pos) ) = span_until_arg. with_source_text ( cx, |src : & str | {
126+ // we don't use `strip_prefix` here, because `argument` might be enclosed in
127+ // parens, and there might be arbitrary whitespace between things
128+ let src_after_addr_raw = src. split_once ( '&' ) ?. 1 . split_once ( "raw" ) ?. 1 . trim_start ( ) ;
108129
109- span_lint_and_then (
110- cx,
111- UNNECESSARY_MUT_PASSED ,
112- argument. span ,
113- format ! ( "the {fn_kind} `{name}` doesn't need a mutable reference" ) ,
114- |diag| {
115- diag. span_suggestion_verbose ( span_to_remove, "remove this `mut`" , String :: new ( ) , applicability) ;
116- } ,
117- ) ;
130+ Some ( src_after_addr_raw)
131+ // just a sanity check, in case some proc-macro messes up the spans
132+ . filter ( |trimmed| trimmed. contains ( "mut" ) )
133+ . map ( |trimmed| {
134+ // SAFETY:
135+ // - `trimmed` is derived from `src` by trimming characters from the latter's start
136+ // - that also means that `trimmed` > `src`
137+ unsafe { trimmed. as_ptr ( ) . offset_from_unsigned ( src. as_ptr ( ) ) }
138+ } )
139+ } ) && let Ok ( lo) = u32:: try_from ( ref_pos)
140+ {
141+ span_until_arg. split_at ( lo) . 1
142+ } else {
143+ return ;
144+ } ;
145+ diag. span_suggestion_verbose (
146+ span_to_remove,
147+ "make this a `const` ptr" ,
148+ // the span points at `&raw mut x`
149+ // ^^^^
150+ // so we append a space to our suggestion
151+ String :: from ( "const " ) ,
152+ applicability,
153+ ) ;
154+ } ,
155+ BorrowKind :: Pin => {
156+ // it's fine to only "check" this after we've emitted the lint -- if the reference was an `&pin`,
157+ // passing it into a function requiring a ptr wouldn't have type-checked in the first place
158+ return ;
159+ } ,
118160 }
119- }
120- }
161+ } ,
162+ )
121163}
0 commit comments