]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/ptr.rs
Auto merge of #3684 - g-bartoszek:sugg-snippet-modifications, r=phansch
[rust.git] / clippy_lints / src / utils / ptr.rs
1 use crate::utils::{get_pat_name, match_var, snippet};
2 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
3 use rustc::hir::*;
4 use rustc::lint::LateContext;
5 use std::borrow::Cow;
6 use syntax::ast::Name;
7 use syntax::source_map::Span;
8
9 pub fn get_spans(
10     cx: &LateContext<'_, '_>,
11     opt_body_id: Option<BodyId>,
12     idx: usize,
13     replacements: &'static [(&'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.arguments[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<'a, 'tcx: 'a>(
26     cx: &LateContext<'a, 'tcx>,
27     name: Name,
28     replace: &'static [(&'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 {
40         None
41     } else {
42         Some(visitor.spans)
43     }
44 }
45
46 struct PtrCloneVisitor<'a, 'tcx: 'a> {
47     cx: &'a LateContext<'a, 'tcx>,
48     name: Name,
49     replace: &'static [(&'static str, &'static str)],
50     spans: Vec<(Span, Cow<'static, str>)>,
51     abort: bool,
52 }
53
54 impl<'a, 'tcx: 'a> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
55     fn visit_expr(&mut self, expr: &'tcx Expr) {
56         if self.abort {
57             return;
58         }
59         if let ExprKind::MethodCall(ref seg, _, ref args) = expr.node {
60             if args.len() == 1 && match_var(&args[0], self.name) {
61                 if seg.ident.name == "capacity" {
62                     self.abort = true;
63                     return;
64                 }
65                 for &(fn_name, suffix) in self.replace {
66                     if seg.ident.name == fn_name {
67                         self.spans
68                             .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
69                         return;
70                     }
71                 }
72             }
73             return;
74         }
75         walk_expr(self, expr);
76     }
77
78     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
79         NestedVisitorMap::None
80     }
81 }
82
83 fn get_binding_name(arg: &Arg) -> Option<Name> {
84     get_pat_name(&arg.pat)
85 }