rust/clippy_utils/src/ptr.rs

80 lines
2.3 KiB
Rust
Raw Normal View History

use crate::source::snippet;
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};
use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
2020-01-12 00:08:41 -06:00
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
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(
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>)>> {
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![])
}
2017-10-08 03:51:44 -05:00
} else {
Some(vec![])
}
}
fn extract_clone_suggestions<'tcx>(
cx: &LateContext<'tcx>,
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,
id,
2017-10-08 03:51:44 -05:00
replace,
spans: vec![],
abort: false,
};
visitor.visit_body(body);
if visitor.abort { None } else { Some(visitor.spans) }
2017-10-08 03:51:44 -05:00
}
struct PtrCloneVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
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,
}
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;
}
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 {
self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
2017-10-08 03:51:44 -05:00
return;
}
}
}
}
walk_expr(self, expr);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
2017-10-08 03:51:44 -05:00
NestedVisitorMap::None
}
}