]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_utils/src/ptr.rs
Rollup merge of #85966 - alexcrichton:wasm-simd-indirect, r=workingjubilee
[rust.git] / src / tools / clippy / clippy_utils / src / ptr.rs
1 use crate::source::snippet;
2 use crate::{get_pat_name, match_var};
3 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
4 use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
5 use rustc_lint::LateContext;
6 use rustc_middle::hir::map::Map;
7 use rustc_span::{Span, Symbol};
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<'tcx>(
27     cx: &LateContext<'tcx>,
28     name: Symbol,
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 { None } else { Some(visitor.spans) }
41 }
42
43 struct PtrCloneVisitor<'a, 'tcx> {
44     cx: &'a LateContext<'tcx>,
45     name: Symbol,
46     replace: &'a [(&'static str, &'static str)],
47     spans: Vec<(Span, Cow<'static, str>)>,
48     abort: bool,
49 }
50
51 impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
52     type Map = Map<'tcx>;
53
54     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
55         if self.abort {
56             return;
57         }
58         if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
59             if args.len() == 1 && match_var(&args[0], self.name) {
60                 if seg.ident.name.as_str() == "capacity" {
61                     self.abort = true;
62                     return;
63                 }
64                 for &(fn_name, suffix) in self.replace {
65                     if seg.ident.name.as_str() == fn_name {
66                         self.spans
67                             .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
68                         return;
69                     }
70                 }
71             }
72         }
73         walk_expr(self, expr);
74     }
75
76     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
77         NestedVisitorMap::None
78     }
79 }
80
81 fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
82     get_pat_name(arg.pat)
83 }