]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/ptr.rs
Merge pull request #2819 from zayenz/no-op-ref-in-macro
[rust.git] / clippy_lints / src / utils / ptr.rs
1 use std::borrow::Cow;
2 use rustc::hir::*;
3 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
4 use rustc::lint::LateContext;
5 use syntax::ast::Name;
6 use syntax::codemap::Span;
7 use crate::utils::{get_pat_name, match_var, snippet};
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])
17             .map_or_else(|| Some(vec![]), |name| extract_clone_suggestions(cx, name, replacements, body))
18     } else {
19         Some(vec![])
20     }
21 }
22
23 fn extract_clone_suggestions<'a, 'tcx: 'a>(
24     cx: &LateContext<'a, 'tcx>,
25     name: Name,
26     replace: &'static [(&'static str, &'static str)],
27     body: &'tcx Body,
28 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
29     let mut visitor = PtrCloneVisitor {
30         cx,
31         name,
32         replace,
33         spans: vec![],
34         abort: false,
35     };
36     visitor.visit_body(body);
37     if visitor.abort {
38         None
39     } else {
40         Some(visitor.spans)
41     }
42 }
43
44 struct PtrCloneVisitor<'a, 'tcx: 'a> {
45     cx: &'a LateContext<'a, 'tcx>,
46     name: Name,
47     replace: &'static [(&'static str, &'static str)],
48     spans: Vec<(Span, Cow<'static, str>)>,
49     abort: bool,
50 }
51
52 impl<'a, 'tcx: 'a> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
53     fn visit_expr(&mut self, expr: &'tcx Expr) {
54         if self.abort {
55             return;
56         }
57         if let ExprMethodCall(ref seg, _, ref args) = expr.node {
58             if args.len() == 1 && match_var(&args[0], self.name) {
59                 if seg.name == "capacity" {
60                     self.abort = true;
61                     return;
62                 }
63                 for &(fn_name, suffix) in self.replace {
64                     if seg.name == fn_name {
65                         self.spans
66                             .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
67                         return;
68                     }
69                 }
70             }
71             return;
72         }
73         walk_expr(self, expr);
74     }
75
76     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
77         NestedVisitorMap::None
78     }
79 }
80
81 fn get_binding_name(arg: &Arg) -> Option<Name> {
82     get_pat_name(&arg.pat)
83 }