]> git.lizzy.rs Git - rust.git/blob - clippy_utils/src/ptr.rs
Rollup merge of #88230 - steffahn:a_an, r=oli-obk
[rust.git] / clippy_utils / src / ptr.rs
1 use crate::source::snippet;
2 use crate::{path_to_local_id, strip_pat_refs};
3 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
4 use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
5 use rustc_lint::LateContext;
6 use rustc_middle::hir::map::Map;
7 use rustc_span::Span;
8 use std::borrow::Cow;
9
10 pub 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
27 fn 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 visitor = PtrCloneVisitor {
34         cx,
35         id,
36         replace,
37         spans: vec![],
38         abort: false,
39     };
40     visitor.visit_body(body);
41     if visitor.abort { None } else { Some(visitor.spans) }
42 }
43
44 struct PtrCloneVisitor<'a, 'tcx> {
45     cx: &'a LateContext<'tcx>,
46     id: HirId,
47     replace: &'a [(&'static str, &'static str)],
48     spans: Vec<(Span, Cow<'static, str>)>,
49     abort: bool,
50 }
51
52 impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
53     type Map = Map<'tcx>;
54
55     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
56         if self.abort {
57             return;
58         }
59         if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind {
60             if path_to_local_id(recv, self.id) {
61                 if seg.ident.name.as_str() == "capacity" {
62                     self.abort = true;
63                     return;
64                 }
65                 for &(fn_name, suffix) in self.replace {
66                     if seg.ident.name.as_str() == fn_name {
67                         self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
68                         return;
69                     }
70                 }
71             }
72         }
73         walk_expr(self, expr);
74     }
75
76     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
77         NestedVisitorMap::None
78     }
79 }