Merge pull request #2202 from topecongiro/format

Run `cargo fmt`
This commit is contained in:
Oliver Schneider 2017-11-06 08:35:52 +01:00 committed by GitHub
commit ed589761e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 804 additions and 613 deletions

View File

@ -120,13 +120,19 @@ fn to_const_range(
array_size: ConstInt, array_size: ConstInt,
) -> Option<(ConstInt, ConstInt)> { ) -> Option<(ConstInt, ConstInt)> {
let start = match *start { 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, Some(_) => return None,
None => ConstInt::U8(0), None => ConstInt::U8(0),
}; };
let end = match *end { 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 { match x {
ConstInt::U8(_) => (x + ConstInt::U8(1)), ConstInt::U8(_) => (x + ConstInt::U8(1)),
ConstInt::U16(_) => (x + ConstInt::U16(1)), ConstInt::U16(_) => (x + ConstInt::U16(1)),

View File

@ -143,7 +143,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
if_chain! { if_chain! {
if parent_impl != ast::CRATE_NODE_ID; if parent_impl != ast::CRATE_NODE_ID;
if let hir::map::Node::NodeItem(item) = cx.tcx.hir.get(parent_impl); 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; if trait_ref.path.def.def_id() == trait_id;
then { return; } then { return; }
} }

View File

@ -7,7 +7,7 @@ use rustc::ty::{self, TyCtxt};
use semver::Version; use semver::Version;
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use syntax::codemap::Span; 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)]`, /// **What it does:** Checks for items annotated with `#[inline(always)]`,
/// unless the annotated function is empty or simply panics. /// unless the annotated function is empty or simply panics.

View File

@ -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 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; \ 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 { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { 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, BLOCK_IN_IF_CONDITION_EXPR,
check.span, check.span,
BRACED_EXPR_MESSAGE, BRACED_EXPR_MESSAGE,
&format!("try\nif {} {} ... ", &format!(
snippet_block(cx, ex.span, ".."), "try\nif {} {} ... ",
snippet_block(cx, then.span, "..")), snippet_block(cx, ex.span, ".."),
snippet_block(cx, then.span, "..")
),
); );
} }
} else { } else {
@ -111,9 +113,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
BLOCK_IN_IF_CONDITION_STMT, BLOCK_IN_IF_CONDITION_STMT,
check.span, check.span,
COMPLEX_BLOCK_MESSAGE, COMPLEX_BLOCK_MESSAGE,
&format!("try\nlet res = {};\nif res {} ... ", &format!(
snippet_block(cx, block.span, ".."), "try\nlet res = {};\nif res {} ... ",
snippet_block(cx, then.span, "..")), snippet_block(cx, block.span, ".."),
snippet_block(cx, then.span, "..")
),
); );
} }
} }

View File

@ -368,9 +368,9 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
} }
// if the number of occurrences of a terminal decreases or any of the stats // if the number of occurrences of a terminal decreases or any of the stats
// decreases while none increases // decreases while none increases
improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) || improvement |= (stats.terminals[i] > simplified_stats.terminals[i])
(stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) || || (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops)
(stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations); || (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
} }
if improvement { if improvement {
improvements.push(suggestion); improvements.push(suggestion);

View File

@ -2,8 +2,8 @@ use rustc::hir::*;
use rustc::lint::*; use rustc::lint::*;
use rustc::ty; use rustc::ty;
use syntax::ast::{Name, UintTy}; use syntax::ast::{Name, UintTy};
use utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, use utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, snippet, span_lint_and_sugg,
snippet, span_lint_and_sugg, walk_ptrs_ty}; walk_ptrs_ty};
/// **What it does:** Checks for naive byte counts /// **What it does:** Checks for naive byte counts
/// ///

View File

@ -1,6 +1,6 @@
use syntax::ast::{Item, ItemKind, TyKind, Ty}; use syntax::ast::{Item, ItemKind, Ty, TyKind};
use rustc::lint::{LintPass, EarlyLintPass, LintArray, EarlyContext}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use utils::{span_lint_and_then, in_macro}; use utils::{in_macro, span_lint_and_then};
/// **What it does:** Checks for constants with an explicit `'static` lifetime. /// **What it does:** Checks for constants with an explicit `'static` lifetime.
/// ///
@ -20,7 +20,7 @@ use utils::{span_lint_and_then, in_macro};
/// ``` /// ```
declare_lint! { declare_lint! {
pub CONST_STATIC_LIFETIME, pub CONST_STATIC_LIFETIME,
Warn, Warn,
"Using explicit `'static` lifetime for constants when elision rules would allow omitting them." "Using explicit `'static` lifetime for constants when elision rules would allow omitting them."
} }
@ -41,10 +41,8 @@ impl StaticConst {
TyKind::Array(ref ty, _) => { TyKind::Array(ref ty, _) => {
self.visit_type(&*ty, cx); self.visit_type(&*ty, cx);
}, },
TyKind::Tup(ref tup) => { TyKind::Tup(ref tup) => for tup_ty in tup {
for tup_ty in tup { self.visit_type(&*tup_ty, cx);
self.visit_type(&*tup_ty, cx);
}
}, },
// This is what we are looking for ! // This is what we are looking for !
TyKind::Rptr(ref optional_lifetime, ref borrow_type) => { TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
@ -54,11 +52,15 @@ impl StaticConst {
// Verify that the path is a str // Verify that the path is a str
if lifetime.ident.name == "'static" { if lifetime.ident.name == "'static" {
let mut sug: String = String::new(); let mut sug: String = String::new();
span_lint_and_then(cx, span_lint_and_then(
CONST_STATIC_LIFETIME, cx,
lifetime.span, CONST_STATIC_LIFETIME,
"Constants have by default a `'static` lifetime", lifetime.span,
|db| {db.span_suggestion(lifetime.span,"consider removing `'static`",sug);}); "Constants have by default a `'static` lifetime",
|db| {
db.span_suggestion(lifetime.span, "consider removing `'static`", sug);
},
);
} }
} }
} }

View File

@ -98,13 +98,13 @@ fn check_hash_peq<'a, 'tcx>(
// Look for the PartialEq implementations for `ty` // Look for the PartialEq implementations for `ty`
cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
let peq_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id)); let peq_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id));
if peq_is_automatically_derived == hash_is_automatically_derived { if peq_is_automatically_derived == hash_is_automatically_derived {
return; return;
} }
let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation"); let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
// Only care about `impl PartialEq<Foo> for Foo` // Only care about `impl PartialEq<Foo> for Foo`
// For `impl PartialEq<B> for A, input_types is [A, B] // For `impl PartialEq<B> for A, input_types is [A, B]
if trait_ref.substs.type_at(1) == ty { if trait_ref.substs.type_at(1) == ty {
@ -113,7 +113,7 @@ fn check_hash_peq<'a, 'tcx>(
} else { } else {
"you are deriving `Hash` but have implemented `PartialEq` explicitly" "you are deriving `Hash` but have implemented `PartialEq` explicitly"
}; };
span_lint_and_then( span_lint_and_then(
cx, DERIVE_HASH_XOR_EQ, span, cx, DERIVE_HASH_XOR_EQ, span,
mess, mess,
@ -157,7 +157,9 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
EXPL_IMPL_CLONE_ON_COPY, EXPL_IMPL_CLONE_ON_COPY,
item.span, item.span,
"you are implementing `Clone` explicitly on a `Copy` type", "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`");
},
); );
} }
} }

View File

@ -204,7 +204,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
End(CodeBlock(_)) | End(Code) => in_code = false, End(CodeBlock(_)) | End(Code) => in_code = false,
Start(Link(link, _)) => in_link = Some(link), Start(Link(link, _)) => in_link = Some(link),
End(Link(_, _)) => in_link = None, 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 Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it
SoftBreak => (), SoftBreak => (),
HardBreak => (), HardBreak => (),
@ -273,8 +273,8 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) {
s s
}; };
s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 && 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().filter(|&c| c.is_lowercase()).take(1).count() > 0
} }
fn has_underscore(s: &str) -> bool { 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) { if let Ok(url) = Url::parse(word) {
// try to get around the fact that `foo::bar` parses as a valid URL // try to get around the fact that `foo::bar` parses as a valid URL
if !url.cannot_be_a_base() { if !url.cannot_be_a_base() {
span_lint(cx, span_lint(
DOC_MARKDOWN, cx,
span, DOC_MARKDOWN,
"you should put bare URLs between `<`/`>` or make a proper Markdown link"); span,
"you should put bare URLs between `<`/`>` or make a proper Markdown link",
);
return; return;
} }

View File

@ -1,7 +1,7 @@
use rustc::lint::*; use rustc::lint::*;
use rustc::ty; use rustc::ty;
use rustc::hir::*; 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 /// **What it does:** Checks for calls to `std::mem::drop` with a reference
/// instead of an owned value. /// instead of an owned value.
@ -125,7 +125,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let msg; let msg;
let arg = &args[0]; let arg = &args[0];
let arg_ty = cx.tables.expr_ty(arg); let arg_ty = cx.tables.expr_ty(arg);
if let ty::TyRef(..) = arg_ty.sty { if let ty::TyRef(..) = arg_ty.sty {
if match_def_path(cx.tcx, def_id, &paths::DROP) { if match_def_path(cx.tcx, def_id, &paths::DROP) {
lint = DROP_REF; lint = DROP_REF;

View File

@ -95,7 +95,7 @@ fn check_cond<'a, 'tcx, 'b>(
then { then {
let map = &params[0]; let map = &params[0];
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map)); let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map));
return if match_type(cx, obj_ty, &paths::BTREEMAP) { return if match_type(cx, obj_ty, &paths::BTREEMAP) {
Some(("BTreeMap", map, key)) Some(("BTreeMap", map, key))
} }
@ -136,14 +136,14 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> {
snippet(self.cx, self.map.span, "map"), snippet(self.cx, self.map.span, "map"),
snippet(self.cx, params[1].span, ".."), snippet(self.cx, params[1].span, ".."),
snippet(self.cx, params[2].span, "..")); snippet(self.cx, params[2].span, ".."));
db.span_suggestion(self.span, "consider using", help); db.span_suggestion(self.span, "consider using", help);
} }
else { else {
let help = format!("{}.entry({})", let help = format!("{}.entry({})",
snippet(self.cx, self.map.span, "map"), snippet(self.cx, self.map.span, "map"),
snippet(self.cx, params[1].span, "..")); snippet(self.cx, params[1].span, ".."));
db.span_suggestion(self.span, "consider using", help); db.span_suggestion(self.span, "consider using", help);
} }
}); });

