use std::borrow::Cow; use crate::rustc::hir::*; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::lint::LateContext; use crate::syntax::ast::Name; use crate::syntax::source_map::Span; use crate::utils::{get_pat_name, match_var, snippet}; pub fn get_spans( cx: &LateContext<'_, '_>, opt_body_id: Option, idx: usize, replacements: &'static [(&'static str, &'static str)], ) -> Option)>> { if let Some(body) = opt_body_id.map(|id| cx.tcx.hir.body(id)) { get_binding_name(&body.arguments[idx]) .map_or_else(|| Some(vec![]), |name| extract_clone_suggestions(cx, name, replacements, body)) } else { Some(vec![]) } } fn extract_clone_suggestions<'a, 'tcx: 'a>( cx: &LateContext<'a, 'tcx>, name: Name, replace: &'static [(&'static str, &'static str)], body: &'tcx Body, ) -> Option)>> { let mut visitor = PtrCloneVisitor { cx, name, replace, spans: vec![], abort: false, }; visitor.visit_body(body); if visitor.abort { None } else { Some(visitor.spans) } } struct PtrCloneVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, name: Name, replace: &'static [(&'static str, &'static str)], spans: Vec<(Span, Cow<'static, str>)>, abort: bool, } impl<'a, 'tcx: 'a> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr) { if self.abort { return; } if let ExprKind::MethodCall(ref seg, _, ref args) = expr.node { if args.len() == 1 && match_var(&args[0], self.name) { if seg.ident.name == "capacity" { self.abort = true; return; } for &(fn_name, suffix) in self.replace { if seg.ident.name == fn_name { self.spans .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix)); return; } } } return; } walk_expr(self, expr); } fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } } fn get_binding_name(arg: &Arg) -> Option { get_pat_name(&arg.pat) }