2021-03-25 13:29:11 -05:00
|
|
|
use crate::source::snippet;
|
2021-07-01 11:17:38 -05:00
|
|
|
use crate::{path_to_local_id, strip_pat_refs};
|
2020-01-09 01:13:22 -06:00
|
|
|
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
2021-07-01 11:17:38 -05:00
|
|
|
use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
|
2020-01-12 00:08:41 -06:00
|
|
|
use rustc_lint::LateContext;
|
2020-03-30 04:02:14 -05:00
|
|
|
use rustc_middle::hir::map::Map;
|
2021-07-01 11:17:38 -05:00
|
|
|
use rustc_span::Span;
|
2018-11-27 14:14:15 -06:00
|
|
|
use std::borrow::Cow;
|
2017-10-08 03:51:44 -05:00
|
|
|
|
|
|
|
pub fn get_spans(
|
2020-06-25 15:41:36 -05:00
|
|
|
cx: &LateContext<'_>,
|
2017-10-08 03:51:44 -05:00
|
|
|
opt_body_id: Option<BodyId>,
|
|
|
|
idx: usize,
|
2019-05-17 16:53:54 -05:00
|
|
|
replacements: &[(&'static str, &'static str)],
|
2017-10-08 03:51:44 -05:00
|
|
|
) -> Option<Vec<(Span, Cow<'static, str>)>> {
|
2018-12-07 18:56:03 -06:00
|
|
|
if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
|
2021-07-01 11:17:38 -05:00
|
|
|
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![])
|
|
|
|
}
|
2017-10-08 03:51:44 -05:00
|
|
|
} else {
|
|
|
|
Some(vec![])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 15:41:36 -05:00
|
|
|
fn extract_clone_suggestions<'tcx>(
|
|
|
|
cx: &LateContext<'tcx>,
|
2021-07-01 11:17:38 -05:00
|
|
|
id: HirId,
|
2019-05-17 16:53:54 -05:00
|
|
|
replace: &[(&'static str, &'static str)],
|
2019-12-22 08:42:41 -06:00
|
|
|
body: &'tcx Body<'_>,
|
2017-10-08 03:51:44 -05:00
|
|
|
) -> Option<Vec<(Span, Cow<'static, str>)>> {
|
|
|
|
let mut visitor = PtrCloneVisitor {
|
|
|
|
cx,
|
2021-07-01 11:17:38 -05:00
|
|
|
id,
|
2017-10-08 03:51:44 -05:00
|
|
|
replace,
|
|
|
|
spans: vec![],
|
|
|
|
abort: false,
|
|
|
|
};
|
|
|
|
visitor.visit_body(body);
|
2021-03-12 08:30:50 -06:00
|
|
|
if visitor.abort { None } else { Some(visitor.spans) }
|
2017-10-08 03:51:44 -05:00
|
|
|
}
|
|
|
|
|
2019-06-19 13:36:23 -05:00
|
|
|
struct PtrCloneVisitor<'a, 'tcx> {
|
2020-06-25 15:41:36 -05:00
|
|
|
cx: &'a LateContext<'tcx>,
|
2021-07-01 11:17:38 -05:00
|
|
|
id: HirId,
|
2019-05-17 16:53:54 -05:00
|
|
|
replace: &'a [(&'static str, &'static str)],
|
2017-10-08 03:51:44 -05:00
|
|
|
spans: Vec<(Span, Cow<'static, str>)>,
|
|
|
|
abort: bool,
|
|
|
|
}
|
|
|
|
|
2019-06-19 13:36:23 -05:00
|
|
|
impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
|
2020-01-09 01:13:22 -06:00
|
|
|
type Map = Map<'tcx>;
|
|
|
|
|
2019-12-27 01:12:26 -06:00
|
|
|
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
2017-10-08 03:51:44 -05:00
|
|
|
if self.abort {
|
|
|
|
return;
|
|
|
|
}
|
2021-07-01 11:17:38 -05:00
|
|
|
if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind {
|
|
|
|
if path_to_local_id(recv, self.id) {
|
2019-05-17 16:53:54 -05:00
|
|
|
if seg.ident.name.as_str() == "capacity" {
|
2017-10-08 03:51:44 -05:00
|
|
|
self.abort = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for &(fn_name, suffix) in self.replace {
|
2019-05-17 16:53:54 -05:00
|
|
|
if seg.ident.name.as_str() == fn_name {
|
2021-07-01 11:17:38 -05:00
|
|
|
self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
|
2017-10-08 03:51:44 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
walk_expr(self, expr);
|
|
|
|
}
|
|
|
|
|
2020-03-15 17:41:20 -05:00
|
|
|
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
2017-10-08 03:51:44 -05:00
|
|
|
NestedVisitorMap::None
|
|
|
|
}
|
|
|
|
}
|