Merge branch 'master' of github.com:Manishearth/rust-clippy into fold_any

This commit is contained in:
Oliver Schneider 2018-01-19 12:10:24 +01:00
commit 70302595a4
No known key found for this signature in database
GPG Key ID: A69F8D225B3AD7D9
201 changed files with 1431 additions and 560 deletions

View File

@ -4,7 +4,7 @@ rust: nightly
os: os:
- linux - linux
- osx # - osx # doesn't even start atm. Not sure what travis is up to. Disabling to reduce the noise
sudo: false sudo: false

View File

@ -1,6 +1,9 @@
# Change Log # Change Log
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## 0.0.180
* Rustup to *rustc 1.25.0-nightly (3f92e8d89 2018-01-14)*
## 0.0.179 ## 0.0.179
* Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)* * Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)*
@ -580,6 +583,7 @@ All notable changes to this project will be documented in this file.
[`ineffective_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ineffective_bit_mask [`ineffective_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ineffective_bit_mask
[`infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infinite_iter [`infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infinite_iter
[`inline_always`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_always [`inline_always`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_always
[`inline_fn_without_body`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_fn_without_body
[`int_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#int_plus_one [`int_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#int_plus_one
[`integer_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#integer_arithmetic [`integer_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#integer_arithmetic
[`invalid_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_ref [`invalid_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_ref
@ -670,6 +674,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_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 [`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 [`regex_macro`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#regex_macro
[`replace_consts`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#replace_consts
[`result_map_unwrap_or_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else [`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 [`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 [`reverse_range_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#reverse_range_loop

View File

@ -1,6 +1,6 @@
[package] [package]
name = "clippy" name = "clippy"
version = "0.0.179" version = "0.0.180"
authors = [ authors = [
"Manish Goregaokar <manishsmail@gmail.com>", "Manish Goregaokar <manishsmail@gmail.com>",
"Andre Bogus <bogusandre@gmail.com>", "Andre Bogus <bogusandre@gmail.com>",
@ -37,13 +37,13 @@ path = "src/driver.rs"
[dependencies] [dependencies]
# begin automatic update # begin automatic update
clippy_lints = { version = "0.0.179", path = "clippy_lints" } clippy_lints = { version = "0.0.180", path = "clippy_lints" }
# end automatic update # end automatic update
cargo_metadata = "0.2" cargo_metadata = "0.2"
regex = "0.2" regex = "0.2"
[dev-dependencies] [dev-dependencies]
compiletest_rs = "0.3" compiletest_rs = "0.3.5"
duct = "0.8.2" duct = "0.8.2"
lazy_static = "1.0" lazy_static = "1.0"
serde_derive = "1.0" serde_derive = "1.0"

View File

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

View File

@ -1,6 +1,6 @@
use syntax::ast::{Item, ItemKind, Ty, TyKind}; use syntax::ast::{Item, ItemKind, Ty, TyKind};
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use utils::{in_macro, span_lint_and_then}; use utils::{in_macro, snippet, span_lint_and_then};
/// **What it does:** Checks for constants with an explicit `'static` lifetime. /// **What it does:** Checks for constants with an explicit `'static` lifetime.
/// ///
@ -51,14 +51,15 @@ impl StaticConst {
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) |
TyKind::Tup(..) => { TyKind::Tup(..) => {
if lifetime.ident.name == "'static" { if lifetime.ident.name == "'static" {
let mut sug: String = String::new(); let snip = snippet(cx, borrow_type.ty.span, "<type>");
let sugg = format!("&{}", snip);
span_lint_and_then( span_lint_and_then(
cx, cx,
CONST_STATIC_LIFETIME, CONST_STATIC_LIFETIME,
lifetime.span, lifetime.span,
"Constants have by default a `'static` lifetime", "Constants have by default a `'static` lifetime",
|db| { |db| {
db.span_suggestion(lifetime.span, "consider removing `'static`", sug); db.span_suggestion(ty.span, "consider removing `'static`", sugg);
}, },
); );
} }

View File

@ -0,0 +1,70 @@
//! lint on if expressions with an else if, but without a final else branch
use rustc::lint::*;
use syntax::ast::*;
use utils::{in_external_macro, span_lint_and_sugg};
/// **What it does:** Checks for usage of if expressions with an `else if` branch,
/// but without a final `else` branch.
///
/// **Why is this bad?** Some coding guidelines require this (e.g. MISRA-C:2004 Rule 14.10).
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x.is_positive() {
/// a();
/// } else if x.is_negative() {
/// b();
/// }
/// ```
///
/// Could be written:
///
/// ```rust
/// if x.is_positive() {
/// a();
/// } else if x.is_negative() {
/// b();
/// } else {
/// // we don't care about zero
/// }
/// ```
declare_restriction_lint! {
pub ELSE_IF_WITHOUT_ELSE,
"if expression with an `else if`, but without a final `else` branch"
}
#[derive(Copy, Clone)]
pub struct ElseIfWithoutElse;
impl LintPass for ElseIfWithoutElse {
fn get_lints(&self) -> LintArray {
lint_array!(ELSE_IF_WITHOUT_ELSE)
}
}
impl EarlyLintPass for ElseIfWithoutElse {
fn check_expr(&mut self, cx: &EarlyContext, mut item: &Expr) {
if in_external_macro(cx, item.span) {
return;
}
while let ExprKind::If(_, _, Some(ref els)) = item.node {
if let ExprKind::If(_, _, None) = els.node {
span_lint_and_sugg(
cx,
ELSE_IF_WITHOUT_ELSE,
els.span,
"if expression with an `else if`, but without a final `else`",
"add an `else` block here",
"".to_string()
);
}
item = els;
}
}
}

View File

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

View File

@ -0,0 +1,65 @@
//! checks for `#[inline]` on trait methods without bodies
use rustc::lint::*;
use rustc::hir::*;
use syntax::ast::{Attribute, Name};
use utils::span_lint_and_then;
use utils::sugg::DiagnosticBuilderExt;
/// **What it does:** Checks for `#[inline]` on trait methods without bodies
///
/// **Why is this bad?** Only implementations of trait methods may be inlined.
/// The inline attribute is ignored for trait methods without bodies.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// trait Animal {
/// #[inline]
/// fn name(&self) -> &'static str;
/// }
/// ```
declare_lint! {
pub INLINE_FN_WITHOUT_BODY,
Warn,
"use of `#[inline]` on trait methods without bodies"
}
#[derive(Copy, Clone)]
pub struct Pass;
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
lint_array!(INLINE_FN_WITHOUT_BODY)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
match item.node {
TraitItemKind::Method(_, TraitMethod::Required(_)) => {
check_attrs(cx, &item.name, &item.attrs);
},
_ => {},
}
}
}
fn check_attrs(cx: &LateContext, name: &Name, attrs: &[Attribute]) {
for attr in attrs {
if attr.name().map_or(true, |n| n != "inline") {
continue;
}
span_lint_and_then(
cx,
INLINE_FN_WITHOUT_BODY,
attr.span,
&format!("use of `#[inline]` on trait method `{}` which has no body", name),
|db| {
db.suggest_remove_item(cx, attr.span, "remove");
},
);
}
}

View File

@ -1,140 +0,0 @@
use rustc::lint::*;
use syntax::ast::*;
use syntax::ext::quote::rt::Span;
use utils::{span_lint, span_note_and_lint};
/// **What it does:** Checks for
/// - () being assigned to a variable
/// - () being passed to a function
///
/// **Why is this bad?** It is extremely unlikely that a user intended to
/// assign '()' to valiable. Instead,
/// Unit is what a block evaluates to when it returns nothing. This is
/// typically caused by a trailing
/// unintended semicolon.
///
/// **Known problems:** None.
///
/// **Example:**
/// * `let x = {"foo" ;}` when the user almost certainly intended `let x
/// ={"foo"}`
declare_lint! {
pub UNIT_EXPR,
Warn,
"unintended assignment or use of a unit typed value"
}
#[derive(Copy, Clone)]
enum UnitCause {
SemiColon,
EmptyBlock,
}
#[derive(Copy, Clone)]
pub struct UnitExpr;
impl LintPass for UnitExpr {
fn get_lints(&self) -> LintArray {
lint_array!(UNIT_EXPR)
}
}
impl EarlyLintPass for UnitExpr {
fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
if let ExprKind::Assign(ref _left, ref right) = expr.node {
check_for_unit(cx, right);
}
if let ExprKind::MethodCall(ref _left, ref args) = expr.node {
for arg in args {
check_for_unit(cx, arg);
}
}
if let ExprKind::Call(_, ref args) = expr.node {
for arg in args {
check_for_unit(cx, arg);
}
}
}
fn check_stmt(&mut self, cx: &EarlyContext, stmt: &Stmt) {
if let StmtKind::Local(ref local) = stmt.node {
if local.pat.node == PatKind::Wild {
return;
}
if let Some(ref expr) = local.init {
check_for_unit(cx, expr);
}
}
}
}
fn check_for_unit(cx: &EarlyContext, expr: &Expr) {
match is_unit_expr(expr) {
Some((span, UnitCause::SemiColon)) => span_note_and_lint(
cx,
UNIT_EXPR,
expr.span,
"This expression evaluates to the Unit type ()",
span,
"Consider removing the trailing semicolon",
),
Some((_span, UnitCause::EmptyBlock)) => span_lint(
cx,
UNIT_EXPR,
expr.span,
"This expression evaluates to the Unit type ()",
),
None => (),
}
}
fn is_unit_expr(expr: &Expr) -> Option<(Span, UnitCause)> {
match expr.node {
ExprKind::Block(ref block) => match check_last_stmt_in_block(block) {
Some(UnitCause::SemiColon) =>
Some((block.stmts[block.stmts.len() - 1].span, UnitCause::SemiColon)),
Some(UnitCause::EmptyBlock) =>
Some((block.span, UnitCause::EmptyBlock)),
None => None
}
ExprKind::If(_, ref then, ref else_) => {
let check_then = check_last_stmt_in_block(then);
if let Some(ref else_) = *else_ {
let check_else = is_unit_expr(else_);
if let Some(ref expr_else) = check_else {
return Some(*expr_else);
}
}
match check_then {
Some(c) => Some((expr.span, c)),
None => None,
}
},
ExprKind::Match(ref _pattern, ref arms) => {
for arm in arms {
if let Some(r) = is_unit_expr(&arm.body) {
return Some(r);
}
}
None
},
_ => None,
}
}
fn check_last_stmt_in_block(block: &Block) -> Option<UnitCause> {
if block.stmts.is_empty() { return Some(UnitCause::EmptyBlock); }
let final_stmt = &block.stmts[block.stmts.len() - 1];
// Made a choice here to risk false positives on divergent macro invocations
// like `panic!()`
match final_stmt.node {
StmtKind::Expr(_) => None,
StmtKind::Semi(ref expr) => match expr.node {
ExprKind::Break(_, _) | ExprKind::Continue(_) | ExprKind::Ret(_) => None,
_ => Some(UnitCause::SemiColon),
},
_ => Some(UnitCause::SemiColon), // not sure what's happening here
}
}

View File

@ -88,6 +88,7 @@ pub mod derive;
pub mod doc; pub mod doc;
pub mod double_parens; pub mod double_parens;
pub mod drop_forget_ref; pub mod drop_forget_ref;
pub mod else_if_without_else;
pub mod empty_enum; pub mod empty_enum;
pub mod entry; pub mod entry;
pub mod enum_clike; pub mod enum_clike;
@ -108,9 +109,9 @@ pub mod identity_op;
pub mod if_let_redundant_pattern_matching; pub mod if_let_redundant_pattern_matching;
pub mod if_not_else; pub mod if_not_else;
pub mod infinite_iter; pub mod infinite_iter;
pub mod inline_fn_without_body;
pub mod int_plus_one; pub mod int_plus_one;
pub mod invalid_ref; pub mod invalid_ref;
pub mod is_unit_expr;
pub mod items_after_statements; pub mod items_after_statements;
pub mod large_enum_variant; pub mod large_enum_variant;
pub mod len_zero; pub mod len_zero;
@ -247,6 +248,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
"string_to_string", "string_to_string",
"using `string::to_string` is common even today and specialization will likely happen soon", "using `string::to_string` is common even today and specialization will likely happen soon",
); );
store.register_removed(
"unit_expr",
"superseded by `let_unit_value` and `unit_arg`",
);
// end deprecated lints, do not remove this comment, its used in `update_lints` // end deprecated lints, do not remove this comment, its used in `update_lints`
reg.register_late_lint_pass(box serde_api::Serde); reg.register_late_lint_pass(box serde_api::Serde);
@ -267,7 +272,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box approx_const::Pass); reg.register_late_lint_pass(box approx_const::Pass);
reg.register_late_lint_pass(box misc::Pass); reg.register_late_lint_pass(box misc::Pass);
reg.register_early_lint_pass(box precedence::Precedence); reg.register_early_lint_pass(box precedence::Precedence);
reg.register_early_lint_pass(box is_unit_expr::UnitExpr);
reg.register_early_lint_pass(box needless_continue::NeedlessContinue); reg.register_early_lint_pass(box needless_continue::NeedlessContinue);
reg.register_late_lint_pass(box eta_reduction::EtaPass); reg.register_late_lint_pass(box eta_reduction::EtaPass);
reg.register_late_lint_pass(box identity_op::IdentityOp); reg.register_late_lint_pass(box identity_op::IdentityOp);
@ -329,6 +333,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_early_lint_pass(box formatting::Formatting); reg.register_early_lint_pass(box formatting::Formatting);
reg.register_late_lint_pass(box swap::Swap); reg.register_late_lint_pass(box swap::Swap);
reg.register_early_lint_pass(box if_not_else::IfNotElse); reg.register_early_lint_pass(box if_not_else::IfNotElse);
reg.register_early_lint_pass(box else_if_without_else::ElseIfWithoutElse);
reg.register_early_lint_pass(box int_plus_one::IntPlusOne); reg.register_early_lint_pass(box int_plus_one::IntPlusOne);
reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional);
reg.register_late_lint_pass(box unused_label::UnusedLabel); reg.register_late_lint_pass(box unused_label::UnusedLabel);
@ -357,18 +362,21 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box use_self::UseSelf); reg.register_late_lint_pass(box use_self::UseSelf);
reg.register_late_lint_pass(box bytecount::ByteCount); reg.register_late_lint_pass(box bytecount::ByteCount);
reg.register_late_lint_pass(box infinite_iter::Pass); reg.register_late_lint_pass(box infinite_iter::Pass);
reg.register_late_lint_pass(box inline_fn_without_body::Pass);
reg.register_late_lint_pass(box invalid_ref::InvalidRef); reg.register_late_lint_pass(box invalid_ref::InvalidRef);
reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default()); reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default());
reg.register_late_lint_pass(box types::ImplicitHasher); reg.register_late_lint_pass(box types::ImplicitHasher);
reg.register_early_lint_pass(box const_static_lifetime::StaticConst); reg.register_early_lint_pass(box const_static_lifetime::StaticConst);
reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom); reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom);
reg.register_late_lint_pass(box replace_consts::ReplaceConsts); reg.register_late_lint_pass(box replace_consts::ReplaceConsts);
reg.register_late_lint_pass(box types::UnitArg);
reg.register_lint_group("clippy_restrictions", vec![ reg.register_lint_group("clippy_restrictions", vec![
arithmetic::FLOAT_ARITHMETIC, arithmetic::FLOAT_ARITHMETIC,
arithmetic::INTEGER_ARITHMETIC, arithmetic::INTEGER_ARITHMETIC,
array_indexing::INDEXING_SLICING, array_indexing::INDEXING_SLICING,
assign_ops::ASSIGN_OPS, assign_ops::ASSIGN_OPS,
else_if_without_else::ELSE_IF_WITHOUT_ELSE,
misc::FLOAT_CMP_CONST, misc::FLOAT_CMP_CONST,
]); ]);
@ -474,8 +482,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
identity_op::IDENTITY_OP, identity_op::IDENTITY_OP,
if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING, if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING,
infinite_iter::INFINITE_ITER, infinite_iter::INFINITE_ITER,
inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
invalid_ref::INVALID_REF, invalid_ref::INVALID_REF,
is_unit_expr::UNIT_EXPR,
large_enum_variant::LARGE_ENUM_VARIANT, large_enum_variant::LARGE_ENUM_VARIANT,
len_zero::LEN_WITHOUT_IS_EMPTY, len_zero::LEN_WITHOUT_IS_EMPTY,
len_zero::LEN_ZERO, len_zero::LEN_ZERO,
@ -602,8 +610,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
types::IMPLICIT_HASHER, types::IMPLICIT_HASHER,
types::LET_UNIT_VALUE, types::LET_UNIT_VALUE,
types::LINKEDLIST, types::LINKEDLIST,
types::OPTION_OPTION,
types::TYPE_COMPLEXITY, types::TYPE_COMPLEXITY,
types::UNIT_CMP, types::UNIT_CMP,
types::UNIT_ARG,
types::UNNECESSARY_CAST, types::UNNECESSARY_CAST,
unicode::ZERO_WIDTH_SPACE, unicode::ZERO_WIDTH_SPACE,
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,

