commit
ed589761e6
@ -120,13 +120,19 @@ fn to_const_range(
|
||||
array_size: ConstInt,
|
||||
) -> Option<(ConstInt, ConstInt)> {
|
||||
let start = match *start {
|
||||
Some(Some(&ty::Const { val: ConstVal::Integral(x), .. })) => x,
|
||||
Some(Some(&ty::Const {
|
||||
val: ConstVal::Integral(x),
|
||||
..
|
||||
})) => x,
|
||||
Some(_) => return None,
|
||||
None => ConstInt::U8(0),
|
||||
};
|
||||
|
||||
let end = match *end {
|
||||
Some(Some(&ty::Const { val: ConstVal::Integral(x), .. })) => if limits == RangeLimits::Closed {
|
||||
Some(Some(&ty::Const {
|
||||
val: ConstVal::Integral(x),
|
||||
..
|
||||
})) => if limits == RangeLimits::Closed {
|
||||
match x {
|
||||
ConstInt::U8(_) => (x + ConstInt::U8(1)),
|
||||
ConstInt::U16(_) => (x + ConstInt::U16(1)),
|
||||
|
@ -143,7 +143,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
|
||||
if_chain! {
|
||||
if parent_impl != ast::CRATE_NODE_ID;
|
||||
if let hir::map::Node::NodeItem(item) = cx.tcx.hir.get(parent_impl);
|
||||
if let hir::Item_::ItemImpl(_, _, _, _, Some(ref trait_ref), _, _) = item.node;
|
||||
if let hir::Item_::ItemImpl(_, _, _, _, Some(ref trait_ref), _, _) =
|
||||
item.node;
|
||||
if trait_ref.path.def.def_id() == trait_id;
|
||||
then { return; }
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use rustc::ty::{self, TyCtxt};
|
||||
use semver::Version;
|
||||
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
|
||||
use syntax::codemap::Span;
|
||||
use utils::{in_macro, match_def_path, paths, snippet_opt, span_lint, span_lint_and_then, opt_def_id};
|
||||
use utils::{in_macro, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then};
|
||||
|
||||
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
|
||||
/// unless the annotated function is empty or simply panics.
|
||||
|
@ -73,7 +73,7 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
|
||||
|
||||
const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
|
||||
const COMPLEX_BLOCK_MESSAGE: &str = "in an 'if' condition, avoid complex blocks or closures with blocks; \
|
||||
instead, move the block or closure higher and bind it with a 'let'";
|
||||
instead, move the block or closure higher and bind it with a 'let'";
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
@ -92,9 +92,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
|
||||
BLOCK_IN_IF_CONDITION_EXPR,
|
||||
check.span,
|
||||
BRACED_EXPR_MESSAGE,
|
||||
&format!("try\nif {} {} ... ",
|
||||
snippet_block(cx, ex.span, ".."),
|
||||
snippet_block(cx, then.span, "..")),
|
||||
&format!(
|
||||
"try\nif {} {} ... ",
|
||||
snippet_block(cx, ex.span, ".."),
|
||||
snippet_block(cx, then.span, "..")
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -111,9 +113,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
|
||||
BLOCK_IN_IF_CONDITION_STMT,
|
||||
check.span,
|
||||
COMPLEX_BLOCK_MESSAGE,
|
||||
&format!("try\nlet res = {};\nif res {} ... ",
|
||||
snippet_block(cx, block.span, ".."),
|
||||
snippet_block(cx, then.span, "..")),
|
||||
&format!(
|
||||
"try\nlet res = {};\nif res {} ... ",
|
||||
snippet_block(cx, block.span, ".."),
|
||||
snippet_block(cx, then.span, "..")
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -368,9 +368,9 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
||||
}
|
||||
// if the number of occurrences of a terminal decreases or any of the stats
|
||||
// decreases while none increases
|
||||
improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) ||
|
||||
(stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) ||
|
||||
(stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
|
||||
improvement |= (stats.terminals[i] > simplified_stats.terminals[i])
|
||||
|| (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops)
|
||||
|| (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
|
||||
}
|
||||
if improvement {
|
||||
improvements.push(suggestion);
|
||||
|
@ -2,8 +2,8 @@ use rustc::hir::*;
|
||||
use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use syntax::ast::{Name, UintTy};
|
||||
use utils::{contains_name, get_pat_name, match_type, paths, single_segment_path,
|
||||
snippet, span_lint_and_sugg, walk_ptrs_ty};
|
||||
use utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, snippet, span_lint_and_sugg,
|
||||
walk_ptrs_ty};
|
||||
|
||||
/// **What it does:** Checks for naive byte counts
|
||||
///
|
||||
|
@ -1,6 +1,6 @@
|
||||
use syntax::ast::{Item, ItemKind, TyKind, Ty};
|
||||
use rustc::lint::{LintPass, EarlyLintPass, LintArray, EarlyContext};
|
||||
use utils::{span_lint_and_then, in_macro};
|
||||
use syntax::ast::{Item, ItemKind, Ty, TyKind};
|
||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
use utils::{in_macro, span_lint_and_then};
|
||||
|
||||
/// **What it does:** Checks for constants with an explicit `'static` lifetime.
|
||||
///
|
||||
@ -41,10 +41,8 @@ impl StaticConst {
|
||||
TyKind::Array(ref ty, _) => {
|
||||
self.visit_type(&*ty, cx);
|
||||
},
|
||||
TyKind::Tup(ref tup) => {
|
||||
for tup_ty in tup {
|
||||
self.visit_type(&*tup_ty, cx);
|
||||
}
|
||||
TyKind::Tup(ref tup) => for tup_ty in tup {
|
||||
self.visit_type(&*tup_ty, cx);
|
||||
},
|
||||
// This is what we are looking for !
|
||||
TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
|
||||
@ -54,11 +52,15 @@ impl StaticConst {
|
||||
// Verify that the path is a str
|
||||
if lifetime.ident.name == "'static" {
|
||||
let mut sug: String = String::new();
|
||||
span_lint_and_then(cx,
|
||||
CONST_STATIC_LIFETIME,
|
||||
lifetime.span,
|
||||
"Constants have by default a `'static` lifetime",
|
||||
|db| {db.span_suggestion(lifetime.span,"consider removing `'static`",sug);});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
CONST_STATIC_LIFETIME,
|
||||
lifetime.span,
|
||||
"Constants have by default a `'static` lifetime",
|
||||
|db| {
|
||||
db.span_suggestion(lifetime.span, "consider removing `'static`", sug);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,9 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
|
||||
EXPL_IMPL_CLONE_ON_COPY,
|
||||
item.span,
|
||||
"you are implementing `Clone` explicitly on a `Copy` type",
|
||||
|db| { db.span_note(item.span, "consider deriving `Clone` or removing `Copy`"); },
|
||||
|db| {
|
||||
db.span_note(item.span, "consider deriving `Clone` or removing `Copy`");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
|
||||
End(CodeBlock(_)) | End(Code) => in_code = false,
|
||||
Start(Link(link, _)) => in_link = Some(link),
|
||||
End(Link(_, _)) => in_link = None,
|
||||
Start(_tag) | End(_tag) => (), // We don't care about other tags
|
||||
Start(_tag) | End(_tag) => (), // We don't care about other tags
|
||||
Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it
|
||||
SoftBreak => (),
|
||||
HardBreak => (),
|
||||
@ -273,8 +273,8 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) {
|
||||
s
|
||||
};
|
||||
|
||||
s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 &&
|
||||
s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
|
||||
s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
|
||||
&& s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
|
||||
}
|
||||
|
||||
fn has_underscore(s: &str) -> bool {
|
||||
@ -284,10 +284,12 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) {
|
||||
if let Ok(url) = Url::parse(word) {
|
||||
// try to get around the fact that `foo::bar` parses as a valid URL
|
||||
if !url.cannot_be_a_base() {
|
||||
span_lint(cx,
|
||||
DOC_MARKDOWN,
|
||||
span,
|
||||
"you should put bare URLs between `<`/`>` or make a proper Markdown link");
|
||||
span_lint(
|
||||
cx,
|
||||
DOC_MARKDOWN,
|
||||
span,
|
||||
"you should put bare URLs between `<`/`>` or make a proper Markdown link",
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use utils::{is_copy, match_def_path, paths, span_note_and_lint, opt_def_id};
|
||||
use utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint};
|
||||
|
||||
/// **What it does:** Checks for calls to `std::mem::drop` with a reference
|
||||
/// instead of an owned value.
|
||||
|
@ -55,8 +55,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
|
||||
.at(expr.span)
|
||||
.const_eval(param_env.and((did, substs)))
|
||||
{
|
||||
Ok(&ty::Const { val: ConstVal::Integral(Usize(Us64(i))), .. }) => u64::from(i as u32) != i,
|
||||
Ok(&ty::Const { val: ConstVal::Integral(Isize(Is64(i))), .. }) => i64::from(i as i32) != i,
|
||||
Ok(&ty::Const {
|
||||
val: ConstVal::Integral(Usize(Us64(i))),
|
||||
..
|
||||
}) => u64::from(i as u32) != i,
|
||||
Ok(&ty::Const {
|
||||
val: ConstVal::Integral(Isize(Is64(i))),
|
||||
..
|
||||
}) => i64::from(i as i32) != i,
|
||||
_ => false,
|
||||
};
|
||||
if bad {
|
||||
|
@ -159,8 +159,11 @@ fn check_variant(
|
||||
}
|
||||
for var in &def.variants {
|
||||
let name = var2str(var);
|
||||
if partial_match(item_name, &name) == item_name_chars &&
|
||||
name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) {
|
||||
if partial_match(item_name, &name) == item_name_chars
|
||||
&& name.chars()
|
||||
.nth(item_name_chars)
|
||||
.map_or(false, |c| !c.is_lowercase())
|
||||
{
|
||||
span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
|
||||
}
|
||||
if partial_rmatch(item_name, &name) == item_name_chars {
|
||||
|
@ -2,7 +2,7 @@ use rustc::lint::*;
|
||||
use rustc::hir;
|
||||
use rustc::ty;
|
||||
use syntax_pos::Span;
|
||||
use utils::{method_chain_args, match_def_path, span_lint_and_then, walk_ptrs_ty};
|
||||
use utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty};
|
||||
use utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
|
||||
|
||||
/// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
|
||||
@ -74,9 +74,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
|
||||
// check for `unwrap`
|
||||
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
||||
let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
|
||||
if match_type(self.tcx, reciever_ty, &OPTION) ||
|
||||
match_type(self.tcx, reciever_ty, &RESULT)
|
||||
{
|
||||
if match_type(self.tcx, reciever_ty, &OPTION) || match_type(self.tcx, reciever_ty, &RESULT) {
|
||||
self.result.push(expr.span);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use syntax::ast::LitKind;
|
||||
use utils::paths;
|
||||
use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty, opt_def_id};
|
||||
use utils::{is_expn_of, match_def_path, match_type, opt_def_id, resolve_node, span_lint, walk_ptrs_ty};
|
||||
|
||||
/// **What it does:** Checks for the use of `format!("string literal with no
|
||||
/// argument")` and `format!("{}", foo)` where `foo` is a string.
|
||||
|
@ -190,8 +190,8 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) {
|
||||
|
||||
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
|
||||
fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) {
|
||||
if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() &&
|
||||
unsugar_if(second).is_some()
|
||||
if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
|
||||
&& unsugar_if(second).is_some()
|
||||
{
|
||||
// where the else would be
|
||||
let else_span = first.span.between(second.span);
|
||||
|
@ -70,7 +70,7 @@ fn all_ones(v: &ConstInt) -> bool {
|
||||
ConstInt::U32(i) => i == !0,
|
||||
ConstInt::U64(i) => i == !0,
|
||||
ConstInt::U128(i) => i == !0,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
use rustc::lint::*;
|
||||
use syntax::ast::*;
|
||||
|
||||
use utils::{span_help_and_lint, in_external_macro};
|
||||
use utils::{in_external_macro, span_help_and_lint};
|
||||
|
||||
/// **What it does:** Checks for usage of `!` or `!=` in an if condition with an
|
||||
/// else branch.
|
||||
|
@ -3,7 +3,7 @@
|
||||
use rustc::lint::*;
|
||||
use syntax::ast::*;
|
||||
|
||||
use utils::{span_lint_and_then, snippet_opt};
|
||||
use utils::{snippet_opt, span_lint_and_then};
|
||||
|
||||
/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
|
||||
///
|
||||
@ -55,7 +55,7 @@ impl IntPlusOne {
|
||||
#[allow(cast_sign_loss)]
|
||||
fn check_lit(&self, lit: &Lit, target_value: i128) -> bool {
|
||||
if let LitKind::Int(value, ..) = lit.node {
|
||||
return value == (target_value as u128)
|
||||
return value == (target_value as u128);
|
||||
}
|
||||
false
|
||||
}
|
||||
@ -66,49 +66,76 @@ impl IntPlusOne {
|
||||
(BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
|
||||
match (lhskind.node, &lhslhs.node, &lhsrhs.node) {
|
||||
// `-1 + x`
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS),
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => {
|
||||
self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
|
||||
},
|
||||
// `x - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS),
|
||||
_ => None
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => {
|
||||
self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
// case where `... >= y + 1` or `... >= 1 + y`
|
||||
(BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => {
|
||||
(BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs))
|
||||
if rhskind.node == BinOpKind::Add =>
|
||||
{
|
||||
match (&rhslhs.node, &rhsrhs.node) {
|
||||
// `y + 1` and `1 + y`
|
||||
(&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS),
|
||||
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS),
|
||||
_ => None
|
||||
(&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => {
|
||||
self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
|
||||
},
|
||||
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => {
|
||||
self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
}
|
||||
// case where `x + 1 <= ...` or `1 + x <= ...`
|
||||
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => {
|
||||
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
|
||||
if lhskind.node == BinOpKind::Add =>
|
||||
{
|
||||
match (&lhslhs.node, &lhsrhs.node) {
|
||||
// `1 + x` and `x + 1`
|
||||
(&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS),
|
||||
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS),
|
||||
_ => None
|
||||
(&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => {
|
||||
self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
|
||||
},
|
||||
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => {
|
||||
self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
}
|
||||
// case where `... >= y - 1` or `... >= -1 + y`
|
||||
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
|
||||
match (rhskind.node, &rhslhs.node, &rhsrhs.node) {
|
||||
// `-1 + y`
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS),
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => {
|
||||
self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
|
||||
},
|
||||
// `y - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS),
|
||||
_ => None
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => {
|
||||
self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_recommendation(&self, cx: &EarlyContext, binop: BinOpKind, node: &Expr, other_side: &Expr, side: Side) -> Option<String> {
|
||||
fn generate_recommendation(
|
||||
&self,
|
||||
cx: &EarlyContext,
|
||||
binop: BinOpKind,
|
||||
node: &Expr,
|
||||
other_side: &Expr,
|
||||
side: Side,
|
||||
) -> Option<String> {
|
||||
let binop_string = match binop {
|
||||
BinOpKind::Ge => ">",
|
||||
BinOpKind::Le => "<",
|
||||
_ => return None
|
||||
_ => return None,
|
||||
};
|
||||
if let Some(snippet) = snippet_opt(cx, node.span) {
|
||||
if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
|
||||
@ -123,11 +150,7 @@ impl IntPlusOne {
|
||||
}
|
||||
|
||||
fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) {
|
||||
span_lint_and_then(cx,
|
||||
INT_PLUS_ONE,
|
||||
block.span,
|
||||
"Unnecessary `>= y + 1` or `x - 1 >=`",
|
||||
|db| {
|
||||
span_lint_and_then(cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", |db| {
|
||||
db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation);
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::ty;
|
||||
use rustc::hir::*;
|
||||
use utils::{match_def_path, paths, span_help_and_lint, opt_def_id};
|
||||
use utils::{match_def_path, opt_def_id, paths, span_help_and_lint};
|
||||
|
||||
/// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
|
||||
///
|
||||
@ -22,7 +22,8 @@ declare_lint! {
|
||||
|
||||
const ZERO_REF_SUMMARY: &str = "reference to zeroed memory";
|
||||
const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory";
|
||||
const HELP: &str = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
|
||||
const HELP: &str = "Creation of a null reference is undefined behavior; \
|
||||
see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
|
||||
|
||||
pub struct InvalidRef;
|
||||
|
||||
@ -41,9 +42,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
|
||||
if let ty::TyRef(..) = cx.tables.expr_ty(expr).sty;
|
||||
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
|
||||
then {
|
||||
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) {
|
||||
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) |
|
||||
match_def_path(cx.tcx, def_id, &paths::INIT)
|
||||
{
|
||||
ZERO_REF_SUMMARY
|
||||
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) {
|
||||
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) |
|
||||
match_def_path(cx.tcx, def_id, &paths::UNINIT)
|
||||
{
|
||||
UNINIT_REF_SUMMARY
|
||||
} else {
|
||||
return;
|
||||
|
@ -139,13 +139,9 @@ fn check_last_stmt_in_block(block: &Block) -> bool {
|
||||
// like `panic!()`
|
||||
match final_stmt.node {
|
||||
StmtKind::Expr(_) => false,
|
||||
StmtKind::Semi(ref expr) => {
|
||||
match expr.node {
|
||||
ExprKind::Break(_, _) |
|
||||
ExprKind::Continue(_) |
|
||||
ExprKind::Ret(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
StmtKind::Semi(ref expr) => match expr.node {
|
||||
ExprKind::Break(_, _) | ExprKind::Continue(_) | ExprKind::Ret(_) => false,
|
||||
_ => true,
|
||||
},
|
||||
_ => true,
|
||||
}
|
||||
|
@ -119,8 +119,8 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai
|
||||
.iter()
|
||||
.flat_map(|&i| cx.tcx.associated_items(i))
|
||||
.any(|i| {
|
||||
i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty" &&
|
||||
cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
|
||||
i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty"
|
||||
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
|
||||
});
|
||||
|
||||
if !is_empty_method_found {
|
||||
|
@ -11,8 +11,7 @@
|
||||
#![feature(inclusive_range_syntax, range_contains)]
|
||||
#![feature(macro_vis_matcher)]
|
||||
#![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)]
|
||||
|
||||
#![recursion_limit="256"]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
|
@ -16,7 +16,7 @@ use rustc::ty::{self, Ty};
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
use rustc_const_eval::ConstContext;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::iter::{Iterator, once};
|
||||
use std::iter::{once, Iterator};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use utils::sugg;
|
||||
@ -377,8 +377,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
|
||||
// check for never_loop
|
||||
match expr.node {
|
||||
ExprWhile(_, ref block, _) |
|
||||
ExprLoop(ref block, _, _) => {
|
||||
ExprWhile(_, ref block, _) | ExprLoop(ref block, _, _) => {
|
||||
let mut state = NeverLoopState {
|
||||
breaks: HashSet::new(),
|
||||
continues: HashSet::new(),
|
||||
@ -413,11 +412,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node {
|
||||
// ensure "if let" compatible match structure
|
||||
match *source {
|
||||
MatchSource::Normal |
|
||||
MatchSource::IfLetDesugar { .. } => {
|
||||
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
|
||||
arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
|
||||
is_simple_break_expr(&arms[1].body)
|
||||
MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
|
||||
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none()
|
||||
&& arms[1].pats.len() == 1 && arms[1].guard.is_none()
|
||||
&& is_simple_break_expr(&arms[1].body)
|
||||
{
|
||||
if in_external_macro(cx, expr.span) {
|
||||
return;
|
||||
@ -449,15 +447,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
}
|
||||
if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node {
|
||||
let pat = &arms[0].pats[0].node;
|
||||
if let (&PatKind::TupleStruct(ref qpath, ref pat_args, _),
|
||||
&ExprMethodCall(ref method_path, _, ref method_args)) = (pat, &match_expr.node)
|
||||
if let (
|
||||
&PatKind::TupleStruct(ref qpath, ref pat_args, _),
|
||||
&ExprMethodCall(ref method_path, _, ref method_args),
|
||||
) = (pat, &match_expr.node)
|
||||
{
|
||||
let iter_expr = &method_args[0];
|
||||
let lhs_constructor = last_path_segment(qpath);
|
||||
if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) &&
|
||||
lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0]) &&
|
||||
!is_iterator_used_after_while_let(cx, iter_expr) &&
|
||||
!is_nested(cx, expr, &method_args[0])
|
||||
if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR)
|
||||
&& lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0])
|
||||
&& !is_iterator_used_after_while_let(cx, iter_expr)
|
||||
&& !is_nested(cx, expr, &method_args[0])
|
||||
{
|
||||
let iterator = snippet(cx, method_args[0].span, "_");
|
||||
let loop_var = snippet(cx, pat_args[0].span, "_");
|
||||
@ -505,8 +505,7 @@ fn never_loop_block(block: &Block, state: &mut NeverLoopState) -> bool {
|
||||
|
||||
fn stmt_to_expr(stmt: &Stmt) -> Option<&Expr> {
|
||||
match stmt.node {
|
||||
StmtSemi(ref e, ..) |
|
||||
StmtExpr(ref e, ..) => Some(e),
|
||||
StmtSemi(ref e, ..) | StmtExpr(ref e, ..) => Some(e),
|
||||
StmtDecl(ref d, ..) => decl_to_expr(d),
|
||||
}
|
||||
}
|
||||
@ -528,9 +527,9 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool {
|
||||
ExprTupField(ref e, _) |
|
||||
ExprAddrOf(_, ref e) |
|
||||
ExprRepeat(ref e, _) => never_loop_expr(e, state),
|
||||
ExprArray(ref es) |
|
||||
ExprMethodCall(_, _, ref es) |
|
||||
ExprTup(ref es) => never_loop_expr_seq(&mut es.iter(), state),
|
||||
ExprArray(ref es) | ExprMethodCall(_, _, ref es) | ExprTup(ref es) => {
|
||||
never_loop_expr_seq(&mut es.iter(), state)
|
||||
},
|
||||
ExprCall(ref e, ref es) => never_loop_expr_seq(&mut once(&**e).chain(es.iter()), state),
|
||||
ExprBinary(_, ref e1, ref e2) |
|
||||
ExprAssign(ref e1, ref e2) |
|
||||
@ -567,12 +566,16 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool {
|
||||
},
|
||||
ExprBlock(ref b) => never_loop_block(b, state),
|
||||
ExprAgain(d) => {
|
||||
let id = d.target_id.opt_id().expect("target id can only be missing in the presence of compilation errors");
|
||||
let id = d.target_id
|
||||
.opt_id()
|
||||
.expect("target id can only be missing in the presence of compilation errors");
|
||||
state.continues.insert(id);
|
||||
false
|
||||
},
|
||||
ExprBreak(d, _) => {
|
||||
let id = d.target_id.opt_id().expect("target id can only be missing in the presence of compilation errors");
|
||||
let id = d.target_id
|
||||
.opt_id()
|
||||
.expect("target id can only be missing in the presence of compilation errors");
|
||||
state.breaks.insert(id);
|
||||
false
|
||||
},
|
||||
@ -586,12 +589,14 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn never_loop_expr_seq<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, state: &mut NeverLoopState) -> bool {
|
||||
es.map(|e| never_loop_expr(e, state)).fold(true, |a, b| a && b)
|
||||
fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, state: &mut NeverLoopState) -> bool {
|
||||
es.map(|e| never_loop_expr(e, state))
|
||||
.fold(true, |a, b| a && b)
|
||||
}
|
||||
|
||||
fn never_loop_expr_branch<'a, T: Iterator<Item=&'a Expr>>(e: &mut T, state: &mut NeverLoopState) -> bool {
|
||||
e.map(|e| never_loop_expr(e, state)).fold(false, |a, b| a || b)
|
||||
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr>>(e: &mut T, state: &mut NeverLoopState) -> bool {
|
||||
e.map(|e| never_loop_expr(e, state))
|
||||
.fold(false, |a, b| a || b)
|
||||
}
|
||||
|
||||
fn check_for_loop<'a, 'tcx>(
|
||||
@ -665,11 +670,9 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty) -> bool {
|
||||
fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> Option<FixedOffsetVar> {
|
||||
fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: ast::NodeId) -> Option<String> {
|
||||
match e.node {
|
||||
ExprLit(ref l) => {
|
||||
match l.node {
|
||||
ast::LitKind::Int(x, _ty) => Some(x.to_string()),
|
||||
_ => None,
|
||||
}
|
||||
ExprLit(ref l) => match l.node {
|
||||
ast::LitKind::Int(x, _ty) => Some(x.to_string()),
|
||||
_ => None,
|
||||
},
|
||||
ExprPath(..) if !same_var(cx, e, var) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())),
|
||||
_ => None,
|
||||
@ -683,29 +686,25 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var:
|
||||
}
|
||||
|
||||
let offset = match idx.node {
|
||||
ExprBinary(op, ref lhs, ref rhs) => {
|
||||
match op.node {
|
||||
BinOp_::BiAdd => {
|
||||
let offset_opt = if same_var(cx, lhs, var) {
|
||||
extract_offset(cx, rhs, var)
|
||||
} else if same_var(cx, rhs, var) {
|
||||
extract_offset(cx, lhs, var)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
ExprBinary(op, ref lhs, ref rhs) => match op.node {
|
||||
BinOp_::BiAdd => {
|
||||
let offset_opt = if same_var(cx, lhs, var) {
|
||||
extract_offset(cx, rhs, var)
|
||||
} else if same_var(cx, rhs, var) {
|
||||
extract_offset(cx, lhs, var)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
offset_opt.map(Offset::positive)
|
||||
},
|
||||
BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
|
||||
_ => None,
|
||||
}
|
||||
offset_opt.map(Offset::positive)
|
||||
},
|
||||
BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
|
||||
_ => None,
|
||||
},
|
||||
ExprPath(..) => {
|
||||
if same_var(cx, idx, var) {
|
||||
Some(Offset::positive("0".into()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
ExprPath(..) => if same_var(cx, idx, var) {
|
||||
Some(Offset::positive("0".into()))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
@ -777,12 +776,13 @@ fn get_indexed_assignments<'a, 'tcx>(
|
||||
.iter()
|
||||
.map(|stmt| match stmt.node {
|
||||
Stmt_::StmtDecl(..) => None,
|
||||
Stmt_::StmtExpr(ref e, _node_id) |
|
||||
Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
|
||||
Stmt_::StmtExpr(ref e, _node_id) | Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
|
||||
})
|
||||
.chain(expr.as_ref().into_iter().map(|e| {
|
||||
Some(get_assignment(cx, &*e, var))
|
||||
}))
|
||||
.chain(
|
||||
expr.as_ref()
|
||||
.into_iter()
|
||||
.map(|e| Some(get_assignment(cx, &*e, var))),
|
||||
)
|
||||
.filter_map(|op| op)
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap_or_else(|| vec![])
|
||||
@ -801,20 +801,18 @@ fn detect_manual_memcpy<'a, 'tcx>(
|
||||
expr: &'tcx Expr,
|
||||
) {
|
||||
if let Some(higher::Range {
|
||||
start: Some(start),
|
||||
ref end,
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
start: Some(start),
|
||||
ref end,
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
{
|
||||
// the var must be a single name
|
||||
if let PatKind::Binding(_, canonical_id, _, _) = pat.node {
|
||||
let print_sum = |arg1: &Offset, arg2: &Offset| -> String {
|
||||
match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) {
|
||||
("0", _, "0", _) => "".into(),
|
||||
("0", _, x, false) |
|
||||
(x, false, "0", false) => x.into(),
|
||||
("0", _, x, true) |
|
||||
(x, false, "0", true) => format!("-{}", x),
|
||||
("0", _, x, false) | (x, false, "0", false) => x.into(),
|
||||
("0", _, x, true) | (x, false, "0", true) => format!("-{}", x),
|
||||
(x, false, y, false) => format!("({} + {})", x, y),
|
||||
(x, false, y, true) => format!("({} - {})", x, y),
|
||||
(x, true, y, false) => format!("({} - {})", y, x),
|
||||
@ -897,10 +895,10 @@ fn check_for_loop_range<'a, 'tcx>(
|
||||
expr: &'tcx Expr,
|
||||
) {
|
||||
if let Some(higher::Range {
|
||||
start: Some(start),
|
||||
ref end,
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
start: Some(start),
|
||||
ref end,
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
{
|
||||
// the var must be a single name
|
||||
if let PatKind::Binding(_, canonical_id, ref ident, _) = pat.node {
|
||||
@ -917,9 +915,11 @@ fn check_for_loop_range<'a, 'tcx>(
|
||||
// linting condition: we only indexed one variable, and indexed it directly
|
||||
// (`indexed_directly` is subset of `indexed`)
|
||||
if visitor.indexed.len() == 1 && visitor.indexed_directly.len() == 1 {
|
||||
let (indexed, indexed_extent) = visitor.indexed_directly.into_iter().next().expect(
|
||||
"already checked that we have exactly 1 element",
|
||||
);
|
||||
let (indexed, indexed_extent) = visitor
|
||||
.indexed_directly
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("already checked that we have exactly 1 element");
|
||||
|
||||
// ensure that the indexed variable was declared before the loop, see #601
|
||||
if let Some(indexed_extent) = indexed_extent {
|
||||
@ -1024,10 +1024,10 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool {
|
||||
fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr, expr: &'tcx Expr) {
|
||||
// if this for loop is iterating over a two-sided range...
|
||||
if let Some(higher::Range {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
limits,
|
||||
}) = higher::range(arg)
|
||||
{
|
||||
// ...and both sides are compile-time constant integers...
|
||||
let parent_item = cx.tcx.hir.get_parent(arg.id);
|
||||
@ -1041,10 +1041,16 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
|
||||
// who think that this will iterate from the larger value to the
|
||||
// smaller value.
|
||||
let (sup, eq) = match (start_idx, end_idx) {
|
||||
(&ty::Const { val: ConstVal::Integral(start_idx), .. },
|
||||
&ty::Const { val: ConstVal::Integral(end_idx), .. }) => {
|
||||
(start_idx > end_idx, start_idx == end_idx)
|
||||
},
|
||||
(
|
||||
&ty::Const {
|
||||
val: ConstVal::Integral(start_idx),
|
||||
..
|
||||
},
|
||||
&ty::Const {
|
||||
val: ConstVal::Integral(end_idx),
|
||||
..
|
||||
},
|
||||
) => (start_idx > end_idx, start_idx == end_idx),
|
||||
_ => (false, false),
|
||||
};
|
||||
|
||||
@ -1132,7 +1138,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) {
|
||||
// If the length is greater than 32 no traits are implemented for array and
|
||||
// therefore we cannot use `&`.
|
||||
ty::TypeVariants::TyArray(_, size) if const_to_u64(size) > 32 => (),
|
||||
_ => lint_iter_method(cx, args, arg, method_name)
|
||||
_ => lint_iter_method(cx, args, arg, method_name),
|
||||
};
|
||||
} else {
|
||||
let object = snippet(cx, args[0].span, "_");
|
||||
@ -1219,14 +1225,14 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
|
||||
// For each candidate, check the parent block to see if
|
||||
// it's initialized to zero at the start of the loop.
|
||||
let map = &cx.tcx.hir;
|
||||
let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| {
|
||||
map.get_enclosing_scope(id)
|
||||
});
|
||||
let parent_scope = map.get_enclosing_scope(expr.id)
|
||||
.and_then(|id| map.get_enclosing_scope(id));
|
||||
if let Some(parent_id) = parent_scope {
|
||||
if let NodeBlock(block) = map.get(parent_id) {
|
||||
for (id, _) in visitor.states.iter().filter(
|
||||
|&(_, v)| *v == VarState::IncrOnce,
|
||||
)
|
||||
for (id, _) in visitor
|
||||
.states
|
||||
.iter()
|
||||
.filter(|&(_, v)| *v == VarState::IncrOnce)
|
||||
{
|
||||
let mut visitor2 = InitializeVisitor {
|
||||
cx: cx,
|
||||
@ -1273,12 +1279,10 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
|
||||
if pat.len() == 2 {
|
||||
let arg_span = arg.span;
|
||||
let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).sty {
|
||||
ty::TyRef(_, ref tam) => {
|
||||
match (&pat[0].node, &pat[1].node) {
|
||||
(key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl),
|
||||
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable),
|
||||
_ => return,
|
||||
}
|
||||
ty::TyRef(_, ref tam) => match (&pat[0].node, &pat[1].node) {
|
||||
(key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl),
|
||||
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable),
|
||||
_ => return,
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
@ -1322,14 +1326,11 @@ struct MutateDelegate {
|
||||
}
|
||||
|
||||
impl<'tcx> Delegate<'tcx> for MutateDelegate {
|
||||
fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) {
|
||||
}
|
||||
fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) {}
|
||||
|
||||
fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {
|
||||
}
|
||||
fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {}
|
||||
|
||||
fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) {
|
||||
}
|
||||
fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) {}
|
||||
|
||||
fn borrow(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) {
|
||||
if let ty::BorrowKind::MutBorrow = bk {
|
||||
@ -1355,8 +1356,7 @@ impl<'tcx> Delegate<'tcx> for MutateDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
fn decl_without_init(&mut self, _: NodeId, _: Span) {
|
||||
}
|
||||
fn decl_without_init(&mut self, _: NodeId, _: Span) {}
|
||||
}
|
||||
|
||||
impl<'tcx> MutateDelegate {
|
||||
@ -1366,8 +1366,16 @@ impl<'tcx> MutateDelegate {
|
||||
}
|
||||
|
||||
fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) {
|
||||
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(arg) {
|
||||
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
|
||||
if let Some(higher::Range {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
..
|
||||
}) = higher::range(arg)
|
||||
{
|
||||
let mut_ids = vec![
|
||||
check_for_mutability(cx, start),
|
||||
check_for_mutability(cx, end),
|
||||
];
|
||||
if mut_ids[0].is_some() || mut_ids[1].is_some() {
|
||||
let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
|
||||
mut_warn_with_span(cx, span_low);
|
||||
@ -1378,7 +1386,12 @@ fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) {
|
||||
|
||||
fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) {
|
||||
if let Some(sp) = span {
|
||||
span_lint(cx, MUT_RANGE_BOUND, sp, "attempt to mutate range bound within loop; note that the range of the loop is unchanged");
|
||||
span_lint(
|
||||
cx,
|
||||
MUT_RANGE_BOUND,
|
||||
sp,
|
||||
"attempt to mutate range bound within loop; note that the range of the loop is unchanged",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1405,7 +1418,12 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option<NodeId> {
|
||||
}
|
||||
|
||||
fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) {
|
||||
let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None };
|
||||
let mut delegate = MutateDelegate {
|
||||
node_id_low: bound_ids[0],
|
||||
node_id_high: bound_ids[1],
|
||||
span_low: None,
|
||||
span_high: None,
|
||||
};
|
||||
let def_id = def_id::DefId::local(body.hir_id.owner);
|
||||
let region_scope_tree = &cx.tcx.region_scope_tree(def_id);
|
||||
ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).walk_expr(body);
|
||||
@ -1430,7 +1448,7 @@ fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool {
|
||||
|
||||
struct UsedVisitor {
|
||||
var: ast::Name, // var to look for
|
||||
used: bool, // has the var been used otherwise?
|
||||
used: bool, // has the var been used otherwise?
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for UsedVisitor {
|
||||
@ -1652,12 +1670,9 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> {
|
||||
fn extract_first_expr(block: &Block) -> Option<&Expr> {
|
||||
match block.expr {
|
||||
Some(ref expr) if block.stmts.is_empty() => Some(expr),
|
||||
None if !block.stmts.is_empty() => {
|
||||
match block.stmts[0].node {
|
||||
StmtExpr(ref expr, _) |
|
||||
StmtSemi(ref expr, _) => Some(expr),
|
||||
StmtDecl(..) => None,
|
||||
}
|
||||
None if !block.stmts.is_empty() => match block.stmts[0].node {
|
||||
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr),
|
||||
StmtDecl(..) => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -1669,11 +1684,9 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> {
|
||||
fn is_simple_break_expr(expr: &Expr) -> bool {
|
||||
match expr.node {
|
||||
ExprBreak(dest, ref passed_expr) if dest.ident.is_none() && passed_expr.is_none() => true,
|
||||
ExprBlock(ref b) => {
|
||||
match extract_first_expr(b) {
|
||||
Some(subexpr) => is_simple_break_expr(subexpr),
|
||||
None => false,
|
||||
}
|
||||
ExprBlock(ref b) => match extract_first_expr(b) {
|
||||
Some(subexpr) => is_simple_break_expr(subexpr),
|
||||
None => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
@ -1684,7 +1697,7 @@ fn is_simple_break_expr(expr: &Expr) -> bool {
|
||||
// at the start of the loop.
|
||||
#[derive(PartialEq)]
|
||||
enum VarState {
|
||||
Initial, // Not examined yet
|
||||
Initial, // Not examined yet
|
||||
IncrOnce, // Incremented exactly once, may be a loop counter
|
||||
Declared, // Declared but not (yet) initialized to zero
|
||||
Warn,
|
||||
@ -1693,9 +1706,9 @@ enum VarState {
|
||||
|
||||
/// Scan a for loop for variables that are incremented exactly once.
|
||||
struct IncrementVisitor<'a, 'tcx: 'a> {
|
||||
cx: &'a LateContext<'a, 'tcx>, // context reference
|
||||
cx: &'a LateContext<'a, 'tcx>, // context reference
|
||||
states: HashMap<NodeId, VarState>, // incremented variables
|
||||
depth: u32, // depth of conditional expressions
|
||||
depth: u32, // depth of conditional expressions
|
||||
done: bool,
|
||||
}
|
||||
|
||||
@ -1749,7 +1762,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
|
||||
/// Check whether a variable is initialized to zero at the start of a loop.
|
||||
struct InitializeVisitor<'a, 'tcx: 'a> {
|
||||
cx: &'a LateContext<'a, 'tcx>, // context reference
|
||||
end_expr: &'tcx Expr, // the for loop. Stop scanning here.
|
||||
end_expr: &'tcx Expr, // the for loop. Stop scanning here.
|
||||
var_id: NodeId,
|
||||
state: VarState,
|
||||
name: Option<Name>,
|
||||
@ -1881,13 +1894,11 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool
|
||||
return false;
|
||||
}
|
||||
match cx.tcx.hir.find(parent) {
|
||||
Some(NodeExpr(expr)) => {
|
||||
match expr.node {
|
||||
ExprLoop(..) | ExprWhile(..) => {
|
||||
return true;
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
Some(NodeExpr(expr)) => match expr.node {
|
||||
ExprLoop(..) | ExprWhile(..) => {
|
||||
return true;
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
Some(NodeBlock(block)) => {
|
||||
let mut block_visitor = LoopNestVisitor {
|
||||
@ -1911,8 +1922,8 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum Nesting {
|
||||
Unknown, // no nesting detected yet
|
||||
RuledOut, // the iterator is initialized or assigned within scope
|
||||
Unknown, // no nesting detected yet
|
||||
RuledOut, // the iterator is initialized or assigned within scope
|
||||
LookFurther, // no nesting detected, no further walk required
|
||||
}
|
||||
|
||||
@ -1942,11 +1953,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
|
||||
return;
|
||||
}
|
||||
match expr.node {
|
||||
ExprAssign(ref path, _) |
|
||||
ExprAssignOp(_, ref path, _) => {
|
||||
if match_var(path, self.iterator) {
|
||||
self.nesting = RuledOut;
|
||||
}
|
||||
ExprAssign(ref path, _) | ExprAssignOp(_, ref path, _) => if match_var(path, self.iterator) {
|
||||
self.nesting = RuledOut;
|
||||
},
|
||||
_ => walk_expr(self, expr),
|
||||
}
|
||||
|
@ -412,7 +412,11 @@ fn check_match_ref_pats(cx: &LateContext, ex: &Expr, arms: &[Arm], source: Match
|
||||
}
|
||||
|
||||
/// Get all arms that are unbounded `PatRange`s.
|
||||
fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm], id: NodeId) -> Vec<SpannedRange<&'tcx ty::Const<'tcx>>> {
|
||||
fn all_ranges<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
arms: &'tcx [Arm],
|
||||
id: NodeId,
|
||||
) -> Vec<SpannedRange<&'tcx ty::Const<'tcx>>> {
|
||||
let parent_item = cx.tcx.hir.get_parent(id);
|
||||
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
|
||||
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
|
||||
@ -471,15 +475,39 @@ fn type_ranges(ranges: &[SpannedRange<&ty::Const>]) -> TypedRanges {
|
||||
ranges
|
||||
.iter()
|
||||
.filter_map(|range| match range.node {
|
||||
(&ty::Const { val: ConstVal::Integral(start), .. }, Bound::Included(&ty::Const { val: ConstVal::Integral(end), .. })) => Some(SpannedRange {
|
||||
(
|
||||
&ty::Const {
|
||||
val: ConstVal::Integral(start),
|
||||
..
|
||||
},
|
||||
Bound::Included(&ty::Const {
|
||||
val: ConstVal::Integral(end),
|
||||
..
|
||||
}),
|
||||
) => Some(SpannedRange {
|
||||
span: range.span,
|
||||
node: (start, Bound::Included(end)),
|
||||
}),
|
||||
(&ty::Const { val: ConstVal::Integral(start), .. }, Bound::Excluded(&ty::Const { val: ConstVal::Integral(end), .. })) => Some(SpannedRange {
|
||||
(
|
||||
&ty::Const {
|
||||
val: ConstVal::Integral(start),
|
||||
..
|
||||
},
|
||||
Bound::Excluded(&ty::Const {
|
||||
val: ConstVal::Integral(end),
|
||||
..
|
||||
}),
|
||||
) => Some(SpannedRange {
|
||||
span: range.span,
|
||||
node: (start, Bound::Excluded(end)),
|
||||
}),
|
||||
(&ty::Const { val: ConstVal::Integral(start), .. }, Bound::Unbounded) => Some(SpannedRange {
|
||||
(
|
||||
&ty::Const {
|
||||
val: ConstVal::Integral(start),
|
||||
..
|
||||
},
|
||||
Bound::Unbounded,
|
||||
) => Some(SpannedRange {
|
||||
span: range.span,
|
||||
node: (start, Bound::Unbounded),
|
||||
}),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::{Expr, ExprCall, ExprPath};
|
||||
use utils::{match_def_path, paths, span_lint, opt_def_id};
|
||||
use utils::{match_def_path, opt_def_id, paths, span_lint};
|
||||
|
||||
/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is
|
||||
/// `Drop`.
|
||||
|
@ -652,7 +652,8 @@ impl LintPass for Pass {
|
||||
GET_UNWRAP,
|
||||
STRING_EXTEND_CHARS,
|
||||
ITER_CLONED_COLLECT,
|
||||
USELESS_ASREF)
|
||||
USELESS_ASREF
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -781,7 +782,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
for &(ref conv, self_kinds) in &CONVENTIONS {
|
||||
if_chain! {
|
||||
if conv.check(&name.as_str());
|
||||
if !self_kinds.iter().any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy, &implitem.generics));
|
||||
if !self_kinds
|
||||
.iter()
|
||||
.any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy, &implitem.generics));
|
||||
then {
|
||||
let lint = if item.vis == hir::Visibility::Public {
|
||||
WRONG_PUB_SELF_CONVENTION
|
||||
@ -887,9 +890,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
|
||||
// don't lint for constant values
|
||||
// FIXME: can we `expect` here instead of match?
|
||||
let owner_def = cx.tcx.hir.get_parent_did(arg.id);
|
||||
let promotable = cx.tcx
|
||||
.rvalue_promotable_map(owner_def)
|
||||
[&arg.hir_id.local_id];
|
||||
let promotable = cx.tcx.rvalue_promotable_map(owner_def)[&arg.hir_id.local_id];
|
||||
if promotable {
|
||||
return;
|
||||
}
|
||||
@ -991,12 +992,8 @@ fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) {
|
||||
expr.span,
|
||||
"using '.clone()' on a ref-counted pointer",
|
||||
"try this",
|
||||
format!("{}::clone(&{})",
|
||||
caller_type,
|
||||
snippet(cx, arg.span, "_")
|
||||
)
|
||||
format!("{}::clone(&{})", caller_type, snippet(cx, arg.span, "_")),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1044,19 +1041,22 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr
|
||||
if let Def::Method(did) = cx.tables.qpath_def(path, fun.hir_id);
|
||||
if match_def_path(cx.tcx, did, &paths::CSTRING_NEW);
|
||||
then {
|
||||
span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span,
|
||||
"you are getting the inner pointer of a temporary `CString`",
|
||||
|db| {
|
||||
db.note("that pointer will be invalid outside this expression");
|
||||
db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
|
||||
});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
TEMPORARY_CSTRING_AS_PTR,
|
||||
expr.span,
|
||||
"you are getting the inner pointer of a temporary `CString`",
|
||||
|db| {
|
||||
db.note("that pointer will be invalid outside this expression");
|
||||
db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr]) {
|
||||
if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) &&
|
||||
derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
|
||||
if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC)
|
||||
&& derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
@ -1231,8 +1231,16 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::Expr]
|
||||
// lint message
|
||||
// comparing the snippet from source to raw text ("None") below is safe
|
||||
// because we already have checked the type.
|
||||
let arg = if unwrap_snippet == "None" { "None" } else { "a" };
|
||||
let suggest = if unwrap_snippet == "None" { "and_then(f)" } else { "map_or(a, f)" };
|
||||
let arg = if unwrap_snippet == "None" {
|
||||
"None"
|
||||
} else {
|
||||
"a"
|
||||
};
|
||||
let suggest = if unwrap_snippet == "None" {
|
||||
"and_then(f)"
|
||||
} else {
|
||||
"map_or(a, f)"
|
||||
};
|
||||
let msg = &format!(
|
||||
"called `map(f).unwrap_or({})` on an Option value. \
|
||||
This can be done more directly by calling `{}` instead",
|
||||
@ -1276,10 +1284,10 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
|
||||
// lint message
|
||||
let msg = if is_option {
|
||||
"called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \
|
||||
`map_or_else(g, f)` instead"
|
||||
`map_or_else(g, f)` instead"
|
||||
} else {
|
||||
"called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \
|
||||
`ok().map_or_else(g, f)` instead"
|
||||
`ok().map_or_else(g, f)` instead"
|
||||
};
|
||||
// get snippets for args to map() and unwrap_or_else()
|
||||
let map_snippet = snippet(cx, map_args[1].span, "..");
|
||||
@ -1323,7 +1331,6 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
|
||||
|
||||
/// lint use of `_.map_or(None, _)` for `Option`s
|
||||
fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_or_args: &'tcx [hir::Expr]) {
|
||||
|
||||
if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) {
|
||||
// check if the first non-self argument to map_or() is None
|
||||
let map_or_arg_is_none = if let hir::Expr_::ExprPath(ref qpath) = map_or_args[1].node {
|
||||
@ -1339,13 +1346,9 @@ fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
|
||||
let map_or_self_snippet = snippet(cx, map_or_args[0].span, "..");
|
||||
let map_or_func_snippet = snippet(cx, map_or_args[2].span, "..");
|
||||
let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
OPTION_MAP_OR_NONE,
|
||||
expr.span,
|
||||
msg,
|
||||
|db| { db.span_suggestion(expr.span, "try using and_then instead", hint); },
|
||||
);
|
||||
span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| {
|
||||
db.span_suggestion(expr.span, "try using and_then instead", hint);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1374,7 +1377,12 @@ fn lint_filter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
|
||||
}
|
||||
|
||||
/// lint use of `filter().map()` for `Iterators`
|
||||
fn lint_filter_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
|
||||
fn lint_filter_map<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
_filter_args: &'tcx [hir::Expr],
|
||||
_map_args: &'tcx [hir::Expr],
|
||||
) {
|
||||
// lint if caller of `.filter().map()` is an Iterator
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter(p).map(q)` on an `Iterator`. \
|
||||
@ -1384,7 +1392,12 @@ fn lint_filter_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
|
||||
}
|
||||
|
||||
/// lint use of `filter().map()` for `Iterators`
|
||||
fn lint_filter_map_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
|
||||
fn lint_filter_map_map<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
_filter_args: &'tcx [hir::Expr],
|
||||
_map_args: &'tcx [hir::Expr],
|
||||
) {
|
||||
// lint if caller of `.filter().map()` is an Iterator
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter_map(p).map(q)` on an `Iterator`. \
|
||||
@ -1394,7 +1407,12 @@ fn lint_filter_map_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Ex
|
||||
}
|
||||
|
||||
/// lint use of `filter().flat_map()` for `Iterators`
|
||||
fn lint_filter_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
|
||||
fn lint_filter_flat_map<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
_filter_args: &'tcx [hir::Expr],
|
||||
_map_args: &'tcx [hir::Expr],
|
||||
) {
|
||||
// lint if caller of `.filter().flat_map()` is an Iterator
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter(p).flat_map(q)` on an `Iterator`. \
|
||||
@ -1405,7 +1423,12 @@ fn lint_filter_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::E
|
||||
}
|
||||
|
||||
/// lint use of `filter_map().flat_map()` for `Iterators`
|
||||
fn lint_filter_map_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
|
||||
fn lint_filter_map_flat_map<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
_filter_args: &'tcx [hir::Expr],
|
||||
_map_args: &'tcx [hir::Expr],
|
||||
) {
|
||||
// lint if caller of `.filter_map().flat_map()` is an Iterator
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`. \
|
||||
@ -1476,7 +1499,13 @@ fn lint_binary_expr_with_method_call<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, i
|
||||
}
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints.
|
||||
fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool {
|
||||
fn lint_chars_cmp<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
info: &BinaryExprInfo,
|
||||
chain_methods: &[&str],
|
||||
lint: &'static Lint,
|
||||
suggest: &str,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprCall(ref fun, ref arg_char) = info.other.node;
|
||||
@ -1524,7 +1553,13 @@ fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprIn
|
||||
}
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
|
||||
fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool {
|
||||
fn lint_chars_cmp_with_unwrap<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
info: &BinaryExprInfo,
|
||||
chain_methods: &[&str],
|
||||
lint: &'static Lint,
|
||||
suggest: &str,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprLit(ref lit) = info.other.node;
|
||||
@ -1569,7 +1604,11 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hi
|
||||
let parent_item = cx.tcx.hir.get_parent(arg.id);
|
||||
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
|
||||
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
|
||||
if let Ok(&ty::Const { val: ConstVal::Str(r), .. }) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg) {
|
||||
if let Ok(&ty::Const {
|
||||
val: ConstVal::Str(r),
|
||||
..
|
||||
}) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg)
|
||||
{
|
||||
if r.len() == 1 {
|
||||
let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r));
|
||||
span_lint_and_then(
|
||||
@ -1577,7 +1616,9 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hi
|
||||
SINGLE_CHAR_PATTERN,
|
||||
arg.span,
|
||||
"single-character string constant used as pattern",
|
||||
|db| { db.span_suggestion(expr.span, "try using a char instead", hint); },
|
||||
|db| {
|
||||
db.span_suggestion(expr.span, "try using a char instead", hint);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1772,31 +1813,25 @@ impl SelfKind {
|
||||
fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[&str]) -> bool {
|
||||
single_segment_ty(ty).map_or(false, |seg| {
|
||||
generics.ty_params.iter().any(|param| {
|
||||
param.name == seg.name &&
|
||||
param
|
||||
.bounds
|
||||
.iter()
|
||||
.any(|bound| if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound {
|
||||
let path = &ptr.trait_ref.path;
|
||||
match_path(path, name) &&
|
||||
path.segments
|
||||
.last()
|
||||
.map_or(false, |s| {
|
||||
if let Some(ref params) = s.parameters {
|
||||
if params.parenthesized {
|
||||
false
|
||||
} else {
|
||||
params.types.len() == 1 &&
|
||||
(is_self_ty(¶ms.types[0])
|
||||
|| is_ty(&*params.types[0], self_ty))
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
false
|
||||
param.name == seg.name && param.bounds.iter().any(|bound| {
|
||||
if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound {
|
||||
let path = &ptr.trait_ref.path;
|
||||
match_path(path, name) && path.segments.last().map_or(false, |s| {
|
||||
if let Some(ref params) = s.parameters {
|
||||
if params.parenthesized {
|
||||
false
|
||||
} else {
|
||||
params.types.len() == 1
|
||||
&& (is_self_ty(¶ms.types[0]) || is_ty(&*params.types[0], self_ty))
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use consts::{constant_simple, Constant};
|
||||
use rustc::lint::*;
|
||||
use rustc::hir::*;
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
use utils::{match_def_path, paths, span_lint, opt_def_id};
|
||||
use utils::{match_def_path, opt_def_id, paths, span_lint};
|
||||
|
||||
/// **What it does:** Checks for expressions where `std::cmp::min` and `max` are
|
||||
/// used to clamp values, but switched so that the result is constant.
|
||||
|
@ -328,8 +328,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
}
|
||||
if let Some(name) = get_item_name(cx, expr) {
|
||||
let name = name.as_str();
|
||||
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") ||
|
||||
name.ends_with("_eq")
|
||||
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_")
|
||||
|| name.ends_with("_eq")
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -410,13 +410,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
|
||||
fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) {
|
||||
if !in_constant(cx, expr.id) {
|
||||
path.segments.last().map(|seg| if seg.name == "NAN" {
|
||||
span_lint(
|
||||
cx,
|
||||
CMP_NAN,
|
||||
expr.span,
|
||||
"doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead",
|
||||
);
|
||||
path.segments.last().map(|seg| {
|
||||
if seg.name == "NAN" {
|
||||
span_lint(
|
||||
cx,
|
||||
CMP_NAN,
|
||||
expr.span,
|
||||
"doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead",
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -426,7 +428,11 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
|
||||
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
|
||||
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
|
||||
let res = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(expr);
|
||||
if let Ok(&ty::Const { val: ConstVal::Float(val), .. }) = res {
|
||||
if let Ok(&ty::Const {
|
||||
val: ConstVal::Float(val),
|
||||
..
|
||||
}) = res
|
||||
{
|
||||
use std::cmp::Ordering;
|
||||
match val.ty {
|
||||
FloatTy::F32 => {
|
||||
@ -445,8 +451,8 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
|
||||
bits: u128::from(::std::f32::NEG_INFINITY.to_bits()),
|
||||
};
|
||||
|
||||
val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) ||
|
||||
val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
|
||||
val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal)
|
||||
|| val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
|
||||
},
|
||||
FloatTy::F64 => {
|
||||
let zero = ConstFloat {
|
||||
@ -464,8 +470,8 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
|
||||
bits: u128::from(::std::f64::NEG_INFINITY.to_bits()),
|
||||
};
|
||||
|
||||
val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) ||
|
||||
val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
|
||||
val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal)
|
||||
|| val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
@ -576,9 +582,7 @@ fn in_attributes_expansion(expr: &Expr) -> bool {
|
||||
/// Test whether `def` is a variable defined outside a macro.
|
||||
fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool {
|
||||
match *def {
|
||||
def::Def::Local(id) | def::Def::Upvar(id, _, _) => {
|
||||
!in_macro(cx.tcx.hir.span(id))
|
||||
},
|
||||
def::Def::Local(id) | def::Def::Upvar(id, _, _) => !in_macro(cx.tcx.hir.span(id)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
|
||||
if let Some(snippet) = snippet_opt(cx, inner.span) {
|
||||
db.span_suggestion(e.span, "change this to", snippet);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -255,13 +255,13 @@ struct LintData<'a> {
|
||||
const MSG_REDUNDANT_ELSE_BLOCK: &str = "This else block is redundant.\n";
|
||||
|
||||
const MSG_ELSE_BLOCK_NOT_NEEDED: &str = "There is no need for an explicit `else` block for this `if` \
|
||||
expression\n";
|
||||
expression\n";
|
||||
|
||||
const DROP_ELSE_BLOCK_AND_MERGE_MSG: &str = "Consider dropping the else clause and merging the code that \
|
||||
follows (in the loop) with the if block, like so:\n";
|
||||
follows (in the loop) with the if block, like so:\n";
|
||||
|
||||
const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving out the code in the else \
|
||||
block, like so:\n";
|
||||
block, like so:\n";
|
||||
|
||||
|
||||
fn emit_warning<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str, typ: LintType) {
|
||||
@ -332,22 +332,24 @@ fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext, data: &'a
|
||||
}
|
||||
|
||||
fn check_and_warn<'a>(ctx: &EarlyContext, expr: &'a ast::Expr) {
|
||||
with_loop_block(expr, |loop_block| for (i, stmt) in loop_block.stmts.iter().enumerate() {
|
||||
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
|
||||
let data = &LintData {
|
||||
stmt_idx: i,
|
||||
if_expr: if_expr,
|
||||
if_cond: cond,
|
||||
if_block: then_block,
|
||||
else_expr: else_expr,
|
||||
block_stmts: &loop_block.stmts,
|
||||
};
|
||||
if needless_continue_in_else(else_expr) {
|
||||
emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock);
|
||||
} else if is_first_block_stmt_continue(then_block) {
|
||||
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
|
||||
}
|
||||
});
|
||||
with_loop_block(expr, |loop_block| {
|
||||
for (i, stmt) in loop_block.stmts.iter().enumerate() {
|
||||
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
|
||||
let data = &LintData {
|
||||
stmt_idx: i,
|
||||
if_expr: if_expr,
|
||||
if_cond: cond,
|
||||
if_block: then_block,
|
||||
else_expr: else_expr,
|
||||
block_stmts: &loop_block.stmts,
|
||||
};
|
||||
if needless_continue_in_else(else_expr) {
|
||||
emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock);
|
||||
} else if is_first_block_stmt_continue(then_block) {
|
||||
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,13 +106,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
|
||||
|
||||
let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
|
||||
.filter(|p| !p.is_global())
|
||||
.filter_map(|pred| if let ty::Predicate::Trait(poly_trait_ref) = pred {
|
||||
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() {
|
||||
return None;
|
||||
.filter_map(|pred| {
|
||||
if let ty::Predicate::Trait(poly_trait_ref) = pred {
|
||||
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() {
|
||||
return None;
|
||||
}
|
||||
Some(poly_trait_ref)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(poly_trait_ref)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -108,55 +108,66 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
|
||||
// can't be implemented by default
|
||||
return;
|
||||
}
|
||||
if !cx.generics.expect("method must have generics").ty_params.is_empty() {
|
||||
// when the result of `new()` depends on a type parameter we should not require
|
||||
// an
|
||||
// impl of `Default`
|
||||
return;
|
||||
if !cx.generics
|
||||
.expect("method must have generics")
|
||||
.ty_params
|
||||
.is_empty()
|
||||
{
|
||||
// when the result of `new()` depends on a type parameter we should not require
|
||||
// an
|
||||
// impl of `Default`
|
||||
return;
|
||||
}
|
||||
if decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
|
||||
let self_ty = cx.tcx
|
||||
.type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)));
|
||||
if_chain! {
|
||||
if same_tys(cx, self_ty, return_ty(cx, id));
|
||||
if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
|
||||
if !implements_trait(cx, self_ty, default_trait_id, &[]);
|
||||
then {
|
||||
if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
|
||||
span_lint_and_then(cx,
|
||||
NEW_WITHOUT_DEFAULT_DERIVE, span,
|
||||
&format!("you should consider deriving a \
|
||||
`Default` implementation for `{}`",
|
||||
self_ty),
|
||||
|db| {
|
||||
db.suggest_item_with_attr(cx, sp, "try this", "#[derive(Default)]");
|
||||
});
|
||||
} else {
|
||||
span_lint_and_then(cx,
|
||||
NEW_WITHOUT_DEFAULT, span,
|
||||
&format!("you should consider adding a \
|
||||
`Default` implementation for `{}`",
|
||||
self_ty),
|
||||
|db| {
|
||||
db.suggest_prepend_item(cx,
|
||||
span,
|
||||
"try this",
|
||||
&format!(
|
||||
"impl Default for {} {{
|
||||
fn default() -> Self {{
|
||||
Self::new()
|
||||
}}
|
||||
}}",
|
||||
self_ty));
|
||||
});
|
||||
}
|
||||
}
|
||||
if same_tys(cx, self_ty, return_ty(cx, id));
|
||||
if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
|
||||
if !implements_trait(cx, self_ty, default_trait_id, &[]);
|
||||
then {
|
||||
if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEW_WITHOUT_DEFAULT_DERIVE,
|
||||
span,
|
||||
&format!("you should consider deriving a `Default` implementation for `{}`", self_ty),
|
||||
|db| {
|
||||
db.suggest_item_with_attr(cx, sp, "try this", "#[derive(Default)]");
|
||||
});
|
||||
} else {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEW_WITHOUT_DEFAULT,
|
||||
span,
|
||||
&format!("you should consider adding a `Default` implementation for `{}`", self_ty),
|
||||
|db| {
|
||||
db.suggest_prepend_item(
|
||||
cx,
|
||||
span,
|
||||
"try this",
|
||||
&create_new_without_default_suggest_msg(self_ty),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_new_without_default_suggest_msg(ty: Ty) -> String {
|
||||
#[rustfmt_skip]
|
||||
format!(
|
||||
"impl Default for {} {{
|
||||
fn default() -> Self {{
|
||||
Self::new()
|
||||
}}
|
||||
}}", ty)
|
||||
}
|
||||
|
||||
fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
|
||||
match ty.sty {
|
||||
ty::TyAdt(adt_def, substs) if adt_def.is_struct() => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::{BiAnd, BiOr, BlockCheckMode, Expr, Expr_, Stmt, StmtSemi, UnsafeSource};
|
||||
use utils::{in_macro, snippet_opt, span_lint, span_lint_and_sugg, has_drop};
|
||||
use utils::{has_drop, in_macro, snippet_opt, span_lint, span_lint_and_sugg};
|
||||
use std::ops::Deref;
|
||||
|
||||
/// **What it does:** Checks for statements which have no effect.
|
||||
@ -146,23 +146,24 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp
|
||||
Expr_::ExprTupField(ref inner, _) |
|
||||
Expr_::ExprAddrOf(_, ref inner) |
|
||||
Expr_::ExprBox(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
|
||||
Expr_::ExprStruct(_, ref fields, ref base) => {
|
||||
if has_drop(cx, expr) {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
fields
|
||||
.iter()
|
||||
.map(|f| &f.expr)
|
||||
.chain(base)
|
||||
.map(Deref::deref)
|
||||
.collect())
|
||||
}
|
||||
Expr_::ExprStruct(_, ref fields, ref base) => if has_drop(cx, expr) {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
fields
|
||||
.iter()
|
||||
.map(|f| &f.expr)
|
||||
.chain(base)
|
||||
.map(Deref::deref)
|
||||
.collect(),
|
||||
)
|
||||
},
|
||||
Expr_::ExprCall(ref callee, ref args) => if let Expr_::ExprPath(ref qpath) = callee.node {
|
||||
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
||||
match def {
|
||||
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) if !has_drop(cx, expr) => {
|
||||
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..)
|
||||
if !has_drop(cx, expr) =>
|
||||
{
|
||||
Some(args.iter().collect())
|
||||
},
|
||||
_ => None,
|
||||
|
@ -216,8 +216,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||
let second_last_e = existing_chars
|
||||
.next_back()
|
||||
.expect("we know we have at least three chars");
|
||||
if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' ||
|
||||
!interned_chars.zip(existing_chars).all(eq_or_numeric)
|
||||
if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_'
|
||||
|| !interned_chars.zip(existing_chars).all(eq_or_numeric)
|
||||
{
|
||||
// allowed similarity foo_x, foo_y
|
||||
// or too many chars differ (foo_x, boo_y) or (foox, booy)
|
||||
@ -232,8 +232,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||
let second_e = existing_chars
|
||||
.next()
|
||||
.expect("we know we have at least two chars");
|
||||
if !eq_or_numeric((second_i, second_e)) || second_i == '_' ||
|
||||
!interned_chars.zip(existing_chars).all(eq_or_numeric)
|
||||
if !eq_or_numeric((second_i, second_e)) || second_i == '_'
|
||||
|| !interned_chars.zip(existing_chars).all(eq_or_numeric)
|
||||
{
|
||||
// allowed similarity x_foo, y_foo
|
||||
// or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
|
||||
|
@ -81,8 +81,8 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp
|
||||
}
|
||||
} else {
|
||||
return; // The function is called with a literal
|
||||
// which is not a boolean literal. This is theoretically
|
||||
// possible, but not very likely.
|
||||
// which is not a boolean literal. This is theoretically
|
||||
// possible, but not very likely.
|
||||
}
|
||||
},
|
||||
_ => Argument::Unknown,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::hir::*;
|
||||
use rustc::lint::*;
|
||||
use syntax::ast::LitKind;
|
||||
use utils::{is_direct_expn_of, match_def_path, paths, resolve_node, span_lint, opt_def_id};
|
||||
use utils::{is_direct_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint};
|
||||
|
||||
/// **What it does:** Checks for missing parameters in `panic!`.
|
||||
///
|
||||
|
@ -6,7 +6,7 @@ use syntax::ast::LitKind;
|
||||
use syntax::symbol::InternedString;
|
||||
use syntax_pos::Span;
|
||||
use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint};
|
||||
use utils::{paths, opt_def_id};
|
||||
use utils::{opt_def_id, paths};
|
||||
|
||||
/// **What it does:** This lint warns when you using `println!("")` to
|
||||
/// print a newline.
|
||||
|
@ -8,8 +8,7 @@ use rustc::ty;
|
||||
use syntax::ast::NodeId;
|
||||
use syntax::codemap::Span;
|
||||
use syntax_pos::MultiSpan;
|
||||
use utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then,
|
||||
walk_ptrs_hir_ty};
|
||||
use utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
|
||||
use utils::ptr::get_spans;
|
||||
|
||||
/// **What it does:** This lint checks for function arguments of type `&String`
|
||||
@ -121,7 +120,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass {
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
|
||||
if let TraitItemKind::Method(ref sig, ref trait_method) = item.node {
|
||||
let body_id = if let TraitMethod::Provided(b) = *trait_method { Some(b) } else { None };
|
||||
let body_id = if let TraitMethod::Provided(b) = *trait_method {
|
||||
Some(b)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
check_fn(cx, &sig.decl, item.id, body_id);
|
||||
}
|
||||
}
|
||||
@ -173,17 +176,19 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<
|
||||
with non-Vec-based slices.",
|
||||
|db| {
|
||||
if let Some(ref snippet) = ty_snippet {
|
||||
db.span_suggestion(arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", 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());
|
||||
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) {
|
||||
@ -194,16 +199,18 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<
|
||||
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());
|
||||
db.span_suggestion(arg.span, "change this to", "&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());
|
||||
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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -82,12 +82,7 @@ pub struct Pass;
|
||||
|
||||
impl LintPass for Pass {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(
|
||||
ITERATOR_STEP_BY_ZERO,
|
||||
RANGE_ZIP_WITH_LEN,
|
||||
RANGE_PLUS_ONE,
|
||||
RANGE_MINUS_ONE
|
||||
)
|
||||
lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE)
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,14 +187,12 @@ fn has_step_by(cx: &LateContext, expr: &Expr) -> bool {
|
||||
|
||||
fn y_plus_one(expr: &Expr) -> Option<&Expr> {
|
||||
match expr.node {
|
||||
ExprBinary(Spanned { node: BiAdd, .. }, ref lhs, ref rhs) => {
|
||||
if is_integer_literal(lhs, 1) {
|
||||
Some(rhs)
|
||||
} else if is_integer_literal(rhs, 1) {
|
||||
Some(lhs)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
ExprBinary(Spanned { node: BiAdd, .. }, ref lhs, ref rhs) => if is_integer_literal(lhs, 1) {
|
||||
Some(rhs)
|
||||
} else if is_integer_literal(rhs, 1) {
|
||||
Some(lhs)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use std::error::Error;
|
||||
use syntax::ast::{LitKind, NodeId};
|
||||
use syntax::codemap::{BytePos, Span};
|
||||
use syntax::symbol::InternedString;
|
||||
use utils::{is_expn_of, match_def_path, match_type, paths, span_help_and_lint, span_lint, opt_def_id};
|
||||
use utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint};
|
||||
|
||||
/// **What it does:** Checks [regex](https://crates.io/crates/regex) creation
|
||||
/// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct
|
||||
@ -151,7 +151,10 @@ fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<Inte
|
||||
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
|
||||
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
|
||||
match ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(e) {
|
||||
Ok(&ty::Const { val: ConstVal::Str(r), .. }) => Some(r),
|
||||
Ok(&ty::Const {
|
||||
val: ConstVal::Str(r),
|
||||
..
|
||||
}) => Some(r),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +253,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
|
||||
snippet(cx, pattern_span, "_"),
|
||||
snippet(cx, expr.span, "..")
|
||||
),
|
||||
|db| { db.span_note(prev_span, "previous binding is here"); },
|
||||
|db| {
|
||||
db.span_note(prev_span, "previous binding is here");
|
||||
},
|
||||
);
|
||||
} else if contains_name(name, expr) {
|
||||
span_lint_and_then(
|
||||
@ -292,7 +294,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
|
||||
SHADOW_UNRELATED,
|
||||
span,
|
||||
&format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")),
|
||||
|db| { db.span_note(prev_span, "previous binding is here"); },
|
||||
|db| {
|
||||
db.span_note(prev_span, "previous binding is here");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -361,8 +365,8 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool {
|
||||
match expr.node {
|
||||
ExprBox(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
|
||||
ExprBlock(ref block) => {
|
||||
block.stmts.is_empty() &&
|
||||
block
|
||||
block.stmts.is_empty()
|
||||
&& block
|
||||
.expr
|
||||
.as_ref()
|
||||
.map_or(false, |e| is_self_shadow(name, e))
|
||||
|
@ -123,8 +123,8 @@ fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool {
|
||||
match src.node {
|
||||
ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
|
||||
ExprBlock(ref block) => {
|
||||
block.stmts.is_empty() &&
|
||||
block
|
||||
block.stmts.is_empty()
|
||||
&& block
|
||||
.expr
|
||||
.as_ref()
|
||||
.map_or(false, |expr| is_add(cx, expr, target))
|
||||
|
@ -156,7 +156,11 @@ fn check_suspicious_swap(cx: &LateContext, block: &Block) {
|
||||
let lhs0 = Sugg::hir_opt(cx, lhs0);
|
||||
let rhs0 = Sugg::hir_opt(cx, rhs0);
|
||||
let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
|
||||
(format!(" `{}` and `{}`", first, second), first.mut_addr().to_string(), second.mut_addr().to_string())
|
||||
(
|
||||
format!(" `{}` and `{}`", first, second),
|
||||
first.mut_addr().to_string(),
|
||||
second.mut_addr().to_string(),
|
||||
)
|
||||
} else {
|
||||
("".to_owned(), "".to_owned(), "".to_owned())
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ use rustc::hir::*;
|
||||
use std::borrow::Cow;
|
||||
use syntax::ast;
|
||||
use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then};
|
||||
use utils::{sugg, opt_def_id};
|
||||
use utils::{opt_def_id, sugg};
|
||||
|
||||
/// **What it does:** Checks for transmutes that can't ever be correct on any
|
||||
/// architecture.
|
||||
@ -190,7 +190,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
||||
if let ExprCall(ref path_expr, ref args) = e.node {
|
||||
if let ExprPath(ref qpath) = path_expr.node {
|
||||
if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path_expr.hir_id)) {
|
||||
|
||||
if match_def_path(cx.tcx, def_id, &paths::TRANSMUTE) {
|
||||
let from_ty = cx.tables.expr_ty(&args[0]);
|
||||
let to_ty = cx.tables.expr_ty(e);
|
||||
@ -217,15 +216,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
||||
db.span_suggestion(e.span, "try", sugg.to_string());
|
||||
},
|
||||
),
|
||||
(&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::TyRawPtr(_)) => span_lint_and_then(
|
||||
cx,
|
||||
USELESS_TRANSMUTE,
|
||||
e.span,
|
||||
"transmute from an integer to a pointer",
|
||||
|db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
|
||||
db.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()).to_string());
|
||||
},
|
||||
),
|
||||
(&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::TyRawPtr(_)) => {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
USELESS_TRANSMUTE,
|
||||
e.span,
|
||||
"transmute from an integer to a pointer",
|
||||
|db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
|
||||
db.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()).to_string());
|
||||
},
|
||||
)
|
||||
},
|
||||
(&ty::TyFloat(_), &ty::TyRef(..)) |
|
||||
(&ty::TyFloat(_), &ty::TyRawPtr(_)) |
|
||||
(&ty::TyChar, &ty::TyRef(..)) |
|
||||
@ -249,7 +250,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
||||
cx,
|
||||
CROSSPOINTER_TRANSMUTE,
|
||||
e.span,
|
||||
&format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", from_ty, to_ty),
|
||||
&format!(
|
||||
"transmute from a type (`{}`) to a pointer to that type (`{}`)",
|
||||
from_ty,
|
||||
to_ty
|
||||
),
|
||||
),
|
||||
(&ty::TyRawPtr(from_pty), &ty::TyRef(_, to_ref_ty)) => span_lint_and_then(
|
||||
cx,
|
||||
@ -257,7 +262,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
||||
e.span,
|
||||
&format!(
|
||||
"transmute from a pointer type (`{}`) to a reference type \
|
||||
(`{}`)",
|
||||
(`{}`)",
|
||||
from_ty,
|
||||
to_ty
|
||||
),
|
||||
@ -291,8 +296,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
db.span_suggestion(e.span, "consider using", format!("std::char::from_u32({}).unwrap()", arg.to_string()));
|
||||
}
|
||||
db.span_suggestion(
|
||||
e.span,
|
||||
"consider using",
|
||||
format!("std::char::from_u32({}).unwrap()", arg.to_string()),
|
||||
);
|
||||
},
|
||||
),
|
||||
(&ty::TyRef(_, ref ref_from), &ty::TyRef(_, ref ref_to)) => {
|
||||
if_chain! {
|
||||
@ -326,34 +335,49 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
||||
}
|
||||
}
|
||||
},
|
||||
(&ty::TyInt(ast::IntTy::I8), &ty::TyBool) |
|
||||
(&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_BOOL,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `bool`", from_ty),
|
||||
|db| {
|
||||
let arg = sugg::Sugg::hir(cx, &args[0], "..");
|
||||
let zero = sugg::Sugg::NonParen(Cow::from("0"));
|
||||
db.span_suggestion(e.span, "consider using", sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string());
|
||||
}
|
||||
),
|
||||
(&ty::TyInt(_), &ty::TyFloat(_)) |
|
||||
(&ty::TyUint(_), &ty::TyFloat(_)) => span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_FLOAT,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
|
||||
|db| {
|
||||
let arg = sugg::Sugg::hir(cx, &args[0], "..");
|
||||
let arg = if let ty::TyInt(int_ty) = from_ty.sty {
|
||||
arg.as_ty(format!("u{}", int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string())))
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
db.span_suggestion(e.span, "consider using", format!("{}::from_bits({})", to_ty, arg.to_string()));
|
||||
}
|
||||
),
|
||||
(&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | (&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_BOOL,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `bool`", from_ty),
|
||||
|db| {
|
||||
let arg = sugg::Sugg::hir(cx, &args[0], "..");
|
||||
let zero = sugg::Sugg::NonParen(Cow::from("0"));
|
||||
db.span_suggestion(
|
||||
e.span,
|
||||
"consider using",
|
||||
sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string(),
|
||||
);
|
||||
},
|
||||
)
|
||||
},
|
||||
(&ty::TyInt(_), &ty::TyFloat(_)) | (&ty::TyUint(_), &ty::TyFloat(_)) => {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_FLOAT,
|
||||
e.span,
|
||||
&format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
|
||||
|db| {
|
||||
let arg = sugg::Sugg::hir(cx, &args[0], "..");
|
||||
let arg = if let ty::TyInt(int_ty) = from_ty.sty {
|
||||
arg.as_ty(format!(
|
||||
"u{}",
|
||||
int_ty
|
||||
.bit_width()
|
||||
.map_or_else(|| "size".to_string(), |v| v.to_string())
|
||||
))
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
db.span_suggestion(
|
||||
e.span,
|
||||
"consider using",
|
||||
format!("{}::from_bits({})", to_ty, arg.to_string()),
|
||||
);
|
||||
},
|
||||
)
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
|
@ -166,11 +166,13 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
|
||||
if let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(vec.id)));
|
||||
if match_def_path(cx.tcx, did, &paths::VEC);
|
||||
then {
|
||||
span_help_and_lint(cx,
|
||||
BOX_VEC,
|
||||
ast_ty.span,
|
||||
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
|
||||
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
|
||||
span_help_and_lint(
|
||||
cx,
|
||||
BOX_VEC,
|
||||
ast_ty.span,
|
||||
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
|
||||
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
|
||||
);
|
||||
return; // don't recurse into the type
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +245,9 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
|
||||
// FIXME: also check int type
|
||||
LitKind::Int(i, _) => println!(" if let LitKind::Int({}, _) = {}.node;", i, lit_pat),
|
||||
LitKind::Float(..) => println!(" if let LitKind::Float(..) = {}.node;", lit_pat),
|
||||
LitKind::FloatUnsuffixed(_) => println!(" if let LitKind::FloatUnsuffixed(_) = {}.node;", lit_pat),
|
||||
LitKind::FloatUnsuffixed(_) => {
|
||||
println!(" if let LitKind::FloatUnsuffixed(_) = {}.node;", lit_pat)
|
||||
},
|
||||
LitKind::ByteStr(ref vec) => {
|
||||
let vec_pat = self.next("vec");
|
||||
println!(" if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat);
|
||||
|
@ -6,7 +6,7 @@
|
||||
use rustc::hir;
|
||||
use rustc::lint::LateContext;
|
||||
use syntax::ast;
|
||||
use utils::{is_expn_of, match_def_path, match_qpath, paths, resolve_node, opt_def_id};
|
||||
use utils::{is_expn_of, match_def_path, match_qpath, opt_def_id, paths, resolve_node};
|
||||
|
||||
/// Convert a hir binary operator to the corresponding `ast` type.
|
||||
pub fn binop(op: hir::BinOp_) -> ast::BinOpKind {
|
||||
@ -48,10 +48,7 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
|
||||
/// Find the field named `name` in the field. Always return `Some` for
|
||||
/// convenience.
|
||||
fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> {
|
||||
let expr = &fields
|
||||
.iter()
|
||||
.find(|field| field.name.node == name)?
|
||||
.expr;
|
||||
let expr = &fields.iter().find(|field| field.name.node == name)?.expr;
|
||||
|
||||
Some(expr)
|
||||
}
|
||||
@ -72,8 +69,8 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
|
||||
None
|
||||
}
|
||||
},
|
||||
hir::ExprStruct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD) ||
|
||||
match_qpath(path, &paths::RANGE_FROM)
|
||||
hir::ExprStruct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD)
|
||||
|| match_qpath(path, &paths::RANGE_FROM)
|
||||
{
|
||||
Some(Range {
|
||||
start: Some(get_field("start", fields)?),
|
||||
|
@ -55,8 +55,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
|
||||
/// Check whether two blocks are the same.
|
||||
pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
|
||||
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) &&
|
||||
both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
|
||||
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
|
||||
&& both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
|
||||
}
|
||||
|
||||
pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool {
|
||||
@ -81,14 +81,14 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
},
|
||||
(&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r),
|
||||
(&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => {
|
||||
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) ||
|
||||
swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
|
||||
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|
||||
|| swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
|
||||
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|
||||
})
|
||||
},
|
||||
(&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => {
|
||||
both(&li.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str()) &&
|
||||
both(le, re, |l, r| self.eq_expr(l, r))
|
||||
both(&li.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str())
|
||||
&& both(le, re, |l, r| self.eq_expr(l, r))
|
||||
},
|
||||
(&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
|
||||
(&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => {
|
||||
@ -109,22 +109,22 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
},
|
||||
(&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
|
||||
ls == rs && self.eq_expr(le, re) && over(la, ra, |l, r| {
|
||||
self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
|
||||
over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
|
||||
self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r))
|
||||
&& over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
|
||||
})
|
||||
},
|
||||
(&ExprMethodCall(ref l_path, _, ref l_args), &ExprMethodCall(ref r_path, _, ref r_args)) => {
|
||||
!self.ignore_fn && l_path == r_path && self.eq_exprs(l_args, r_args)
|
||||
},
|
||||
(&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => {
|
||||
self.eq_expr(le, re) &&
|
||||
self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
|
||||
self.eq_expr(le, re)
|
||||
&& self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
|
||||
},
|
||||
(&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
|
||||
(&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r),
|
||||
(&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
|
||||
self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
|
||||
over(lf, rf, |l, r| self.eq_field(l, r))
|
||||
self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r))
|
||||
&& over(lf, rf, |l, r| self.eq_field(l, r))
|
||||
},
|
||||
(&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
|
||||
(&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
|
||||
@ -169,8 +169,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
},
|
||||
(&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
|
||||
(&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
|
||||
over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) &&
|
||||
both(li, ri, |l, r| self.eq_pat(l, r))
|
||||
over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r))
|
||||
&& both(li, ri, |l, r| self.eq_pat(l, r))
|
||||
},
|
||||
(&PatKind::Wild, &PatKind::Wild) => true,
|
||||
_ => false,
|
||||
@ -190,18 +190,18 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn eq_path(&self, left: &Path, right: &Path) -> bool {
|
||||
left.is_global() == right.is_global() &&
|
||||
over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
|
||||
left.is_global() == right.is_global()
|
||||
&& over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
|
||||
}
|
||||
|
||||
fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool {
|
||||
if !(left.parenthesized || right.parenthesized) {
|
||||
over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r)) &&
|
||||
over(&left.types, &right.types, |l, r| self.eq_ty(l, r)) &&
|
||||
over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
|
||||
over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r))
|
||||
&& over(&left.types, &right.types, |l, r| self.eq_ty(l, r))
|
||||
&& over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
|
||||
} else if left.parenthesized && right.parenthesized {
|
||||
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) &&
|
||||
both(
|
||||
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
|
||||
&& both(
|
||||
&Some(&left.bindings[0].ty),
|
||||
&Some(&right.bindings[0].ty),
|
||||
|l, r| self.eq_ty(l, r),
|
||||
@ -220,7 +220,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
match (&left.parameters, &right.parameters) {
|
||||
(&None, &None) => true,
|
||||
(&Some(ref l), &Some(ref r)) => self.eq_path_parameters(l, r),
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,8 +228,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
|
||||
match (&left.node, &right.node) {
|
||||
(&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
|
||||
(&TyArray(ref lt, ll_id), &TyArray(ref rt, rl_id)) => {
|
||||
self.eq_ty(lt, rt) &&
|
||||
self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
|
||||
self.eq_ty(lt, rt)
|
||||
&& self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
|
||||
},
|
||||
(&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
|
||||
(&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {
|
||||
|
@ -125,8 +125,8 @@ pub fn match_def_path(tcx: TyCtxt, def_id: DefId, path: &[&str]) -> bool {
|
||||
|
||||
tcx.push_item_path(&mut apb, def_id);
|
||||
|
||||
apb.names.len() == path.len() &&
|
||||
apb.names
|
||||
apb.names.len() == path.len()
|
||||
&& apb.names
|
||||
.into_iter()
|
||||
.zip(path.iter())
|
||||
.all(|(a, &b)| *a == *b)
|
||||
@ -201,8 +201,8 @@ pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool {
|
||||
QPath::Resolved(_, ref path) => match_path(path, segments),
|
||||
QPath::TypeRelative(ref ty, ref segment) => match ty.node {
|
||||
TyPath(ref inner_path) => {
|
||||
!segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) &&
|
||||
segment.name == segments[segments.len() - 1]
|
||||
!segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)])
|
||||
&& segment.name == segments[segments.len() - 1]
|
||||
},
|
||||
_ => false,
|
||||
},
|
||||
@ -233,7 +233,6 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
|
||||
|
||||
/// Get the definition associated to a path.
|
||||
pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
|
||||
|
||||
let crates = cx.tcx.crates();
|
||||
let krate = crates
|
||||
.iter()
|
||||
@ -269,7 +268,11 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
|
||||
}
|
||||
|
||||
pub fn const_to_u64(c: &ty::Const) -> u64 {
|
||||
c.val.to_const_int().expect("eddyb says this works").to_u64().expect("see previous expect")
|
||||
c.val
|
||||
.to_const_int()
|
||||
.expect("eddyb says this works")
|
||||
.to_u64()
|
||||
.expect("see previous expect")
|
||||
}
|
||||
|
||||
/// Convenience function to get the `DefId` of a trait by path.
|
||||
@ -473,10 +476,12 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> {
|
||||
Cow::Owned(
|
||||
s.lines()
|
||||
.enumerate()
|
||||
.map(|(i, l)| if (ignore_first && i == 0) || l.is_empty() {
|
||||
l
|
||||
} else {
|
||||
l.split_at(x).1
|
||||
.map(|(i, l)| {
|
||||
if (ignore_first && i == 0) || l.is_empty() {
|
||||
l
|
||||
} else {
|
||||
l.split_at(x).1
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
@ -494,12 +499,13 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> {
|
||||
if node_id == parent_id {
|
||||
return None;
|
||||
}
|
||||
map.find(parent_id)
|
||||
.and_then(|node| if let Node::NodeExpr(parent) = node {
|
||||
map.find(parent_id).and_then(|node| {
|
||||
if let Node::NodeExpr(parent) = node {
|
||||
Some(parent)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> {
|
||||
@ -598,7 +604,9 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
|
||||
help: &str,
|
||||
sugg: String,
|
||||
) {
|
||||
span_lint_and_then(cx, lint, sp, msg, |db| { db.span_suggestion(sp, help, sugg); });
|
||||
span_lint_and_then(cx, lint, sp, msg, |db| {
|
||||
db.span_suggestion(sp, help, sugg);
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a suggestion made from several `span → replacement`.
|
||||
@ -609,7 +617,7 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
|
||||
/// the whole suggestion.
|
||||
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder, help_msg: String, sugg: I)
|
||||
where
|
||||
I: IntoIterator<Item=(Span, String)>,
|
||||
I: IntoIterator<Item = (Span, String)>,
|
||||
{
|
||||
let sugg = rustc_errors::CodeSuggestion {
|
||||
substitution_parts: sugg.into_iter()
|
||||
@ -629,9 +637,8 @@ where
|
||||
/// Return the base type for HIR references and pointers.
|
||||
pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty {
|
||||
match ty.node {
|
||||
TyPtr(ref mut_ty) |
|
||||
TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
|
||||
_ => ty
|
||||
TyPtr(ref mut_ty) | TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,11 +267,11 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
|
||||
/// in the direction
|
||||
/// `dir`.
|
||||
fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
|
||||
other.precedence() < op.precedence() ||
|
||||
(other.precedence() == op.precedence() &&
|
||||
((op != other && associativity(op) != dir) ||
|
||||
(op == other && associativity(op) != Associativity::Both))) ||
|
||||
is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op)
|
||||
other.precedence() < op.precedence()
|
||||
|| (other.precedence() == op.precedence()
|
||||
&& ((op != other && associativity(op) != dir)
|
||||
|| (op == other && associativity(op) != Associativity::Both)))
|
||||
|| is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op)
|
||||
}
|
||||
|
||||
let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
|
||||
@ -472,11 +472,13 @@ impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_error
|
||||
let mut first = true;
|
||||
let new_item = new_item
|
||||
.lines()
|
||||
.map(|l| if first {
|
||||
first = false;
|
||||
format!("{}\n", l)
|
||||
} else {
|
||||
format!("{}{}\n", indent, l)
|
||||
.map(|l| {
|
||||
if first {
|
||||
first = false;
|
||||
format!("{}\n", l)
|
||||
} else {
|
||||
format!("{}{}\n", indent, l)
|
||||
}
|
||||
})
|
||||
.collect::<String>();
|
||||
|
||||
|
@ -52,7 +52,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)));
|
||||
then {
|
||||
// report the error around the `vec!` not inside `<std macros>:`
|
||||
let span = arg.span.ctxt().outer().expn_info().map(|info| info.call_site).expect("unable to get call_site");
|
||||
let span = arg.span
|
||||
.ctxt()
|
||||
.outer()
|
||||
.expn_info()
|
||||
.map(|info| info.call_site)
|
||||
.expect("unable to get call_site");
|
||||
check_vec_macro(cx, &vec_args, span);
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
| (_, FloatWidth::F64) => "f64",
|
||||
_ => "f32"
|
||||
};
|
||||
span_help_and_lint(cx, ZERO_DIVIDED_BY_ZERO, expr.span,
|
||||
span_help_and_lint(
|
||||
cx,
|
||||
ZERO_DIVIDED_BY_ZERO,
|
||||
expr.span,
|
||||
"constant division of 0.0 with 0.0 will always result in NaN",
|
||||
&format!("Consider using `std::{}::NAN` if you would like a constant representing NaN", float_type));
|
||||
&format!(
|
||||
"Consider using `std::{}::NAN` if you would like a constant representing NaN",
|
||||
float_type,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
max_width = 120
|
||||
ideal_width = 100
|
||||
comment_width = 100
|
||||
fn_call_width = 80
|
||||
match_block_trailing_comma = true
|
||||
fn_args_layout = "Block"
|
||||
closure_block_indent_threshold = 0
|
||||
fn_return_indent = "WithWhereClause"
|
||||
wrap_comments = true
|
||||
|
@ -154,9 +154,7 @@ pub fn main() {
|
||||
.and_then(|out| String::from_utf8(out.stdout).ok())
|
||||
.map(|s| s.trim().to_owned())
|
||||
})
|
||||
.expect(
|
||||
"need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
|
||||
)
|
||||
.expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust")
|
||||
};
|
||||
|
||||
rustc_driver::in_rustc_thread(|| {
|
||||
@ -176,7 +174,9 @@ pub fn main() {
|
||||
let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
|
||||
orig_args.clone()
|
||||
} else {
|
||||
orig_args.clone().into_iter()
|
||||
orig_args
|
||||
.clone()
|
||||
.into_iter()
|
||||
.chain(Some("--sysroot".to_owned()))
|
||||
.chain(Some(sys_root))
|
||||
.collect()
|
||||
@ -185,8 +185,10 @@ pub fn main() {
|
||||
// this check ensures that dependencies are built but not linted and the final
|
||||
// crate is
|
||||
// linted but not built
|
||||
let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") ||
|
||||
orig_args.iter().any(|s| s == "--emit=metadata");
|
||||
let clippy_enabled = env::var("CLIPPY_TESTS")
|
||||
.ok()
|
||||
.map_or(false, |val| val == "true")
|
||||
|| orig_args.iter().any(|s| s == "--emit=metadata");
|
||||
|
||||
if clippy_enabled {
|
||||
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
|
||||
|
@ -69,8 +69,7 @@ pub fn main() {
|
||||
.skip(2)
|
||||
.find(|val| val.starts_with("--manifest-path="));
|
||||
|
||||
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
|
||||
{
|
||||
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
|
||||
metadata
|
||||
} else {
|
||||
let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
|
||||
|
@ -1,3 +1,2 @@
|
||||
#![feature(plugin)]
|
||||
#![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))]
|
||||
|
||||
#![plugin(clippy(conf_file = "./tests/auxiliary/conf_whitelisted.toml"))]
|
||||
|
@ -24,9 +24,7 @@ fn dogfood() {
|
||||
let mut s = String::new();
|
||||
s.push_str(" -L target/debug/");
|
||||
s.push_str(" -L target/debug/deps");
|
||||
s.push_str(
|
||||
" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal",
|
||||
);
|
||||
s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal");
|
||||
config.target_rustcflags = Some(s);
|
||||
if let Ok(name) = var("TESTNAME") {
|
||||
config.filter = Some(name.to_owned())
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
// this should compile in a reasonable amount of time
|
||||
fn rust_type_id(name: &str) {
|
||||
if "bool" == &name[..] || "uint" == &name[..] || "u8" == &name[..] || "u16" == &name[..] || "u32" == &name[..] ||
|
||||
"f32" == &name[..] || "f64" == &name[..] || "i8" == &name[..] || "i16" == &name[..] ||
|
||||
"i32" == &name[..] || "i64" == &name[..] || "Self" == &name[..] || "str" == &name[..]
|
||||
if "bool" == &name[..] || "uint" == &name[..] || "u8" == &name[..] || "u16" == &name[..] || "u32" == &name[..]
|
||||
|| "f32" == &name[..] || "f64" == &name[..] || "i8" == &name[..] || "i16" == &name[..]
|
||||
|| "i32" == &name[..] || "i64" == &name[..] || "Self" == &name[..] || "str" == &name[..]
|
||||
{
|
||||
unreachable!();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user