]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/ptr.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / ptr.rs
CommitLineData
f20569fa
XL
1//! Checks for usage of `&Vec[_]` and `&String`.
2
cdc7bbd5 3use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
cdc7bbd5 4use clippy_utils::source::snippet_opt;
5099ac24 5use clippy_utils::ty::expr_sig;
04454e1e 6use clippy_utils::visitors::contains_unsafe_block;
5099ac24 7use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
f20569fa 8use if_chain::if_chain;
04454e1e 9use rustc_errors::{Applicability, MultiSpan};
5099ac24
FG
10use rustc_hir::def_id::DefId;
11use rustc_hir::hir_id::HirIdMap;
12use rustc_hir::intravisit::{walk_expr, Visitor};
f20569fa 13use rustc_hir::{
04454e1e 14 self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg,
5099ac24 15 ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
04454e1e 16 TraitItem, TraitItemKind, TyKind, Unsafety,
f20569fa
XL
17};
18use rustc_lint::{LateContext, LateLintPass};
5099ac24 19use rustc_middle::hir::nested_filter;
5e7ed085 20use rustc_middle::ty::{self, Ty};
f20569fa
XL
21use rustc_session::{declare_lint_pass, declare_tool_lint};
22use rustc_span::source_map::Span;
04454e1e 23use rustc_span::sym;
cdc7bbd5 24use rustc_span::symbol::Symbol;
5099ac24
FG
25use std::fmt;
26use std::iter;
f20569fa
XL
27
28declare_clippy_lint! {
94222f64 29 /// ### What it does
5099ac24
FG
30 /// This lint checks for function arguments of type `&String`, `&Vec`,
31 /// `&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls
32 /// with the appropriate `.to_owned()`/`to_string()` calls.
f20569fa 33 ///
94222f64
XL
34 /// ### Why is this bad?
35 /// Requiring the argument to be of the specific size
f20569fa
XL
36 /// makes the function less useful for no benefit; slices in the form of `&[T]`
37 /// or `&str` usually suffice and can be obtained from other types, too.
38 ///
94222f64 39 /// ### Known problems
5099ac24 40 /// There may be `fn(&Vec)`-typed references pointing to your function.
f20569fa
XL
41 /// If you have them, you will get a compiler error after applying this lint's
42 /// suggestions. You then have the choice to undo your changes or change the
43 /// type of the reference.
44 ///
45 /// Note that if the function is part of your public interface, there may be
46 /// other crates referencing it, of which you may not be aware. Carefully
47 /// deprecate the function before applying the lint suggestions in this case.
48 ///
94222f64 49 /// ### Example
f20569fa 50 /// ```ignore
f20569fa 51 /// fn foo(&Vec<u32>) { .. }
923072b8 52 /// ```
f20569fa 53 ///
923072b8
FG
54 /// Use instead:
55 /// ```ignore
f20569fa
XL
56 /// fn foo(&[u32]) { .. }
57 /// ```
a2a8927a 58 #[clippy::version = "pre 1.29.0"]
f20569fa
XL
59 pub PTR_ARG,
60 style,
61 "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
62}
63
64declare_clippy_lint! {
94222f64
XL
65 /// ### What it does
66 /// This lint checks for equality comparisons with `ptr::null`
f20569fa 67 ///
94222f64
XL
68 /// ### Why is this bad?
69 /// It's easier and more readable to use the inherent
f20569fa
XL
70 /// `.is_null()`
71 /// method instead
72 ///
94222f64 73 /// ### Example
923072b8
FG
74 /// ```rust,ignore
75 /// use std::ptr;
76 ///
f20569fa 77 /// if x == ptr::null {
923072b8 78 /// // ..
f20569fa 79 /// }
923072b8 80 /// ```
f20569fa 81 ///
923072b8
FG
82 /// Use instead:
83 /// ```rust,ignore
f20569fa 84 /// if x.is_null() {
923072b8 85 /// // ..
f20569fa
XL
86 /// }
87 /// ```
a2a8927a 88 #[clippy::version = "pre 1.29.0"]
f20569fa
XL
89 pub CMP_NULL,
90 style,
cdc7bbd5 91 "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead"
f20569fa
XL
92}
93
94declare_clippy_lint! {
94222f64 95 /// ### What it does
04454e1e
FG
96 /// This lint checks for functions that take immutable references and return
97 /// mutable ones. This will not trigger if no unsafe code exists as there
98 /// are multiple safe functions which will do this transformation
99 ///
100 /// To be on the conservative side, if there's at least one mutable
101 /// reference with the output lifetime, this lint will not trigger.
f20569fa 102 ///
94222f64 103 /// ### Why is this bad?
04454e1e
FG
104 /// Creating a mutable reference which can be repeatably derived from an
105 /// immutable reference is unsound as it allows creating multiple live
106 /// mutable references to the same object.
107 ///
108 /// This [error](https://github.com/rust-lang/rust/issues/39465) actually
109 /// lead to an interim Rust release 1.15.1.
f20569fa 110 ///
94222f64 111 /// ### Known problems
04454e1e
FG
112 /// This pattern is used by memory allocators to allow allocating multiple
113 /// objects while returning mutable references to each one. So long as
114 /// different mutable references are returned each time such a function may
115 /// be safe.
f20569fa 116 ///
94222f64 117 /// ### Example
f20569fa
XL
118 /// ```ignore
119 /// fn foo(&Foo) -> &mut Bar { .. }
120 /// ```
a2a8927a 121 #[clippy::version = "pre 1.29.0"]
f20569fa
XL
122 pub MUT_FROM_REF,
123 correctness,
124 "fns that create mutable refs from immutable ref args"
125}
126
cdc7bbd5 127declare_clippy_lint! {
94222f64
XL
128 /// ### What it does
129 /// This lint checks for invalid usages of `ptr::null`.
cdc7bbd5 130 ///
94222f64
XL
131 /// ### Why is this bad?
132 /// This causes undefined behavior.
cdc7bbd5 133 ///
94222f64 134 /// ### Example
cdc7bbd5 135 /// ```ignore
923072b8 136 /// // Undefined behavior
cdc7bbd5
XL
137 /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
138 /// ```
139 ///
923072b8 140 /// Use instead:
3c0e092e 141 /// ```ignore
cdc7bbd5
XL
142 /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
143 /// ```
a2a8927a 144 #[clippy::version = "1.53.0"]
cdc7bbd5
XL
145 pub INVALID_NULL_PTR_USAGE,
146 correctness,
147 "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead"
148}
149
150declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USAGE]);
f20569fa
XL
151
152impl<'tcx> LateLintPass<'tcx> for Ptr {
5099ac24
FG
153 fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
154 if let TraitItemKind::Fn(sig, trait_method) = &item.kind {
155 if matches!(trait_method, TraitFn::Provided(_)) {
156 // Handled by check body.
157 return;
158 }
f20569fa 159
04454e1e 160 check_mut_from_ref(cx, sig, None);
5099ac24
FG
161 for arg in check_fn_args(
162 cx,
163 cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
164 sig.decl.inputs,
165 &[],
166 )
167 .filter(|arg| arg.mutability() == Mutability::Not)
168 {
169 span_lint_and_sugg(
170 cx,
171 PTR_ARG,
172 arg.span,
173 &arg.build_msg(),
174 "change this to",
175 format!("{}{}", arg.ref_prefix, arg.deref_ty.display(cx)),
176 Applicability::Unspecified,
177 );
f20569fa 178 }
f20569fa
XL
179 }
180 }
181
5099ac24
FG
182 fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
183 let hir = cx.tcx.hir();
184 let mut parents = hir.parent_iter(body.value.hir_id);
04454e1e 185 let (item_id, sig, is_trait_item) = match parents.next() {
5099ac24
FG
186 Some((_, Node::Item(i))) => {
187 if let ItemKind::Fn(sig, ..) = &i.kind {
04454e1e 188 (i.def_id, sig, false)
5099ac24
FG
189 } else {
190 return;
191 }
192 },
193 Some((_, Node::ImplItem(i))) => {
194 if !matches!(parents.next(),
195 Some((_, Node::Item(i))) if matches!(&i.kind, ItemKind::Impl(i) if i.of_trait.is_none())
196 ) {
197 return;
198 }
199 if let ImplItemKind::Fn(sig, _) = &i.kind {
04454e1e 200 (i.def_id, sig, false)
5099ac24
FG
201 } else {
202 return;
203 }
204 },
205 Some((_, Node::TraitItem(i))) => {
206 if let TraitItemKind::Fn(sig, _) = &i.kind {
04454e1e 207 (i.def_id, sig, true)
5099ac24
FG
208 } else {
209 return;
210 }
211 },
212 _ => return,
213 };
214
04454e1e
FG
215 check_mut_from_ref(cx, sig, Some(body));
216 let decl = sig.decl;
5099ac24
FG
217 let sig = cx.tcx.fn_sig(item_id).skip_binder();
218 let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
219 .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
220 .collect();
221 let results = check_ptr_arg_usage(cx, body, &lint_args);
222
223 for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) {
224 span_lint_and_then(cx, PTR_ARG, args.span, &args.build_msg(), |diag| {
225 diag.multipart_suggestion(
226 "change this to",
227 iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx))))
228 .chain(result.replacements.iter().map(|r| {
229 (
230 r.expr_span,
231 format!("{}{}", snippet_opt(cx, r.self_span).unwrap(), r.replacement),
232 )
233 }))
234 .collect(),
235 Applicability::Unspecified,
236 );
237 });
f20569fa
XL
238 }
239 }
240
241 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
cdc7bbd5
XL
242 if let ExprKind::Binary(ref op, l, r) = expr.kind {
243 if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(cx, l) || is_null_path(cx, r)) {
f20569fa
XL
244 span_lint(
245 cx,
246 CMP_NULL,
247 expr.span,
248 "comparing with null is better expressed by the `.is_null()` method",
249 );
250 }
cdc7bbd5
XL
251 } else {
252 check_invalid_ptr_usage(cx, expr);
253 }
254 }
255}
256
257fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
258 // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B.
259 const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 16] = [
260 (&paths::SLICE_FROM_RAW_PARTS, &[0]),
261 (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]),
262 (&paths::PTR_COPY, &[0, 1]),
263 (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]),
264 (&paths::PTR_READ, &[0]),
265 (&paths::PTR_READ_UNALIGNED, &[0]),
266 (&paths::PTR_READ_VOLATILE, &[0]),
267 (&paths::PTR_REPLACE, &[0]),
268 (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]),
269 (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]),
270 (&paths::PTR_SWAP, &[0, 1]),
271 (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]),
272 (&paths::PTR_WRITE, &[0]),
273 (&paths::PTR_WRITE_UNALIGNED, &[0]),
274 (&paths::PTR_WRITE_VOLATILE, &[0]),
275 (&paths::PTR_WRITE_BYTES, &[0]),
276 ];
277
278 if_chain! {
17df50a5 279 if let ExprKind::Call(fun, args) = expr.kind;
cdc7bbd5
XL
280 if let ExprKind::Path(ref qpath) = fun.kind;
281 if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
282 let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
283 if let Some(&(_, arg_indices)) = INVALID_NULL_PTR_USAGE_TABLE
284 .iter()
285 .find(|&&(fn_path, _)| fn_path == fun_def_path);
286 then {
287 for &arg_idx in arg_indices {
288 if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {
289 span_lint_and_sugg(
290 cx,
291 INVALID_NULL_PTR_USAGE,
292 arg.span,
293 "pointer must be non-null",
294 "change this to",
295 "core::ptr::NonNull::dangling().as_ptr()".to_string(),
296 Applicability::MachineApplicable,
297 );
298 }
299 }
f20569fa
XL
300 }
301 }
302}
303
5099ac24
FG
304#[derive(Default)]
305struct PtrArgResult {
306 skip: bool,
307 replacements: Vec<PtrArgReplacement>,
308}
f20569fa 309
5099ac24
FG
310struct PtrArgReplacement {
311 expr_span: Span,
312 self_span: Span,
313 replacement: &'static str,
314}
3c0e092e 315
5099ac24
FG
316struct PtrArg<'tcx> {
317 idx: usize,
318 span: Span,
319 ty_did: DefId,
320 ty_name: Symbol,
321 method_renames: &'static [(&'static str, &'static str)],
322 ref_prefix: RefPrefix,
323 deref_ty: DerefTy<'tcx>,
5099ac24
FG
324}
325impl PtrArg<'_> {
326 fn build_msg(&self) -> String {
327 format!(
328 "writing `&{}{}` instead of `&{}{}` involves a new object where a slice will do",
329 self.ref_prefix.mutability.prefix_str(),
330 self.ty_name,
331 self.ref_prefix.mutability.prefix_str(),
332 self.deref_ty.argless_str(),
333 )
334 }
335
336 fn mutability(&self) -> Mutability {
337 self.ref_prefix.mutability
338 }
339}
340
341struct RefPrefix {
342 lt: LifetimeName,
343 mutability: Mutability,
344}
345impl fmt::Display for RefPrefix {
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 use fmt::Write;
348 f.write_char('&')?;
349 match self.lt {
923072b8 350 LifetimeName::Param(_, ParamName::Plain(name)) => {
5099ac24
FG
351 name.fmt(f)?;
352 f.write_char(' ')?;
3c0e092e 353 },
5099ac24
FG
354 LifetimeName::Underscore => f.write_str("'_ ")?,
355 LifetimeName::Static => f.write_str("'static ")?,
356 _ => (),
357 }
358 f.write_str(self.mutability.prefix_str())
359 }
360}
361
362struct DerefTyDisplay<'a, 'tcx>(&'a LateContext<'tcx>, &'a DerefTy<'tcx>);
363impl fmt::Display for DerefTyDisplay<'_, '_> {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 use std::fmt::Write;
366 match self.1 {
367 DerefTy::Str => f.write_str("str"),
368 DerefTy::Path => f.write_str("Path"),
369 DerefTy::Slice(hir_ty, ty) => {
370 f.write_char('[')?;
371 match hir_ty.and_then(|s| snippet_opt(self.0, s)) {
372 Some(s) => f.write_str(&s)?,
373 None => ty.fmt(f)?,
f20569fa 374 }
5099ac24 375 f.write_char(']')
3c0e092e 376 },
5099ac24
FG
377 }
378 }
379}
380
381enum DerefTy<'tcx> {
382 Str,
383 Path,
384 Slice(Option<Span>, Ty<'tcx>),
385}
386impl<'tcx> DerefTy<'tcx> {
387 fn argless_str(&self) -> &'static str {
388 match *self {
389 Self::Str => "str",
390 Self::Path => "Path",
391 Self::Slice(..) => "[_]",
392 }
393 }
394
395 fn display<'a>(&'a self, cx: &'a LateContext<'tcx>) -> DerefTyDisplay<'a, 'tcx> {
396 DerefTyDisplay(cx, self)
397 }
398}
399
400fn check_fn_args<'cx, 'tcx: 'cx>(
401 cx: &'cx LateContext<'tcx>,
923072b8
FG
402 tys: &'tcx [Ty<'tcx>],
403 hir_tys: &'tcx [hir::Ty<'tcx>],
404 params: &'tcx [Param<'tcx>],
5099ac24
FG
405) -> impl Iterator<Item = PtrArg<'tcx>> + 'cx {
406 tys.iter()
407 .zip(hir_tys.iter())
408 .enumerate()
409 .filter_map(|(i, (ty, hir_ty))| {
410 if_chain! {
411 if let ty::Ref(_, ty, mutability) = *ty.kind();
412 if let ty::Adt(adt, substs) = *ty.kind();
413
414 if let TyKind::Rptr(lt, ref ty) = hir_ty.kind;
415 if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind;
416
417 // Check that the name as typed matches the actual name of the type.
418 // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec`
419 if let [.., name] = path.segments;
5e7ed085 420 if cx.tcx.item_name(adt.did()) == name.ident.name;
5099ac24
FG
421
422 if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id);
423 if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id));
424
425 then {
5e7ed085 426 let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) {
5099ac24
FG
427 Some(sym::Vec) => (
428 [("clone", ".to_owned()")].as_slice(),
429 DerefTy::Slice(
430 name.args
431 .and_then(|args| args.args.first())
432 .and_then(|arg| if let GenericArg::Type(ty) = arg {
433 Some(ty.span)
434 } else {
435 None
436 }),
437 substs.type_at(0),
438 ),
5099ac24
FG
439 ),
440 Some(sym::String) => (
441 [("clone", ".to_owned()"), ("as_str", "")].as_slice(),
442 DerefTy::Str,
5099ac24
FG
443 ),
444 Some(sym::PathBuf) => (
445 [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(),
446 DerefTy::Path,
5099ac24 447 ),
5e7ed085 448 Some(sym::Cow) if mutability == Mutability::Not => {
5099ac24
FG
449 let ty_name = name.args
450 .and_then(|args| {
451 args.args.iter().find_map(|a| match a {
452 GenericArg::Type(x) => Some(x),
453 _ => None,
454 })
455 })
456 .and_then(|arg| snippet_opt(cx, arg.span))
457 .unwrap_or_else(|| substs.type_at(1).to_string());
458 span_lint_and_sugg(
459 cx,
460 PTR_ARG,
461 hir_ty.span,
462 "using a reference to `Cow` is not recommended",
f20569fa 463 "change this to",
5099ac24 464 format!("&{}{}", mutability.prefix_str(), ty_name),
f20569fa
XL
465 Applicability::Unspecified,
466 );
5099ac24 467 return None;
f20569fa 468 },
5099ac24
FG
469 _ => return None,
470 };
471 return Some(PtrArg {
472 idx: i,
473 span: hir_ty.span,
5e7ed085 474 ty_did: adt.did(),
5099ac24
FG
475 ty_name: name.ident.name,
476 method_renames,
477 ref_prefix: RefPrefix {
478 lt: lt.name,
479 mutability,
480 },
481 deref_ty,
f20569fa 482 });
f20569fa 483 }
5099ac24
FG
484 }
485 None
486 })
487}
f20569fa 488
04454e1e
FG
489fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&'tcx Body<'_>>) {
490 if let FnRetTy::Return(ty) = sig.decl.output
491 && let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty)
492 {
493 let args: Option<Vec<_>> = sig
494 .decl
495 .inputs
496 .iter()
497 .filter_map(get_rptr_lm)
498 .filter(|&(lt, _, _)| lt.name == out.name)
499 .map(|(_, mutability, span)| (mutability == Mutability::Not).then(|| span))
500 .collect();
501 if let Some(args) = args
502 && !args.is_empty()
503 && body.map_or(true, |body| {
504 sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, &body.value)
505 })
506 {
f20569fa
XL
507 span_lint_and_then(
508 cx,
509 MUT_FROM_REF,
510 ty.span,
511 "mutable borrow from immutable input(s)",
512 |diag| {
04454e1e 513 let ms = MultiSpan::from_spans(args);
f20569fa
XL
514 diag.span_note(ms, "immutable borrow here");
515 },
516 );
517 }
518 }
519}
520
923072b8 521#[expect(clippy::too_many_lines)]
5099ac24
FG
522fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> {
523 struct V<'cx, 'tcx> {
524 cx: &'cx LateContext<'tcx>,
525 /// Map from a local id to which argument it came from (index into `Self::args` and
526 /// `Self::results`)
527 bindings: HirIdMap<usize>,
528 /// The arguments being checked.
529 args: &'cx [PtrArg<'tcx>],
530 /// The results for each argument (len should match args.len)
531 results: Vec<PtrArgResult>,
532 /// The number of arguments which can't be linted. Used to return early.
533 skip_count: usize,
534 }
535 impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
536 type NestedFilter = nested_filter::OnlyBodies;
537 fn nested_visit_map(&mut self) -> Self::Map {
538 self.cx.tcx.hir()
539 }
540
541 fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
542
543 fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
544 if self.skip_count == self.args.len() {
545 return;
546 }
547
548 // Check if this is local we care about
549 let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) {
550 Some(&i) => i,
551 None => return walk_expr(self, e),
552 };
553 let args = &self.args[args_idx];
554 let result = &mut self.results[args_idx];
555
556 // Helper function to handle early returns.
557 let mut set_skip_flag = || {
5e7ed085 558 if !result.skip {
5099ac24
FG
559 self.skip_count += 1;
560 }
561 result.skip = true;
562 };
563
564 match get_expr_use_or_unification_node(self.cx.tcx, e) {
565 Some((Node::Stmt(_), _)) => (),
566 Some((Node::Local(l), _)) => {
567 // Only trace simple bindings. e.g `let x = y;`
568 if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
569 self.bindings.insert(id, args_idx);
570 } else {
571 set_skip_flag();
572 }
573 },
574 Some((Node::Expr(e), child_id)) => match e.kind {
575 ExprKind::Call(f, expr_args) => {
576 let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
577 if expr_sig(self.cx, f)
578 .map(|sig| sig.input(i).skip_binder().peel_refs())
579 .map_or(true, |ty| match *ty.kind() {
580 ty::Param(_) => true,
5e7ed085 581 ty::Adt(def, _) => def.did() == args.ty_did,
5099ac24
FG
582 _ => false,
583 })
584 {
585 // Passed to a function taking the non-dereferenced type.
586 set_skip_flag();
587 }
588 },
589 ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
590 let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
591 if i == 0 {
592 // Check if the method can be renamed.
593 let name = name.ident.as_str();
594 if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
595 result.replacements.push(PtrArgReplacement {
596 expr_span: e.span,
597 self_span: self_arg.span,
598 replacement,
599 });
600 return;
601 }
602 }
603
604 let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) {
605 x
606 } else {
607 set_skip_flag();
608 return;
609 };
610
611 match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
612 ty::Param(_) => {
613 set_skip_flag();
614 },
615 // If the types match check for methods which exist on both types. e.g. `Vec::len` and
616 // `slice::len`
04454e1e 617 ty::Adt(def, _) if def.did() == args.ty_did => {
5099ac24
FG
618 set_skip_flag();
619 },
620 _ => (),
621 }
622 },
623 // Indexing is fine for currently supported types.
624 ExprKind::Index(e, _) if e.hir_id == child_id => (),
625 _ => set_skip_flag(),
626 },
627 _ => set_skip_flag(),
628 }
f20569fa
XL
629 }
630 }
5099ac24
FG
631
632 let mut skip_count = 0;
633 let mut results = args.iter().map(|_| PtrArgResult::default()).collect::<Vec<_>>();
634 let mut v = V {
635 cx,
636 bindings: args
637 .iter()
638 .enumerate()
639 .filter_map(|(i, arg)| {
640 let param = &body.params[arg.idx];
641 match param.pat.kind {
642 PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
643 if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
644 {
645 Some((id, i))
646 },
647 _ => {
648 skip_count += 1;
649 results[i].skip = true;
650 None
651 },
652 }
653 })
654 .collect(),
655 args,
656 results,
657 skip_count,
658 };
659 v.visit_expr(&body.value);
660 v.results
f20569fa
XL
661}
662
5099ac24 663fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
f20569fa
XL
664 if let TyKind::Rptr(ref lt, ref m) = ty.kind {
665 Some((lt, m.mutbl, ty.span))
666 } else {
667 None
668 }
669}
670
cdc7bbd5
XL
671fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
672 if let ExprKind::Call(pathexp, []) = expr.kind {
5099ac24
FG
673 path_def_id(cx, pathexp).map_or(false, |id| {
674 matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut))
cdc7bbd5
XL
675 })
676 } else {
677 false
f20569fa 678 }
f20569fa 679}