mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-18 03:25:55 +00:00
Merge pull request #807 from mcarton/vec
Add `for _ in vec![…]` to the `USELESS_VEC` lint
This commit is contained in:
commit
9cbfa5dbc9
26
src/loops.rs
26
src/loops.rs
@ -14,7 +14,7 @@ use syntax::ast;
|
||||
|
||||
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro,
|
||||
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then,
|
||||
unsugar_range, walk_ptrs_ty};
|
||||
unsugar_range, walk_ptrs_ty, recover_for_loop};
|
||||
use utils::{BTREEMAP_PATH, HASHMAP_PATH, LL_PATH, OPTION_PATH, RESULT_PATH, VEC_PATH};
|
||||
use utils::UnsugaredRange;
|
||||
|
||||
@ -641,30 +641,6 @@ impl<'a> Visitor<'a> for UsedVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/// Recover the essential nodes of a desugared for loop:
|
||||
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
|
||||
fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
|
||||
if_let_chain! {
|
||||
[
|
||||
let ExprMatch(ref iterexpr, ref arms, _) = expr.node,
|
||||
let ExprCall(_, ref iterargs) = iterexpr.node,
|
||||
iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
|
||||
let ExprLoop(ref block, _) = arms[0].body.node,
|
||||
block.stmts.is_empty(),
|
||||
let Some(ref loopexpr) = block.expr,
|
||||
let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node,
|
||||
innerarms.len() == 2 && innerarms[0].pats.len() == 1,
|
||||
let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node,
|
||||
somepats.len() == 1
|
||||
], {
|
||||
return Some((&somepats[0],
|
||||
&iterargs[0],
|
||||
&innerarms[0].body));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
struct VarVisitor<'v, 't: 'v> {
|
||||
cx: &'v LateContext<'v, 't>, // context reference
|
||||
var: Name, // var name to look for as index
|
||||
|
@ -800,3 +800,27 @@ pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty
|
||||
let new_b = b.subst(infcx.tcx, &infcx.parameter_environment.free_substs);
|
||||
infcx.can_equate(&new_a, &new_b).is_ok()
|
||||
}
|
||||
|
||||
/// Recover the essential nodes of a desugared for loop:
|
||||
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
|
||||
pub fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
|
||||
if_let_chain! {
|
||||
[
|
||||
let ExprMatch(ref iterexpr, ref arms, _) = expr.node,
|
||||
let ExprCall(_, ref iterargs) = iterexpr.node,
|
||||
iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
|
||||
let ExprLoop(ref block, _) = arms[0].body.node,
|
||||
block.stmts.is_empty(),
|
||||
let Some(ref loopexpr) = block.expr,
|
||||
let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node,
|
||||
innerarms.len() == 2 && innerarms[0].pats.len() == 1,
|
||||
let PatKind::TupleStruct(_, Some(ref somepats)) = innerarms[0].pats[0].node,
|
||||
somepats.len() == 1
|
||||
], {
|
||||
return Some((&somepats[0],
|
||||
&iterargs[0],
|
||||
&innerarms[0].body));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
60
src/vec.rs
60
src/vec.rs
@ -4,7 +4,7 @@ use rustc_front::hir::*;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ptr::P;
|
||||
use utils::VEC_FROM_ELEM_PATH;
|
||||
use utils::{is_expn_of, match_path, snippet, span_lint_and_then};
|
||||
use utils::{is_expn_of, match_path, recover_for_loop, snippet, span_lint_and_then};
|
||||
|
||||
/// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible.
|
||||
///
|
||||
@ -38,32 +38,42 @@ impl LateLintPass for UselessVec {
|
||||
let TypeVariants::TyRef(_, ref ty) = cx.tcx.expr_ty_adjusted(expr).sty,
|
||||
let TypeVariants::TySlice(..) = ty.ty.sty,
|
||||
let ExprAddrOf(_, ref addressee) = expr.node,
|
||||
let Some(vec_args) = unexpand_vec(cx, addressee)
|
||||
], {
|
||||
let snippet = match vec_args {
|
||||
VecArgs::Repeat(elem, len) => {
|
||||
format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
|
||||
}
|
||||
VecArgs::Vec(args) => {
|
||||
if let Some(last) = args.iter().last() {
|
||||
let span = Span {
|
||||
lo: args[0].span.lo,
|
||||
hi: last.span.hi,
|
||||
expn_id: args[0].span.expn_id,
|
||||
};
|
||||
|
||||
format!("&[{}]", snippet(cx, span, "..")).into()
|
||||
}
|
||||
else {
|
||||
"&[]".into()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| {
|
||||
db.span_suggestion(expr.span, "you can use a slice directly", snippet);
|
||||
});
|
||||
check_vec_macro(cx, expr, addressee);
|
||||
}}
|
||||
|
||||
// search for `for _ in vec![…]`
|
||||
if let Some((_, arg, _)) = recover_for_loop(expr) {
|
||||
check_vec_macro(cx, arg, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_vec_macro(cx: &LateContext, expr: &Expr, vec: &Expr) {
|
||||
if let Some(vec_args) = unexpand_vec(cx, vec) {
|
||||
let snippet = match vec_args {
|
||||
VecArgs::Repeat(elem, len) => {
|
||||
format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
|
||||
}
|
||||
VecArgs::Vec(args) => {
|
||||
if let Some(last) = args.iter().last() {
|
||||
let span = Span {
|
||||
lo: args[0].span.lo,
|
||||
hi: last.span.hi,
|
||||
expn_id: args[0].span.expn_id,
|
||||
};
|
||||
|
||||
format!("&[{}]", snippet(cx, span, "..")).into()
|
||||
}
|
||||
else {
|
||||
"&[]".into()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
span_lint_and_then(cx, USELESS_VEC, expr.span, "useless use of `vec!`", |db| {
|
||||
db.span_suggestion(expr.span, "you can use a slice directly", snippet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,4 +41,11 @@ fn main() {
|
||||
on_vec(&vec![]);
|
||||
on_vec(&vec![1, 2]);
|
||||
on_vec(&vec![1; 2]);
|
||||
|
||||
for a in vec![1, 2, 3] {
|
||||
//~^ ERROR useless use of `vec!`
|
||||
//~| HELP you can use
|
||||
//~| SUGGESTION for a in &[1, 2, 3] {
|
||||
println!("{}", a);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user