View File

@ -10,7 +10,9 @@ use utils::{get_arg_name, is_adjusted, iter_input_pats, match_qpath, match_trait
/// **Why is this bad?** It makes the code less readable than using the /// **Why is this bad?** It makes the code less readable than using the
/// `.cloned()` adapter. /// `.cloned()` adapter.
/// ///
/// **Known problems:** None. /// **Known problems:** Sometimes `.cloned()` requires stricter trait
/// bound than `.map(|e| e.clone())` (which works because of the coercion).
/// See [#498](https://github.com/rust-lang-nursery/rust-clippy/issues/498).
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust

View File

@ -361,9 +361,8 @@ declare_lint! {
/// ```rust /// ```rust
/// x.clone() /// x.clone()
/// ``` /// ```
declare_lint! { declare_restriction_lint! {
pub CLONE_ON_REF_PTR, pub CLONE_ON_REF_PTR,
Warn,
"using 'clone' on a ref-counted pointer" "using 'clone' on a ref-counted pointer"
} }
@ -1039,24 +1038,26 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t
fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) { fn lint_clone_on_ref_ptr(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr) {
let (obj_ty, _) = walk_ptrs_ty_depth(cx.tables.expr_ty(arg)); let (obj_ty, _) = walk_ptrs_ty_depth(cx.tables.expr_ty(arg));
let caller_type = if match_type(cx, obj_ty, &paths::RC) { if let ty::TyAdt(_, subst) = obj_ty.sty {
"Rc" let caller_type = if match_type(cx, obj_ty, &paths::RC) {
} else if match_type(cx, obj_ty, &paths::ARC) { "Rc"
"Arc" } else if match_type(cx, obj_ty, &paths::ARC) {
} else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) { "Arc"
"Weak" } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
} else { "Weak"
return; } else {
}; return;
};
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
CLONE_ON_REF_PTR, CLONE_ON_REF_PTR,
expr.span, expr.span,
"using '.clone()' on a ref-counted pointer", "using '.clone()' on a ref-counted pointer",
"try this", "try this",
format!("{}::clone(&{})", caller_type, snippet(cx, arg.span, "_")), format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet(cx, arg.span, "_")),
); );
}
} }

