]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/ptr.rs
Auto merge of #3598 - xfix:apply-cargo-fix-edition-idioms, r=phansch
[rust.git] / clippy_lints / src / utils / ptr.rs
1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 use crate::utils::{get_pat_name, match_var, snippet};
11 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
12 use rustc::hir::*;
13 use rustc::lint::LateContext;
14 use std::borrow::Cow;
15 use syntax::ast::Name;
16 use syntax::source_map::Span;
17
18 pub fn get_spans(
19     cx: &LateContext<'_, '_>,
20     opt_body_id: Option<BodyId>,
21     idx: usize,
22     replacements: &'static [(&'static str, &'static str)],
23 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
24     if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
25         get_binding_name(&body.arguments[idx]).map_or_else(
26             || Some(vec![]),
27             |name| extract_clone_suggestions(cx, name, replacements, body),
28         )
29     } else {
30         Some(vec![])
31     }
32 }
33
34 fn extract_clone_suggestions<'a, 'tcx: 'a>(
35     cx: &LateContext<'a, 'tcx>,
36     name: Name,
37     replace: &'static [(&'static str, &'static str)],
38     body: &'tcx Body,
39 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
40     let mut visitor = PtrCloneVisitor {
41         cx,
42         name,
43         replace,
44         spans: vec![],
45         abort: false,
46     };
47     visitor.visit_body(body);
48     if visitor.abort {
49         None
50     } else {
51         Some(visitor.spans)
52     }
53 }
54
55 struct PtrCloneVisitor<'a, 'tcx: 'a> {
56     cx: &'a LateContext<'a, 'tcx>,
57     name: Name,
58     replace: &'static [(&'static str, &'static str)],
59     spans: Vec<(Span, Cow<'static, str>)>,
60     abort: bool,
61 }
62
63 impl<'a, 'tcx: 'a> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
64     fn visit_expr(&mut self, expr: &'tcx Expr) {
65         if self.abort {
66             return;
67         }
68         if let ExprKind::MethodCall(ref seg, _, ref args) = expr.node {
69             if args.len() == 1 && match_var(&args[0], self.name) {
70                 if seg.ident.name == "capacity" {
71                     self.abort = true;
72                     return;
73                 }
74                 for &(fn_name, suffix) in self.replace {
75                     if seg.ident.name == fn_name {
76                         self.spans
77                             .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
78                         return;
79                     }
80                 }
81             }
82             return;
83         }
84         walk_expr(self, expr);
85     }
86
87     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
88         NestedVisitorMap::None
89     }
90 }
91
92 fn get_binding_name(arg: &Arg) -> Option<Name> {
93     get_pat_name(&arg.pat)
94 }