]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_utils/src/ptr.rs
Rollup merge of #82846 - GuillaumeGomez:doc-alias-list, r=jyn514
[rust.git] / src / tools / clippy / clippy_utils / src / ptr.rs
1 use crate::{get_pat_name, match_var, snippet};
2 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
3 use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
4 use rustc_lint::LateContext;
5 use rustc_middle::hir::map::Map;
6 use rustc_span::{Span, Symbol};
7 use std::borrow::Cow;
8
9 pub fn get_spans(
10     cx: &LateContext<'_>,
11     opt_body_id: Option<BodyId>,
12     idx: usize,
13     replacements: &[(&'static str, &'static str)],
14 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
15     if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
16         get_binding_name(&body.params[idx]).map_or_else(
17             || Some(vec![]),
18             |name| extract_clone_suggestions(cx, name, replacements, body),
19         )
20     } else {
21         Some(vec![])
22     }
23 }
24
25 fn extract_clone_suggestions<'tcx>(
26     cx: &LateContext<'tcx>,
27     name: Symbol,
28     replace: &[(&'static str, &'static str)],
29     body: &'tcx Body<'_>,
30 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
31     let mut visitor = PtrCloneVisitor {
32         cx,
33         name,
34         replace,
35         spans: vec![],
36         abort: false,
37     };
38     visitor.visit_body(body);
39     if visitor.abort { None } else { Some(visitor.spans) }
40 }
41
42 struct PtrCloneVisitor<'a, 'tcx> {
43     cx: &'a LateContext<'tcx>,
44     name: Symbol,
45     replace: &'a [(&'static str, &'static str)],
46     spans: Vec<(Span, Cow<'static, str>)>,
47     abort: bool,
48 }
49
50 impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
51     type Map = Map<'tcx>;
52
53     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
54         if self.abort {
55             return;
56         }
57         if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind {
58             if args.len() == 1 && match_var(&args[0], self.name) {
59                 if seg.ident.name.as_str() == "capacity" {
60                     self.abort = true;
61                     return;
62                 }
63                 for &(fn_name, suffix) in self.replace {
64                     if seg.ident.name.as_str() == fn_name {
65                         self.spans
66                             .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
67                         return;
68                     }
69                 }
70             }
71         }
72         walk_expr(self, expr);
73     }
74
75     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
76         NestedVisitorMap::None
77     }
78 }
79
80 fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
81     get_pat_name(&arg.pat)
82 }