Merge pull request #2079 from rust-lang-nursery/ptr_arg-vs-capacity
avoid linting `ptr_arg` if `.capacity()` is called.
This commit is contained in:
commit
6842a522bb
8 changed files with 154 additions and 103 deletions
|
|
@ -279,12 +279,19 @@ impl LiteralDigitGrouping {
|
|||
let fractional_part = &parts[1].chars().rev().collect::<String>();
|
||||
let _ = Self::do_lint(fractional_part)
|
||||
.map(|fractional_group_size| {
|
||||
let consistent = Self::parts_consistent(integral_group_size, fractional_group_size, parts[0].len(), parts[1].len());
|
||||
let consistent = Self::parts_consistent(integral_group_size,
|
||||
fractional_group_size,
|
||||
parts[0].len(),
|
||||
parts[1].len());
|
||||
if !consistent {
|
||||
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(), cx, &lit.span);
|
||||
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
&lit.span);
|
||||
}
|
||||
})
|
||||
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span));
|
||||
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
&lit.span));
|
||||
}
|
||||
})
|
||||
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span));
|
||||
|
|
@ -332,7 +339,8 @@ impl LiteralDigitGrouping {
|
|||
.windows(2)
|
||||
.all(|ps| ps[1] - ps[0] == group_size + 1)
|
||||
// number of digits to the left of the last group cannot be bigger than group size.
|
||||
&& (digits.len() - underscore_positions.last().expect("there's at least one element") <= group_size + 1);
|
||||
&& (digits.len() - underscore_positions.last()
|
||||
.expect("there's at least one element") <= group_size + 1);
|
||||
|
||||
if !consistent {
|
||||
return Err(WarningType::InconsistentDigitGrouping);
|
||||
|
|
|
|||
|
|
@ -15,16 +15,7 @@
|
|||
// *rustc*'s
|
||||
// [`missing_doc`].
|
||||
//
|
||||
// [`missing_doc`]:
|
||||
// https://github.
|
||||
// com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// rs#L246
|
||||
// [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246
|
||||
//
|
||||
|
||||
use rustc::hir;
|
||||
|
|
|
|||
|
|
@ -124,7 +124,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
else if args.len() == 2 && match_def_path(cx.tcx, fun_id, &paths::FMT_ARGUMENTV1_NEW) {
|
||||
if let ExprPath(ref qpath) = args[1].node {
|
||||
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, args[1].hir_id)) {
|
||||
if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() {
|
||||
if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD)
|
||||
&& !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() {
|
||||
span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Checks for usage of `&Vec[_]` and `&String`.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use rustc::hir::*;
|
||||
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use rustc::hir::map::NodeItem;
|
||||
|
|
@ -163,44 +164,48 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<
|
|||
], {
|
||||
ty_snippet = snippet_opt(cx, parameters.types[0].span);
|
||||
});
|
||||
let spans = get_spans(cx, opt_body_id, idx, "to_owned");
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
|
||||
with non-Vec-based slices.",
|
||||
|db| {
|
||||
if let Some(ref snippet) = ty_snippet {
|
||||
if let Ok(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
|
||||
with non-Vec-based slices.",
|
||||
|db| {
|
||||
if let Some(ref snippet) = ty_snippet {
|
||||
db.span_suggestion(arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", snippet));
|
||||
}
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion(clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(),
|
||||
|x| Cow::Owned(format!("change `{}` to", x))),
|
||||
suggestion.into());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
} else if match_type(cx, ty, &paths::STRING) {
|
||||
if let Ok(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&String` instead of `&str` involves a new object where a slice will do.",
|
||||
|db| {
|
||||
db.span_suggestion(arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", snippet));
|
||||
"&str".into());
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion_short(clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(),
|
||||
|x| Cow::Owned(format!("change `{}` to", x))),
|
||||
suggestion.into());
|
||||
}
|
||||
}
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion(clonespan,
|
||||
"change the `.clone()` to",
|
||||
suggestion);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else if match_type(cx, ty, &paths::STRING) {
|
||||
let spans = get_spans(cx, opt_body_id, idx, "to_string");
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&String` instead of `&str` involves a new object where a slice will do.",
|
||||
|db| {
|
||||
db.span_suggestion(arg.span,
|
||||
"change this to",
|
||||
"&str".into());
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion_short(clonespan,
|
||||
"change the `.clone` to ",
|
||||
suggestion);
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -229,38 +234,50 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<
|
|||
}
|
||||
}
|
||||
|
||||
fn get_spans(cx: &LateContext, opt_body_id: Option<BodyId>, idx: usize, fn_name: &'static str) -> Vec<(Span, String)> {
|
||||
fn get_spans(cx: &LateContext, opt_body_id: Option<BodyId>, idx: usize, replacements: &'static [(&'static str, &'static str)]) -> Result<Vec<(Span, Cow<'static, str>)>, ()> {
|
||||
if let Some(body) = opt_body_id.map(|id| cx.tcx.hir.body(id)) {
|
||||
get_binding_name(&body.arguments[idx]).map_or_else(Vec::new,
|
||||
|name| extract_clone_suggestions(cx, name, fn_name, body))
|
||||
get_binding_name(&body.arguments[idx]).map_or_else(|| Ok(vec![]),
|
||||
|name| extract_clone_suggestions(cx, name, replacements, body))
|
||||
} else {
|
||||
vec![]
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_clone_suggestions<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, fn_name: &'static str, body: &'tcx Body) -> Vec<(Span, String)> {
|
||||
fn extract_clone_suggestions<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, replace: &'static [(&'static str, &'static str)], body: &'tcx Body) -> Result<Vec<(Span, Cow<'static, str>)>, ()> {
|
||||
let mut visitor = PtrCloneVisitor {
|
||||
cx,
|
||||
name,
|
||||
fn_name,
|
||||
spans: vec![]
|
||||
replace,
|
||||
spans: vec![],
|
||||
abort: false,
|
||||
};
|
||||
visitor.visit_body(body);
|
||||
visitor.spans
|
||||
if visitor.abort { Err(()) } else { Ok(visitor.spans) }
|
||||
}
|
||||
|
||||
struct PtrCloneVisitor<'a, 'tcx: 'a> {
|
||||
cx: &'a LateContext<'a, 'tcx>,
|
||||
name: Name,
|
||||
fn_name: &'static str,
|
||||
spans: Vec<(Span, String)>,
|
||||
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; }
|
||||
if let ExprMethodCall(ref seg, _, ref args) = expr.node {
|
||||
if args.len() == 1 && match_var(&args[0], self.name) && seg.name == "clone" {
|
||||
self.spans.push((expr.span, format!("{}.{}()", snippet(self.cx, args[0].span, "_"), self.fn_name)));
|
||||
if args.len() == 1 && match_var(&args[0], self.name) {
|
||||
if seg.name == "capacity" {
|
||||
self.abort = true;
|
||||
return;
|
||||
}
|
||||
for &(fn_name, suffix) in self.replace {
|
||||
if seg.name == fn_name {
|
||||
self.spans.push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ macro_rules! define_Conf {
|
|||
#[serde(rename_all="kebab-case")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Conf {
|
||||
$(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)] pub $rust_name: define_Conf!(TY $($ty)+),)+
|
||||
$(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)]
|
||||
pub $rust_name: define_Conf!(TY $($ty)+),)+
|
||||
#[allow(dead_code)]
|
||||
#[serde(default)]
|
||||
third_party: Option<::toml::Value>,
|
||||
|
|
@ -91,10 +92,12 @@ macro_rules! define_Conf {
|
|||
mod $rust_name {
|
||||
use serde;
|
||||
use serde::Deserialize;
|
||||
pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<define_Conf!(TY $($ty)+), D::Error> {
|
||||
pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D)
|
||||
-> Result<define_Conf!(TY $($ty)+), D::Error> {
|
||||
type T = define_Conf!(TY $($ty)+);
|
||||
Ok(T::deserialize(deserializer).unwrap_or_else(|e| {
|
||||
::utils::conf::ERRORS.lock().expect("no threading here").push(::utils::conf::Error::Toml(e.to_string()));
|
||||
::utils::conf::ERRORS.lock().expect("no threading here")
|
||||
.push(::utils::conf::Error::Toml(e.to_string()));
|
||||
super::$rust_name()
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue