rust-clippy/clippy_utils/src/ptr.rs

83 lines
2.4 KiB
Rust
Raw Normal View History

use crate::{get_pat_name, match_var, snippet};
2020-01-09 07:13:22 +00:00
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
2020-02-21 08:39:38 +00:00
use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
2020-01-12 06:08:41 +00:00
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
2020-05-08 11:57:01 +00:00
use rustc_span::{Span, Symbol};
2018-11-27 20:14:15 +00:00
use std::borrow::Cow;
2017-10-08 08:51:44 +00:00
pub fn get_spans(
cx: &LateContext<'_>,
2017-10-08 08:51:44 +00:00
opt_body_id: Option<BodyId>,
idx: usize,
2019-05-17 21:53:54 +00:00
replacements: &[(&'static str, &'static str)],
2017-10-08 08:51:44 +00:00
) -> Option<Vec<(Span, Cow<'static, str>)>> {
if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
2019-08-28 09:27:06 +00:00
get_binding_name(&body.params[idx]).map_or_else(
2018-11-27 20:14:15 +00:00
|| Some(vec![]),
|name| extract_clone_suggestions(cx, name, replacements, body),
)
2017-10-08 08:51:44 +00:00
} else {
Some(vec![])
}
}
fn extract_clone_suggestions<'tcx>(
cx: &LateContext<'tcx>,
2020-05-08 11:57:01 +00:00
name: Symbol,
2019-05-17 21:53:54 +00:00
replace: &[(&'static str, &'static str)],
2019-12-22 14:42:41 +00:00
body: &'tcx Body<'_>,
2017-10-08 08:51:44 +00:00
) -> Option<Vec<(Span, Cow<'static, str>)>> {
let mut visitor = PtrCloneVisitor {
cx,
name,
replace,
spans: vec![],
abort: false,
};
visitor.visit_body(body);
if visitor.abort { None } else { Some(visitor.spans) }
2017-10-08 08:51:44 +00:00
}
struct PtrCloneVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
2020-05-08 11:57:01 +00:00
name: Symbol,
2019-05-17 21:53:54 +00:00
replace: &'a [(&'static str, &'static str)],
2017-10-08 08:51:44 +00:00
spans: Vec<(Span, Cow<'static, str>)>,
abort: bool,
}
impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
2020-01-09 07:13:22 +00:00
type Map = Map<'tcx>;
2019-12-27 07:12:26 +00:00
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
2017-10-08 08:51:44 +00:00
if self.abort {
return;
}
2020-06-09 21:44:04 +00:00
if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind {
2017-10-08 08:51:44 +00:00
if args.len() == 1 && match_var(&args[0], self.name) {
2019-05-17 21:53:54 +00:00
if seg.ident.name.as_str() == "capacity" {
2017-10-08 08:51:44 +00:00
self.abort = true;
return;
}
for &(fn_name, suffix) in self.replace {
2019-05-17 21:53:54 +00:00
if seg.ident.name.as_str() == fn_name {
2017-10-08 08:51:44 +00:00
self.spans
.push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
return;
}
}
}
}
walk_expr(self, expr);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
2017-10-08 08:51:44 +00:00
NestedVisitorMap::None
}
}
2020-05-08 11:57:01 +00:00
fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
2017-10-08 08:51:44 +00:00
get_pat_name(&arg.pat)
}