View File

@ -55,8 +55,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
.at(expr.span) .at(expr.span)
.const_eval(param_env.and((did, substs))) .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 {
Ok(&ty::Const { val: ConstVal::Integral(Isize(Is64(i))), .. }) => i64::from(i as i32) != i, 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, _ => false,
}; };
if bad { if bad {

View File

@ -159,8 +159,11 @@ fn check_variant(
} }
for var in &def.variants { for var in &def.variants {
let name = var2str(var); let name = var2str(var);
if partial_match(item_name, &name) == item_name_chars && if partial_match(item_name, &name) == item_name_chars
name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) { && 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"); span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
} }
if partial_rmatch(item_name, &name) == item_name_chars { if partial_rmatch(item_name, &name) == item_name_chars {

View File

@ -2,7 +2,7 @@ use rustc::lint::*;
use rustc::hir; use rustc::hir;
use rustc::ty; use rustc::ty;
use syntax_pos::Span; 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}; 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()` /// **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` // check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0])); let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
if match_type(self.tcx, reciever_ty, &OPTION) || if match_type(self.tcx, reciever_ty, &OPTION) || match_type(self.tcx, reciever_ty, &RESULT) {
match_type(self.tcx, reciever_ty, &RESULT)
{
self.result.push(expr.span); self.result.push(expr.span);
} }
} }
@ -105,7 +103,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
result: Vec::new(), result: Vec::new(),
}; };
fpu.visit_expr(&body.value); fpu.visit_expr(&body.value);
// if we've found one, lint // if we've found one, lint
if !fpu.result.is_empty() { if !fpu.result.is_empty() {
span_lint_and_then( span_lint_and_then(

View File

@ -3,7 +3,7 @@ use rustc::lint::*;
use rustc::ty; use rustc::ty;
use syntax::ast::LitKind; use syntax::ast::LitKind;
use utils::paths; 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 /// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string. /// argument")` and `format!("{}", foo)` where `foo` is a string.
@ -109,7 +109,7 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD); if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD);
then { then {
let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0])); let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
return ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING); return ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING);
} }
} }

View File