View File

@ -124,7 +124,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
let desc = match it.node { let desc = match it.node {
hir::ItemConst(..) => "a constant", hir::ItemConst(..) => "a constant",
hir::ItemEnum(..) => "an enum", hir::ItemEnum(..) => "an enum",
hir::ItemFn(..) => "a function", hir::ItemFn(..) => {
// ignore main()
if it.name == "main" {
let def_id = cx.tcx.hir.local_def_id(it.id);
let def_key = cx.tcx.hir.def_key(def_id);
if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
return;
}
}
"a function"
},
hir::ItemMod(..) => "a module", hir::ItemMod(..) => "a module",
hir::ItemStatic(..) => "a static", hir::ItemStatic(..) => "a static",
hir::ItemStruct(..) => "a struct", hir::ItemStruct(..) => "a struct",
@ -133,7 +143,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
hir::ItemGlobalAsm(..) => "an assembly blob", hir::ItemGlobalAsm(..) => "an assembly blob",
hir::ItemTy(..) => "a type alias", hir::ItemTy(..) => "a type alias",
hir::ItemUnion(..) => "a union", hir::ItemUnion(..) => "a union",
hir::ItemAutoImpl(..) |
hir::ItemExternCrate(..) | hir::ItemExternCrate(..) |
hir::ItemForeignMod(..) | hir::ItemForeignMod(..) |
hir::ItemImpl(..) | hir::ItemImpl(..) |

View File

@ -6,6 +6,7 @@ use rustc::ty::{self, RegionKind, TypeFoldable};
use rustc::traits; use rustc::traits;
use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization as mc;
use syntax::abi::Abi;
use syntax::ast::NodeId; use syntax::ast::NodeId;
use syntax_pos::Span; use syntax_pos::Span;
use syntax::errors::DiagnosticBuilder; use syntax::errors::DiagnosticBuilder;
@ -71,13 +72,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
} }
match kind { match kind {
FnKind::ItemFn(.., attrs) => for a in attrs { FnKind::ItemFn(.., abi, _, attrs) => {
if_chain! { if abi != Abi::Rust {
if a.meta_item_list().is_some(); return;
if let Some(name) = a.name(); }
if name == "proc_macro_derive"; for a in attrs {
then { if_chain! {
return; if a.meta_item_list().is_some();
if let Some(name) = a.name();
if name == "proc_macro_derive";
then {
return;
}
} }
} }
}, },
@ -87,7 +93,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
// Exclude non-inherent impls // Exclude non-inherent impls
if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(node_id)) { if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(node_id)) {
if matches!(item.node, ItemImpl(_, _, _, _, Some(_), _, _) | ItemAutoImpl(..) | if matches!(item.node, ItemImpl(_, _, _, _, Some(_), _, _) |
ItemTrait(..)) ItemTrait(..))
{ {
return; return;
@ -96,10 +102,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
// Allow `Borrow` or functions to be taken by value // Allow `Borrow` or functions to be taken by value
let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT)); let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));
let fn_traits = [ let whitelisted_traits = [
need!(cx.tcx.lang_items().fn_trait()), need!(cx.tcx.lang_items().fn_trait()),
need!(cx.tcx.lang_items().fn_once_trait()), need!(cx.tcx.lang_items().fn_once_trait()),
need!(cx.tcx.lang_items().fn_mut_trait()), need!(cx.tcx.lang_items().fn_mut_trait()),
need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT))
]; ];
let sized_trait = need!(cx.tcx.lang_items().sized_trait()); let sized_trait = need!(cx.tcx.lang_items().sized_trait());
@ -183,7 +190,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
if !is_self(arg); if !is_self(arg);
if !ty.is_mutable_pointer(); if !ty.is_mutable_pointer();
if !is_copy(cx, ty); if !is_copy(cx, ty);
if !fn_traits.iter().any(|&t| implements_trait(cx, ty, t, &[])); if !whitelisted_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
if !implements_borrow_trait; if !implements_borrow_trait;
if !all_borrowable_trait; if !all_borrowable_trait;
@ -196,6 +203,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
// Dereference suggestion // Dereference suggestion
let sugg = |db: &mut DiagnosticBuilder| { let sugg = |db: &mut DiagnosticBuilder| {
if let ty::TypeVariants::TyAdt(ref def, ..) = ty.sty {
if let Some(span) = cx.tcx.hir.span_if_local(def.did) {
let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing);
if param_env.can_type_implement_copy(cx.tcx, ty, span).is_ok() {
db.span_help(span, "consider marking this type as Copy");
}
}
}
let deref_span = spans_need_deref.get(&canonical_id); let deref_span = spans_need_deref.get(&canonical_id);
if_chain! { if_chain! {
if match_type(cx, ty, &paths::VEC); if match_type(cx, ty, &paths::VEC);

View File

@ -1,7 +1,7 @@
use rustc::lint::*; use rustc::lint::*;
use syntax::ast::*; use syntax::ast::*;
use syntax::codemap::Spanned; use syntax::codemap::Spanned;
use utils::{snippet, span_lint_and_sugg}; use utils::{in_macro, snippet, span_lint_and_sugg};
/// **What it does:** Checks for operations where precedence may be unclear /// **What it does:** Checks for operations where precedence may be unclear
/// and suggests to add parentheses. Currently it catches the following: /// and suggests to add parentheses. Currently it catches the following:
@ -37,6 +37,10 @@ impl LintPass for Precedence {
impl EarlyLintPass for Precedence { impl EarlyLintPass for Precedence {
fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
if in_macro(expr.span) {
return;
}
if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node { if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node {
let span_sugg = |expr: &Expr, sugg| { let span_sugg = |expr: &Expr, sugg| {
span_lint_and_sugg( span_lint_and_sugg(

View File

@ -50,6 +50,26 @@ declare_lint! {
"usage of `Box<Vec<T>>`, vector elements are already on the heap" "usage of `Box<Vec<T>>`, vector elements are already on the heap"
} }
/// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
/// definitions
///
/// **Why is this bad?** `Option<_>` represents an optional value. `Option<Option<_>>`
/// represents an optional optional value which is logically the same thing as an optional
/// value but has an unneeded extra level of wrapping.
///
/// **Known problems:** None.
///
/// **Example**
/// ```rust
/// fn x() -> Option<Option<u32>> {
/// None
/// }
declare_lint! {
pub OPTION_OPTION,
Warn,
"usage of `Option<Option<T>>`"
}
/// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a /// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a
/// `Vec` or a `VecDeque` (formerly called `RingBuf`). /// `Vec` or a `VecDeque` (formerly called `RingBuf`).
/// ///
@ -111,7 +131,7 @@ declare_lint! {
impl LintPass for TypePass { impl LintPass for TypePass {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(BOX_VEC, LINKEDLIST, BORROWED_BOX) lint_array!(BOX_VEC, OPTION_OPTION, LINKEDLIST, BORROWED_BOX)
} }
} }
@ -156,6 +176,23 @@ fn check_fn_decl(cx: &LateContext, decl: &FnDecl) {
} }
} }
/// Check if `qpath` has last segment with type parameter matching `path`
fn match_type_parameter(cx: &LateContext, qpath: &QPath, path: &[&str]) -> bool {
let last = last_path_segment(qpath);
if_chain! {
if let Some(ref params) = last.parameters;
if !params.parenthesized;
if let Some(ty) = params.types.get(0);
if let TyPath(ref qpath) = ty.node;
if let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(ty.id)));
if match_def_path(cx.tcx, did, path);
then {
return true;
}
}
false
}
/// Recursively check for `TypePass` lints in the given type. Stop at the first /// Recursively check for `TypePass` lints in the given type. Stop at the first
/// lint found. /// lint found.
/// ///
@ -171,24 +208,26 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) {
let def = cx.tables.qpath_def(qpath, hir_id); let def = cx.tables.qpath_def(qpath, hir_id);
if let Some(def_id) = opt_def_id(def) { if let Some(def_id) = opt_def_id(def) {
if Some(def_id) == cx.tcx.lang_items().owned_box() { if Some(def_id) == cx.tcx.lang_items().owned_box() {
let last = last_path_segment(qpath); if match_type_parameter(cx, qpath, &paths::VEC) {
if_chain! { span_help_and_lint(
if let Some(ref params) = last.parameters; cx,
if !params.parenthesized; BOX_VEC,
if let Some(vec) = params.types.get(0); ast_ty.span,
if let TyPath(ref qpath) = vec.node; "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
if let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(vec.id))); "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
if match_def_path(cx.tcx, did, &paths::VEC); );
then { return; // don't recurse into the type
span_help_and_lint( }
cx, } else if match_def_path(cx.tcx, def_id, &paths::OPTION) {
BOX_VEC, if match_type_parameter(cx, qpath, &paths::OPTION) {
ast_ty.span, span_lint(
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`", cx,
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.", OPTION_OPTION,
); ast_ty.span,
return; // don't recurse into the type "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
} enum if you need to distinguish all 3 cases",
);
return; // don't recurse into the type
} }
} else if match_def_path(cx.tcx, def_id, &paths::LINKED_LIST) { } else if match_def_path(cx.tcx, def_id, &paths::LINKED_LIST) {
span_help_and_lint( span_help_and_lint(
@ -322,25 +361,22 @@ declare_lint! {
fn check_let_unit(cx: &LateContext, decl: &Decl) { fn check_let_unit(cx: &LateContext, decl: &Decl) {
if let DeclLocal(ref local) = decl.node { if let DeclLocal(ref local) = decl.node {
match cx.tables.pat_ty(&local.pat).sty { if is_unit(cx.tables.pat_ty(&local.pat)) {
ty::TyTuple(slice, _) if slice.is_empty() => { if in_external_macro(cx, decl.span) || in_macro(local.pat.span) {
if in_external_macro(cx, decl.span) || in_macro(local.pat.span) { return;
return; }
} if higher::is_from_for_desugar(decl) {
if higher::is_from_for_desugar(decl) { return;
return; }
} span_lint(
span_lint( cx,
cx, LET_UNIT_VALUE,
LET_UNIT_VALUE, decl.span,
decl.span, &format!(
&format!( "this let-binding has unit value. Consider omitting `let {} =`",
"this let-binding has unit value. Consider omitting `let {} =`", snippet(cx, local.pat.span, "..")
snippet(cx, local.pat.span, "..") ),
), );
);
},
_ => (),
} }
} }
} }
@ -395,31 +431,118 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp {
} }
if let ExprBinary(ref cmp, ref left, _) = expr.node { if let ExprBinary(ref cmp, ref left, _) = expr.node {
let op = cmp.node; let op = cmp.node;
if op.is_comparison() { if op.is_comparison() && is_unit(cx.tables.expr_ty(left)) {
match cx.tables.expr_ty(left).sty { let result = match op {
ty::TyTuple(slice, _) if slice.is_empty() => { BiEq | BiLe | BiGe => "true",
let result = match op { _ => "false",
BiEq | BiLe | BiGe => "true", };
_ => "false", span_lint(
}; cx,
span_lint( UNIT_CMP,
cx, expr.span,
UNIT_CMP, &format!(
expr.span, "{}-comparison of unit values detected. This will always be {}",
&format!( op.as_str(),
"{}-comparison of unit values detected. This will always be {}", result
op.as_str(), ),
result );
),
);
},
_ => (),
}
} }
} }
} }
} }
/// **What it does:** Checks for passing a unit value as an argument to a function without using a unit literal (`()`).
///
/// **Why is this bad?** This is likely the result of an accidental semicolon.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// foo({
/// let a = bar();
/// baz(a);
/// })
/// ```
declare_lint! {
pub UNIT_ARG,
Warn,
"passing unit to a function"
}
pub struct UnitArg;
impl LintPass for UnitArg {
fn get_lints(&self) -> LintArray {
lint_array!(UNIT_ARG)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if in_macro(expr.span) {
return;
}
match expr.node {
ExprCall(_, ref args) | ExprMethodCall(_, _, ref args) => {
for arg in args {
if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
let map = &cx.tcx.hir;
// apparently stuff in the desugaring of `?` can trigger this
// so check for that here
// only the calls to `Try::from_error` is marked as desugared,
// so we need to check both the current Expr and its parent.
if !is_questionmark_desugar_marked_call(expr) {
if_chain!{
let opt_parent_node = map.find(map.get_parent_node(expr.id));
if let Some(hir::map::NodeExpr(parent_expr)) = opt_parent_node;
if is_questionmark_desugar_marked_call(parent_expr);
then {}
else {
// `expr` and `parent_expr` where _both_ not from
// desugaring `?`, so lint
span_lint_and_sugg(
cx,
UNIT_ARG,
arg.span,
"passing a unit value to a function",
"if you intended to pass a unit value, use a unit literal instead",
"()".to_string(),
);
}
}
}
}
}
},
_ => (),
}
}
}
fn is_questionmark_desugar_marked_call(expr: &Expr) -> bool {
use syntax_pos::hygiene::CompilerDesugaringKind;
if let ExprCall(ref callee, _) = expr.node {
callee.span.is_compiler_desugaring(CompilerDesugaringKind::QuestionMark)
} else {
false
}
}
fn is_unit(ty: Ty) -> bool {
match ty.sty {
ty::TyTuple(slice, _) if slice.is_empty() => true,
_ => false,
}
}
fn is_unit_literal(expr: &Expr) -> bool {
match expr.node {
ExprTup(ref slice) if slice.is_empty() => true,
_ => false,
}
}
pub struct CastPass; pub struct CastPass;
/// **What it does:** Checks for casts from any numerical to a float type where /// **What it does:** Checks for casts from any numerical to a float type where
@ -1106,6 +1229,20 @@ enum AbsurdComparisonResult {
} }
fn is_cast_between_fixed_and_target<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx Expr
) -> bool {
if let ExprCast(ref cast_exp, _) = expr.node {
let precast_ty = cx.tables.expr_ty(cast_exp);
let cast_ty = cx.tables.expr_ty(expr);
return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty)
}
return false;
}
fn detect_absurd_comparison<'a, 'tcx>( fn detect_absurd_comparison<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>, cx: &LateContext<'a, 'tcx>,
@ -1123,6 +1260,11 @@ fn detect_absurd_comparison<'a, 'tcx>(
return None; return None;
} }
// comparisons between fix sized types and target sized types are considered unanalyzable
if is_cast_between_fixed_and_target(cx, lhs) || is_cast_between_fixed_and_target(cx, rhs) {
return None;
}
let normalized = normalize_comparison(op, lhs, rhs); let normalized = normalize_comparison(op, lhs, rhs);
let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized { let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
val val

View File

@ -406,9 +406,6 @@ fn print_item(cx: &LateContext, item: &hir::Item) {
hir::ItemTraitAlias(..) => { hir::ItemTraitAlias(..) => {
println!("trait alias"); println!("trait alias");
} }
hir::ItemAutoImpl(_, ref _trait_ref) => {
println!("auto impl");
},
hir::ItemImpl(_, _, _, _, Some(ref _trait_ref), _, _) => { hir::ItemImpl(_, _, _, _, Some(ref _trait_ref), _, _) => {
println!("trait impl"); println!("trait impl");
}, },

View File

@ -55,6 +55,7 @@ pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
pub const PTR_NULL: [&str; 2] = ["ptr", "null"]; pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"]; pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
pub const RANGE: [&str; 3] = ["core", "ops", "Range"]; pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["alloc", "range", "RangeArgument"];
pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"]; pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"]; pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
pub const RANGE_FULL: [&str; 3] = ["core", "ops", "RangeFull"]; pub const RANGE_FULL: [&str; 3] = ["core", "ops", "RangeFull"];

View File

@ -15,6 +15,7 @@ use syntax::print::pprust::token_to_string;
use syntax::util::parser::AssocOp; use syntax::util::parser::AssocOp;
use syntax::ast; use syntax::ast;
use utils::{higher, snippet, snippet_opt}; use utils::{higher, snippet, snippet_opt};
use syntax_pos::{BytePos, Pos};
/// A helper type to build suggestion correctly handling parenthesis. /// A helper type to build suggestion correctly handling parenthesis.
pub enum Sugg<'a> { pub enum Sugg<'a> {
@ -454,6 +455,19 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
/// }"); /// }");
/// ``` /// ```
fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str); fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str);
/// Suggest to completely remove an item.
///
/// This will remove an item and all following whitespace until the next non-whitespace
/// character. This should work correctly if item is on the same indentation level as the
/// following item.
///
/// # Example
///
/// ```rust,ignore
/// db.suggest_remove_item(cx, item, "remove this")
/// ```
fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str);
} }
impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> { impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
@ -485,4 +499,21 @@ impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_error
self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent)); self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent));
} }
} }
fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str) {
let mut remove_span = item;
let fmpos = cx.sess()
.codemap()
.lookup_byte_offset(remove_span.next_point().hi());
if let Some(ref src) = fmpos.fm.src {
let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n');
if let Some(non_whitespace_offset) = non_whitespace_offset {
remove_span = remove_span.with_hi(remove_span.hi() + BytePos(non_whitespace_offset as u32))
}
}
self.span_suggestion(remove_span, msg, String::new());
}
} }

