]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/ptr.rs
rustup https://github.com/rust-lang/rust/pull/68944
[rust.git] / clippy_lints / src / utils / ptr.rs
1 use crate::utils::{get_pat_name, match_var, snippet};
2 use rustc::hir::map::Map;
3 use rustc_ast::ast::Name;
4 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
5 use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
6 use rustc_lint::LateContext;
7 use rustc_span::source_map::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         get_binding_name(&body.params[idx]).map_or_else(
18             || Some(vec![]),
19             |name| extract_clone_suggestions(cx, name, replacements, body),
20         )
21     } else {
22         Some(vec![])
23     }
24 }
25
26 fn extract_clone_suggestions<'a, 'tcx>(
27     cx: &LateContext<'a, 'tcx>,
28     name: Name,
29     replace: &[(&'static str, &'static str)],
30     body: &'tcx Body<'_>,
31 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
32     let mut visitor = PtrCloneVisitor {
33         cx,
34         name,
35         replace,
36         spans: vec![],
37         abort: false,
38     };
39     visitor.visit_body(body);
40     if visitor.abort {
41         None
42     } else {
43         Some(visitor.spans)
44     }
45 }
46
47 struct PtrCloneVisitor<'a, 'tcx> {
48     cx: &'a LateContext<'a, 'tcx>,
49     name: Name,
50     replace: &'a [(&'static str, &'static str)],
51     spans: Vec<(Span, Cow<'static, str>)>,
52     abort: bool,
53 }
54
55 impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
56     type Map = Map<'tcx>;
57
58     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
59         if self.abort {
60             return;
61         }
62         if let ExprKind::MethodCall(ref seg, _, ref args) = expr.kind {
63             if args.len() == 1 && match_var(&args[0], self.name) {
64                 if seg.ident.name.as_str() == "capacity" {
65                     self.abort = true;
66                     return;
67                 }
68                 for &(fn_name, suffix) in self.replace {
69                     if seg.ident.name.as_str() == fn_name {
70                         self.spans
71                             .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
72                         return;
73                     }
74                 }
75             }
76             return;
77         }
78         walk_expr(self, expr);
79     }
80
81     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
82         NestedVisitorMap::None
83     }
84 }
85
86 fn get_binding_name(arg: &Param<'_>) -> Option<Name> {
87     get_pat_name(&arg.pat)
88 }