@ -190,8 +190,8 @@ fn check_array(cx: &EarlyContext, expr: &ast::Expr) {
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { 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() && if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
unsugar_if(second).is_some() && unsugar_if(second).is_some()
{ {
// where the else would be // where the else would be
let else_span = first.span.between(second.span); let else_span = first.span.between(second.span);

View File

@ -70,7 +70,7 @@ fn all_ones(v: &ConstInt) -> bool {
ConstInt::U32(i) => i == !0, ConstInt::U32(i) => i == !0,
ConstInt::U64(i) => i == !0, ConstInt::U64(i) => i == !0,
ConstInt::U128(i) => i == !0, ConstInt::U128(i) => i == !0,
_ => false _ => false,
} }
} }

View File

@ -4,7 +4,7 @@
use rustc::lint::*; use rustc::lint::*;
use syntax::ast::*; 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 /// **What it does:** Checks for usage of `!` or `!=` in an if condition with an
/// else branch. /// else branch.

View File

@ -3,7 +3,7 @@
use rustc::lint::*; use rustc::lint::*;
use syntax::ast::*; 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 /// **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)] #[allow(cast_sign_loss)]
fn check_lit(&self, lit: &Lit, target_value: i128) -> bool { fn check_lit(&self, lit: &Lit, target_value: i128) -> bool {
if let LitKind::Int(value, ..) = lit.node { if let LitKind::Int(value, ..) = lit.node {
return value == (target_value as u128) return value == (target_value as u128);
} }
false false
} }
@ -66,49 +66,76 @@ impl IntPlusOne {
(BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
match (lhskind.node, &lhslhs.node, &lhsrhs.node) { match (lhskind.node, &lhslhs.node, &lhsrhs.node) {
// `-1 + x` // `-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` // `x - 1`
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS), (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => {
_ => None self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
},
_ => None,
} }
}, },
// case where `... >= y + 1` or `... >= 1 + y` // 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) { match (&rhslhs.node, &rhsrhs.node) {
// `y + 1` and `1 + y` // `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) => {
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS), self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
_ => None },
(_, &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 <= ...` // 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) { match (&lhslhs.node, &lhsrhs.node) {
// `1 + x` and `x + 1` // `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) => {
(_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS), self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
_ => None },
(_, &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` // case where `... >= y - 1` or `... >= -1 + y`
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
match (rhskind.node, &rhslhs.node, &rhsrhs.node) { match (rhskind.node, &rhslhs.node, &rhsrhs.node) {
// `-1 + y` // `-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` // `y - 1`
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS), (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => {
_ => None 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 { let binop_string = match binop {
BinOpKind::Ge => ">", BinOpKind::Ge => ">",
BinOpKind::Le => "<", BinOpKind::Le => "<",
_ => return None _ => return None,
}; };
if let Some(snippet) = snippet_opt(cx, node.span) { if let Some(snippet) = snippet_opt(cx, node.span) {
if let Some(other_side_snippet) = snippet_opt(cx, other_side.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) { fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) {
span_lint_and_then(cx, span_lint_and_then(cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", |db| {
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); db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation);
}); });
} }

View File

@ -1,13 +1,13 @@
use rustc::lint::*; use rustc::lint::*;
use rustc::ty; use rustc::ty;
use rustc::hir::*; 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. /// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
/// ///
/// **Why is this bad?** Creation of null references is undefined behavior. /// **Why is this bad?** Creation of null references is undefined behavior.
/// ///
/// **Known problems:** None. /// **Known problems:** None.
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
@ -22,9 +22,10 @@ declare_lint! {
const ZERO_REF_SUMMARY: &str = "reference to zeroed memory"; const ZERO_REF_SUMMARY: &str = "reference to zeroed memory";
const UNINIT_REF_SUMMARY: &str = "reference to uninitialized 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; pub struct InvalidRef;
impl LintPass for InvalidRef { impl LintPass for InvalidRef {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
@ -38,19 +39,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
if let ExprCall(ref path, ref args) = expr.node; if let ExprCall(ref path, ref args) = expr.node;
if let ExprPath(ref qpath) = path.node; if let ExprPath(ref qpath) = path.node;
if args.len() == 0; if args.len() == 0;
if let ty::TyRef(..) = cx.tables.expr_ty(expr).sty; 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)); if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
then { 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 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 UNINIT_REF_SUMMARY
} else { } else {
return; return;
}; };
span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP); span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP);
} }
} }
return; return;
} }
} }

View File

@ -139,13 +139,9 @@ fn check_last_stmt_in_block(block: &Block) -> bool {
// like `panic!()` // like `panic!()`
match final_stmt.node { match final_stmt.node {
StmtKind::Expr(_) => false, StmtKind::Expr(_) => false,
StmtKind::Semi(ref expr) => { StmtKind::Semi(ref expr) => match expr.node {
match expr.node { ExprKind::Break(_, _) | ExprKind::Continue(_) | ExprKind::Ret(_) => false,
ExprKind::Break(_, _) | _ => true,
ExprKind::Continue(_) |
ExprKind::Ret(_) => false,
_ => true,
}
}, },
_ => true, _ => true,
} }

View File

@ -119,8 +119,8 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai
.iter() .iter()
.flat_map(|&i| cx.tcx.associated_items(i)) .flat_map(|&i| cx.tcx.associated_items(i))
.any(|i| { .any(|i| {
i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty" && 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 && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
}); });
if !is_empty_method_found { if !is_empty_method_found {

View File

@ -76,7 +76,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq {
if !used_in_expr(cx, canonical_id, value); if !used_in_expr(cx, canonical_id, value);
then { then {
let span = stmt.span.to(if_.span); let span = stmt.span.to(if_.span);
let (default_multi_stmts, default) = if let Some(ref else_) = *else_ { let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
if let hir::ExprBlock(ref else_) = else_.node { if let hir::ExprBlock(ref else_) = else_.node {
if let Some(default) = check_assign(cx, canonical_id, else_) { if let Some(default) = check_assign(cx, canonical_id, else_) {
@ -94,15 +94,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq {
} else { } else {
continue; continue;
}; };
let mutability = match mode { let mutability = match mode {
BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ", BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ",
_ => "", _ => "",
}; };
// FIXME: this should not suggest `mut` if we can detect that the variable is not // FIXME: this should not suggest `mut` if we can detect that the variable is not
// use mutably after the `if` // use mutably after the `if`
let sug = format!( let sug = format!(
"let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};", "let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
mut=mutability, mut=mutability,
@ -174,15 +174,15 @@ fn check_assign<'a, 'tcx>(
id: decl, id: decl,
used: false, used: false,
}; };
for s in block.stmts.iter().take(block.stmts.len()-1) { for s in block.stmts.iter().take(block.stmts.len()-1) {
hir::intravisit::walk_stmt(&mut v, s); hir::intravisit::walk_stmt(&mut v, s);
if v.used { if v.used {
return None; return None;
} }
} }
return Some(value); return Some(value);
} }
} }

View File

@ -11,8 +11,7 @@
#![feature(inclusive_range_syntax, range_contains)] #![feature(inclusive_range_syntax, range_contains)]
#![feature(macro_vis_matcher)] #![feature(macro_vis_matcher)]
#![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)] #![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)]
#![recursion_limit = "256"]
#![recursion_limit="256"]
#[macro_use] #[macro_use]
extern crate rustc; extern crate rustc;

View File

@ -270,7 +270,7 @@ impl LiteralDigitGrouping {
.digits .digits
.split_terminator('.') .split_terminator('.')
.collect(); .collect();
// Lint integral and fractional parts separately, and then check consistency of digit // Lint integral and fractional parts separately, and then check consistency of digit
// groups if both pass. // groups if both pass.
let _ = Self::do_lint(parts[0]) let _ = Self::do_lint(parts[0])

View File

@ -16,7 +16,7 @@ use rustc::ty::{self, Ty};
use rustc::ty::subst::{Subst, Substs}; use rustc::ty::subst::{Subst, Substs};
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::iter::{Iterator, once}; use std::iter::{once, Iterator};
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use utils::sugg; use utils::sugg;
@ -377,8 +377,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// check for never_loop // check for never_loop
match expr.node { match expr.node {
ExprWhile(_, ref block, _) | ExprWhile(_, ref block, _) | ExprLoop(ref block, _, _) => {
ExprLoop(ref block, _, _) => {
let mut state = NeverLoopState { let mut state = NeverLoopState {
breaks: HashSet::new(), breaks: HashSet::new(),
continues: 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 { if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node {
// ensure "if let" compatible match structure // ensure "if let" compatible match structure
match *source { match *source {
MatchSource::Normal | MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
MatchSource::IfLetDesugar { .. } => { if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none()
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && && arms[1].pats.len() == 1 && arms[1].guard.is_none()
arms[1].pats.len() == 1 && arms[1].guard.is_none() && && is_simple_break_expr(&arms[1].body)
is_simple_break_expr(&arms[1].body)
{ {
if in_external_macro(cx, expr.span) { if in_external_macro(cx, expr.span) {
return; 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 { if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node {
let pat = &arms[0].pats[0].node; let pat = &arms[0].pats[0].node;
if let (&PatKind::TupleStruct(ref qpath, ref pat_args, _), if let (
&ExprMethodCall(ref method_path, _, ref method_args)) = (pat, &match_expr.node) &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 iter_expr = &method_args[0];
let lhs_constructor = last_path_segment(qpath); let lhs_constructor = last_path_segment(qpath);
if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) && if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR)
lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0]) && && lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0])
!is_iterator_used_after_while_let(cx, iter_expr) && && !is_iterator_used_after_while_let(cx, iter_expr)
!is_nested(cx, expr, &method_args[0]) && !is_nested(cx, expr, &method_args[0])
{ {
let iterator = snippet(cx, method_args[0].span, "_"); let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_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> { fn stmt_to_expr(stmt: &Stmt) -> Option<&Expr> {
match stmt.node { match stmt.node {
StmtSemi(ref e, ..) | StmtSemi(ref e, ..) | StmtExpr(ref e, ..) => Some(e),
StmtExpr(ref e, ..) => Some(e),
StmtDecl(ref d, ..) => decl_to_expr(d), StmtDecl(ref d, ..) => decl_to_expr(d),
} }
} }
@ -528,9 +527,9 @@ fn never_loop_expr(expr: &Expr, state: &mut NeverLoopState) -> bool {
ExprTupField(ref e, _) | ExprTupField(ref e, _) |
ExprAddrOf(_, ref e) | ExprAddrOf(_, ref e) |
ExprRepeat(ref e, _) => never_loop_expr(e, state), ExprRepeat(ref e, _) => never_loop_expr(e, state),
ExprArray(ref es) | ExprArray(ref es) | ExprMethodCall(_, _, ref es) | ExprTup(ref es) => {
ExprMethodCall(_, _, ref es) | never_loop_expr_seq(&mut es.iter(), state)
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), ExprCall(ref e, ref es) => never_loop_expr_seq(&mut once(&**e).chain(es.iter()), state),
ExprBinary(_, ref e1, ref e2) | ExprBinary(_, ref e1, ref e2) |
ExprAssign(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), ExprBlock(ref b) => never_loop_block(b, state),
ExprAgain(d) => { 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); state.continues.insert(id);
false false
}, },
ExprBreak(d, _) => { 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); state.breaks.insert(id);
false 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 { 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) 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 { 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) e.map(|e| never_loop_expr(e, state))
.fold(false, |a, b| a || b)
} }
fn check_for_loop<'a, 'tcx>( 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 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> { fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: ast::NodeId) -> Option<String> {
match e.node { match e.node {
ExprLit(ref l) => { ExprLit(ref l) => match l.node {
match l.node { ast::LitKind::Int(x, _ty) => Some(x.to_string()),
ast::LitKind::Int(x, _ty) => Some(x.to_string()), _ => None,
_ => None,
}
}, },
ExprPath(..) if !same_var(cx, e, var) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())), ExprPath(..) if !same_var(cx, e, var) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())),
_ => None, _ => None,
@ -683,29 +686,25 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var:
} }
let offset = match idx.node { let offset = match idx.node {
ExprBinary(op, ref lhs, ref rhs) => { ExprBinary(op, ref lhs, ref rhs) => match op.node {
match op.node { BinOp_::BiAdd => {
BinOp_::BiAdd => { let offset_opt = if same_var(cx, lhs, var) {
let offset_opt = if same_var(cx, lhs, var) { extract_offset(cx, rhs, var)
extract_offset(cx, rhs, var) } else if same_var(cx, rhs, var) {
} else if same_var(cx, rhs, var) { extract_offset(cx, lhs, var)
extract_offset(cx, lhs, var) } else {
} else { None
None };
};
offset_opt.map(Offset::positive) offset_opt.map(Offset::positive)
}, },
BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative), BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
_ => None, _ => None,
}
}, },
ExprPath(..) => { ExprPath(..) => if same_var(cx, idx, var) {
if same_var(cx, idx, var) { Some(Offset::positive("0".into()))
Some(Offset::positive("0".into())) } else {
} else { None
None
}
}, },
_ => None, _ => None,
}; };
@ -777,12 +776,13 @@ fn get_indexed_assignments<'a, 'tcx>(
.iter() .iter()
.map(|stmt| match stmt.node { .map(|stmt| match stmt.node {
Stmt_::StmtDecl(..) => None, Stmt_::StmtDecl(..) => None,
Stmt_::StmtExpr(ref e, _node_id) | Stmt_::StmtExpr(ref e, _node_id) | Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
}) })
.chain(expr.as_ref().into_iter().map(|e| { .chain(
Some(get_assignment(cx, &*e, var)) expr.as_ref()
})) .into_iter()
.map(|e| Some(get_assignment(cx, &*e, var))),
)
.filter_map(|op| op) .filter_map(|op| op)
.collect::<Option<Vec<_>>>() .collect::<Option<Vec<_>>>()
.unwrap_or_else(|| vec![]) .unwrap_or_else(|| vec![])
@ -801,20 +801,18 @@ fn detect_manual_memcpy<'a, 'tcx>(
expr: &'tcx Expr, expr: &'tcx Expr,
) { ) {
if let Some(higher::Range { if let Some(higher::Range {
start: Some(start), start: Some(start),
ref end, ref end,
limits, limits,
}) = higher::range(arg) }) = higher::range(arg)
{ {
// the var must be a single name // the var must be a single name
if let PatKind::Binding(_, canonical_id, _, _) = pat.node { if let PatKind::Binding(_, canonical_id, _, _) = pat.node {
let print_sum = |arg1: &Offset, arg2: &Offset| -> String { let print_sum = |arg1: &Offset, arg2: &Offset| -> String {
match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) { match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) {
("0", _, "0", _) => "".into(), ("0", _, "0", _) => "".into(),
("0", _, x, false) | ("0", _, x, false) | (x, false, "0", false) => x.into(),
(x, false, "0", false) => x.into(), ("0", _, x, true) | (x, false, "0", true) => format!("-{}", x),
("0", _, x, true) |
(x, false, "0", true) => format!("-{}", x),
(x, false, y, false) => format!("({} + {})", x, y), (x, false, y, false) => format!("({} + {})", x, y),
(x, false, y, true) => format!("({} - {})", x, y), (x, false, y, true) => format!("({} - {})", x, y),
(x, true, y, false) => format!("({} - {})", y, x), (x, true, y, false) => format!("({} - {})", y, x),
@ -897,10 +895,10 @@ fn check_for_loop_range<'a, 'tcx>(
expr: &'tcx Expr, expr: &'tcx Expr,
) { ) {
if let Some(higher::Range { if let Some(higher::Range {
start: Some(start), start: Some(start),
ref end, ref end,
limits, limits,
}) = higher::range(arg) }) = higher::range(arg)
{ {
// the var must be a single name // the var must be a single name
if let PatKind::Binding(_, canonical_id, ref ident, _) = pat.node { 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 // linting condition: we only indexed one variable, and indexed it directly
// (`indexed_directly` is subset of `indexed`) // (`indexed_directly` is subset of `indexed`)
if visitor.indexed.len() == 1 && visitor.indexed_directly.len() == 1 { if visitor.indexed.len() == 1 && visitor.indexed_directly.len() == 1 {
let (indexed, indexed_extent) = visitor.indexed_directly.into_iter().next().expect( let (indexed, indexed_extent) = visitor
"already checked that we have exactly 1 element", .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 // ensure that the indexed variable was declared before the loop, see #601
if let Some(indexed_extent) = indexed_extent { 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) { 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 this for loop is iterating over a two-sided range...
if let Some(higher::Range { if let Some(higher::Range {
start: Some(start), start: Some(start),
end: Some(end), end: Some(end),
limits, limits,
}) = higher::range(arg) }) = higher::range(arg)
{ {
// ...and both sides are compile-time constant integers... // ...and both sides are compile-time constant integers...
let parent_item = cx.tcx.hir.get_parent(arg.id); 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 // who think that this will iterate from the larger value to the
// smaller value. // smaller value.
let (sup, eq) = match (start_idx, end_idx) { let (sup, eq) = match (start_idx, end_idx) {
(&ty::Const { val: ConstVal::Integral(start_idx), .. }, (
&ty::Const { val: ConstVal::Integral(end_idx), .. }) => { &ty::Const {
(start_idx > end_idx, start_idx == end_idx) val: ConstVal::Integral(start_idx),
}, ..
},
&ty::Const {
val: ConstVal::Integral(end_idx),
..
},
) => (start_idx > end_idx, start_idx == end_idx),
_ => (false, false), _ => (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 // If the length is greater than 32 no traits are implemented for array and
// therefore we cannot use `&`. // therefore we cannot use `&`.
ty::TypeVariants::TyArray(_, size) if const_to_u64(size) > 32 => (), 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 { } else {
let object = snippet(cx, args[0].span, "_"); 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 // For each candidate, check the parent block to see if
// it's initialized to zero at the start of the loop. // it's initialized to zero at the start of the loop.
let map = &cx.tcx.hir; let map = &cx.tcx.hir;
let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| { let parent_scope = map.get_enclosing_scope(expr.id)
map.get_enclosing_scope(id) .and_then(|id| map.get_enclosing_scope(id));
});
if let Some(parent_id) = parent_scope { if let Some(parent_id) = parent_scope {
if let NodeBlock(block) = map.get(parent_id) { if let NodeBlock(block) = map.get(parent_id) {
for (id, _) in visitor.states.iter().filter( for (id, _) in visitor
|&(_, v)| *v == VarState::IncrOnce, .states
) .iter()
.filter(|&(_, v)| *v == VarState::IncrOnce)
{ {
let mut visitor2 = InitializeVisitor { let mut visitor2 = InitializeVisitor {
cx: cx, cx: cx,
@ -1273,12 +1279,10 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
if pat.len() == 2 { if pat.len() == 2 {
let arg_span = arg.span; let arg_span = arg.span;
let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).sty { let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).sty {
ty::TyRef(_, ref tam) => { ty::TyRef(_, ref tam) => match (&pat[0].node, &pat[1].node) {
match (&pat[0].node, &pat[1].node) { (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl),
(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),
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable), _ => return,
_ => return,
}
}, },
_ => return, _ => return,
}; };
@ -1322,14 +1326,11 @@ struct MutateDelegate {
} }
impl<'tcx> Delegate<'tcx> for 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) { fn borrow(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) {
if let ty::BorrowKind::MutBorrow = bk { 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 { impl<'tcx> MutateDelegate {
@ -1366,8 +1366,16 @@ impl<'tcx> MutateDelegate {
} }
fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { 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) { if let Some(higher::Range {
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)]; 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() { if mut_ids[0].is_some() || mut_ids[1].is_some() {
let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids); let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
mut_warn_with_span(cx, span_low); 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>) { fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) {
if let Some(sp) = 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>) { 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 def_id = def_id::DefId::local(body.hir_id.owner);
let region_scope_tree = &cx.tcx.region_scope_tree(def_id); 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); 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 { struct UsedVisitor {
var: ast::Name, // var to look for 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 { 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> { fn extract_first_expr(block: &Block) -> Option<&Expr> {
match block.expr { match block.expr {
Some(ref expr) if block.stmts.is_empty() => Some(expr), Some(ref expr) if block.stmts.is_empty() => Some(expr),
None if !block.stmts.is_empty() => { None if !block.stmts.is_empty() => match block.stmts[0].node {
match block.stmts[0].node { StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr),
StmtExpr(ref expr, _) | StmtDecl(..) => None,
StmtSemi(ref expr, _) => Some(expr),
StmtDecl(..) => None,
}
}, },
_ => None, _ => None,
} }
@ -1669,11 +1684,9 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> {
fn is_simple_break_expr(expr: &Expr) -> bool { fn is_simple_break_expr(expr: &Expr) -> bool {
match expr.node { match expr.node {
ExprBreak(dest, ref passed_expr) if dest.ident.is_none() && passed_expr.is_none() => true, ExprBreak(dest, ref passed_expr) if dest.ident.is_none() && passed_expr.is_none() => true,
ExprBlock(ref b) => { ExprBlock(ref b) => match extract_first_expr(b) {
match extract_first_expr(b) { Some(subexpr) => is_simple_break_expr(subexpr),
Some(subexpr) => is_simple_break_expr(subexpr), None => false,
None => false,
}
}, },
_ => false, _ => false,
} }
@ -1684,7 +1697,7 @@ fn is_simple_break_expr(expr: &Expr) -> bool {
// at the start of the loop. // at the start of the loop.
#[derive(PartialEq)] #[derive(PartialEq)]
enum VarState { enum VarState {
Initial, // Not examined yet Initial, // Not examined yet
IncrOnce, // Incremented exactly once, may be a loop counter IncrOnce, // Incremented exactly once, may be a loop counter
Declared, // Declared but not (yet) initialized to zero Declared, // Declared but not (yet) initialized to zero
Warn, Warn,
@ -1693,9 +1706,9 @@ enum VarState {
/// Scan a for loop for variables that are incremented exactly once. /// Scan a for loop for variables that are incremented exactly once.
struct IncrementVisitor<'a, 'tcx: 'a> { 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 states: HashMap<NodeId, VarState>, // incremented variables
depth: u32, // depth of conditional expressions depth: u32, // depth of conditional expressions
done: bool, 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. /// Check whether a variable is initialized to zero at the start of a loop.
struct InitializeVisitor<'a, 'tcx: 'a> { struct InitializeVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>, // context reference 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, var_id: NodeId,
state: VarState, state: VarState,
name: Option<Name>, name: Option<Name>,
@ -1881,13 +1894,11 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool
return false; return false;
} }
match cx.tcx.hir.find(parent) { match cx.tcx.hir.find(parent) {
Some(NodeExpr(expr)) => { Some(NodeExpr(expr)) => match expr.node {
match expr.node { ExprLoop(..) | ExprWhile(..) => {
ExprLoop(..) | ExprWhile(..) => { return true;
return true; },
}, _ => (),
_ => (),
}
}, },
Some(NodeBlock(block)) => { Some(NodeBlock(block)) => {
let mut block_visitor = LoopNestVisitor { 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)] #[derive(PartialEq, Eq)]
enum Nesting { enum Nesting {
Unknown, // no nesting detected yet Unknown, // no nesting detected yet
RuledOut, // the iterator is initialized or assigned within scope RuledOut, // the iterator is initialized or assigned within scope
LookFurther, // no nesting detected, no further walk required LookFurther, // no nesting detected, no further walk required
} }
@ -1942,11 +1953,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
return; return;
} }
match expr.node { match expr.node {
ExprAssign(ref path, _) | ExprAssign(ref path, _) | ExprAssignOp(_, ref path, _) => if match_var(path, self.iterator) {
ExprAssignOp(_, ref path, _) => { self.nesting = RuledOut;
if match_var(path, self.iterator) {
self.nesting = RuledOut;
}
}, },
_ => walk_expr(self, expr), _ => walk_expr(self, expr),
} }

View File

@ -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. /// 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_item = cx.tcx.hir.get_parent(id);
let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id); let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
@ -471,15 +475,39 @@ fn type_ranges(ranges: &[SpannedRange<&ty::Const>]) -> TypedRanges {
ranges ranges
.iter() .iter()
.filter_map(|range| match range.node { .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, span: range.span,
node: (start, Bound::Included(end)), 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, span: range.span,
node: (start, Bound::Excluded(end)), 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, span: range.span,
node: (start, Bound::Unbounded), node: (start, Bound::Unbounded),
}), }),

View File

@ -1,6 +1,6 @@
use rustc::lint::*; use rustc::lint::*;
use rustc::hir::{Expr, ExprCall, ExprPath}; 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 /// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is
/// `Drop`. /// `Drop`.

View File

@ -652,7 +652,8 @@ impl LintPass for Pass {
GET_UNWRAP, GET_UNWRAP,
STRING_EXTEND_CHARS, STRING_EXTEND_CHARS,
ITER_CLONED_COLLECT, ITER_CLONED_COLLECT,
USELESS_ASREF) USELESS_ASREF
)
} }
} }
@ -773,7 +774,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
} }
} }
// check conventions w.r.t. conversion method names and predicates // check conventions w.r.t. conversion method names and predicates
let def_id = cx.tcx.hir.local_def_id(item.id); let def_id = cx.tcx.hir.local_def_id(item.id);
let ty = cx.tcx.type_of(def_id); let ty = cx.tcx.type_of(def_id);
@ -781,7 +782,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
for &(ref conv, self_kinds) in &CONVENTIONS { for &(ref conv, self_kinds) in &CONVENTIONS {
if_chain! { if_chain! {
if conv.check(&name.as_str()); 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 { then {
let lint = if item.vis == hir::Visibility::Public { let lint = if item.vis == hir::Visibility::Public {
WRONG_PUB_SELF_CONVENTION WRONG_PUB_SELF_CONVENTION
@ -801,7 +804,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
} }
} }
let ret_ty = return_ty(cx, implitem.id); let ret_ty = return_ty(cx, implitem.id);
if name == "new" && if name == "new" &&
!ret_ty.walk().any(|t| same_tys(cx, t, ty)) { !ret_ty.walk().any(|t| same_tys(cx, t, ty)) {
@ -887,9 +890,7 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
// don't lint for constant values // don't lint for constant values
// FIXME: can we `expect` here instead of match? // FIXME: can we `expect` here instead of match?
let owner_def = cx.tcx.hir.get_parent_did(arg.id); let owner_def = cx.tcx.hir.get_parent_did(arg.id);
let promotable = cx.tcx let promotable = cx.tcx.rvalue_promotable_map(owner_def)[&arg.hir_id.local_id];
.rvalue_promotable_map(owner_def)
[&arg.hir_id.local_id];
if promotable { if promotable {
return; return;
} }
@ -991,12 +992,8 @@ fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) {
expr.span, expr.span,
"using '.clone()' on a ref-counted pointer", "using '.clone()' on a ref-counted pointer",
"try this", "try this",
format!("{}::clone(&{})", format!("{}::clone(&{})", caller_type, snippet(cx, arg.span, "_")),
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 let Def::Method(did) = cx.tables.qpath_def(path, fun.hir_id);
if match_def_path(cx.tcx, did, &paths::CSTRING_NEW); if match_def_path(cx.tcx, did, &paths::CSTRING_NEW);
then { then {
span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span, span_lint_and_then(
"you are getting the inner pointer of a temporary `CString`", cx,
|db| { TEMPORARY_CSTRING_AS_PTR,
db.note("that pointer will be invalid outside this expression"); expr.span,
db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime"); "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]) { 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) && 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() && derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
{ {
span_lint( span_lint(
cx, cx,
@ -1231,8 +1231,16 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::Expr]
// lint message // lint message
// comparing the snippet from source to raw text ("None") below is safe // comparing the snippet from source to raw text ("None") below is safe
// because we already have checked the type. // because we already have checked the type.
let arg = if unwrap_snippet == "None" { "None" } else { "a" }; let arg = if unwrap_snippet == "None" {
let suggest = if unwrap_snippet == "None" { "and_then(f)" } else { "map_or(a, f)" }; "None"
} else {
"a"
};
let suggest = if unwrap_snippet == "None" {
"and_then(f)"
} else {
"map_or(a, f)"
};
let msg = &format!( let msg = &format!(
"called `map(f).unwrap_or({})` on an Option value. \ "called `map(f).unwrap_or({})` on an Option value. \
This can be done more directly by calling `{}` instead", This can be done more directly by calling `{}` instead",
@ -1276,10 +1284,10 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
// lint message // lint message
let msg = if is_option { let msg = if is_option {
"called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \ "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 { } else {
"called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \ "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() // get snippets for args to map() and unwrap_or_else()
let map_snippet = snippet(cx, map_args[1].span, ".."); 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 /// 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]) { 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) { 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 // 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 { 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_self_snippet = snippet(cx, map_or_args[0].span, "..");
let map_or_func_snippet = snippet(cx, map_or_args[2].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); let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
span_lint_and_then( span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| {
cx, db.span_suggestion(expr.span, "try using and_then instead", hint);
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` /// 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 // lint if caller of `.filter().map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) { if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter(p).map(q)` on an `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` /// 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 // lint if caller of `.filter().map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) { if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter_map(p).map(q)` on an `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` /// 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 // lint if caller of `.filter().flat_map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) { if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter(p).flat_map(q)` on an `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` /// 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 // lint if caller of `.filter_map().flat_map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) { if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter_map(p).flat_map(q)` on an `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. /// 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_chain! {
if let Some(args) = method_chain_args(info.chain, chain_methods); if let Some(args) = method_chain_args(info.chain, chain_methods);
if let hir::ExprCall(ref fun, ref arg_char) = info.other.node; if let hir::ExprCall(ref fun, ref arg_char) = info.other.node;
@ -1486,11 +1515,11 @@ fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, c
if segment.name == "Some"; if segment.name == "Some";
then { then {
let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0])); let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
if self_ty.sty != ty::TyStr { if self_ty.sty != ty::TyStr {
return false; return false;
} }
span_lint_and_sugg(cx, span_lint_and_sugg(cx,
lint, lint,
info.expr.span, info.expr.span,
@ -1501,7 +1530,7 @@ fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, c
snippet(cx, args[0][0].span, "_"), snippet(cx, args[0][0].span, "_"),
suggest, suggest,
snippet(cx, arg_char[0].span, "_"))); snippet(cx, arg_char[0].span, "_")));
return true; return true;
} }
} }
@ -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()`. /// 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_chain! {
if let Some(args) = method_chain_args(info.chain, chain_methods); if let Some(args) = method_chain_args(info.chain, chain_methods);
if let hir::ExprLit(ref lit) = info.other.node; if let hir::ExprLit(ref lit) = info.other.node;
@ -1542,7 +1577,7 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &Binar
suggest, suggest,
c) c)
); );
return true; return true;
} }
} }
@ -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_item = cx.tcx.hir.get_parent(arg.id);
let parent_def_id = cx.tcx.hir.local_def_id(parent_item); let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id); 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 { if r.len() == 1 {
let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r)); let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r));
span_lint_and_then( 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, SINGLE_CHAR_PATTERN,
arg.span, arg.span,
"single-character string constant used as pattern", "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 { 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| { single_segment_ty(ty).map_or(false, |seg| {
generics.ty_params.iter().any(|param| { generics.ty_params.iter().any(|param| {
param.name == seg.name && param.name == seg.name && param.bounds.iter().any(|bound| {
param if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound {
.bounds let path = &ptr.trait_ref.path;
.iter() match_path(path, name) && path.segments.last().map_or(false, |s| {
.any(|bound| if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound { if let Some(ref params) = s.parameters {
let path = &ptr.trait_ref.path; if params.parenthesized {
match_path(path, name) && false
path.segments } else {
.last() params.types.len() == 1
.map_or(false, |s| { && (is_self_ty(&params.types[0]) || is_ty(&*params.types[0], self_ty))
if let Some(ref params) = s.parameters { }
if params.parenthesized { } else {
false false
} else { }
params.types.len() == 1 &&
(is_self_ty(&params.types[0])
|| is_ty(&*params.types[0], self_ty))
}
} else {
false
}
})
} else {
false
}) })
} else {
false
}
})
}) })
}) })
} }

View File

@ -2,7 +2,7 @@ use consts::{constant_simple, Constant};
use rustc::lint::*; use rustc::lint::*;
use rustc::hir::*; use rustc::hir::*;
use std::cmp::{Ordering, PartialOrd}; 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 /// **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. /// used to clamp values, but switched so that the result is constant.

View File

@ -328,8 +328,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
if let Some(name) = get_item_name(cx, expr) { if let Some(name) = get_item_name(cx, expr) {
let name = name.as_str(); let name = name.as_str();
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_")
name.ends_with("_eq") || name.ends_with("_eq")
{ {
return; return;
} }
@ -410,13 +410,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) { fn check_nan(cx: &LateContext, path: &Path, expr: &Expr) {
if !in_constant(cx, expr.id) { if !in_constant(cx, expr.id) {
path.segments.last().map(|seg| if seg.name == "NAN" { path.segments.last().map(|seg| {
span_lint( if seg.name == "NAN" {
cx, span_lint(
CMP_NAN, cx,
expr.span, CMP_NAN,
"doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead", 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 parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id); 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); 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; use std::cmp::Ordering;
match val.ty { match val.ty {
FloatTy::F32 => { 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()), 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(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal)
val.try_cmp(neg_infinity) == Ok(Ordering::Equal) || val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
}, },
FloatTy::F64 => { FloatTy::F64 => {
let zero = ConstFloat { 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()), 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(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal)
val.try_cmp(neg_infinity) == Ok(Ordering::Equal) || val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
}, },
} }
} else { } else {
@ -576,9 +582,7 @@ fn in_attributes_expansion(expr: &Expr) -> bool {
/// Test whether `def` is a variable defined outside a macro. /// Test whether `def` is a variable defined outside a macro.
fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool { fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool {
match *def { match *def {
def::Def::Local(id) | def::Def::Upvar(id, _, _) => { def::Def::Local(id) | def::Def::Upvar(id, _, _) => !in_macro(cx.tcx.hir.span(id)),
!in_macro(cx.tcx.hir.span(id))
},
_ => false, _ => false,
} }
} }

View File

@ -64,7 +64,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
if let Some(snippet) = snippet_opt(cx, inner.span) { if let Some(snippet) = snippet_opt(cx, inner.span) {
db.span_suggestion(e.span, "change this to", snippet); db.span_suggestion(e.span, "change this to", snippet);
} }
} },
); );
} }
} }

View File

@ -255,13 +255,13 @@ struct LintData<'a> {
const MSG_REDUNDANT_ELSE_BLOCK: &str = "This else block is redundant.\n"; 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` \ 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 \ 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 \ 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) { 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) { 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_loop_block(expr, |loop_block| {
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { for (i, stmt) in loop_block.stmts.iter().enumerate() {
let data = &LintData { with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
stmt_idx: i, let data = &LintData {
if_expr: if_expr, stmt_idx: i,
if_cond: cond, if_expr: if_expr,
if_block: then_block, if_cond: cond,
else_expr: else_expr, if_block: then_block,
block_stmts: &loop_block.stmts, 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); if needless_continue_in_else(else_expr) {
} else if is_first_block_stmt_continue(then_block) { emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock);
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock); } else if is_first_block_stmt_continue(then_block) {
} emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
}); }
});
}
}); });
} }

