clippy_utils/
ptr.rs

1use crate::source::snippet;
2use crate::visitors::{Descend, for_each_expr_without_closures};
3use crate::{path_to_local_id, strip_pat_refs};
4use core::ops::ControlFlow;
5use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
6use rustc_lint::LateContext;
7use rustc_span::Span;
8use std::borrow::Cow;
9
10pub fn get_spans(
11    cx: &LateContext<'_>,
12    opt_body_id: Option<BodyId>,
13    idx: usize,
14    replacements: &[(&'static str, &'static str)],
15) -> Option<Vec<(Span, Cow<'static, str>)>> {
16    if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
17        if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind {
18            extract_clone_suggestions(cx, binding_id, replacements, body)
19        } else {
20            Some(vec![])
21        }
22    } else {
23        Some(vec![])
24    }
25}
26
27fn extract_clone_suggestions<'tcx>(
28    cx: &LateContext<'tcx>,
29    id: HirId,
30    replace: &[(&'static str, &'static str)],
31    body: &'tcx Body<'_>,
32) -> Option<Vec<(Span, Cow<'static, str>)>> {
33    let mut spans = Vec::new();
34    for_each_expr_without_closures(body, |e| {
35        if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
36            && path_to_local_id(recv, id)
37        {
38            if seg.ident.as_str() == "capacity" {
39                return ControlFlow::Break(());
40            }
41            for &(fn_name, suffix) in replace {
42                if seg.ident.as_str() == fn_name {
43                    spans.push((e.span, snippet(cx, recv.span, "_") + suffix));
44                    return ControlFlow::Continue(Descend::No);
45                }
46            }
47        }
48        ControlFlow::Continue(Descend::Yes)
49    })
50    .is_none()
51    .then_some(spans)
52}