@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
44use clippy_utils:: ptr:: get_spans;
55use clippy_utils:: source:: snippet_opt;
66use 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} ;
88use if_chain:: if_chain;
99use rustc_errors:: Applicability ;
1010use rustc_hir:: {
@@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
174174
175175 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
176176 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) ) {
178178 span_lint (
179179 cx,
180180 CMP_NULL ,
@@ -188,47 +188,56 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
188188 }
189189}
190190
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 ) ,
214216 ] ;
215217
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+ }
232241}
233242
234243#[ allow( clippy:: too_many_lines) ]
@@ -411,16 +420,16 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability,
411420 }
412421}
413422
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
423433 }
424434 }
425- false
426435}
0 commit comments