BIN
main Executable file

Binary file not shown.

View File

@ -12,7 +12,7 @@ extern crate rustc_plugin;
extern crate syntax; extern crate syntax;
use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc::session::{config, CompileIncomplete, Session}; use rustc::session::{config, Session};
use rustc::session::config::{ErrorOutputType, Input}; use rustc::session::config::{ErrorOutputType, Input};
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
@ -153,47 +153,44 @@ pub fn main() {
}) })
.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(|| { // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
// Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. // We're invoking the compiler programmatically, so we ignore this/
// We're invoking the compiler programmatically, so we ignore this/ let mut orig_args: Vec<String> = env::args().collect();
let mut orig_args: Vec<String> = env::args().collect(); if orig_args.len() <= 1 {
if orig_args.len() <= 1 { std::process::exit(1);
std::process::exit(1); }
} if orig_args[1] == "rustc" {
if orig_args[1] == "rustc" { // we still want to be able to invoke it normally though
// we still want to be able to invoke it normally though orig_args.remove(1);
orig_args.remove(1); }
} // this conditional check for the --sysroot flag is there so users can call
// this conditional check for the --sysroot flag is there so users can call // `clippy_driver` directly
// `clippy_driver` directly // without having to pass --sysroot or anything
// without having to pass --sysroot or anything let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") { orig_args.clone()
orig_args.clone() } else {
} else { orig_args
orig_args .clone()
.clone() .into_iter()
.into_iter() .chain(Some("--sysroot".to_owned()))
.chain(Some("--sysroot".to_owned())) .chain(Some(sys_root))
.chain(Some(sys_root)) .collect()
.collect() };
};
// this check ensures that dependencies are built but not linted and the final // this check ensures that dependencies are built but not linted and the final
// crate is // crate is
// linted but not built // linted but not built
let clippy_enabled = env::var("CLIPPY_TESTS") let clippy_enabled = env::var("CLIPPY_TESTS")
.ok() .ok()
.map_or(false, |val| val == "true") .map_or(false, |val| val == "true")
|| orig_args.iter().any(|s| s == "--emit=metadata"); || orig_args.iter().any(|s| s == "--emit=metadata");
if clippy_enabled { if clippy_enabled {
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
} }
let mut ccc = ClippyCompilerCalls::new(clippy_enabled); let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); rustc_driver::run(move || {
if let Err(CompileIncomplete::Errored(_)) = result { rustc_driver::run_compiler(&args, &mut ccc, None, None)
std::process::exit(1); });
}
}).expect("rustc_thread failed");
} }

