use crate::source::snippet; use crate::visitors::{for_each_expr_without_closures, Descend}; use crate::{path_to_local_id, strip_pat_refs}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; use std::borrow::Cow; pub fn get_spans( cx: &LateContext<'_>, opt_body_id: Option, idx: usize, replacements: &[(&'static str, &'static str)], ) -> Option)>> { if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) { if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind { extract_clone_suggestions(cx, binding_id, replacements, body) } else { Some(vec![]) } } else { Some(vec![]) } } fn extract_clone_suggestions<'tcx>( cx: &LateContext<'tcx>, id: HirId, replace: &[(&'static str, &'static str)], body: &'tcx Body<'_>, ) -> Option)>> { let mut spans = Vec::new(); for_each_expr_without_closures(body, |e| { if let ExprKind::MethodCall(seg, recv, [], _) = e.kind && path_to_local_id(recv, id) { if seg.ident.as_str() == "capacity" { return ControlFlow::Break(()); } for &(fn_name, suffix) in replace { if seg.ident.as_str() == fn_name { spans.push((e.span, snippet(cx, recv.span, "_") + suffix)); return ControlFlow::Continue(Descend::No); } } } ControlFlow::Continue(Descend::Yes) }) .is_none() .then_some(spans) }