Fix merge issues.

This commit is contained in:
laurent 2017-11-06 23:22:19 +00:00
commit e2b9cf836a
72 changed files with 880 additions and 626 deletions

View file

@ -1,6 +1,10 @@
# Change Log
All notable changes to this project will be documented in this file.
## 0.0.169
* Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)*
* New lints: [`just_underscores_and_digits`], [`result_map_unwrap_or_else`], [`transmute_bytes_to_str`]
## 0.0.168
* Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)*
@ -555,6 +559,7 @@ All notable changes to this project will be documented in this file.
[`iter_nth`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iter_nth
[`iter_skip_next`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iter_skip_next
[`iterator_step_by_zero`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iterator_step_by_zero
[`just_underscores_and_digits`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#just_underscores_and_digits
[`large_digit_groups`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#large_digit_groups
[`large_enum_variant`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#large_enum_variant
[`len_without_is_empty`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#len_without_is_empty
@ -632,6 +637,7 @@ All notable changes to this project will be documented in this file.
[`redundant_closure_call`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#redundant_closure_call
[`redundant_pattern`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#redundant_pattern
[`regex_macro`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#regex_macro
[`result_map_unwrap_or_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
[`result_unwrap_used`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#result_unwrap_used
[`reverse_range_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#reverse_range_loop
[`search_is_some`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#search_is_some
@ -659,6 +665,7 @@ All notable changes to this project will be documented in this file.
[`temporary_cstring_as_ptr`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
[`too_many_arguments`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#too_many_arguments
[`toplevel_ref_arg`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#toplevel_ref_arg
[`transmute_bytes_to_str`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
[`transmute_int_to_bool`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_int_to_bool
[`transmute_int_to_char`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_int_to_char
[`transmute_int_to_float`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_int_to_float

View file

@ -1,6 +1,6 @@
[package]
name = "clippy"
version = "0.0.168"
version = "0.0.169"
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",
"Andre Bogus <bogusandre@gmail.com>",
@ -37,7 +37,7 @@ path = "src/driver.rs"
[dependencies]
# begin automatic update
clippy_lints = { version = "0.0.168", path = "clippy_lints" }
clippy_lints = { version = "0.0.169", path = "clippy_lints" }
# end automatic update
cargo_metadata = "0.2"

View file

@ -1,7 +1,7 @@
[package]
name = "clippy_lints"
# begin automatic update
version = "0.0.168"
version = "0.0.169"
# end automatic update
authors = [
"Manish Goregaokar <manishsmail@gmail.com>",

View file

@ -120,13 +120,19 @@ fn to_const_range(
array_size: ConstInt,
) -> Option<(ConstInt, ConstInt)> {
let start = match *start {
Some(Some(&ty::Const { val: ConstVal::Integral(x), .. })) => x,
Some(Some(&ty::Const {
val: ConstVal::Integral(x),
..
})) => x,
Some(_) => return None,
None => ConstInt::U8(0),
};
let end = match *end {
Some(Some(&ty::Const { val: ConstVal::Integral(x), .. })) => if limits == RangeLimits::Closed {
Some(Some(&ty::Const {
val: ConstVal::Integral(x),
..
})) => if limits == RangeLimits::Closed {
match x {
ConstInt::U8(_) => (x + ConstInt::U8(1)),
ConstInt::U16(_) => (x + ConstInt::U16(1)),

View file

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

View file

@ -7,7 +7,7 @@ use rustc::ty::{self, TyCtxt};
use semver::Version;
use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use syntax::codemap::Span;
use utils::{in_macro, match_def_path, paths, snippet_opt, span_lint, span_lint_and_then, opt_def_id};
use utils::{in_macro, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then};
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
/// unless the annotated function is empty or simply panics.

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 COMPLEX_BLOCK_MESSAGE: &str = "in an 'if' condition, avoid complex blocks or closures with blocks; \
instead, move the block or closure higher and bind it with a 'let'";
instead, move the block or closure higher and bind it with a 'let'";
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
@ -92,9 +92,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
BLOCK_IN_IF_CONDITION_EXPR,
check.span,
BRACED_EXPR_MESSAGE,
&format!("try\nif {} {} ... ",
snippet_block(cx, ex.span, ".."),
snippet_block(cx, then.span, "..")),
&format!(
"try\nif {} {} ... ",
snippet_block(cx, ex.span, ".."),
snippet_block(cx, then.span, "..")
),
);
}
} else {
@ -111,9 +113,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
BLOCK_IN_IF_CONDITION_STMT,
check.span,
COMPLEX_BLOCK_MESSAGE,
&format!("try\nlet res = {};\nif res {} ... ",
snippet_block(cx, block.span, ".."),
snippet_block(cx, then.span, "..")),
&format!(
"try\nlet res = {};\nif res {} ... ",
snippet_block(cx, block.span, ".."),
snippet_block(cx, then.span, "..")
),
);
}
}

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
// decreases while none increases
improvement |= (stats.terminals[i] > simplified_stats.terminals[i]) ||
(stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops) ||
(stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
improvement |= (stats.terminals[i] > simplified_stats.terminals[i])
|| (stats.negations > simplified_stats.negations && stats.ops == simplified_stats.ops)
|| (stats.ops > simplified_stats.ops && stats.negations == simplified_stats.negations);
}
if improvement {
improvements.push(suggestion);

View file

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

View file

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

View file

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

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

View file

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

View file

@ -95,7 +95,7 @@ fn check_cond<'a, 'tcx, 'b>(
then {
let map = &params[0];
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map));
return if match_type(cx, obj_ty, &paths::BTREEMAP) {
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, params[1].span, ".."),
snippet(self.cx, params[2].span, ".."));
db.span_suggestion(self.span, "consider using", help);
}
else {
let help = format!("{}.entry({})",
snippet(self.cx, self.map.span, "map"),
snippet(self.cx, params[1].span, ".."));
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)
.const_eval(param_env.and((did, substs)))
{
Ok(&ty::Const { val: ConstVal::Integral(Usize(Us64(i))), .. }) => u64::from(i as u32) != i,
Ok(&ty::Const { val: ConstVal::Integral(Isize(Is64(i))), .. }) => i64::from(i as i32) != i,
Ok(&ty::Const {
val: ConstVal::Integral(Usize(Us64(i))),
..
}) => u64::from(i as u32) != i,
Ok(&ty::Const {
val: ConstVal::Integral(Isize(Is64(i))),
..
}) => i64::from(i as i32) != i,
_ => false,
};
if bad {

View file

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

View file

@ -2,7 +2,7 @@ use rustc::lint::*;
use rustc::hir;
use rustc::ty;
use syntax_pos::Span;
use utils::{method_chain_args, match_def_path, span_lint_and_then, walk_ptrs_ty};
use utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty};
use utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
/// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
@ -74,9 +74,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
if match_type(self.tcx, reciever_ty, &OPTION) ||
match_type(self.tcx, reciever_ty, &RESULT)
{
if match_type(self.tcx, reciever_ty, &OPTION) || match_type(self.tcx, reciever_ty, &RESULT) {
self.result.push(expr.span);
}
}
@ -105,7 +103,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
result: Vec::new(),
};
fpu.visit_expr(&body.value);
// if we've found one, lint
if !fpu.result.is_empty() {
span_lint_and_then(

View file

@ -3,7 +3,7 @@ use rustc::lint::*;
use rustc::ty;
use syntax::ast::LitKind;
use utils::paths;
use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty, opt_def_id};
use utils::{is_expn_of, match_def_path, match_type, opt_def_id, resolve_node, span_lint, walk_ptrs_ty};
/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
@ -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);
then {
let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
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.
fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) {
if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() &&
unsugar_if(second).is_some()
if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
&& unsugar_if(second).is_some()
{
// where the else would be
let else_span = first.span.between(second.span);

View file

@ -86,7 +86,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
use rustc::hir::map::Node::*;
let is_impl = if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(nodeid)) {
matches!(item.node, hir::ItemImpl(_, _, _, _, Some(_), _, _) | hir::ItemDefaultImpl(..))
matches!(item.node, hir::ItemImpl(_, _, _, _, Some(_), _, _) | hir::ItemAutoImpl(..))
} else {
false
};

View file

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

View file

@ -4,7 +4,7 @@
use rustc::lint::*;
use syntax::ast::*;
use utils::{span_help_and_lint, in_external_macro};
use utils::{in_external_macro, span_help_and_lint};
/// **What it does:** Checks for usage of `!` or `!=` in an if condition with an
/// else branch.

View file

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

View file

@ -1,13 +1,13 @@
use rustc::lint::*;
use rustc::ty;
use rustc::hir::*;
use utils::{match_def_path, paths, span_help_and_lint, opt_def_id};
use utils::{match_def_path, opt_def_id, paths, span_help_and_lint};
/// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
///
/// **Why is this bad?** Creation of null references is undefined behavior.
///
/// **Known problems:** None.
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
@ -22,9 +22,10 @@ declare_lint! {
const ZERO_REF_SUMMARY: &str = "reference to zeroed memory";
const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory";
const HELP: &str = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
const HELP: &str = "Creation of a null reference is undefined behavior; \
see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
pub struct InvalidRef;
pub struct InvalidRef;
impl LintPass for InvalidRef {
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 ExprPath(ref qpath) = path.node;
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));
then {
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) {
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) |
match_def_path(cx.tcx, def_id, &paths::INIT)
{
ZERO_REF_SUMMARY
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) {
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) |
match_def_path(cx.tcx, def_id, &paths::UNINIT)
{
UNINIT_REF_SUMMARY
} else {
return;
};
span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP);
}
}
}
return;
}
}

View file

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

View file

@ -68,7 +68,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
}
match item.node {
ItemTrait(_, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
ItemTrait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
ItemImpl(_, _, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items),
_ => (),
}
@ -119,8 +119,8 @@ fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[Trai
.iter()
.flat_map(|&i| cx.tcx.associated_items(i))
.any(|i| {
i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty" &&
cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.name == "is_empty"
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
});
if !is_empty_method_found {

View file

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

View file

@ -11,8 +11,7 @@
#![feature(inclusive_range_syntax, range_contains)]
#![feature(macro_vis_matcher)]
#![allow(unknown_lints, indexing_slicing, shadow_reuse, missing_docs_in_private_items)]
#![recursion_limit="256"]
#![recursion_limit = "256"]
#[macro_use]
extern crate rustc;
@ -375,8 +374,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
methods::FILTER_MAP,
methods::OPTION_MAP_UNWRAP_OR,
methods::OPTION_MAP_UNWRAP_OR_ELSE,
methods::RESULT_MAP_UNWRAP_OR_ELSE,
methods::OPTION_UNWRAP_USED,
methods::RESULT_MAP_UNWRAP_OR_ELSE,
methods::RESULT_UNWRAP_USED,
methods::WRONG_PUB_SELF_CONVENTION,
misc::USED_UNDERSCORE_BINDING,
@ -544,6 +543,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
new_without_default::NEW_WITHOUT_DEFAULT_DERIVE,
no_effect::NO_EFFECT,
no_effect::UNNECESSARY_OPERATION,
non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
non_expressive_names::MANY_SINGLE_CHAR_NAMES,
ok_if_let::IF_LET_SOME_RESULT,
open_options::NONSENSICAL_OPEN_OPTIONS,
@ -571,6 +571,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
swap::MANUAL_SWAP,
temporary_assignment::TEMPORARY_ASSIGNMENT,
transmute::CROSSPOINTER_TRANSMUTE,
transmute::TRANSMUTE_BYTES_TO_STR,
transmute::TRANSMUTE_INT_TO_BOOL,
transmute::TRANSMUTE_INT_TO_CHAR,
transmute::TRANSMUTE_INT_TO_FLOAT,

View file

@ -270,7 +270,7 @@ impl LiteralDigitGrouping {
.digits
.split_terminator('.')
.collect();
// Lint integral and fractional parts separately, and then check consistency of digit
// groups if both pass.
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_const_eval::ConstContext;
use std::collections::{HashMap, HashSet};
use std::iter::{Iterator, once};
use std::iter::{once, Iterator};
use syntax::ast;
use syntax::codemap::Span;
use utils::sugg;
@ -377,8 +377,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// check for never_loop
match expr.node {
ExprWhile(_, ref block, _) |
ExprLoop(ref block, _, _) => {
ExprWhile(_, ref block, _) | ExprLoop(ref block, _, _) => {
match never_loop_block(block, &expr.id) {
NeverLoopResult::AlwaysBreak =>
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
@ -410,11 +409,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node {
// ensure "if let" compatible match structure
match *source {
MatchSource::Normal |
MatchSource::IfLetDesugar { .. } => {
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
is_simple_break_expr(&arms[1].body)
MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none()
&& arms[1].pats.len() == 1 && arms[1].guard.is_none()
&& is_simple_break_expr(&arms[1].body)
{
if in_external_macro(cx, expr.span) {
return;
@ -446,15 +444,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
if let ExprMatch(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.node {
let pat = &arms[0].pats[0].node;
if let (&PatKind::TupleStruct(ref qpath, ref pat_args, _),
&ExprMethodCall(ref method_path, _, ref method_args)) = (pat, &match_expr.node)
if let (
&PatKind::TupleStruct(ref qpath, ref pat_args, _),
&ExprMethodCall(ref method_path, _, ref method_args),
) = (pat, &match_expr.node)
{
let iter_expr = &method_args[0];
let lhs_constructor = last_path_segment(qpath);
if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) &&
lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0]) &&
!is_iterator_used_after_while_let(cx, iter_expr) &&
!is_nested(cx, expr, &method_args[0])
if method_path.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR)
&& lhs_constructor.name == "Some" && !is_refutable(cx, &pat_args[0])
&& !is_iterator_used_after_while_let(cx, iter_expr)
&& !is_nested(cx, expr, &method_args[0])
{
let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_args[0].span, "_");
@ -545,8 +545,7 @@ fn never_loop_block(block: &Block, main_loop_id: &NodeId) -> NeverLoopResult {
fn stmt_to_expr(stmt: &Stmt) -> Option<&Expr> {
match stmt.node {
StmtSemi(ref e, ..) |
StmtExpr(ref e, ..) => Some(e),
StmtSemi(ref e, ..) | StmtExpr(ref e, ..) => Some(e),
StmtDecl(ref d, ..) => decl_to_expr(d),
}
}
@ -569,9 +568,9 @@ fn never_loop_expr(expr: &Expr, main_loop_id: &NodeId) -> NeverLoopResult {
ExprAddrOf(_, ref e) |
ExprStruct(_, _, Some(ref e)) |
ExprRepeat(ref e, _) => never_loop_expr(e, main_loop_id),
ExprArray(ref es) |
ExprMethodCall(_, _, ref es) |
ExprTup(ref es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
ExprArray(ref es) | ExprMethodCall(_, _, ref es) | ExprTup(ref es) => {
never_loop_expr_all(&mut es.iter(), main_loop_id)
},
ExprCall(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id),
ExprBinary(_, ref e1, ref e2) |
ExprAssign(ref e1, ref e2) |
@ -604,7 +603,9 @@ fn never_loop_expr(expr: &Expr, main_loop_id: &NodeId) -> NeverLoopResult {
},
ExprBlock(ref b) => never_loop_block(b, main_loop_id),
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");
if id == *main_loop_id {
NeverLoopResult::MayContinueMainLoop
} else {
@ -631,15 +632,18 @@ fn never_loop_expr(expr: &Expr, main_loop_id: &NodeId) -> NeverLoopResult {
}
fn never_loop_expr_seq<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: &NodeId) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, main_loop_id)).fold(NeverLoopResult::Otherwise, combine_seq)
es.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_seq)
}
fn never_loop_expr_all<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: &NodeId) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, main_loop_id)).fold(NeverLoopResult::Otherwise, combine_both)
es.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_both)
}
fn never_loop_expr_branch<'a, T: Iterator<Item=&'a Expr>>(e: &mut T, main_loop_id: &NodeId) -> NeverLoopResult {
e.map(|e| never_loop_expr(e, main_loop_id)).fold(NeverLoopResult::AlwaysBreak, combine_branches)
e.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
}
fn check_for_loop<'a, 'tcx>(
@ -713,11 +717,9 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty) -> bool {
fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> Option<FixedOffsetVar> {
fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: ast::NodeId) -> Option<String> {
match e.node {
ExprLit(ref l) => {
match l.node {
ast::LitKind::Int(x, _ty) => Some(x.to_string()),
_ => None,
}
ExprLit(ref l) => match l.node {
ast::LitKind::Int(x, _ty) => Some(x.to_string()),
_ => None,
},
ExprPath(..) if !same_var(cx, e, var) => Some(snippet_opt(cx, e.span).unwrap_or_else(|| "??".into())),
_ => None,
@ -731,29 +733,25 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var:
}
let offset = match idx.node {
ExprBinary(op, ref lhs, ref rhs) => {
match op.node {
BinOp_::BiAdd => {
let offset_opt = if same_var(cx, lhs, var) {
extract_offset(cx, rhs, var)
} else if same_var(cx, rhs, var) {
extract_offset(cx, lhs, var)
} else {
None
};
ExprBinary(op, ref lhs, ref rhs) => match op.node {
BinOp_::BiAdd => {
let offset_opt = if same_var(cx, lhs, var) {
extract_offset(cx, rhs, var)
} else if same_var(cx, rhs, var) {
extract_offset(cx, lhs, var)
} else {
None
};
offset_opt.map(Offset::positive)
},
BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
_ => None,
}
offset_opt.map(Offset::positive)
},
BinOp_::BiSub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
_ => None,
},
ExprPath(..) => {
if same_var(cx, idx, var) {
Some(Offset::positive("0".into()))
} else {
None
}
ExprPath(..) => if same_var(cx, idx, var) {
Some(Offset::positive("0".into()))
} else {
None
},
_ => None,
};
@ -825,12 +823,13 @@ fn get_indexed_assignments<'a, 'tcx>(
.iter()
.map(|stmt| match stmt.node {
Stmt_::StmtDecl(..) => None,
Stmt_::StmtExpr(ref e, _node_id) |
Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
Stmt_::StmtExpr(ref e, _node_id) | Stmt_::StmtSemi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
})
.chain(expr.as_ref().into_iter().map(|e| {
Some(get_assignment(cx, &*e, var))
}))
.chain(
expr.as_ref()
.into_iter()
.map(|e| Some(get_assignment(cx, &*e, var))),
)
.filter_map(|op| op)
.collect::<Option<Vec<_>>>()
.unwrap_or_else(|| vec![])
@ -849,20 +848,18 @@ fn detect_manual_memcpy<'a, 'tcx>(
expr: &'tcx Expr,
) {
if let Some(higher::Range {
start: Some(start),
ref end,
limits,
}) = higher::range(arg)
start: Some(start),
ref end,
limits,
}) = higher::range(arg)
{
// the var must be a single name
if let PatKind::Binding(_, canonical_id, _, _) = pat.node {
let print_sum = |arg1: &Offset, arg2: &Offset| -> String {
match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) {
("0", _, "0", _) => "".into(),
("0", _, x, false) |
(x, false, "0", false) => x.into(),
("0", _, x, true) |
(x, false, "0", true) => format!("-{}", x),
("0", _, x, false) | (x, false, "0", false) => x.into(),
("0", _, x, true) | (x, false, "0", true) => format!("-{}", x),
(x, false, y, false) => format!("({} + {})", x, y),
(x, false, y, true) => format!("({} - {})", x, y),
(x, true, y, false) => format!("({} - {})", y, x),
@ -945,10 +942,10 @@ fn check_for_loop_range<'a, 'tcx>(
expr: &'tcx Expr,
) {
if let Some(higher::Range {
start: Some(start),
ref end,
limits,
}) = higher::range(arg)
start: Some(start),
ref end,
limits,
}) = higher::range(arg)
{
// the var must be a single name
if let PatKind::Binding(_, canonical_id, ref ident, _) = pat.node {
@ -965,9 +962,11 @@ fn check_for_loop_range<'a, 'tcx>(
// linting condition: we only indexed one variable, and indexed it directly
// (`indexed_directly` is subset of `indexed`)
if visitor.indexed.len() == 1 && visitor.indexed_directly.len() == 1 {
let (indexed, indexed_extent) = visitor.indexed_directly.into_iter().next().expect(
"already checked that we have exactly 1 element",
);
let (indexed, indexed_extent) = visitor
.indexed_directly
.into_iter()
.next()
.expect("already checked that we have exactly 1 element");
// ensure that the indexed variable was declared before the loop, see #601
if let Some(indexed_extent) = indexed_extent {
@ -1072,10 +1071,10 @@ fn is_len_call(expr: &Expr, var: &Name) -> bool {
fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr, expr: &'tcx Expr) {
// if this for loop is iterating over a two-sided range...
if let Some(higher::Range {
start: Some(start),
end: Some(end),
limits,
}) = higher::range(arg)
start: Some(start),
end: Some(end),
limits,
}) = higher::range(arg)
{
// ...and both sides are compile-time constant integers...
let parent_item = cx.tcx.hir.get_parent(arg.id);
@ -1089,10 +1088,16 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
// who think that this will iterate from the larger value to the
// smaller value.
let (sup, eq) = match (start_idx, end_idx) {
(&ty::Const { val: ConstVal::Integral(start_idx), .. },
&ty::Const { val: ConstVal::Integral(end_idx), .. }) => {
(start_idx > end_idx, start_idx == end_idx)
},
(
&ty::Const {
val: ConstVal::Integral(start_idx),
..
},
&ty::Const {
val: ConstVal::Integral(end_idx),
..
},
) => (start_idx > end_idx, start_idx == end_idx),
_ => (false, false),
};
@ -1180,7 +1185,7 @@ fn check_for_loop_arg(cx: &LateContext, pat: &Pat, arg: &Expr, expr: &Expr) {
// If the length is greater than 32 no traits are implemented for array and
// therefore we cannot use `&`.
ty::TypeVariants::TyArray(_, size) if const_to_u64(size) > 32 => (),
_ => lint_iter_method(cx, args, arg, method_name)
_ => lint_iter_method(cx, args, arg, method_name),
};
} else {
let object = snippet(cx, args[0].span, "_");
@ -1267,14 +1272,14 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
// For each candidate, check the parent block to see if
// it's initialized to zero at the start of the loop.
let map = &cx.tcx.hir;
let parent_scope = map.get_enclosing_scope(expr.id).and_then(|id| {
map.get_enclosing_scope(id)
});
let parent_scope = map.get_enclosing_scope(expr.id)
.and_then(|id| map.get_enclosing_scope(id));
if let Some(parent_id) = parent_scope {
if let NodeBlock(block) = map.get(parent_id) {
for (id, _) in visitor.states.iter().filter(
|&(_, v)| *v == VarState::IncrOnce,
)
for (id, _) in visitor
.states
.iter()
.filter(|&(_, v)| *v == VarState::IncrOnce)
{
let mut visitor2 = InitializeVisitor {
cx: cx,
@ -1321,12 +1326,10 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
if pat.len() == 2 {
let arg_span = arg.span;
let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).sty {
ty::TyRef(_, ref tam) => {
match (&pat[0].node, &pat[1].node) {
(key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl),
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable),
_ => return,
}
ty::TyRef(_, ref tam) => match (&pat[0].node, &pat[1].node) {
(key, _) if pat_is_wild(key, body) => (pat[1].span, "value", tam.ty, tam.mutbl),
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key", tam.ty, MutImmutable),
_ => return,
},
_ => return,
};
@ -1370,14 +1373,11 @@ struct MutateDelegate {
}
impl<'tcx> Delegate<'tcx> for MutateDelegate {
fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) {
}
fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) {}
fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {
}
fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) {}
fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) {
}
fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) {}
fn borrow(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) {
if let ty::BorrowKind::MutBorrow = bk {
@ -1403,8 +1403,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 {
@ -1414,8 +1413,16 @@ impl<'tcx> MutateDelegate {
}
fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) {
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(arg) {
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
if let Some(higher::Range {
start: Some(start),
end: Some(end),
..
}) = higher::range(arg)
{
let mut_ids = vec![
check_for_mutability(cx, start),
check_for_mutability(cx, end),
];
if mut_ids[0].is_some() || mut_ids[1].is_some() {
let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
mut_warn_with_span(cx, span_low);
@ -1426,7 +1433,12 @@ fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) {
fn mut_warn_with_span(cx: &LateContext, span: Option<Span>) {
if let Some(sp) = span {
span_lint(cx, MUT_RANGE_BOUND, sp, "attempt to mutate range bound within loop; note that the range of the loop is unchanged");
span_lint(
cx,
MUT_RANGE_BOUND,
sp,
"attempt to mutate range bound within loop; note that the range of the loop is unchanged",
);
}
}
@ -1453,7 +1465,12 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option<NodeId> {
}
fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) {
let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None };
let mut delegate = MutateDelegate {
node_id_low: bound_ids[0],
node_id_high: bound_ids[1],
span_low: None,
span_high: None,
};
let def_id = def_id::DefId::local(body.hir_id.owner);
let region_scope_tree = &cx.tcx.region_scope_tree(def_id);
ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).walk_expr(body);
@ -1478,7 +1495,7 @@ fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool {
struct UsedVisitor {
var: ast::Name, // var to look for
used: bool, // has the var been used otherwise?
used: bool, // has the var been used otherwise?
}
impl<'tcx> Visitor<'tcx> for UsedVisitor {
@ -1700,12 +1717,9 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> {
fn extract_first_expr(block: &Block) -> Option<&Expr> {
match block.expr {
Some(ref expr) if block.stmts.is_empty() => Some(expr),
None if !block.stmts.is_empty() => {
match block.stmts[0].node {
StmtExpr(ref expr, _) |
StmtSemi(ref expr, _) => Some(expr),
StmtDecl(..) => None,
}
None if !block.stmts.is_empty() => match block.stmts[0].node {
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr),
StmtDecl(..) => None,
},
_ => None,
}
@ -1717,11 +1731,9 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> {
fn is_simple_break_expr(expr: &Expr) -> bool {
match expr.node {
ExprBreak(dest, ref passed_expr) if dest.ident.is_none() && passed_expr.is_none() => true,
ExprBlock(ref b) => {
match extract_first_expr(b) {
Some(subexpr) => is_simple_break_expr(subexpr),
None => false,
}
ExprBlock(ref b) => match extract_first_expr(b) {
Some(subexpr) => is_simple_break_expr(subexpr),
None => false,
},
_ => false,
}
@ -1732,7 +1744,7 @@ fn is_simple_break_expr(expr: &Expr) -> bool {
// at the start of the loop.
#[derive(PartialEq)]
enum VarState {
Initial, // Not examined yet
Initial, // Not examined yet
IncrOnce, // Incremented exactly once, may be a loop counter
Declared, // Declared but not (yet) initialized to zero
Warn,
@ -1741,9 +1753,9 @@ enum VarState {
/// Scan a for loop for variables that are incremented exactly once.
struct IncrementVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>, // context reference
cx: &'a LateContext<'a, 'tcx>, // context reference
states: HashMap<NodeId, VarState>, // incremented variables
depth: u32, // depth of conditional expressions
depth: u32, // depth of conditional expressions
done: bool,
}
@ -1797,7 +1809,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
/// Check whether a variable is initialized to zero at the start of a loop.
struct InitializeVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>, // context reference
end_expr: &'tcx Expr, // the for loop. Stop scanning here.
end_expr: &'tcx Expr, // the for loop. Stop scanning here.
var_id: NodeId,
state: VarState,
name: Option<Name>,
@ -1929,13 +1941,11 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool
return false;
}
match cx.tcx.hir.find(parent) {
Some(NodeExpr(expr)) => {
match expr.node {
ExprLoop(..) | ExprWhile(..) => {
return true;
},
_ => (),
}
Some(NodeExpr(expr)) => match expr.node {
ExprLoop(..) | ExprWhile(..) => {
return true;
},
_ => (),
},
Some(NodeBlock(block)) => {
let mut block_visitor = LoopNestVisitor {
@ -1959,8 +1969,8 @@ fn is_loop_nested(cx: &LateContext, loop_expr: &Expr, iter_expr: &Expr) -> bool
#[derive(PartialEq, Eq)]
enum Nesting {
Unknown, // no nesting detected yet
RuledOut, // the iterator is initialized or assigned within scope
Unknown, // no nesting detected yet
RuledOut, // the iterator is initialized or assigned within scope
LookFurther, // no nesting detected, no further walk required
}
@ -1990,11 +2000,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
return;
}
match expr.node {
ExprAssign(ref path, _) |
ExprAssignOp(_, ref path, _) => {
if match_var(path, self.iterator) {
self.nesting = RuledOut;
}
ExprAssign(ref path, _) | ExprAssignOp(_, ref path, _) => if match_var(path, self.iterator) {
self.nesting = RuledOut;
},
_ => walk_expr(self, expr),
}

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

View file

@ -1,6 +1,6 @@
use rustc::lint::*;
use rustc::hir::{Expr, ExprCall, ExprPath};
use utils::{match_def_path, paths, span_lint, opt_def_id};
use utils::{match_def_path, opt_def_id, paths, span_lint};
/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is
/// `Drop`.

View file

@ -652,7 +652,8 @@ impl LintPass for Pass {
GET_UNWRAP,
STRING_EXTEND_CHARS,
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
let def_id = cx.tcx.hir.local_def_id(item.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 {
if_chain! {
if conv.check(&name.as_str());
if !self_kinds.iter().any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy, &implitem.generics));
if !self_kinds
.iter()
.any(|k| k.matches(first_arg_ty, first_arg, self_ty, is_copy, &implitem.generics));
then {
let lint = if item.vis == hir::Visibility::Public {
WRONG_PUB_SELF_CONVENTION
@ -801,7 +804,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
}
}
let ret_ty = return_ty(cx, implitem.id);
if name == "new" &&
!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
// FIXME: can we `expect` here instead of match?
let owner_def = cx.tcx.hir.get_parent_did(arg.id);
let promotable = cx.tcx
.rvalue_promotable_map(owner_def)
[&arg.hir_id.local_id];
let promotable = cx.tcx.rvalue_promotable_map(owner_def)[&arg.hir_id.local_id];
if promotable {
return;
}
@ -991,12 +992,8 @@ fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) {
expr.span,
"using '.clone()' on a ref-counted pointer",
"try this",
format!("{}::clone(&{})",
caller_type,
snippet(cx, arg.span, "_")
)
format!("{}::clone(&{})", caller_type, snippet(cx, arg.span, "_")),
);
}
@ -1044,19 +1041,22 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr
if let Def::Method(did) = cx.tables.qpath_def(path, fun.hir_id);
if match_def_path(cx.tcx, did, &paths::CSTRING_NEW);
then {
span_lint_and_then(cx, TEMPORARY_CSTRING_AS_PTR, expr.span,
"you are getting the inner pointer of a temporary `CString`",
|db| {
db.note("that pointer will be invalid outside this expression");
db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
});
span_lint_and_then(
cx,
TEMPORARY_CSTRING_AS_PTR,
expr.span,
"you are getting the inner pointer of a temporary `CString`",
|db| {
db.note("that pointer will be invalid outside this expression");
db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
});
}
}
}
fn lint_iter_cloned_collect(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr]) {
if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC) &&
derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC)
&& derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
{
span_lint(
cx,
@ -1231,8 +1231,16 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::Expr]
// lint message
// comparing the snippet from source to raw text ("None") below is safe
// because we already have checked the type.
let arg = if unwrap_snippet == "None" { "None" } else { "a" };
let suggest = if unwrap_snippet == "None" { "and_then(f)" } else { "map_or(a, f)" };
let arg = if unwrap_snippet == "None" {
"None"
} else {
"a"
};
let suggest = if unwrap_snippet == "None" {
"and_then(f)"
} else {
"map_or(a, f)"
};
let msg = &format!(
"called `map(f).unwrap_or({})` on an Option value. \
This can be done more directly by calling `{}` instead",
@ -1276,10 +1284,10 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
// lint message
let msg = if is_option {
"called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \
`map_or_else(g, f)` instead"
`map_or_else(g, f)` instead"
} else {
"called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \
`ok().map_or_else(g, f)` instead"
`ok().map_or_else(g, f)` instead"
};
// get snippets for args to map() and unwrap_or_else()
let map_snippet = snippet(cx, map_args[1].span, "..");
@ -1323,7 +1331,6 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
/// lint use of `_.map_or(None, _)` for `Option`s
fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_or_args: &'tcx [hir::Expr]) {
if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) {
// check if the first non-self argument to map_or() is None
let map_or_arg_is_none = if let hir::Expr_::ExprPath(ref qpath) = map_or_args[1].node {
@ -1339,13 +1346,9 @@ fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
let map_or_self_snippet = snippet(cx, map_or_args[0].span, "..");
let map_or_func_snippet = snippet(cx, map_or_args[2].span, "..");
let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
span_lint_and_then(
cx,
OPTION_MAP_OR_NONE,
expr.span,
msg,
|db| { db.span_suggestion(expr.span, "try using and_then instead", hint); },
);
span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| {
db.span_suggestion(expr.span, "try using and_then instead", hint);
});
}
}
}
@ -1374,7 +1377,12 @@ fn lint_filter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
}
/// lint use of `filter().map()` for `Iterators`
fn lint_filter_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
fn lint_filter_map<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr,
_filter_args: &'tcx [hir::Expr],
_map_args: &'tcx [hir::Expr],
) {
// lint if caller of `.filter().map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter(p).map(q)` on an `Iterator`. \
@ -1384,7 +1392,12 @@ fn lint_filter_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
}
/// lint use of `filter().map()` for `Iterators`
fn lint_filter_map_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
fn lint_filter_map_map<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr,
_filter_args: &'tcx [hir::Expr],
_map_args: &'tcx [hir::Expr],
) {
// lint if caller of `.filter().map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter_map(p).map(q)` on an `Iterator`. \
@ -1394,7 +1407,12 @@ fn lint_filter_map_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Ex
}
/// lint use of `filter().flat_map()` for `Iterators`
fn lint_filter_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
fn lint_filter_flat_map<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr,
_filter_args: &'tcx [hir::Expr],
_map_args: &'tcx [hir::Expr],
) {
// lint if caller of `.filter().flat_map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter(p).flat_map(q)` on an `Iterator`. \
@ -1405,7 +1423,12 @@ fn lint_filter_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::E
}
/// lint use of `filter_map().flat_map()` for `Iterators`
fn lint_filter_map_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, _filter_args: &'tcx [hir::Expr], _map_args: &'tcx [hir::Expr]) {
fn lint_filter_map_flat_map<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr,
_filter_args: &'tcx [hir::Expr],
_map_args: &'tcx [hir::Expr],
) {
// lint if caller of `.filter_map().flat_map()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`. \
@ -1476,7 +1499,13 @@ fn lint_binary_expr_with_method_call<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, i
}
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints.
fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool {
fn lint_chars_cmp<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
info: &BinaryExprInfo,
chain_methods: &[&str],
lint: &'static Lint,
suggest: &str,
) -> bool {
if_chain! {
if let Some(args) = method_chain_args(info.chain, chain_methods);
if let hir::ExprCall(ref fun, ref arg_char) = info.other.node;
@ -1486,11 +1515,11 @@ fn lint_chars_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, c
if segment.name == "Some";
then {
let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
if self_ty.sty != ty::TyStr {
return false;
}
span_lint_and_sugg(cx,
lint,
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, "_"),
suggest,
snippet(cx, arg_char[0].span, "_")));
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()`.
fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo, chain_methods: &[&str], lint: &'static Lint, suggest: &str) -> bool {
fn lint_chars_cmp_with_unwrap<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
info: &BinaryExprInfo,
chain_methods: &[&str],
lint: &'static Lint,
suggest: &str,
) -> bool {
if_chain! {
if let Some(args) = method_chain_args(info.chain, chain_methods);
if let hir::ExprLit(ref lit) = info.other.node;
@ -1542,7 +1577,7 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &Binar
suggest,
c)
);
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_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
if let Ok(&ty::Const { val: ConstVal::Str(r), .. }) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg) {
if let Ok(&ty::Const {
val: ConstVal::Str(r),
..
}) = ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(arg)
{
if r.len() == 1 {
let hint = snippet(cx, expr.span, "..").replace(&format!("\"{}\"", r), &format!("'{}'", r));
span_lint_and_then(
@ -1577,7 +1616,9 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hi
SINGLE_CHAR_PATTERN,
arg.span,
"single-character string constant used as pattern",
|db| { db.span_suggestion(expr.span, "try using a char instead", hint); },
|db| {
db.span_suggestion(expr.span, "try using a char instead", hint);
},
);
}
}
@ -1772,31 +1813,25 @@ impl SelfKind {
fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[&str]) -> bool {
single_segment_ty(ty).map_or(false, |seg| {
generics.ty_params.iter().any(|param| {
param.name == seg.name &&
param
.bounds
.iter()
.any(|bound| if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound {
let path = &ptr.trait_ref.path;
match_path(path, name) &&
path.segments
.last()
.map_or(false, |s| {
if let Some(ref params) = s.parameters {
if params.parenthesized {
false
} else {
params.types.len() == 1 &&
(is_self_ty(&params.types[0])
|| is_ty(&*params.types[0], self_ty))
}
} else {
false
}
})
} else {
false
param.name == seg.name && param.bounds.iter().any(|bound| {
if let hir::TyParamBound::TraitTyParamBound(ref ptr, ..) = *bound {
let path = &ptr.trait_ref.path;
match_path(path, name) && path.segments.last().map_or(false, |s| {
if let Some(ref params) = s.parameters {
if params.parenthesized {
false
} else {
params.types.len() == 1
&& (is_self_ty(&params.types[0]) || is_ty(&*params.types[0], self_ty))
}
} else {
false
}
})
} else {
false
}
})
})
})
}

View file

@ -2,7 +2,7 @@ use consts::{constant_simple, Constant};
use rustc::lint::*;
use rustc::hir::*;
use std::cmp::{Ordering, PartialOrd};
use utils::{match_def_path, paths, span_lint, opt_def_id};
use utils::{match_def_path, opt_def_id, paths, span_lint};
/// **What it does:** Checks for expressions where `std::cmp::min` and `max` are
/// used to clamp values, but switched so that the result is constant.

View file

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

View file

@ -132,7 +132,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
hir::ItemGlobalAsm(..) => "an assembly blob",
hir::ItemTy(..) => "a type alias",
hir::ItemUnion(..) => "a union",
hir::ItemDefaultImpl(..) |
hir::ItemAutoImpl(..) |
hir::ItemExternCrate(..) |
hir::ItemForeignMod(..) |
hir::ItemImpl(..) |

View file

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

View file

@ -255,13 +255,13 @@ struct LintData<'a> {
const MSG_REDUNDANT_ELSE_BLOCK: &str = "This else block is redundant.\n";
const MSG_ELSE_BLOCK_NOT_NEEDED: &str = "There is no need for an explicit `else` block for this `if` \
expression\n";
expression\n";
const DROP_ELSE_BLOCK_AND_MERGE_MSG: &str = "Consider dropping the else clause and merging the code that \
follows (in the loop) with the if block, like so:\n";
follows (in the loop) with the if block, like so:\n";
const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving out the code in the else \
block, like so:\n";
block, like so:\n";
fn emit_warning<'a>(ctx: &EarlyContext, data: &'a LintData, header: &str, typ: LintType) {
@ -332,22 +332,24 @@ fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext, data: &'a
}
fn check_and_warn<'a>(ctx: &EarlyContext, expr: &'a ast::Expr) {
with_loop_block(expr, |loop_block| for (i, stmt) in loop_block.stmts.iter().enumerate() {
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
let data = &LintData {
stmt_idx: i,
if_expr: if_expr,
if_cond: cond,
if_block: then_block,
else_expr: else_expr,
block_stmts: &loop_block.stmts,
};
if needless_continue_in_else(else_expr) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock);
} else if is_first_block_stmt_continue(then_block) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
}
});
with_loop_block(expr, |loop_block| {
for (i, stmt) in loop_block.stmts.iter().enumerate() {
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
let data = &LintData {
stmt_idx: i,
if_expr: if_expr,
if_cond: cond,
if_block: then_block,
else_expr: else_expr,
block_stmts: &loop_block.stmts,
};
if needless_continue_in_else(else_expr) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock);
} else if is_first_block_stmt_continue(then_block) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
}
});
}
});
}

View file

@ -87,7 +87,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
// Exclude non-inherent impls
if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(node_id)) {
if matches!(item.node, ItemImpl(_, _, _, _, Some(_), _, _) | ItemDefaultImpl(..)) {
if matches!(item.node, ItemImpl(_, _, _, _, Some(_), _, _) | ItemAutoImpl(..)) {
return;
}
}
@ -106,13 +106,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
.filter(|p| !p.is_global())
.filter_map(|pred| if let ty::Predicate::Trait(poly_trait_ref) = pred {
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() {
return None;
.filter_map(|pred| {
if let ty::Predicate::Trait(poly_trait_ref) = pred {
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() {
return None;
}
Some(poly_trait_ref)
} else {
None
}
Some(poly_trait_ref)
} else {
None
})
.collect::<Vec<_>>();

View file

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

View file

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

View file

@ -42,13 +42,33 @@ declare_lint! {
"too many single character bindings"
}
/// **What it does:** Checks if you have variables whose name consists of just
/// underscores and digits.
///
/// **Why is this bad?** It's hard to memorize what a variable means without a
/// descriptive name.
///
/// **Known problems:** None?
///
/// **Example:**
/// ```rust
/// let _1 = 1;
/// let ___1 = 1;
/// let __1___2 = 11;
/// ```
declare_lint! {
pub JUST_UNDERSCORES_AND_DIGITS,
Warn,
"unclear name"
}
pub struct NonExpressiveNames {
pub single_char_binding_names_threshold: u64,
}
impl LintPass for NonExpressiveNames {
fn get_lints(&self) -> LintArray {
lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES)
lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS)
}
}
@ -133,6 +153,15 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
if interned_name.chars().any(char::is_uppercase) {
return;
}
if interned_name.chars().all(|c| c.is_digit(10) || c == '_') {
span_lint(
self.0.cx,
JUST_UNDERSCORES_AND_DIGITS,
span,
"consider choosing a more descriptive name",
);
return;
}
let count = interned_name.chars().count();
if count < 3 {
if count == 1 {
@ -187,8 +216,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
let second_last_e = existing_chars
.next_back()
.expect("we know we have at least three chars");
if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' ||
!interned_chars.zip(existing_chars).all(eq_or_numeric)
if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_'
|| !interned_chars.zip(existing_chars).all(eq_or_numeric)
{
// allowed similarity foo_x, foo_y
// or too many chars differ (foo_x, boo_y) or (foox, booy)
@ -203,8 +232,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
let second_e = existing_chars
.next()
.expect("we know we have at least two chars");
if !eq_or_numeric((second_i, second_e)) || second_i == '_' ||
!interned_chars.zip(existing_chars).all(eq_or_numeric)
if !eq_or_numeric((second_i, second_e)) || second_i == '_'
|| !interned_chars.zip(existing_chars).all(eq_or_numeric)
{
// allowed similarity x_foo, y_foo
// or too many chars differ (x_foo, y_boo) or (xfoo, yboo)

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 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;
then {
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, "");

View file

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

View file

@ -1,7 +1,7 @@
use rustc::hir::*;
use rustc::lint::*;
use syntax::ast::LitKind;
use utils::{is_direct_expn_of, match_def_path, paths, resolve_node, span_lint, opt_def_id};
use utils::{is_direct_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint};
/// **What it does:** Checks for missing parameters in `panic!`.
///

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@ use std::error::Error;
use syntax::ast::{LitKind, NodeId};
use syntax::codemap::{BytePos, Span};
use syntax::symbol::InternedString;
use utils::{is_expn_of, match_def_path, match_type, paths, span_help_and_lint, span_lint, opt_def_id};
use utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint};
/// **What it does:** Checks [regex](https://crates.io/crates/regex) creation
/// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct
@ -151,7 +151,10 @@ fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<Inte
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
match ConstContext::new(cx.tcx, cx.param_env.and(substs), cx.tables).eval(e) {
Ok(&ty::Const { val: ConstVal::Str(r), .. }) => Some(r),
Ok(&ty::Const {
val: ConstVal::Str(r),
..
}) => Some(r),
_ => None,
}
}

View file

@ -253,7 +253,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
snippet(cx, pattern_span, "_"),
snippet(cx, expr.span, "..")
),
|db| { db.span_note(prev_span, "previous binding is here"); },
|db| {
db.span_note(prev_span, "previous binding is here");
},
);
} else if contains_name(name, expr) {
span_lint_and_then(
@ -292,7 +294,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
SHADOW_UNRELATED,
span,
&format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")),
|db| { db.span_note(prev_span, "previous binding is here"); },
|db| {
db.span_note(prev_span, "previous binding is here");
},
);
}
}
@ -361,8 +365,8 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool {
match expr.node {
ExprBox(ref inner) | ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
ExprBlock(ref block) => {
block.stmts.is_empty() &&
block
block.stmts.is_empty()
&& block
.expr
.as_ref()
.map_or(false, |e| is_self_shadow(name, e))

View file

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

View file

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

View file

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

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 match_def_path(cx.tcx, did, &paths::VEC);
then {
span_help_and_lint(cx,
BOX_VEC,
ast_ty.span,
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
span_help_and_lint(
cx,
BOX_VEC,
ast_ty.span,
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
);
return; // don't recurse into the type
}
}
@ -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.
return;
}
let ltopt = if lt.is_elided() {
"".to_owned()
} 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)) {
return;
}
if match_path(ty_path, &paths::HASHMAP) {
if method.name == "new" {
self.suggestions

View file

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

View file

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

View file

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

View file

@ -55,8 +55,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
/// Check whether two blocks are the same.
pub fn eq_block(&self, left: &Block, right: &Block) -> bool {
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) &&
both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
&& both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
}
pub fn eq_expr(&self, left: &Expr, right: &Expr) -> bool {
@ -81,14 +81,14 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
},
(&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r),
(&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => {
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) ||
swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|| swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
})
},
(&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => {
both(&li.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str()) &&
both(le, re, |l, r| self.eq_expr(l, r))
both(&li.ident, &ri.ident, |l, r| l.node.name.as_str() == r.node.name.as_str())
&& both(le, re, |l, r| self.eq_expr(l, r))
},
(&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
(&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => {
@ -109,22 +109,22 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
},
(&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
ls == rs && self.eq_expr(le, re) && over(la, ra, |l, r| {
self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r))
&& over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
})
},
(&ExprMethodCall(ref l_path, _, ref l_args), &ExprMethodCall(ref r_path, _, ref r_args)) => {
!self.ignore_fn && l_path == r_path && self.eq_exprs(l_args, r_args)
},
(&ExprRepeat(ref le, ll_id), &ExprRepeat(ref re, rl_id)) => {
self.eq_expr(le, re) &&
self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
self.eq_expr(le, re)
&& self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
},
(&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r),
(&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
over(lf, rf, |l, r| self.eq_field(l, r))
self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r))
&& over(lf, rf, |l, r| self.eq_field(l, r))
},
(&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
(&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
@ -169,8 +169,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
},
(&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
(&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) &&
both(li, ri, |l, r| self.eq_pat(l, r))
over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r))
&& both(li, ri, |l, r| self.eq_pat(l, r))
},
(&PatKind::Wild, &PatKind::Wild) => true,
_ => false,
@ -190,18 +190,18 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
}
fn eq_path(&self, left: &Path, right: &Path) -> bool {
left.is_global() == right.is_global() &&
over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
left.is_global() == right.is_global()
&& over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
}
fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool {
if !(left.parenthesized || right.parenthesized) {
over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r)) &&
over(&left.types, &right.types, |l, r| self.eq_ty(l, r)) &&
over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r))
&& over(&left.types, &right.types, |l, r| self.eq_ty(l, r))
&& over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
} else if left.parenthesized && right.parenthesized {
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) &&
both(
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
&& both(
&Some(&left.bindings[0].ty),
&Some(&right.bindings[0].ty),
|l, r| self.eq_ty(l, r),
@ -220,7 +220,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
match (&left.parameters, &right.parameters) {
(&None, &None) => true,
(&Some(ref l), &Some(ref r)) => self.eq_path_parameters(l, r),
_ => false
_ => false,
}
}
@ -228,8 +228,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
match (&left.node, &right.node) {
(&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
(&TyArray(ref lt, ll_id), &TyArray(ref rt, rl_id)) => {
self.eq_ty(lt, rt) &&
self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
self.eq_ty(lt, rt)
&& self.eq_expr(&self.cx.tcx.hir.body(ll_id).value, &self.cx.tcx.hir.body(rl_id).value)
},
(&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
(&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {

View file

@ -397,14 +397,14 @@ fn print_item(cx: &LateContext, item: &hir::Item) {
},
hir::ItemTrait(..) => {
println!("trait decl");
if cx.tcx.trait_has_default_impl(did) {
println!("trait has a default impl");
if cx.tcx.trait_is_auto(did) {
println!("trait is auto");
} else {
println!("trait has no default impl");
println!("trait is not auto");
}
},
hir::ItemDefaultImpl(_, ref _trait_ref) => {
println!("default impl");
hir::ItemAutoImpl(_, ref _trait_ref) => {
println!("auto impl");
},
hir::ItemImpl(_, _, _, _, Some(ref _trait_ref), _, _) => {
println!("trait impl");

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);
apb.names.len() == path.len() &&
apb.names
apb.names.len() == path.len()
&& apb.names
.into_iter()
.zip(path.iter())
.all(|(a, &b)| *a == *b)
@ -201,8 +201,8 @@ pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool {
QPath::Resolved(_, ref path) => match_path(path, segments),
QPath::TypeRelative(ref ty, ref segment) => match ty.node {
TyPath(ref inner_path) => {
!segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) &&
segment.name == segments[segments.len() - 1]
!segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)])
&& segment.name == segments[segments.len() - 1]
},
_ => false,
},
@ -233,7 +233,6 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
/// Get the definition associated to a path.
pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
let crates = cx.tcx.crates();
let krate = crates
.iter()
@ -269,7 +268,11 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
}
pub fn const_to_u64(c: &ty::Const) -> u64 {
c.val.to_const_int().expect("eddyb says this works").to_u64().expect("see previous expect")
c.val
.to_const_int()
.expect("eddyb says this works")
.to_u64()
.expect("see previous expect")
}
/// Convenience function to get the `DefId` of a trait by path.
@ -473,10 +476,12 @@ fn trim_multiline_inner(s: Cow<str>, ignore_first: bool, ch: char) -> Cow<str> {
Cow::Owned(
s.lines()
.enumerate()
.map(|(i, l)| if (ignore_first && i == 0) || l.is_empty() {
l
} else {
l.split_at(x).1
.map(|(i, l)| {
if (ignore_first && i == 0) || l.is_empty() {
l
} else {
l.split_at(x).1
}
})
.collect::<Vec<_>>()
.join("\n"),
@ -494,12 +499,13 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext, e: &Expr) -> Option<&'c Expr> {
if node_id == parent_id {
return None;
}
map.find(parent_id)
.and_then(|node| if let Node::NodeExpr(parent) = node {
map.find(parent_id).and_then(|node| {
if let Node::NodeExpr(parent) = node {
Some(parent)
} else {
None
})
}
})
}
pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> {
@ -598,7 +604,9 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
help: &str,
sugg: String,
) {
span_lint_and_then(cx, lint, sp, msg, |db| { db.span_suggestion(sp, help, sugg); });
span_lint_and_then(cx, lint, sp, msg, |db| {
db.span_suggestion(sp, help, sugg);
});
}
/// Create a suggestion made from several `span → replacement`.
@ -609,7 +617,7 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
/// the whole suggestion.
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder, help_msg: String, sugg: I)
where
I: IntoIterator<Item=(Span, String)>,
I: IntoIterator<Item = (Span, String)>,
{
let sugg = rustc_errors::CodeSuggestion {
substitution_parts: sugg.into_iter()
@ -629,9 +637,8 @@ where
/// Return the base type for HIR references and pointers.
pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty {
match ty.node {
TyPtr(ref mut_ty) |
TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
_ => ty
TyPtr(ref mut_ty) | TyRptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
_ => ty,
}
}

View file

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

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)));
then {
// report the error around the `vec!` not inside `<std macros>:`
let span = arg.span.ctxt().outer().expn_info().map(|info| info.call_site).expect("unable to get call_site");
let span = arg.span
.ctxt()
.outer()
.expn_info()
.map(|info| info.call_site)
.expect("unable to get call_site");
check_vec_macro(cx, &vec_args, span);
}
}

View file

@ -49,9 +49,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
| (_, FloatWidth::F64) => "f64",
_ => "f32"
};
span_help_and_lint(cx, ZERO_DIVIDED_BY_ZERO, expr.span,
span_help_and_lint(
cx,
ZERO_DIVIDED_BY_ZERO,
expr.span,
"constant division of 0.0 with 0.0 will always result in NaN",
&format!("Consider using `std::{}::NAN` if you would like a constant representing NaN", float_type));
&format!(
"Consider using `std::{}::NAN` if you would like a constant representing NaN",
float_type,
),
);
}
}
}

View file

@ -1 +0,0 @@
workspace_mode=true

View file

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

View file

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

View file

@ -69,8 +69,7 @@ pub fn main() {
.skip(2)
.find(|val| val.starts_with("--manifest-path="));
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
{
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
metadata
} else {
let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));

View file

@ -1,3 +1,2 @@
#![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();
s.push_str(" -L target/debug/");
s.push_str(" -L target/debug/deps");
s.push_str(
" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal",
);
s.push_str(" -Zextra-plugins=clippy -Ltarget_recur/debug -Dwarnings -Dclippy_pedantic -Dclippy -Dclippy_internal");
config.target_rustcflags = Some(s);
if let Ok(name) = var("TESTNAME") {
config.filter = Some(name.to_owned())

View file

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

View file

@ -134,3 +134,10 @@ fn bla() {
}
}
}
fn underscores_and_numbers() {
let _1 = 1; //~ERROR Consider a more descriptive name
let ____1 = 1; //~ERROR Consider a more descriptive name
let __1___2 = 12; //~ERROR Consider a more descriptive name
let _1_ok= 1;
}

View file

@ -129,3 +129,23 @@ error: 5th binding whose name is just one char
129 | e => panic!(),
| ^
error: consider choosing a more descriptive name
--> $DIR/non_expressive_names.rs:139:9
|
139 | let _1 = 1; //~ERROR Consider a more descriptive name
| ^^
|
= note: `-D just-underscores-and-digits` implied by `-D warnings`
error: consider choosing a more descriptive name
--> $DIR/non_expressive_names.rs:140:9
|
140 | let ____1 = 1; //~ERROR Consider a more descriptive name
| ^^^^^
error: consider choosing a more descriptive name
--> $DIR/non_expressive_names.rs:141:9
|
141 | let __1___2 = 12; //~ERROR Consider a more descriptive name
| ^^^^^^^