Merge branch 'master' of github.com:rust-lang-nursery/rust-clippy

This commit is contained in:
cgm616 2017-11-02 22:57:07 -05:00
commit ee289c9f88
23 changed files with 484 additions and 70 deletions

View file

@ -37,7 +37,7 @@ impl StaticConst {
// Recursively visit types
fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext) {
match ty.node {
// Be carefull of nested structures (arrays and tuples)
// Be careful of nested structures (arrays and tuples)
TyKind::Array(ref ty, _) => {
self.visit_type(&*ty, cx);
},

View file

@ -224,7 +224,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
let (begin, span) = spans[index];
// Adjust for the begining of the current `Event`
// Adjust for the beginning of the current `Event`
let span = span.with_lo(span.lo() + BytePos::from_usize(offset - begin));
check_text(cx, valid_idents, &text, span);

View file

@ -9,6 +9,7 @@
#![feature(stmt_expr_attributes)]
#![feature(conservative_impl_trait)]
#![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"]
@ -93,12 +94,13 @@ pub mod entry;
pub mod enum_clike;
pub mod enum_glob_use;
pub mod enum_variants;
pub mod erasing_op;
pub mod eq_op;
pub mod erasing_op;
pub mod escape;
pub mod eta_reduction;
pub mod eval_order_dependence;
pub mod explicit_write;
pub mod fallible_impl_from;
pub mod format;
pub mod formatting;
pub mod functions;
@ -106,7 +108,6 @@ pub mod identity_conversion;
pub mod identity_op;
pub mod if_let_redundant_pattern_matching;
pub mod if_not_else;
pub mod fallible_impl_from;
pub mod infinite_iter;
pub mod int_plus_one;
pub mod invalid_ref;
@ -209,7 +210,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
let mut store = reg.sess.lint_store.borrow_mut();
store.register_removed(
"should_assert_eq",
"`assert!()` will be more flexible with RFC 2011"
"`assert!()` will be more flexible with RFC 2011",
);
store.register_removed(
"extend_from_slice",
@ -360,11 +361,11 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_lint_group("clippy_pedantic", vec![
booleans::NONMINIMAL_BOOL,
const_static_lifetime::CONST_STATIC_LIFETIME,
empty_enum::EMPTY_ENUM,
enum_glob_use::ENUM_GLOB_USE,
enum_variants::PUB_ENUM_VARIANT_NAMES,
enum_variants::STUTTER,
fallible_impl_from::FALLIBLE_IMPL_FROM,
if_not_else::IF_NOT_ELSE,
infinite_iter::MAYBE_INFINITE_ITER,
int_plus_one::INT_PLUS_ONE,
@ -374,6 +375,7 @@ 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_UNWRAP_USED,
methods::WRONG_PUB_SELF_CONVENTION,
@ -423,6 +425,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
booleans::LOGIC_BUG,
bytecount::NAIVE_BYTECOUNT,
collapsible_if::COLLAPSIBLE_IF,
const_static_lifetime::CONST_STATIC_LIFETIME,
copies::IF_SAME_THEN_ELSE,
copies::IFS_SAME_COND,
copies::MATCH_SAME_ARMS,
@ -441,6 +444,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
enum_variants::MODULE_INCEPTION,
eq_op::EQ_OP,
eq_op::OP_REF,
erasing_op::ERASING_OP,
escape::BOXED_LOCAL,
eta_reduction::REDUNDANT_CLOSURE,
eval_order_dependence::DIVERGING_SUB_EXPRESSION,
@ -455,7 +459,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
identity_conversion::IDENTITY_CONVERSION,
identity_op::IDENTITY_OP,
if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING,
fallible_impl_from::FALLIBLE_IMPL_FROM,
infinite_iter::INFINITE_ITER,
invalid_ref::INVALID_REF,
is_unit_expr::UNIT_EXPR,
@ -509,6 +512,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
methods::SINGLE_CHAR_PATTERN,
methods::STRING_EXTEND_CHARS,
methods::TEMPORARY_CSTRING_AS_PTR,
methods::USELESS_ASREF,
methods::WRONG_SELF_CONVENTION,
minmax::MIN_MAX,
misc::CMP_NAN,

View file

@ -66,7 +66,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass {
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
if let ImplItemKind::Method(ref sig, id) = item.node {
check_fn_inner(cx, &sig.decl, Some(id), &sig.generics, item.span);
check_fn_inner(cx, &sig.decl, Some(id), &item.generics, item.span);
}
}
@ -76,7 +76,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass {
TraitMethod::Required(_) => None,
TraitMethod::Provided(id) => Some(id),
};
check_fn_inner(cx, &sig.decl, body, &sig.generics, item.span);
check_fn_inner(cx, &sig.decl, body, &item.generics, item.span);
}
}
}

View file

@ -193,6 +193,24 @@ declare_lint! {
`map_or_else(g, f)`"
}
/// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`.
///
/// **Why is this bad?** Readability, this can be written more concisely as
/// `result.ok().map_or_else(_, _)`.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// x.map(|a| a + 1).unwrap_or_else(some_function)
/// ```
declare_lint! {
pub RESULT_MAP_UNWRAP_OR_ELSE,
Allow,
"using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
`.ok().map_or_else(g, f)`"
}
/// **What it does:** Checks for usage of `_.map_or(None, _)`.
///
/// **Why is this bad?** Readability, this can be written more concisely as
@ -615,6 +633,7 @@ impl LintPass for Pass {
OK_EXPECT,
OPTION_MAP_UNWRAP_OR,
OPTION_MAP_UNWRAP_OR_ELSE,
RESULT_MAP_UNWRAP_OR_ELSE,
OPTION_MAP_OR_NONE,
OR_FUN_CALL,
CHARS_NEXT_CMP,
@ -748,7 +767,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if name == method_name &&
sig.decl.inputs.len() == n_args &&
out_type.matches(&sig.decl.output) &&
self_kind.matches(first_arg_ty, first_arg, self_ty, false, &sig.generics) {
self_kind.matches(first_arg_ty, first_arg, self_ty, false, &implitem.generics) {
span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!(
"defining a method called `{}` on this type; consider implementing \
the `{}` trait or choosing a less ambiguous name", name, trait_name));
@ -763,7 +782,7 @@ 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, &sig.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
@ -1244,13 +1263,25 @@ fn lint_map_unwrap_or(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::Expr]
}
}
/// lint use of `map().unwrap_or_else()` for `Option`s
fn lint_map_unwrap_or_else<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_args: &'tcx [hir::Expr], unwrap_args: &'tcx [hir::Expr]) {
/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
fn lint_map_unwrap_or_else<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr,
map_args: &'tcx [hir::Expr],
unwrap_args: &'tcx [hir::Expr],
) {
// lint if the caller of `map()` is an `Option`
if match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION) {
let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
if is_option || is_result {
// lint message
let msg = "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";
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"
} 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"
};
// get snippets for args to map() and unwrap_or_else()
let map_snippet = snippet(cx, map_args[1].span, "..");
let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
@ -1261,18 +1292,32 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir
if same_span && !multiline {
span_note_and_lint(
cx,
OPTION_MAP_UNWRAP_OR_ELSE,
if is_option {
OPTION_MAP_UNWRAP_OR_ELSE
} else {
RESULT_MAP_UNWRAP_OR_ELSE
},
expr.span,
msg,
expr.span,
&format!(
"replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`",
"replace `map({0}).unwrap_or_else({1})` with `{2}map_or_else({1}, {0})`",
map_snippet,
unwrap_snippet
unwrap_snippet,
if is_result { "ok()." } else { "" }
),
);
} else if same_span && multiline {
span_lint(cx, OPTION_MAP_UNWRAP_OR_ELSE, expr.span, msg);
span_lint(
cx,
if is_option {
OPTION_MAP_UNWRAP_OR_ELSE
} else {
RESULT_MAP_UNWRAP_OR_ELSE
},
expr.span,
msg,
);
};
}
}

View file

@ -108,11 +108,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
// can't be implemented by default
return;
}
if !sig.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

View file

@ -80,15 +80,24 @@ declare_lint! {
/// **What it does:** Checks for transmutes from an integer to a `char`.
///
/// **Why is this bad?** Not every integer is a unicode scalar value.
/// **Why is this bad?** Not every integer is a Unicode scalar value.
///
/// **Known problems:** None.
/// **Known problems:**
/// - [`from_u32`] which this lint suggests using is slower than `transmute`
/// as it needs to validate the input.
/// If you are certain that the input is always a valid Unicode scalar value,
/// use [`from_u32_unchecked`] which is as fast as `transmute`
/// but has a semantically meaningful name.
/// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
///
/// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
/// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
///
/// **Example:**
/// ```rust
/// let _: char = std::mem::transmute(x); // where x: u32
/// // should be:
/// let _: Option<char> = std::char::from_u32(x);
/// let _ = std::char::from_u32(x).unwrap();
/// ```
declare_lint! {
pub TRANSMUTE_INT_TO_CHAR,
@ -96,6 +105,33 @@ declare_lint! {
"transmutes from an integer to a `char`"
}
/// **What it does:** Checks for transmutes from a `&[u8]` to a `&str`.
///
/// **Why is this bad?** Not every byte slice is a valid UTF-8 string.
///
/// **Known problems:**
/// - [`from_utf8`] which this lint suggests using is slower than `transmute`
/// as it needs to validate the input.
/// If you are certain that the input is always a valid UTF-8,
/// use [`from_utf8_unchecked`] which is as fast as `transmute`
/// but has a semantically meaningful name.
/// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
///
/// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
/// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
///
/// **Example:**
/// ```rust
/// let _: &str = std::mem::transmute(b); // where b: &[u8]
/// // should be:
/// let _ = std::str::from_utf8(b).unwrap();
/// ```
declare_lint! {
pub TRANSMUTE_BYTES_TO_STR,
Warn,
"transmutes from a `&[u8]` to a `&str`"
}
/// **What it does:** Checks for transmutes from an integer to a `bool`.
///
/// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`.
@ -142,6 +178,7 @@ impl LintPass for Transmute {
USELESS_TRANSMUTE,
WRONG_TRANSMUTE,
TRANSMUTE_INT_TO_CHAR,
TRANSMUTE_BYTES_TO_STR,
TRANSMUTE_INT_TO_BOOL,
TRANSMUTE_INT_TO_FLOAT
)
@ -254,9 +291,41 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
} else {
arg
};
db.span_suggestion(e.span, "consider using", format!("std::char::from_u32({})", 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! {
if let (&ty::TySlice(slice_ty), &ty::TyStr) = (&ref_from.ty.sty, &ref_to.ty.sty);
if let ty::TyUint(ast::UintTy::U8) = slice_ty.sty;
if ref_from.mutbl == ref_to.mutbl;
then {
let postfix = if ref_from.mutbl == Mutability::MutMutable {
"_mut"
} else {
""
};
span_lint_and_then(
cx,
TRANSMUTE_BYTES_TO_STR,
e.span,
&format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
|db| {
db.span_suggestion(
e.span,
"consider using",
format!(
"std::str::from_utf8{}({}).unwrap()",
postfix,
snippet(cx, args[0].span, ".."),
),
);
}
)
}
}
},
(&ty::TyInt(ast::IntTy::I8), &ty::TyBool) |
(&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => span_lint_and_then(
cx,

View file

@ -161,16 +161,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
fn is_lint_ref_type(ty: &Ty) -> bool {
if let TyRptr(
ref lt,
_,
MutTy {
ty: ref inner,
mutbl: MutImmutable,
},
) = ty.node
{
if lt.is_elided() {
return false;
}
if let TyPath(ref path) = inner.node {
return match_qpath(path, &paths::LINT);
}

View file

@ -924,6 +924,7 @@ pub fn opt_def_id(def: Def) -> Option<DefId> {
Def::TyAlias(id) |
Def::AssociatedTy(id) |
Def::TyParam(id) |
Def::TyForeign(id) |
Def::Struct(id) |
Def::StructCtor(id, ..) |
Def::Union(id) |

View file

@ -41,8 +41,8 @@ pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 4] = ["core", "iter", "iterator", "Iterator"];
pub const LINKED_LIST: [&str; 3] = ["alloc", "linked_list", "LinkedList"];
pub const LINT: [&str; 3] = ["rustc", "lint", "Lint"];
pub const LINT_ARRAY: [&str; 3] = ["rustc", "lint", "LintArray"];
pub const LINT: [&str; 2] = ["lint", "Lint"];
pub const LINT_ARRAY: [&str; 2] = ["lint", "LintArray"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
pub const MEM_UNINIT: [&str; 3] = ["core", "mem", "uninitialized"];
pub const MEM_ZEROED: [&str; 3] = ["core", "mem", "zeroed"];