@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
4
4
use clippy_utils:: ptr:: get_spans;
5
5
use clippy_utils:: source:: snippet_opt;
6
6
use clippy_utils:: ty:: { is_type_diagnostic_item, match_type, walk_ptrs_hir_ty} ;
7
- use clippy_utils:: { is_allowed, match_function_call , match_qpath , paths} ;
7
+ use clippy_utils:: { is_allowed, match_def_path , paths} ;
8
8
use if_chain:: if_chain;
9
9
use rustc_errors:: Applicability ;
10
10
use rustc_hir:: {
@@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
174
174
175
175
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
176
176
if let ExprKind :: Binary ( ref op, l, r) = expr. kind {
177
- if ( op. node == BinOpKind :: Eq || op. node == BinOpKind :: Ne ) && ( is_null_path ( l) || is_null_path ( r) ) {
177
+ if ( op. node == BinOpKind :: Eq || op. node == BinOpKind :: Ne ) && ( is_null_path ( cx , l) || is_null_path ( cx , r) ) {
178
178
span_lint (
179
179
cx,
180
180
CMP_NULL ,
@@ -188,47 +188,56 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
188
188
}
189
189
}
190
190
191
- fn check_invalid_ptr_usage < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) -> Option < ( ) > {
192
- // fn_name, arg_idx
193
- const INVALID_NULL_PTR_USAGE_TABLE : [ ( & [ & str ] , usize ) ; 20 ] = [
194
- ( & paths:: SLICE_FROM_RAW_PARTS , 0 ) ,
195
- ( & paths:: SLICE_FROM_RAW_PARTS_MUT , 0 ) ,
196
- ( & paths:: PTR_COPY , 0 ) ,
197
- ( & paths:: PTR_COPY , 1 ) ,
198
- ( & paths:: PTR_COPY_NONOVERLAPPING , 0 ) ,
199
- ( & paths:: PTR_COPY_NONOVERLAPPING , 1 ) ,
200
- ( & paths:: PTR_READ , 0 ) ,
201
- ( & paths:: PTR_READ_UNALIGNED , 0 ) ,
202
- ( & paths:: PTR_READ_VOLATILE , 0 ) ,
203
- ( & paths:: PTR_REPLACE , 0 ) ,
204
- ( & paths:: PTR_SLICE_FROM_RAW_PARTS , 0 ) ,
205
- ( & paths:: PTR_SLICE_FROM_RAW_PARTS_MUT , 0 ) ,
206
- ( & paths:: PTR_SWAP , 0 ) ,
207
- ( & paths:: PTR_SWAP , 1 ) ,
208
- ( & paths:: PTR_SWAP_NONOVERLAPPING , 0 ) ,
209
- ( & paths:: PTR_SWAP_NONOVERLAPPING , 1 ) ,
210
- ( & paths:: PTR_WRITE , 0 ) ,
211
- ( & paths:: PTR_WRITE_UNALIGNED , 0 ) ,
212
- ( & paths:: PTR_WRITE_VOLATILE , 0 ) ,
213
- ( & paths:: PTR_WRITE_BYTES , 0 ) ,
191
+ fn check_invalid_ptr_usage < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
192
+ // (fn_path, arg_idx, num_args) -
193
+ // `arg_idx` is the `arg` position where null would cause U.B.
194
+ // `num_args` is the numbers of arguments of the function
195
+ const INVALID_NULL_PTR_USAGE_TABLE : [ ( & [ & str ] , usize , usize ) ; 20 ] = [
196
+ ( & paths:: SLICE_FROM_RAW_PARTS , 0 , 2 ) ,
197
+ ( & paths:: SLICE_FROM_RAW_PARTS_MUT , 0 , 2 ) ,
198
+ ( & paths:: PTR_COPY , 0 , 3 ) ,
199
+ ( & paths:: PTR_COPY , 1 , 3 ) ,
200
+ ( & paths:: PTR_COPY_NONOVERLAPPING , 0 , 3 ) ,
201
+ ( & paths:: PTR_COPY_NONOVERLAPPING , 1 , 3 ) ,
202
+ ( & paths:: PTR_READ , 0 , 1 ) ,
203
+ ( & paths:: PTR_READ_UNALIGNED , 0 , 1 ) ,
204
+ ( & paths:: PTR_READ_VOLATILE , 0 , 1 ) ,
205
+ ( & paths:: PTR_REPLACE , 0 , 2 ) ,
206
+ ( & paths:: PTR_SLICE_FROM_RAW_PARTS , 0 , 2 ) ,
207
+ ( & paths:: PTR_SLICE_FROM_RAW_PARTS_MUT , 0 , 2 ) ,
208
+ ( & paths:: PTR_SWAP , 0 , 2 ) ,
209
+ ( & paths:: PTR_SWAP , 1 , 2 ) ,
210
+ ( & paths:: PTR_SWAP_NONOVERLAPPING , 0 , 3 ) ,
211
+ ( & paths:: PTR_SWAP_NONOVERLAPPING , 1 , 3 ) ,
212
+ ( & paths:: PTR_WRITE , 0 , 2 ) ,
213
+ ( & paths:: PTR_WRITE_UNALIGNED , 0 , 2 ) ,
214
+ ( & paths:: PTR_WRITE_VOLATILE , 0 , 2 ) ,
215
+ ( & paths:: PTR_WRITE_BYTES , 0 , 3 ) ,
214
216
] ;
215
217
216
- let arg = INVALID_NULL_PTR_USAGE_TABLE . iter ( ) . find_map ( |( fn_name, arg_idx) | {
217
- let args = match_function_call ( cx, expr, fn_name) ?;
218
- args. get ( * arg_idx) . filter ( |arg| is_null_path ( arg) )
219
- } ) ?;
220
-
221
- span_lint_and_sugg (
222
- cx,
223
- INVALID_NULL_PTR_USAGE ,
224
- arg. span ,
225
- "pointer must be non-null" ,
226
- "change this to" ,
227
- "core::ptr::NonNull::dangling().as_ptr()" . to_string ( ) ,
228
- Applicability :: MachineApplicable ,
229
- ) ;
230
-
231
- Some ( ( ) )
218
+ for ( fn_path, arg_idx, num_args) in & INVALID_NULL_PTR_USAGE_TABLE {
219
+ if_chain ! {
220
+ if let ExprKind :: Call ( ref fun, ref args) = expr. kind;
221
+ if args. len( ) == * num_args;
222
+ if let ExprKind :: Path ( ref qpath) = fun. kind;
223
+ if let Some ( arg) = args. get( * arg_idx) ;
224
+ if let Some ( fun_def_id) = cx. qpath_res( qpath, fun. hir_id) . opt_def_id( ) ;
225
+ if match_def_path( cx, fun_def_id, fn_path) ;
226
+ if is_null_path( cx, arg) ;
227
+ then {
228
+ span_lint_and_sugg(
229
+ cx,
230
+ INVALID_NULL_PTR_USAGE ,
231
+ arg. span,
232
+ "pointer must be non-null" ,
233
+ "change this to" ,
234
+ "core::ptr::NonNull::dangling().as_ptr()" . to_string( ) ,
235
+ Applicability :: MachineApplicable ,
236
+ ) ;
237
+ return ;
238
+ }
239
+ }
240
+ }
232
241
}
233
242
234
243
#[ allow( clippy:: too_many_lines) ]
@@ -411,16 +420,16 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability,
411
420
}
412
421
}
413
422
414
- fn is_null_path ( expr : & Expr < ' _ > ) -> bool {
415
- if let ExprKind :: Call ( pathexp, args) = expr. kind {
416
- if args. is_empty ( ) {
417
- if let ExprKind :: Path ( ref path) = pathexp. kind {
418
- return match_qpath ( path, & paths:: PTR_NULL )
419
- || match_qpath ( path, & paths:: PTR_NULL_MUT )
420
- || match_qpath ( path, & paths:: STD_PTR_NULL )
421
- || match_qpath ( path, & paths:: STD_PTR_NULL_MUT ) ;
422
- }
423
+ fn is_null_path ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
424
+ if_chain ! {
425
+ if let ExprKind :: Call ( path, args) = expr. kind;
426
+ if args. is_empty( ) ;
427
+ if let ExprKind :: Path ( ref qpath) = path. kind;
428
+ if let Some ( fn_def_id) = cx. qpath_res( qpath, path. hir_id) . opt_def_id( ) ;
429
+ then {
430
+ match_def_path( cx, fn_def_id, & paths:: PTR_NULL ) || match_def_path( cx, fn_def_id, & paths:: PTR_NULL_MUT )
431
+ } else {
432
+ false
423
433
}
424
434
}
425
- false
426
435
}
0 commit comments