View File

@ -46,7 +46,9 @@ fn config(dir: &'static str, mode: &'static str) -> compiletest::Config {
config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display())); config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display()));
config.mode = cfg_mode; config.mode = cfg_mode;
config.build_base = { config.build_base = if rustc_test_suite().is_some() {
PathBuf::from("/tmp/clippy_test_build_base")
} else {
let mut path = std::env::current_dir().unwrap(); let mut path = std::env::current_dir().unwrap();
path.push("target/debug/test_build_base"); path.push("target/debug/test_build_base");
path path

View File

@ -1,5 +1,8 @@
#[test] #[test]
fn dogfood() { fn dogfood() {
if option_env!("RUSTC_TEST_SUITE").is_some() {
return;
}
let root_dir = std::env::current_dir().unwrap(); let root_dir = std::env::current_dir().unwrap();
for d in &[".", "clippy_lints"] { for d in &[".", "clippy_lints"] {
std::env::set_current_dir(root_dir.join(d)).unwrap(); std::env::set_current_dir(root_dir.join(d)).unwrap();

View File

@ -50,3 +50,8 @@ impl PartialOrd<u32> for U {
pub fn foo(val: U) -> bool { pub fn foo(val: U) -> bool {
val > std::u32::MAX val > std::u32::MAX
} }
pub fn bar(len: u64) -> bool {
// This is OK as we are casting from target sized to fixed size
len >= std::usize::MAX as u64
}

View File

@ -143,3 +143,5 @@ error: <-comparison of unit values detected. This will always be false
| |
= note: `-D unit-cmp` implied by `-D warnings` = note: `-D unit-cmp` implied by `-D warnings`
error: aborting due to 18 previous errors

View File

@ -114,3 +114,5 @@ error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it
55 | let my_sq2 = 1.4142; 55 | let my_sq2 = 1.4142;
| ^^^^^^ | ^^^^^^
error: aborting due to 19 previous errors

View File

@ -69,3 +69,5 @@ error: floating-point arithmetic detected
29 | -f; 29 | -f;
| ^^ | ^^
error: aborting due to 11 previous errors

View File

@ -116,3 +116,5 @@ error: range is out of bounds
44 | &empty[..4]; 44 | &empty[..4];
| ^^^^^^^^^^ | ^^^^^^^^^^
error: aborting due to 19 previous errors

View File

@ -134,3 +134,5 @@ error: manual implementation of an assign operation
40 | s = s + "bla"; 40 | s = s + "bla";
| ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
error: aborting due to 22 previous errors

View File

@ -48,3 +48,5 @@ error: variable appears on both sides of an assignment operation
15 | a &= a & 1; 15 | a &= a & 1;
| ^^^^^^^^^^ help: replace it with: `a &= 1` | ^^^^^^^^^^ help: replace it with: `a &= 1`
error: aborting due to 8 previous errors

View File

@ -20,3 +20,5 @@ error: the since field must contain a semver-compliant version
30 | #[deprecated(since = "1")] 30 | #[deprecated(since = "1")]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: aborting due to 3 previous errors

View File

@ -106,3 +106,5 @@ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared
55 | x | 1 >= 8; 55 | x | 1 >= 8;
| ^^^^^^^^^^ | ^^^^^^^^^^
error: aborting due to 17 previous errors

View File

@ -84,3 +84,5 @@ error: use of a blacklisted/placeholder name `baz`
35 | if let Some(ref mut baz) = Some(42) {} 35 | if let Some(ref mut baz) = Some(42) {}
| ^^^ | ^^^
error: aborting due to 14 previous errors

View File

@ -50,3 +50,5 @@ error: this boolean expression can be simplified
| |
= note: `-D nonminimal-bool` implied by `-D warnings` = note: `-D nonminimal-bool` implied by `-D warnings`
error: aborting due to 5 previous errors

View File

@ -24,3 +24,5 @@ error: equality checks against false can be replaced by a negation
10 | if false == x { "yes" } else { "no" }; 10 | if false == x { "yes" } else { "no" };
| ^^^^^^^^^^ help: try simplifying it as shown: `!x` | ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: aborting due to 4 previous errors

View File

@ -175,3 +175,5 @@ error: this boolean expression can be simplified
58 | let _ = !c ^ c || !a.is_some(); 58 | let _ = !c ^ c || !a.is_some();
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `!c ^ c || a.is_none()` | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `!c ^ c || a.is_none()`
error: aborting due to 21 previous errors

View File

@ -28,3 +28,5 @@ error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
22 | fn test4(a: &Box<bool>); 22 | fn test4(a: &Box<bool>);
| ^^^^^^^^^^ help: try: `&bool` | ^^^^^^^^^^ help: try: `&bool`
error: aborting due to 4 previous errors

View File

@ -7,3 +7,5 @@ error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`
= note: `-D box-vec` implied by `-D warnings` = note: `-D box-vec` implied by `-D warnings`
= help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation. = help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.
error: aborting due to previous error

View File

@ -17,3 +17,5 @@ error[E0308]: mismatched types
= note: expected type `u32` = note: expected type `u32`
found type `{integer}` found type `{integer}`
error: aborting due to 2 previous errors

View File

@ -22,3 +22,5 @@ error: You appear to be counting bytes the naive way
22 | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count 22 | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)`
error: aborting due to 3 previous errors

View File

@ -178,3 +178,5 @@ error: casting to the same type is unnecessary (`bool` -> `bool`)
39 | false as bool; 39 | false as bool;
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: aborting due to 28 previous errors

View File

@ -60,3 +60,5 @@ error: casting u32 to f64 may become silently lossy if types change
14 | 1u32 as f64; 14 | 1u32 as f64;
| ^^^^^^^^^^^ help: try: `f64::from(1u32)` | ^^^^^^^^^^^ help: try: `f64::from(1u32)`
error: aborting due to 10 previous errors

View File

@ -108,3 +108,5 @@ error: casting u32 to u64 may become silently lossy if types change
23 | 1u32 as u64; 23 | 1u32 as u64;
| ^^^^^^^^^^^ help: try: `u64::from(1u32)` | ^^^^^^^^^^^ help: try: `u64::from(1u32)`
error: aborting due to 18 previous errors

View File

@ -120,3 +120,5 @@ error: casting i32 to usize may lose the sign of the value
22 | 1i32 as usize; 22 | 1i32 as usize;
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: aborting due to 19 previous errors

View File

@ -8,3 +8,5 @@ error: casting character literal to u8. `char`s are 4 bytes wide in rust, so cas
= help: Consider using a byte literal instead: = help: Consider using a byte literal instead:
b'a' b'a'
error: aborting due to previous error

View File

@ -72,3 +72,5 @@ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
21 | y >= std::f64::NAN; 21 | y >= std::f64::NAN;
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: aborting due to 12 previous errors

View File

@ -12,3 +12,5 @@ error: Comparing with null is better expressed by the .is_null() method
16 | if m == ptr::null_mut() { 16 | if m == ptr::null_mut() {
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -36,3 +36,5 @@ error: this creates an owned instance just for comparison
30 | self.to_owned() == *other 30 | self.to_owned() == *other
| ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating | ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating
error: aborting due to 6 previous errors

View File

@ -240,3 +240,5 @@ help: try
112 | } 112 | }
| |
error: aborting due to 13 previous errors

View File

@ -90,3 +90,5 @@ error: very complex type used. Consider factoring parts into `type` definitions
40 | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; 40 | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 15 previous errors

View File

@ -1,4 +1,4 @@
error: compiler plugins are experimental and possibly buggy (see issue #29597) error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597)
--> $DIR/conf_bad_arg.rs:4:1 --> $DIR/conf_bad_arg.rs:4:1
| |
4 | #![plugin(clippy(conf_file))] 4 | #![plugin(clippy(conf_file))]
@ -6,3 +6,5 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597)
| |
= help: add #![feature(plugin)] to the crate attributes to enable = help: add #![feature(plugin)] to the crate attributes to enable
error: aborting due to previous error

View File

@ -1,4 +1,4 @@
error: compiler plugins are experimental and possibly buggy (see issue #29597) error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597)
--> $DIR/conf_bad_toml.rs:4:1 --> $DIR/conf_bad_toml.rs:4:1
| |
4 | #![plugin(clippy(conf_file="../ui/conf_bad_toml.toml"))] 4 | #![plugin(clippy(conf_file="../ui/conf_bad_toml.toml"))]
@ -6,3 +6,5 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597)
| |
= help: add #![feature(plugin)] to the crate attributes to enable = help: add #![feature(plugin)] to the crate attributes to enable
error: aborting due to previous error

View File

@ -1,4 +1,4 @@
error: compiler plugins are experimental and possibly buggy (see issue #29597) error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597)
--> $DIR/conf_bad_type.rs:4:1 --> $DIR/conf_bad_type.rs:4:1
| |
4 | #![plugin(clippy(conf_file="../ui/conf_bad_type.toml"))] 4 | #![plugin(clippy(conf_file="../ui/conf_bad_type.toml"))]
@ -6,3 +6,5 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597)
| |
= help: add #![feature(plugin)] to the crate attributes to enable = help: add #![feature(plugin)] to the crate attributes to enable
error: aborting due to previous error

View File

@ -1,4 +1,4 @@
error: compiler plugins are experimental and possibly buggy (see issue #29597) error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597)
--> $DIR/conf_french_blacklisted_name.rs:2:1 --> $DIR/conf_french_blacklisted_name.rs:2:1
| |
2 | #![plugin(clippy(conf_file="../auxiliary/conf_french_blacklisted_name.toml"))] 2 | #![plugin(clippy(conf_file="../auxiliary/conf_french_blacklisted_name.toml"))]
@ -6,3 +6,5 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597)
| |
= help: add #![feature(plugin)] to the crate attributes to enable = help: add #![feature(plugin)] to the crate attributes to enable
error: aborting due to previous error

View File

@ -1,4 +1,4 @@
error: compiler plugins are experimental and possibly buggy (see issue #29597) error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597)
--> $DIR/conf_path_non_string.rs:3:1 --> $DIR/conf_path_non_string.rs:3:1
| |
3 | #![plugin(clippy(conf_file=42))] 3 | #![plugin(clippy(conf_file=42))]
@ -6,3 +6,5 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597)
| |
= help: add #![feature(plugin)] to the crate attributes to enable = help: add #![feature(plugin)] to the crate attributes to enable
error: aborting due to previous error

View File

@ -1,4 +1,4 @@
error: compiler plugins are experimental and possibly buggy (see issue #29597) error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597)
--> $DIR/conf_unknown_key.rs:4:1 --> $DIR/conf_unknown_key.rs:4:1
| |
4 | #![plugin(clippy(conf_file="../auxiliary/conf_unknown_key.toml"))] 4 | #![plugin(clippy(conf_file="../auxiliary/conf_unknown_key.toml"))]
@ -6,3 +6,5 @@ error: compiler plugins are experimental and possibly buggy (see issue #29597)
| |
= help: add #![feature(plugin)] to the crate attributes to enable = help: add #![feature(plugin)] to the crate attributes to enable
error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:4:17 --> $DIR/const_static_lifetime.rs:4:17
| |
4 | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static. 4 | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^---- help: consider removing `'static`: `&str`
| |
= note: `-D const-static-lifetime` implied by `-D warnings` = note: `-D const-static-lifetime` implied by `-D warnings`
@ -10,71 +10,73 @@ error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:8:21 --> $DIR/const_static_lifetime.rs:8:21
| |
8 | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static 8 | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^---- help: consider removing `'static`: `&str`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:10:32 --> $DIR/const_static_lifetime.rs:10:32
| |
10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static 10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^---- help: consider removing `'static`: `&str`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:10:47 --> $DIR/const_static_lifetime.rs:10:47
| |
10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static 10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^---- help: consider removing `'static`: `&str`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:12:18 --> $DIR/const_static_lifetime.rs:12:18
| |
12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static 12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:12:30 --> $DIR/const_static_lifetime.rs:12:30
| |
12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static 12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^---- help: consider removing `'static`: `&str`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:14:17 --> $DIR/const_static_lifetime.rs:14:17
| |
14 | const VAR_SIX: &'static u8 = &5; 14 | const VAR_SIX: &'static u8 = &5;
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^--- help: consider removing `'static`: `&u8`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:16:29 --> $DIR/const_static_lifetime.rs:16:29
| |
16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; 16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:16:39 --> $DIR/const_static_lifetime.rs:16:39
| |
16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; 16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^---- help: consider removing `'static`: `&str`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:18:20 --> $DIR/const_static_lifetime.rs:18:20
| |
18 | const VAR_HEIGHT: &'static Foo = &Foo {}; 18 | const VAR_HEIGHT: &'static Foo = &Foo {};
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^---- help: consider removing `'static`: `&Foo`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:20:19 --> $DIR/const_static_lifetime.rs:20:19
| |
20 | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static. 20 | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^----- help: consider removing `'static`: `&[u8]`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:22:19 --> $DIR/const_static_lifetime.rs:22:19
| |
22 | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. 22 | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
error: Constants have by default a `'static` lifetime error: Constants have by default a `'static` lifetime
--> $DIR/const_static_lifetime.rs:24:19 --> $DIR/const_static_lifetime.rs:24:19
| |
24 | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. 24 | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
| ^^^^^^^ help: consider removing `'static` | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
error: aborting due to 13 previous errors

View File

@ -33,3 +33,5 @@ error: This else block is redundant.
} }
error: aborting due to 2 previous errors

View File

@ -12,3 +12,5 @@ help: assign the `CString` to a variable to extend its lifetime
7 | CString::new("foo").unwrap().as_ptr(); 7 | CString::new("foo").unwrap().as_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -269,3 +269,5 @@ error: the function has a cyclomatic complexity of 8
| |
= help: you could split it up into multiple smaller functions = help: you could split it up into multiple smaller functions
error: aborting due to 20 previous errors

View File

@ -13,3 +13,5 @@ error: the function has a cyclomatic complexity of 3
= note: `-D cyclomatic-complexity` implied by `-D warnings` = note: `-D cyclomatic-complexity` implied by `-D warnings`
= help: you could split it up into multiple smaller functions = help: you could split it up into multiple smaller functions
error: aborting due to previous error

View File

@ -24,3 +24,5 @@ error: lint unstable_as_mut_slice has been removed: `Vec::as_mut_slice` has been
10 | #[warn(unstable_as_mut_slice)] 10 | #[warn(unstable_as_mut_slice)]
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View File

@ -106,3 +106,5 @@ note: consider deriving `Clone` or removing `Copy`
87 | | } 87 | | }
| |_^ | |_^
error: aborting due to 7 previous errors

View File

@ -36,3 +36,5 @@ error: sub-expression diverges
37 | _ => true || break, 37 | _ => true || break,
| ^^^^^ | ^^^^^
error: aborting due to 6 previous errors

View File

@ -47,3 +47,5 @@ error: I see you're using a LinkedList! Perhaps you meant some other data struct
| |
= help: a VecDeque might work = help: a VecDeque might work
error: aborting due to 6 previous errors

View File

@ -180,3 +180,5 @@ error: you should put bare URLs between `<`/`>` or make a proper Markdown link
168 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels 168 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 30 previous errors

View File

@ -6,3 +6,5 @@ error: `--x` could be misinterpreted as pre-decrement by C programmers, is usual
| |
= note: `-D double-neg` implied by `-D warnings` = note: `-D double-neg` implied by `-D warnings`
error: aborting due to previous error

View File

@ -30,3 +30,5 @@ error: Consider removing unnecessary double parentheses
32 | (()) 32 | (())
| ^^^^ | ^^^^
error: aborting due to 5 previous errors

View File

@ -72,3 +72,5 @@ note: argument has type SomeStruct
42 | forget(s4); 42 | forget(s4);
| ^^ | ^^
error: aborting due to 6 previous errors

View File

@ -216,3 +216,5 @@ note: argument has type &SomeStruct
59 | std::mem::forget(&SomeStruct); 59 | std::mem::forget(&SomeStruct);
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: aborting due to 18 previous errors

View File

@ -6,3 +6,5 @@ error: `darth` already exists, having another argument having almost the same na
| |
= note: `-D duplicate-underscore-argument` implied by `-D warnings` = note: `-D duplicate-underscore-argument` implied by `-D warnings`
error: aborting due to previous error

View File

@ -0,0 +1,50 @@
#![warn(clippy)]
#![warn(else_if_without_else)]
fn bla1() -> bool { unimplemented!() }
fn bla2() -> bool { unimplemented!() }
fn bla3() -> bool { unimplemented!() }
fn main() {
if bla1() {
println!("if");
}
if bla1() {
println!("if");
} else {
println!("else");
}
if bla1() {
println!("if");
} else if bla2() {
println!("else if");
} else {
println!("else")
}
if bla1() {
println!("if");
} else if bla2() {
println!("else if 1");
} else if bla3() {
println!("else if 2");
} else {
println!("else")
}
if bla1() {
println!("if");
} else if bla2() { //~ ERROR else if without else
println!("else if");
}
if bla1() {
println!("if");
} else if bla2() {
println!("else if 1");
} else if bla3() { //~ ERROR else if without else
println!("else if 2");
}
}

View File

@ -0,0 +1,22 @@
error: if expression with an `else if`, but without a final `else`
--> $DIR/else_if_without_else.rs:39:12
|
39 | } else if bla2() { //~ ERROR else if without else
| ____________^
40 | | println!("else if");
41 | | }
| |_____^ help: add an `else` block here
|
= note: `-D else-if-without-else` implied by `-D warnings`
error: if expression with an `else if`, but without a final `else`
--> $DIR/else_if_without_else.rs:47:12
|
47 | } else if bla3() { //~ ERROR else if without else
| ____________^
48 | | println!("else if 2");
49 | | }
| |_____^ help: add an `else` block here
error: aborting due to 2 previous errors

View File

@ -11,3 +11,5 @@ help: consider using the uninhabited type `!` or a wrapper around it
7 | enum Empty {} 7 | enum Empty {}
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -42,3 +42,5 @@ error: usage of `contains_key` followed by `insert` on a `BTreeMap`
37 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; 37 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)`
error: aborting due to 7 previous errors

View File

@ -12,3 +12,5 @@ error: don't use glob imports for enum variants
12 | use self::Enum::*; 12 | use self::Enum::*;
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -97,3 +97,5 @@ error: All variants have the same prefix: `With`
= note: `-D pub-enum-variant-names` implied by `-D warnings` = note: `-D pub-enum-variant-names` implied by `-D warnings`
= help: remove the prefixes and use full paths to the variants instead of glob imports = help: remove the prefixes and use full paths to the variants instead of glob imports
error: aborting due to 10 previous errors

View File

@ -48,3 +48,5 @@ error: Clike enum variant discriminant is not portable to 32-bit targets
37 | A = 0x1_0000_0000, 37 | A = 0x1_0000_0000,
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: aborting due to 8 previous errors

View File

@ -204,3 +204,5 @@ error: taken reference of right operand
| |
= note: `-D op-ref` implied by `-D warnings` = note: `-D op-ref` implied by `-D warnings`
error: aborting due to 33 previous errors

View File

@ -18,3 +18,5 @@ error: this operation will always return zero. This is likely not the intended o
11 | 0 / x; 11 | 0 / x;
| ^^^^^ | ^^^^^
error: aborting due to 3 previous errors

View File

@ -32,3 +32,5 @@ error: redundant closure found
18 | let e = Some(1u8).map(|a| generic(a)); 18 | let e = Some(1u8).map(|a| generic(a));
| ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic`
error: aborting due to 5 previous errors

View File

@ -47,3 +47,5 @@ note: whether read occurs before this write depends on evaluation order
21 | x += { x = 20; 2 }; 21 | x += { x = 20; 2 };
| ^^^^^^ | ^^^^^^
error: aborting due to 4 previous errors

View File

@ -36,3 +36,5 @@ error: use of `stderr().write_fmt(...).unwrap()`. Consider using `eprint!` inste
21 | std::io::stderr().write_fmt(format_args!("test")).unwrap(); 21 | std::io::stderr().write_fmt(format_args!("test")).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors

View File

@ -89,3 +89,5 @@ note: potential failure(s)
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: aborting due to 4 previous errors

View File

@ -36,3 +36,5 @@ error: called `filter_map(p).map(q)` on an `Iterator`. This is more succinctly e
25 | | .map(|x| x.checked_mul(2)) 25 | | .map(|x| x.checked_mul(2))
| |__________________________________________________________^ | |__________________________________________________________^
error: aborting due to 4 previous errors

View File

@ -95,3 +95,5 @@ note: std::f32::EPSILON and std::f64::EPSILON are available.
57 | twice(x) != twice(ONE as f64); 57 | twice(x) != twice(ONE as f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 8 previous errors

View File

@ -83,3 +83,5 @@ note: std::f32::EPSILON and std::f64::EPSILON are available.
25 | v != ONE; 25 | v != ONE;
| ^^^^^^^^ | ^^^^^^^^
error: aborting due to 7 previous errors

View File

@ -565,3 +565,5 @@ error: it looks like you're manually copying between slices
549 | | } 549 | | }
| |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
error: aborting due to 59 previous errors

View File

@ -6,3 +6,5 @@ error: useless use of `format!`
| |
= note: `-D useless-format` implied by `-D warnings` = note: `-D useless-format` implied by `-D warnings`
error: aborting due to previous error

View File

@ -86,3 +86,5 @@ error: possibly missing a comma here
| |
= note: to remove this lint, add a comma or write the expr in a single line = note: to remove this lint, add a comma or write the expr in a single line
error: aborting due to 10 previous errors

View File

@ -75,3 +75,5 @@ error: this public function dereferences a raw pointer but is not marked `unsafe
63 | unsafe { std::ptr::read(p) }; 63 | unsafe { std::ptr::read(p) };
| ^ | ^
error: aborting due to 12 previous errors

View File

@ -60,3 +60,5 @@ error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and
40 | *some_vecdeque.get_mut(0).unwrap() = 1; 40 | *some_vecdeque.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vecdeque[0]` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vecdeque[0]`
error: aborting due to 10 previous errors

View File

@ -40,3 +40,5 @@ error: identical conversion
39 | let _ = String::from("foo".to_string()); 39 | let _ = String::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
error: aborting due to 6 previous errors

View File

@ -48,3 +48,5 @@ error: the operation is ineffective. Consider reducing it to `u`
32 | u & 255; 32 | u & 255;
| ^^^^^^^ | ^^^^^^^
error: aborting due to 8 previous errors

View File

@ -24,3 +24,5 @@ error: redundant pattern matching, consider using `is_some()`
17 | if let Some(_) = Some(42) { 17 | if let Some(_) = Some(42) {
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()` | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
error: aborting due to 4 previous errors

View File

@ -23,3 +23,5 @@ error: Unnecessary `!=` operation
| |
= help: change to `==` and swap the blocks of the if/else = help: change to `==` and swap the blocks of the if/else
error: aborting due to 2 previous errors

View File

@ -133,3 +133,5 @@ help: consider adding a type parameter
78 | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) { 78 | pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {
| |
error: aborting due to 10 previous errors

View File

@ -39,3 +39,5 @@ error: digits grouped inconsistently by underscores
| |
= help: consider: 1.234_567_8_f32 = help: consider: 1.234_567_8_f32
error: aborting due to 5 previous errors

View File

@ -96,3 +96,5 @@ error: possible infinite iteration detected
30 | (0..).all(|x| x == 24); // maybe infinite iter 30 | (0..).all(|x| x == 24); // maybe infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 14 previous errors

View File

@ -0,0 +1,23 @@
#![warn(inline_fn_without_body)]
#![allow(inline_always)]
trait Foo {
#[inline]
fn default_inline();
#[inline(always)]fn always_inline();
#[inline(never)]
fn never_inline();
#[inline]
fn has_body() {
}
}
fn main() {
}

Some files were not shown because too many files have changed in this diff Show More