Merge branch 'master' of github.com:rust-lang-nursery/rust-clippy
This commit is contained in:
commit
ee289c9f88
23 changed files with 484 additions and 70 deletions
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) |
|
||||
|
|
|
|||
|
|
@ -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"];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue