2018-10-06 16:18:06 +00:00
|
|
|
// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2018-09-15 07:21:58 +00:00
|
|
|
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
2018-11-27 20:14:15 +00:00
|
|
|
use crate::rustc::hir::*;
|
2018-09-15 07:21:58 +00:00
|
|
|
use crate::rustc::lint::LateContext;
|
|
|
|
use crate::syntax::ast::Name;
|
|
|
|
use crate::syntax::source_map::Span;
|
2018-05-30 08:15:50 +00:00
|
|
|
use crate::utils::{get_pat_name, match_var, snippet};
|
2018-11-27 20:14:15 +00:00
|
|
|
use std::borrow::Cow;
|
2017-10-08 08:51:44 +00:00
|
|
|
|
|
|
|
pub fn get_spans(
|
2018-07-23 11:01:12 +00:00
|
|
|
cx: &LateContext<'_, '_>,
|
2017-10-08 08:51:44 +00:00
|
|
|
opt_body_id: Option<BodyId>,
|
|
|
|
idx: usize,
|
|
|
|
replacements: &'static [(&'static str, &'static str)],
|
|
|
|
) -> Option<Vec<(Span, Cow<'static, str>)>> {
|
|
|
|
if let Some(body) = opt_body_id.map(|id| cx.tcx.hir.body(id)) {
|
2018-11-27 20:14:15 +00:00
|
|
|
get_binding_name(&body.arguments[idx]).map_or_else(
|
|
|
|
|| 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<'a, 'tcx: 'a>(
|
|
|
|
cx: &LateContext<'a, 'tcx>,
|
|
|
|
name: Name,
|
|
|
|
replace: &'static [(&'static str, &'static str)],
|
|
|
|
body: &'tcx Body,
|
|
|
|
) -> 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-07-12 07:30:57 +00:00
|
|
|
if let ExprKind::MethodCall(ref seg, _, ref args) = expr.node {
|
2017-10-08 08:51:44 +00:00
|
|
|
if args.len() == 1 && match_var(&args[0], self.name) {
|
2018-06-28 13:46:58 +00:00
|
|
|
if seg.ident.name == "capacity" {
|
2017-10-08 08:51:44 +00:00
|
|
|
self.abort = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for &(fn_name, suffix) in self.replace {
|
2018-06-28 13:46:58 +00:00
|
|
|
if seg.ident.name == fn_name {
|
2017-10-08 08:51:44 +00:00
|
|
|
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<Name> {
|
|
|
|
get_pat_name(&arg.pat)
|
|
|
|
}
|