View File

@ -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()) let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
.filter(|p| !p.is_global()) .filter(|p| !p.is_global())
.filter_map(|pred| if let ty::Predicate::Trait(poly_trait_ref) = pred { .filter_map(|pred| {
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() { if let ty::Predicate::Trait(poly_trait_ref) = pred {
return None; 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<_>>(); .collect::<Vec<_>>();

View File

@ -108,55 +108,66 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
// can't be implemented by default // can't be implemented by default
return; return;
} }
if !cx.generics.expect("method must have generics").ty_params.is_empty() { if !cx.generics
// when the result of `new()` depends on a type parameter we should not require .expect("method must have generics")
// an .ty_params
// impl of `Default` .is_empty()
return; {
// 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) { if decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
let self_ty = cx.tcx let self_ty = cx.tcx
.type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id))); .type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)));
if_chain! { if_chain! {
if same_tys(cx, self_ty, return_ty(cx, id)); 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 let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
if !implements_trait(cx, self_ty, default_trait_id, &[]); if !implements_trait(cx, self_ty, default_trait_id, &[]);
then { then {
if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) { if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
span_lint_and_then(cx, span_lint_and_then(
NEW_WITHOUT_DEFAULT_DERIVE, span, cx,
&format!("you should consider deriving a \ NEW_WITHOUT_DEFAULT_DERIVE,
`Default` implementation for `{}`", span,
self_ty), &format!("you should consider deriving a `Default` implementation for `{}`", self_ty),
|db| { |db| {
db.suggest_item_with_attr(cx, sp, "try this", "#[derive(Default)]"); db.suggest_item_with_attr(cx, sp, "try this", "#[derive(Default)]");
}); });
} else { } else {
span_lint_and_then(cx, span_lint_and_then(
NEW_WITHOUT_DEFAULT, span, cx,
&format!("you should consider adding a \ NEW_WITHOUT_DEFAULT,
`Default` implementation for `{}`", span,
self_ty), &format!("you should consider adding a `Default` implementation for `{}`", self_ty),
|db| { |db| {
db.suggest_prepend_item(cx, db.suggest_prepend_item(
span, cx,
"try this", span,
&format!( "try this",
"impl Default for {} {{ &create_new_without_default_suggest_msg(self_ty),
fn default() -> Self {{ );
Self::new() },
}} );
}}", }
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> { fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
match ty.sty { match ty.sty {
ty::TyAdt(adt_def, substs) if adt_def.is_struct() => { ty::TyAdt(adt_def, substs) if adt_def.is_struct() => {

View File

@ -1,7 +1,7 @@
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::hir::def::Def; use rustc::hir::def::Def;
use rustc::hir::{BiAnd, BiOr, BlockCheckMode, Expr, Expr_, Stmt, StmtSemi, UnsafeSource}; 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; use std::ops::Deref;
/// **What it does:** Checks for statements which have no effect. /// **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_::ExprTupField(ref inner, _) |
Expr_::ExprAddrOf(_, ref inner) | Expr_::ExprAddrOf(_, ref inner) |
Expr_::ExprBox(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), Expr_::ExprBox(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
Expr_::ExprStruct(_, ref fields, ref base) => { Expr_::ExprStruct(_, ref fields, ref base) => if has_drop(cx, expr) {
if has_drop(cx, expr) { None
None } else {
} else { Some(
Some( fields
fields .iter()
.iter() .map(|f| &f.expr)
.map(|f| &f.expr) .chain(base)
.chain(base) .map(Deref::deref)
.map(Deref::deref) .collect(),
.collect()) )
}
}, },
Expr_::ExprCall(ref callee, ref args) => if let Expr_::ExprPath(ref qpath) = callee.node { Expr_::ExprCall(ref callee, ref args) => if let Expr_::ExprPath(ref qpath) = callee.node {
let def = cx.tables.qpath_def(qpath, callee.hir_id); let def = cx.tables.qpath_def(qpath, callee.hir_id);
match def { 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()) Some(args.iter().collect())
}, },
_ => None, _ => None,

View File

@ -216,8 +216,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
let second_last_e = existing_chars let second_last_e = existing_chars
.next_back() .next_back()
.expect("we know we have at least three chars"); .expect("we know we have at least three chars");
if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' || if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_'
!interned_chars.zip(existing_chars).all(eq_or_numeric) || !interned_chars.zip(existing_chars).all(eq_or_numeric)
{ {
// allowed similarity foo_x, foo_y // allowed similarity foo_x, foo_y
// or too many chars differ (foo_x, boo_y) or (foox, booy) // 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 let second_e = existing_chars
.next() .next()
.expect("we know we have at least two chars"); .expect("we know we have at least two chars");
if !eq_or_numeric((second_i, second_e)) || second_i == '_' || if !eq_or_numeric((second_i, second_e)) || second_i == '_'
!interned_chars.zip(existing_chars).all(eq_or_numeric) || !interned_chars.zip(existing_chars).all(eq_or_numeric)
{ {
// allowed similarity x_foo, y_foo // allowed similarity x_foo, y_foo
// or too many chars differ (x_foo, y_boo) or (xfoo, yboo) // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)

View File

@ -49,7 +49,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if let ExprMethodCall(_, _, ref result_types) = op.node; //check is expr.ok() has type Result<T,E>.ok() if let ExprMethodCall(_, _, ref result_types) = op.node; //check is expr.ok() has type Result<T,E>.ok()
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pats[0].node; //get operation if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pats[0].node; //get operation
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
then { then {
let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
let some_expr_string = snippet(cx, y[0].span, ""); let some_expr_string = snippet(cx, y[0].span, "");

View File

@ -81,8 +81,8 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp
} }
} else { } else {
return; // The function is called with a literal return; // The function is called with a literal
// which is not a boolean literal. This is theoretically // which is not a boolean literal. This is theoretically
// possible, but not very likely. // possible, but not very likely.
} }
}, },
_ => Argument::Unknown, _ => Argument::Unknown,

View File

@ -1,7 +1,7 @@
use rustc::hir::*; use rustc::hir::*;
use rustc::lint::*; use rustc::lint::*;
use syntax::ast::LitKind; 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!`. /// **What it does:** Checks for missing parameters in `panic!`.
/// ///

View File

@ -6,7 +6,7 @@ use syntax::ast::LitKind;
use syntax::symbol::InternedString; use syntax::symbol::InternedString;
use syntax_pos::Span; use syntax_pos::Span;
use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint}; 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 /// **What it does:** This lint warns when you using `println!("")` to
/// print a newline. /// print a newline.
@ -94,7 +94,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if let ExprPath(ref qpath) = fun.node; if let ExprPath(ref qpath) = fun.node;
if let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)); if let Some(fun_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
then { then {
// Search for `std::io::_print(..)` which is unique in a // Search for `std::io::_print(..)` which is unique in a
// `print!` expansion. // `print!` expansion.
if match_def_path(cx.tcx, fun_id, &paths::IO_PRINT) { if match_def_path(cx.tcx, fun_id, &paths::IO_PRINT) {
@ -104,9 +104,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
Some(span) => (span, "println"), Some(span) => (span, "println"),
None => (span, "print"), None => (span, "print"),
}; };
span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name)); span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));
if_chain! { if_chain! {
// ensure we're calling Arguments::new_v1 // ensure we're calling Arguments::new_v1
if args.len() == 1; if args.len() == 1;

View File

@ -8,8 +8,7 @@ use rustc::ty;
use syntax::ast::NodeId; use syntax::ast::NodeId;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax_pos::MultiSpan; use syntax_pos::MultiSpan;
use utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, use utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
walk_ptrs_hir_ty};
use utils::ptr::get_spans; use utils::ptr::get_spans;
/// **What it does:** This lint checks for function arguments of type `&String` /// **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) { fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
if let TraitItemKind::Method(ref sig, ref trait_method) = item.node { 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); 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.", with non-Vec-based slices.",
|db| { |db| {
if let Some(ref snippet) = ty_snippet { if let Some(ref snippet) = ty_snippet {
db.span_suggestion(arg.span, db.span_suggestion(arg.span, "change this to", format!("&[{}]", snippet));
"change this to",
format!("&[{}]", snippet));
} }
for (clonespan, suggestion) in spans { for (clonespan, suggestion) in spans {
db.span_suggestion(clonespan, db.span_suggestion(
&snippet_opt(cx, clonespan).map_or("change the call to".into(), clonespan,
|x| Cow::Owned(format!("change `{}` to", x))), &snippet_opt(cx, clonespan).map_or(
suggestion.into()); "change the call to".into(),
|x| Cow::Owned(format!("change `{}` to", x)),
),
suggestion.into(),
);
} }
} },
); );
} }
} else if match_type(cx, ty, &paths::STRING) { } 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, arg.span,
"writing `&String` instead of `&str` involves a new object where a slice will do.", "writing `&String` instead of `&str` involves a new object where a slice will do.",
|db| { |db| {
db.span_suggestion(arg.span, db.span_suggestion(arg.span, "change this to", "&str".into());
"change this to",
"&str".into());
for (clonespan, suggestion) in spans { for (clonespan, suggestion) in spans {
db.span_suggestion_short(clonespan, db.span_suggestion_short(
&snippet_opt(cx, clonespan).map_or("change the call to".into(), clonespan,
|x| Cow::Owned(format!("change `{}` to", x))), &snippet_opt(cx, clonespan).map_or(
suggestion.into()); "change the call to".into(),
|x| Cow::Owned(format!("change `{}` to", x)),
),
suggestion.into(),
);
} }
} },
); );
} }
} }

View File

@ -82,12 +82,7 @@ pub struct Pass;
impl LintPass for Pass { impl LintPass for Pass {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!( lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE)
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> { fn y_plus_one(expr: &Expr) -> Option<&Expr> {
match expr.node { match expr.node {
ExprBinary(Spanned { node: BiAdd, .. }, ref lhs, ref rhs) => { ExprBinary(Spanned { node: BiAdd, .. }, ref lhs, ref rhs) => if is_integer_literal(lhs, 1) {
if is_integer_literal(lhs, 1) { Some(rhs)
Some(rhs) } else if is_integer_literal(rhs, 1) {
} else if is_integer_literal(rhs, 1) { Some(lhs)
Some(lhs) } else {
} else { None
None
}
}, },
_ => None, _ => None,
} }

View File

@ -10,7 +10,7 @@ use std::error::Error;
use syntax::ast::{LitKind, NodeId}; use syntax::ast::{LitKind, NodeId};
use syntax::codemap::{BytePos, Span}; use syntax::codemap::{BytePos, Span};
use syntax::symbol::InternedString; 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 /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation
/// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct /// (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 parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id); 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) { 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, _ => None,
} }
} }

View File

@ -253,7 +253,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
snippet(cx, pattern_span, "_"), snippet(cx, pattern_span, "_"),
snippet(cx, expr.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) { } else if contains_name(name, expr) {
span_lint_and_then( span_lint_and_then(
@ -292,7 +294,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
SHADOW_UNRELATED, SHADOW_UNRELATED,
span, span,
&format!("`{}` shadows a previous declaration", snippet(cx, pattern_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 { match expr.node {
ExprBox(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), ExprBox(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
ExprBlock(ref block) => { ExprBlock(ref block) => {
block.stmts.is_empty() && block.stmts.is_empty()
block && block
.expr .expr
.as_ref() .as_ref()
.map_or(false, |e| is_self_shadow(name, e)) .map_or(false, |e| is_self_shadow(name, e))

View File

@ -123,8 +123,8 @@ fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool {
match src.node { match src.node {
ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
ExprBlock(ref block) => { ExprBlock(ref block) => {
block.stmts.is_empty() && block.stmts.is_empty()
block && block
.expr .expr
.as_ref() .as_ref()
.map_or(false, |expr| is_add(cx, expr, target)) .map_or(false, |expr| is_add(cx, expr, target))

View File

@ -89,7 +89,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) {
if let ExprIndex(ref lhs2, ref idx2) = lhs2.node { if let ExprIndex(ref lhs2, ref idx2) = lhs2.node {
if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) { if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1)); let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));
if matches!(ty.sty, ty::TySlice(_)) || if matches!(ty.sty, ty::TySlice(_)) ||
matches!(ty.sty, ty::TyArray(_, _)) || matches!(ty.sty, ty::TyArray(_, _)) ||
match_type(cx, ty, &paths::VEC) || match_type(cx, ty, &paths::VEC) ||
@ -99,10 +99,10 @@ fn check_manual_swap(cx: &LateContext, block: &Block) {
} }
} }
} }
None None
} }
let (replace, what, sugg) = if let Some((slice, idx1, idx2)) = check_for_slice(cx, lhs1, lhs2) { let (replace, what, sugg) = if let Some((slice, idx1, idx2)) = check_for_slice(cx, lhs1, lhs2) {
if let Some(slice) = Sugg::hir_opt(cx, slice) { if let Some(slice) = Sugg::hir_opt(cx, slice) {
(false, (false,
@ -120,9 +120,9 @@ fn check_manual_swap(cx: &LateContext, block: &Block) {
} else { } else {
(true, "".to_owned(), "".to_owned()) (true, "".to_owned(), "".to_owned())
}; };
let span = w[0].span.to(second.span); let span = w[0].span.to(second.span);
span_lint_and_then(cx, span_lint_and_then(cx,
MANUAL_SWAP, MANUAL_SWAP,
span, span,
@ -130,7 +130,7 @@ fn check_manual_swap(cx: &LateContext, block: &Block) {
|db| { |db| {
if !sugg.is_empty() { if !sugg.is_empty() {
db.span_suggestion(span, "try", sugg); db.span_suggestion(span, "try", sugg);
if replace { if replace {
db.note("or maybe you should use `std::mem::replace`?"); db.note("or maybe you should use `std::mem::replace`?");
} }
@ -156,13 +156,17 @@ fn check_suspicious_swap(cx: &LateContext, block: &Block) {
let lhs0 = Sugg::hir_opt(cx, lhs0); let lhs0 = Sugg::hir_opt(cx, lhs0);
let rhs0 = Sugg::hir_opt(cx, rhs0); let rhs0 = Sugg::hir_opt(cx, rhs0);
let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, 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 { } else {
("".to_owned(), "".to_owned(), "".to_owned()) ("".to_owned(), "".to_owned(), "".to_owned())
}; };
let span = first.span.to(second.span); let span = first.span.to(second.span);
span_lint_and_then(cx, span_lint_and_then(cx,
ALMOST_SWAPPED, ALMOST_SWAPPED,
span, span,

View File

@ -4,7 +4,7 @@ use rustc::hir::*;
use std::borrow::Cow; use std::borrow::Cow;
use syntax::ast; use syntax::ast;
use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then}; 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 /// **What it does:** Checks for transmutes that can't ever be correct on any
/// architecture. /// 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 ExprCall(ref path_expr, ref args) = e.node {
if let ExprPath(ref qpath) = path_expr.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 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) { if match_def_path(cx.tcx, def_id, &paths::TRANSMUTE) {
let from_ty = cx.tables.expr_ty(&args[0]); let from_ty = cx.tables.expr_ty(&args[0]);
let to_ty = cx.tables.expr_ty(e); 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()); db.span_suggestion(e.span, "try", sugg.to_string());
}, },
), ),
(&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::TyRawPtr(_)) => span_lint_and_then( (&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::TyRawPtr(_)) => {
cx, span_lint_and_then(
USELESS_TRANSMUTE, cx,
e.span, USELESS_TRANSMUTE,
"transmute from an integer to a pointer", e.span,
|db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { "transmute from an integer to a pointer",
db.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()).to_string()); |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::TyRef(..)) |
(&ty::TyFloat(_), &ty::TyRawPtr(_)) | (&ty::TyFloat(_), &ty::TyRawPtr(_)) |
(&ty::TyChar, &ty::TyRef(..)) | (&ty::TyChar, &ty::TyRef(..)) |
@ -249,7 +250,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
cx, cx,
CROSSPOINTER_TRANSMUTE, CROSSPOINTER_TRANSMUTE,
e.span, 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( (&ty::TyRawPtr(from_pty), &ty::TyRef(_, to_ref_ty)) => span_lint_and_then(
cx, cx,
@ -257,7 +262,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
e.span, e.span,
&format!( &format!(
"transmute from a pointer type (`{}`) to a reference type \ "transmute from a pointer type (`{}`) to a reference type \
(`{}`)", (`{}`)",
from_ty, from_ty,
to_ty to_ty
), ),
@ -291,8 +296,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
} else { } else {
arg 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)) => { (&ty::TyRef(_, ref ref_from), &ty::TyRef(_, ref ref_to)) => {
if_chain! { if_chain! {
@ -326,34 +335,49 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
} }
} }
}, },
(&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | (&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | (&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => {
(&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => span_lint_and_then( span_lint_and_then(
cx, cx,
TRANSMUTE_INT_TO_BOOL, TRANSMUTE_INT_TO_BOOL,
e.span, e.span,
&format!("transmute from a `{}` to a `bool`", from_ty), &format!("transmute from a `{}` to a `bool`", from_ty),
|db| { |db| {
let arg = sugg::Sugg::hir(cx, &args[0], ".."); let arg = sugg::Sugg::hir(cx, &args[0], "..");
let zero = sugg::Sugg::NonParen(Cow::from("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()); db.span_suggestion(
} e.span,
), "consider using",
(&ty::TyInt(_), &ty::TyFloat(_)) | sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string(),
(&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), (&ty::TyInt(_), &ty::TyFloat(_)) | (&ty::TyUint(_), &ty::TyFloat(_)) => {
|db| { span_lint_and_then(
let arg = sugg::Sugg::hir(cx, &args[0], ".."); cx,
let arg = if let ty::TyInt(int_ty) = from_ty.sty { TRANSMUTE_INT_TO_FLOAT,
arg.as_ty(format!("u{}", int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()))) e.span,
} else { &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
arg |db| {
}; let arg = sugg::Sugg::hir(cx, &args[0], "..");
db.span_suggestion(e.span, "consider using", format!("{}::from_bits({})", to_ty, arg.to_string())); 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, _ => return,
}; };
} }

View File

@ -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 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); if match_def_path(cx.tcx, did, &paths::VEC);
then { then {
span_help_and_lint(cx, span_help_and_lint(
BOX_VEC, cx,
ast_ty.span, BOX_VEC,
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", ast_ty.span,
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation."); "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 return; // don't recurse into the type
} }
} }
@ -241,7 +243,7 @@ fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifeti
// Ignore `Box<Any>` types, see #1884 for details. // Ignore `Box<Any>` types, see #1884 for details.
return; return;
} }
let ltopt = if lt.is_elided() { let ltopt = if lt.is_elided() {
"".to_owned() "".to_owned()
} else { } else {
@ -1730,7 +1732,7 @@ impl<'a, 'b, 'tcx: 'a + 'b> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'
if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) { if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) {
return; return;
} }
if match_path(ty_path, &paths::HASHMAP) { if match_path(ty_path, &paths::HASHMAP) {
if method.name == "new" { if method.name == "new" {
self.suggestions self.suggestions

View File

@ -60,7 +60,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
then { then {
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).parameters; let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).parameters;
let should_check = if let Some(ref params) = *parameters { let should_check = if let Some(ref params) = *parameters {
!params.parenthesized && params.lifetimes.len() == 0 !params.parenthesized && params.lifetimes.len() == 0
} else { } else {
true true
}; };

View File

@ -245,7 +245,9 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
// FIXME: also check int type // FIXME: also check int type
LitKind::Int(i, _) => println!(" if let LitKind::Int({}, _) = {}.node;", i, lit_pat), LitKind::Int(i, _) => println!(" if let LitKind::Int({}, _) = {}.node;", i, lit_pat),
LitKind::Float(..) => println!(" if let LitKind::Float(..) = {}.node;", 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) => { LitKind::ByteStr(ref vec) => {
let vec_pat = self.next("vec"); let vec_pat = self.next("vec");
println!(" if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat); println!(" if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat);

View File

@ -6,7 +6,7 @@
use rustc::hir; use rustc::hir;
use rustc::lint::LateContext; use rustc::lint::LateContext;
use syntax::ast; 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. /// Convert a hir binary operator to the corresponding `ast` type.
pub fn binop(op: hir::BinOp_) -> ast::BinOpKind { 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 /// Find the field named `name` in the field. Always return `Some` for
/// convenience. /// convenience.
fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> { fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> {
let expr = &fields let expr = &fields.iter().find(|field| field.name.node == name)?.expr;
.iter()
.find(|field| field.name.node == name)?
.expr;
Some(expr) Some(expr)
} }
@ -72,8 +69,8 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
None None
} }
}, },
hir::ExprStruct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD) || hir::ExprStruct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD)
match_qpath(path, &paths::RANGE_FROM) || match_qpath(path, &paths::RANGE_FROM)
{ {
Some(Range { Some(Range {
start: Some(get_field("start", fields)?), start: Some(get_field("start", fields)?),
@ -198,7 +195,7 @@ pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option<VecArgs<'e
return Some(VecArgs::Vec(&*args)); return Some(VecArgs::Vec(&*args));
} }
} }
None None
} }
else { else {

View File

@ -55,8 +55,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
/// Check whether two blocks are the same. /// Check whether two blocks are the same.
pub fn eq_block(&self, left: &Block, right: &Block) -> bool { pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(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)) && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
} }
pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool { 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), (&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)) => { (&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) || 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)| { || 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) l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
}) })
}, },
(&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => { (&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(&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(le, re, |l, r| self.eq_expr(l, r))
}, },
(&ExprBox(ref l), &ExprBox(ref 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)) => { (&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)) => { (&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| { 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)) && 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)) && 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)) => { (&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) !self.ignore_fn && l_path == r_path && self.eq_exprs(l_args, r_args)
}, },
(&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => { (&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => {
self.eq_expr(le, re) && 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(&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)), (&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), (&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)) => { (&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)) && 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)) && 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), (&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), (&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::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)) => { (&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)) && 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)) && both(li, ri, |l, r| self.eq_pat(l, r))
}, },
(&PatKind::Wild, &PatKind::Wild) => true, (&PatKind::Wild, &PatKind::Wild) => true,
_ => false, _ => false,
@ -190,18 +190,18 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
} }
fn eq_path(&self, left: &Path, right: &Path) -> bool { fn eq_path(&self, left: &Path, right: &Path) -> bool {
left.is_global() == right.is_global() && left.is_global() == right.is_global()
over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)) && over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
} }
fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool { fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool {
if !(left.parenthesized || right.parenthesized) { if !(left.parenthesized || right.parenthesized) {
over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(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.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.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
} else if left.parenthesized && right.parenthesized { } else if left.parenthesized && right.parenthesized {
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) && over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
both( && both(
&Some(&left.bindings[0].ty), &Some(&left.bindings[0].ty),
&Some(&right.bindings[0].ty), &Some(&right.bindings[0].ty),
|l, r| self.eq_ty(l, r), |l, r| self.eq_ty(l, r),
@ -220,7 +220,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
match (&left.parameters, &right.parameters) { match (&left.parameters, &right.parameters) {
(&None, &None) => true, (&None, &None) => true,
(&Some(ref l), &Some(ref r)) => self.eq_path_parameters(l, r), (&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) { match (&left.node, &right.node) {
(&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec), (&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)) => { (&TyArray(ref lt, ll_id), &TyArray(ref rt, rl_id)) => {
self.eq_ty(lt, rt) && 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_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), (&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)) => { (&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {

View File

@ -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); tcx.push_item_path(&mut apb, def_id);
apb.names.len() == path.len() && apb.names.len() == path.len()
apb.names && apb.names
.into_iter() .into_iter()
.zip(path.iter()) .zip(path.iter())
.all(|(a, &b)| *a == *b) .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::Resolved(_, ref path) => match_path(path, segments),
QPath::TypeRelative(ref ty, ref segment) => match ty.node { QPath::TypeRelative(ref ty, ref segment) => match ty.node {
TyPath(ref inner_path) => { TyPath(ref inner_path) => {
!segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) && !segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)])
segment.name == segments[segments.len() - 1] && segment.name == segments[segments.len() - 1]
}, },
_ => false, _ => false,
}, },
@ -233,7 +233,6 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
/// Get the definition associated to a path. /// Get the definition associated to a path.
pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> { pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
let crates = cx.tcx.crates(); let crates = cx.tcx.crates();
let krate = crates let krate = crates
.iter() .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 { 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. /// 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( Cow::Owned(
s.lines() s.lines()
.enumerate() .enumerate()
.map(|(i, l)| if (ignore_first && i == 0) || l.is_empty() { .map(|(i, l)| {
l if (ignore_first && i == 0) || l.is_empty() {
} else { l
l.split_at(x).1 } else {
l.split_at(x).1
}
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n"), .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 { if node_id == parent_id {
return None; return None;
} }
map.find(parent_id) map.find(parent_id).and_then(|node| {
.and_then(|node| if let Node::NodeExpr(parent) = node { if let Node::NodeExpr(parent) = node {
Some(parent) Some(parent)
} else { } else {
None None
}) }
})
} }
pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> { 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, help: &str,
sugg: String, 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`. /// 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. /// the whole suggestion.
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder, help_msg: String, sugg: I) pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder, help_msg: String, sugg: I)
where where
I: IntoIterator<Item=(Span, String)>, I: IntoIterator<Item = (Span, String)>,
{ {
let sugg = rustc_errors::CodeSuggestion { let sugg = rustc_errors::CodeSuggestion {
substitution_parts: sugg.into_iter() substitution_parts: sugg.into_iter()
@ -629,9 +637,8 @@ where
/// Return the base type for HIR references and pointers. /// Return the base type for HIR references and pointers.
pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty { pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty {
match ty.node { match ty.node {
TyPtr(ref mut_ty) | TyPtr(ref mut_ty) | TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), _ => ty,
_ => ty
} }
} }

View File

@ -267,11 +267,11 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
/// in the direction /// in the direction
/// `dir`. /// `dir`.
fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool { fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
other.precedence() < op.precedence() || other.precedence() < op.precedence()
(other.precedence() == op.precedence() && || (other.precedence() == op.precedence()
((op != other && associativity(op) != dir) || && ((op != other && associativity(op) != dir)
(op == other && associativity(op) != Associativity::Both))) || || (op == other && associativity(op) != Associativity::Both)))
is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op) || is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op)
} }
let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs { 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 mut first = true;
let new_item = new_item let new_item = new_item
.lines() .lines()
.map(|l| if first { .map(|l| {
first = false; if first {
format!("{}\n", l) first = false;
} else { format!("{}\n", l)
format!("{}{}\n", indent, l) } else {
format!("{}{}\n", indent, l)
}
}) })
.collect::<String>(); .collect::<String>();

View File

@ -52,7 +52,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg))); if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)));
then { then {
// report the error around the `vec!` not inside `<std macros>:` // 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); check_vec_macro(cx, &vec_args, span);
} }
} }

View File

@ -49,9 +49,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
| (_, FloatWidth::F64) => "f64", | (_, FloatWidth::F64) => "f64",
_ => "f32" _ => "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", "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,
),
);
} }
} }
} }

View File

@ -1,8 +1,6 @@
max_width = 120 max_width = 120
ideal_width = 100 comment_width = 100
fn_call_width = 80 fn_call_width = 80
match_block_trailing_comma = true match_block_trailing_comma = true
fn_args_layout = "Block"
closure_block_indent_threshold = 0 closure_block_indent_threshold = 0
fn_return_indent = "WithWhereClause"
wrap_comments = true wrap_comments = true

View File

@ -154,9 +154,7 @@ pub fn main() {
.and_then(|out| String::from_utf8(out.stdout).ok()) .and_then(|out| String::from_utf8(out.stdout).ok())
.map(|s| s.trim().to_owned()) .map(|s| s.trim().to_owned())
}) })
.expect( .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust")
"need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
)
}; };
rustc_driver::in_rustc_thread(|| { 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") { let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
orig_args.clone() orig_args.clone()
} else { } else {
orig_args.clone().into_iter() orig_args
.clone()
.into_iter()
.chain(Some("--sysroot".to_owned())) .chain(Some("--sysroot".to_owned()))
.chain(Some(sys_root)) .chain(Some(sys_root))
.collect() .collect()
@ -185,8 +185,10 @@ pub fn main() {
// this check ensures that dependencies are built but not linted and the final // this check ensures that dependencies are built but not linted and the final
// crate is // crate is
// linted but not built // linted but not built
let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") || let clippy_enabled = env::var("CLIPPY_TESTS")
orig_args.iter().any(|s| s == "--emit=metadata"); .ok()
.map_or(false, |val| val == "true")
|| orig_args.iter().any(|s| s == "--emit=metadata");
if clippy_enabled { if clippy_enabled {
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);

View File

@ -69,8 +69,7 @@ pub fn main() {
.skip(2) .skip(2)
.find(|val| val.starts_with("--manifest-path=")); .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 metadata
} else { } else {
let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));

View File

@ -1,3 +1,2 @@
#![feature(plugin)] #![feature(plugin)]
#![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))] #![plugin(clippy(conf_file = "./tests/auxiliary/conf_whitelisted.toml"))]

View File

@ -24,9 +24,7 @@ fn dogfood() {
let mut s = String::new(); let mut s = String::new();
s.push_str(" -L target/debug/"); s.push_str(" -L target/debug/");
s.push_str(" -L target/debug/deps"); s.push_str(" -L target/debug/deps");
s.push_str( s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal");
" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal",
);
config.target_rustcflags = Some(s); config.target_rustcflags = Some(s);
if let Ok(name) = var("TESTNAME") { if let Ok(name) = var("TESTNAME") {
config.filter = Some(name.to_owned()) config.filter = Some(name.to_owned())

View File

@ -4,9 +4,9 @@
// this should compile in a reasonable amount of time // this should compile in a reasonable amount of time
fn rust_type_id(name: &str) { fn rust_type_id(name: &str) {
if "bool" == &name[..] || "uint" == &name[..] || "u8" == &name[..] || "u16" == &name[..] || "u32" == &name[..] || if "bool" == &name[..] || "uint" == &name[..] || "u8" == &name[..] || "u16" == &name[..] || "u32" == &name[..]
"f32" == &name[..] || "f64" == &name[..] || "i8" == &name[..] || "i16" == &name[..] || || "f32" == &name[..] || "f64" == &name[..] || "i8" == &name[..] || "i16" == &name[..]
"i32" == &name[..] || "i64" == &name[..] || "Self" == &name[..] || "str" == &name[..] || "i32" == &name[..] || "i64" == &name[..] || "Self" == &name[..] || "str" == &name[..]
{ {
unreachable!(); unreachable!();
} }