Merge remote-tracking branch 'upstream/master' into rustup2

This commit is contained in:
flip1995 2020-06-30 15:40:22 +02:00
commit 1e861a2663
No known key found for this signature in database
GPG Key ID: 693086869D506637
28 changed files with 693 additions and 142 deletions

View File

@ -1508,6 +1508,7 @@ Released 2018-09-13
[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool

View File

@ -11,7 +11,7 @@ declare_clippy_lint! {
/// non-async-aware MutexGuard.
///
/// **Why is this bad?** The Mutex types found in syd::sync and parking_lot
/// are not designed to operator in an async context across await points.
/// are not designed to operate in an async context across await points.
///
/// There are two potential solutions. One is to use an asynx-aware Mutex
/// type. Many asynchronous foundation crates provide such a Mutex type. The

View File

@ -73,9 +73,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
fn lint_deref(cx: &LateContext<'_, '_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) {
match method_name {
"deref" => {
if cx.tcx.lang_items().deref_trait().map_or(false, |id| {
let impls_deref_trait = cx.tcx.lang_items().deref_trait().map_or(false, |id| {
implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
}) {
});
if impls_deref_trait {
span_lint_and_sugg(
cx,
EXPLICIT_DEREF_METHODS,
@ -88,9 +89,10 @@ fn lint_deref(cx: &LateContext<'_, '_>, method_name: &str, call_expr: &Expr<'_>,
}
},
"deref_mut" => {
if cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
let impls_deref_mut_trait = cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
}) {
});
if impls_deref_mut_trait {
span_lint_and_sugg(
cx,
EXPLICIT_DEREF_METHODS,

View File

@ -229,6 +229,7 @@ mod main_recursion;
mod manual_async_fn;
mod manual_non_exhaustive;
mod map_clone;
mod map_identity;
mod map_unit_fn;
mod match_on_vec_items;
mod matches;
@ -608,6 +609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&manual_async_fn::MANUAL_ASYNC_FN,
&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
&map_clone::MAP_CLONE,
&map_identity::MAP_IDENTITY,
&map_unit_fn::OPTION_MAP_UNIT_FN,
&map_unit_fn::RESULT_MAP_UNIT_FN,
&match_on_vec_items::MATCH_ON_VEC_ITEMS,
@ -1057,6 +1059,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
store.register_late_pass(|| box macro_use::MacroUseImports::default());
store.register_late_pass(|| box map_identity::MapIdentity);
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@ -1273,6 +1276,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
LintId::of(&map_clone::MAP_CLONE),
LintId::of(&map_identity::MAP_IDENTITY),
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
@ -1550,6 +1554,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
LintId::of(&loops::MUT_RANGE_BOUND),
LintId::of(&loops::WHILE_LET_LOOP),
LintId::of(&map_identity::MAP_IDENTITY),
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(&matches::MATCH_AS_REF),

View File

@ -0,0 +1,126 @@
use crate::utils::{
is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks,
span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// **What it does:** Checks for instances of `map(f)` where `f` is the identity function.
///
/// **Why is this bad?** It can be written more concisely without the call to `map`.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x = [1, 2, 3];
/// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
/// ```
/// Use instead:
/// ```rust
/// let x = [1, 2, 3];
/// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
/// ```
pub MAP_IDENTITY,
complexity,
"using iterator.map(|x| x)"
}
declare_lint_pass!(MapIdentity => [MAP_IDENTITY]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapIdentity {
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
if expr.span.from_expansion() {
return;
}
if_chain! {
if let Some([caller, func]) = get_map_argument(cx, expr);
if is_expr_identity_function(cx, func);
then {
span_lint_and_sugg(
cx,
MAP_IDENTITY,
expr.span.trim_start(caller.span).unwrap(),
"unnecessary map of the identity function",
"remove the call to `map`",
String::new(),
Applicability::MachineApplicable
)
}
}
}
}
/// Returns the arguments passed into map() if the expression is a method call to
/// map(). Otherwise, returns None.
fn get_map_argument<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> {
if_chain! {
if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind;
if args.len() == 2 && method.ident.as_str() == "map";
let caller_ty = cx.tables().expr_ty(&args[0]);
if match_trait_method(cx, expr, &paths::ITERATOR)
|| is_type_diagnostic_item(cx, caller_ty, sym!(result_type))
|| is_type_diagnostic_item(cx, caller_ty, sym!(option_type));
then {
Some(args)
} else {
None
}
}
}
/// Checks if an expression represents the identity function
/// Only examines closures and `std::convert::identity`
fn is_expr_identity_function(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
match expr.kind {
ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
ExprKind::Path(QPath::Resolved(_, ref path)) => match_path(path, &paths::STD_CONVERT_IDENTITY),
_ => false,
}
}
/// Checks if a function's body represents the identity function
/// Looks for bodies of the form `|x| x`, `|x| return x`, `|x| { return x }` or `|x| {
/// return x; }`
fn is_body_identity_function(cx: &LateContext<'_, '_>, func: &Body<'_>) -> bool {
let params = func.params;
let body = remove_blocks(&func.value);
// if there's less/more than one parameter, then it is not the identity function
if params.len() != 1 {
return false;
}
match body.kind {
ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat),
ExprKind::Ret(Some(ref ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
ExprKind::Block(ref block, _) => {
if_chain! {
if block.stmts.len() == 1;
if let StmtKind::Semi(ref expr) | StmtKind::Expr(ref expr) = block.stmts[0].kind;
if let ExprKind::Ret(Some(ref ret_val)) = expr.kind;
then {
match_expr_param(cx, ret_val, params[0].pat)
} else {
false
}
}
},
_ => false,
}
}
/// Returns true iff an expression returns the same thing as a parameter's pattern
fn match_expr_param(cx: &LateContext<'_, '_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
if let PatKind::Binding(_, _, ident, _) = pat.kind {
match_var(expr, ident.name) && !(cx.tables().hir_owner == Some(expr.hir_id.owner) && is_adjusted(cx, expr))
} else {
false
}
}

View File

@ -2044,7 +2044,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir:
}
span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| {
if let Some((text, snip)) = snip {
diag.span_suggestion(expr.span, text, snip, Applicability::Unspecified);
diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
}
});
}

View File

@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, StmtKind, Ty,
TyKind, UnOp,
self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
StmtKind, TyKind, UnOp,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{ExpnKind, Span};
@ -371,8 +371,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
if op.is_comparison() {
check_nan(cx, left, expr);
check_nan(cx, right, expr);
check_to_owned(cx, left, right);
check_to_owned(cx, right, left);
check_to_owned(cx, left, right, true);
check_to_owned(cx, right, left, false);
}
if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) {
if is_allowed(cx, left) || is_allowed(cx, right) {
@ -570,11 +570,30 @@ fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _))
}
fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
#[derive(Default)]
struct EqImpl {
ty_eq_other: bool,
other_eq_ty: bool,
}
impl EqImpl {
fn is_implemented(&self) -> bool {
self.ty_eq_other || self.other_eq_ty
}
}
fn symmetric_partial_eq<'tcx>(cx: &LateContext<'_, 'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option<EqImpl> {
cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl {
ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]),
other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]),
})
}
let (arg_ty, snip) = match expr.kind {
ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
(cx.tables().expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
(cx.tables().expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
} else {
return;
}
@ -582,7 +601,7 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
ExprKind::Call(ref path, ref v) if v.len() == 1 => {
if let ExprKind::Path(ref path) = path.kind {
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
(cx.tables().expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
(cx.tables().expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
} else {
return;
}
@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
_ => return,
};
let other_ty = cx.tables().expr_ty_adjusted(other);
let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() {
Some(id) => id,
None => return,
};
let other_ty = cx.tables().expr_ty(other);
let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| {
implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])
});
let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| {
implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])
});
let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]);
let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
let with_deref = arg_ty
.builtin_deref(true)
.and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty))
.unwrap_or_default();
if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
if !with_deref.is_implemented() && !without_deref.is_implemented() {
return;
}
let other_gets_derefed = match other.kind {
ExprKind::Unary(UnOp::UnDeref, _) => true,
_ => false,
};
let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _));
let lint_span = if other_gets_derefed {
expr.span.to(other.span)
@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
return;
}
let try_hint = if deref_arg_impl_partial_eq_other {
// suggest deref on the left
format!("*{}", snip)
let expr_snip;
let eq_impl;
if with_deref.is_implemented() {
expr_snip = format!("*{}", snip);
eq_impl = with_deref;
} else {
// suggest dropping the to_owned on the left
snip.to_string()
expr_snip = snip.to_string();
eq_impl = without_deref;
};
let span;
let hint;
if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) {
span = expr.span;
hint = expr_snip;
} else {
span = expr.span.to(other.span);
if eq_impl.ty_eq_other {
hint = format!("{} == {}", expr_snip, snippet(cx, other.span, ".."));
} else {
hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip);
}
}
diag.span_suggestion(
lint_span,
span,
"try",
try_hint,
hint,
Applicability::MachineApplicable, // snippet
);
},
@ -694,7 +720,7 @@ fn non_macro_local(cx: &LateContext<'_, '_>, res: def::Res) -> bool {
}
}
fn check_cast(cx: &LateContext<'_, '_>, span: Span, e: &Expr<'_>, ty: &Ty<'_>) {
fn check_cast(cx: &LateContext<'_, '_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
if_chain! {
if let TyKind::Ptr(ref mut_ty) = ty.kind;
if let ExprKind::Lit(ref lit) = e.kind;

View File

@ -40,9 +40,8 @@ declare_clippy_lint! {
/// assert_eq!(v.len(), 42);
/// }
/// ```
///
/// should be
/// ```rust
/// // should be
/// fn foo(v: &[i32]) {
/// assert_eq!(v.len(), 42);
/// }

View File

@ -325,22 +325,22 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
/// parenthesis will always be added for a mix of these.
pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
/// Returns `true` if the operator is a shift operator `<<` or `>>`.
fn is_shift(op: &AssocOp) -> bool {
matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
fn is_shift(op: AssocOp) -> bool {
matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
}
/// Returns `true` if the operator is a arithmetic operator
/// (i.e., `+`, `-`, `*`, `/`, `%`).
fn is_arith(op: &AssocOp) -> bool {
fn is_arith(op: AssocOp) -> bool {
matches!(
*op,
op,
AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus
)
}
/// Returns `true` if the operator `op` needs parenthesis with the operator
/// `other` in the direction `dir`.
fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
fn needs_paren(op: AssocOp, other: AssocOp, dir: Associativity) -> bool {
other.precedence() < op.precedence()
|| (other.precedence() == op.precedence()
&& ((op != other && associativity(op) != dir)
@ -349,14 +349,14 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static>
|| is_shift(other) && is_arith(op)
}
let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
needs_paren(&op, lop, Associativity::Left)
let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs {
needs_paren(op, lop, Associativity::Left)
} else {
false
};
let rhs_paren = if let Sugg::BinOp(ref rop, _) = *rhs {
needs_paren(&op, rop, Associativity::Right)
let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs {
needs_paren(op, rop, Associativity::Right)
} else {
false
};
@ -424,13 +424,13 @@ enum Associativity {
/// they are considered
/// associative.
#[must_use]
fn associativity(op: &AssocOp) -> Associativity {
fn associativity(op: AssocOp) -> Associativity {
use rustc_ast::util::parser::AssocOp::{
Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater,
GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
};
match *op {
match op {
Assign | AssignOp(_) => Associativity::Right,
Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both,
Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight

View File

@ -23,7 +23,11 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// // Bad
/// println!("");
///
/// // Good
/// println!();
/// ```
pub PRINTLN_EMPTY_STRING,
style,
@ -32,8 +36,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
/// string that ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
@ -125,7 +128,12 @@ declare_clippy_lint! {
/// ```rust
/// # use std::fmt::Write;
/// # let mut buf = String::new();
///
/// // Bad
/// writeln!(buf, "");
///
/// // Good
/// writeln!(buf);
/// ```
pub WRITELN_EMPTY_STRING,
style,
@ -147,7 +155,12 @@ declare_clippy_lint! {
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// # let name = "World";
///
/// // Bad
/// write!(buf, "Hello {}!\n", name);
///
/// // Good
/// writeln!(buf, "Hello {}!", name);
/// ```
pub WRITE_WITH_NEWLINE,
style,
@ -168,7 +181,12 @@ declare_clippy_lint! {
/// ```rust
/// # use std::fmt::Write;
/// # let mut buf = String::new();
///
/// // Bad
/// writeln!(buf, "{}", "foo");
///
/// // Good
/// writeln!(buf, "foo");
/// ```
pub WRITE_LITERAL,
style,
@ -279,12 +297,11 @@ impl EarlyLintPass for Write {
if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) {
if fmt_str.symbol == Symbol::intern("") {
let mut applicability = Applicability::MachineApplicable;
let suggestion = match expr {
Some(expr) => snippet_with_applicability(cx, expr.span, "v", &mut applicability),
None => {
applicability = Applicability::HasPlaceholders;
Cow::Borrowed("v")
},
let suggestion = if let Some(e) = expr {
snippet_with_applicability(cx, e.span, "v", &mut applicability)
} else {
applicability = Applicability::HasPlaceholders;
Cow::Borrowed("v")
};
span_lint_and_sugg(

View File

@ -1144,6 +1144,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
deprecation: None,
module: "methods",
},
Lint {
name: "map_identity",
group: "complexity",
desc: "using iterator.map(|x| x)",
deprecation: None,
module: "map_identity",
},
Lint {
name: "map_unwrap_or",
group: "pedantic",

View File

@ -155,9 +155,6 @@ fn run_ui_toml(config: &mut compiletest::Config) {
}
fn run_ui_cargo(config: &mut compiletest::Config) {
if cargo::is_rustc_test_suite() {
return;
}
fn run_tests(
config: &compiletest::Config,
filter: &Option<String>,

View File

@ -1,4 +1,4 @@
error: multiple versions for dependency `winapi`: 0.2.8, 0.3.8
error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9
|
= note: `-D clippy::multiple-crate-versions` implied by `-D warnings`

View File

@ -0,0 +1,40 @@
// run-rustfix
#![allow(
unused,
clippy::redundant_clone,
clippy::deref_addrof,
clippy::no_effect,
clippy::unnecessary_operation
)]
use std::cell::RefCell;
use std::rc::{self, Rc};
use std::sync::{self, Arc};
fn main() {}
fn is_ascii(ch: char) -> bool {
ch.is_ascii()
}
fn clone_on_copy() {
42;
vec![1].clone(); // ok, not a Copy type
Some(vec![1]).clone(); // ok, not a Copy type
*(&42);
let rc = RefCell::new(0);
*rc.borrow();
// Issue #4348
let mut x = 43;
let _ = &x.clone(); // ok, getting a ref
'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
is_ascii('z');
// Issue #5436
let mut vec = Vec::new();
vec.push(42);
}

40
tests/ui/clone_on_copy.rs Normal file
View File

@ -0,0 +1,40 @@
// run-rustfix
#![allow(
unused,
clippy::redundant_clone,
clippy::deref_addrof,
clippy::no_effect,
clippy::unnecessary_operation
)]
use std::cell::RefCell;
use std::rc::{self, Rc};
use std::sync::{self, Arc};
fn main() {}
fn is_ascii(ch: char) -> bool {
ch.is_ascii()
}
fn clone_on_copy() {
42.clone();
vec![1].clone(); // ok, not a Copy type
Some(vec![1]).clone(); // ok, not a Copy type
(&42).clone();
let rc = RefCell::new(0);
rc.borrow().clone();
// Issue #4348
let mut x = 43;
let _ = &x.clone(); // ok, getting a ref
'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
is_ascii('z'.clone());
// Issue #5436
let mut vec = Vec::new();
vec.push(42.clone());
}

View File

@ -0,0 +1,34 @@
error: using `clone` on a `Copy` type
--> $DIR/clone_on_copy.rs:22:5
|
LL | 42.clone();
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
|
= note: `-D clippy::clone-on-copy` implied by `-D warnings`
error: using `clone` on a `Copy` type
--> $DIR/clone_on_copy.rs:26:5
|
LL | (&42).clone();
| ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
error: using `clone` on a `Copy` type
--> $DIR/clone_on_copy.rs:29:5
|
LL | rc.borrow().clone();
| ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
error: using `clone` on a `Copy` type
--> $DIR/clone_on_copy.rs:35:14
|
LL | is_ascii('z'.clone());
| ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
error: using `clone` on a `Copy` type
--> $DIR/clone_on_copy.rs:39:14
|
LL | vec.push(42.clone());
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
error: aborting due to 5 previous errors

View File

@ -0,0 +1,93 @@
// run-rustfix
#![allow(unused, clippy::redundant_clone)] // See #5700
// Define the types in each module to avoid trait impls leaking between modules.
macro_rules! impl_types {
() => {
#[derive(PartialEq)]
pub struct Owned;
pub struct Borrowed;
impl ToOwned for Borrowed {
type Owned = Owned;
fn to_owned(&self) -> Owned {
Owned {}
}
}
impl std::borrow::Borrow<Borrowed> for Owned {
fn borrow(&self) -> &Borrowed {
static VALUE: Borrowed = Borrowed {};
&VALUE
}
}
};
}
// Only Borrowed == Owned is implemented
mod borrowed_eq_owned {
impl_types!();
impl PartialEq<Owned> for Borrowed {
fn eq(&self, _: &Owned) -> bool {
true
}
}
pub fn compare() {
let owned = Owned {};
let borrowed = Borrowed {};
if borrowed == owned {}
if borrowed == owned {}
}
}
// Only Owned == Borrowed is implemented
mod owned_eq_borrowed {
impl_types!();
impl PartialEq<Borrowed> for Owned {
fn eq(&self, _: &Borrowed) -> bool {
true
}
}
fn compare() {
let owned = Owned {};
let borrowed = Borrowed {};
if owned == borrowed {}
if owned == borrowed {}
}
}
mod issue_4874 {
impl_types!();
// NOTE: PartialEq<Borrowed> for T can't be implemented due to the orphan rules
impl<T> PartialEq<T> for Borrowed
where
T: AsRef<str> + ?Sized,
{
fn eq(&self, _: &T) -> bool {
true
}
}
impl std::fmt::Display for Borrowed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "borrowed")
}
}
fn compare() {
let borrowed = Borrowed {};
if borrowed == "Hi" {}
if borrowed == "Hi" {}
}
}
fn main() {}

View File

@ -0,0 +1,93 @@
// run-rustfix
#![allow(unused, clippy::redundant_clone)] // See #5700
// Define the types in each module to avoid trait impls leaking between modules.
macro_rules! impl_types {
() => {
#[derive(PartialEq)]
pub struct Owned;
pub struct Borrowed;
impl ToOwned for Borrowed {
type Owned = Owned;
fn to_owned(&self) -> Owned {
Owned {}
}
}
impl std::borrow::Borrow<Borrowed> for Owned {
fn borrow(&self) -> &Borrowed {
static VALUE: Borrowed = Borrowed {};
&VALUE
}
}
};
}
// Only Borrowed == Owned is implemented
mod borrowed_eq_owned {
impl_types!();
impl PartialEq<Owned> for Borrowed {
fn eq(&self, _: &Owned) -> bool {
true
}
}
pub fn compare() {
let owned = Owned {};
let borrowed = Borrowed {};
if borrowed.to_owned() == owned {}
if owned == borrowed.to_owned() {}
}
}
// Only Owned == Borrowed is implemented
mod owned_eq_borrowed {
impl_types!();
impl PartialEq<Borrowed> for Owned {
fn eq(&self, _: &Borrowed) -> bool {
true
}
}
fn compare() {
let owned = Owned {};
let borrowed = Borrowed {};
if owned == borrowed.to_owned() {}
if borrowed.to_owned() == owned {}
}
}
mod issue_4874 {
impl_types!();
// NOTE: PartialEq<Borrowed> for T can't be implemented due to the orphan rules
impl<T> PartialEq<T> for Borrowed
where
T: AsRef<str> + ?Sized,
{
fn eq(&self, _: &T) -> bool {
true
}
}
impl std::fmt::Display for Borrowed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "borrowed")
}
}
fn compare() {
let borrowed = Borrowed {};
if "Hi" == borrowed.to_string() {}
if borrowed.to_string() == "Hi" {}
}
}
fn main() {}

View File

@ -0,0 +1,46 @@
error: this creates an owned instance just for comparison
--> $DIR/asymmetric_partial_eq.rs:42:12
|
LL | if borrowed.to_owned() == owned {}
| ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
|
= note: `-D clippy::cmp-owned` implied by `-D warnings`
error: this creates an owned instance just for comparison
--> $DIR/asymmetric_partial_eq.rs:43:21
|
LL | if owned == borrowed.to_owned() {}
| ---------^^^^^^^^^^^^^^^^^^^
| |
| help: try: `borrowed == owned`
error: this creates an owned instance just for comparison
--> $DIR/asymmetric_partial_eq.rs:61:21
|
LL | if owned == borrowed.to_owned() {}
| ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
error: this creates an owned instance just for comparison
--> $DIR/asymmetric_partial_eq.rs:62:12
|
LL | if borrowed.to_owned() == owned {}
| ^^^^^^^^^^^^^^^^^^^---------
| |
| help: try: `owned == borrowed`
error: this creates an owned instance just for comparison
--> $DIR/asymmetric_partial_eq.rs:88:20
|
LL | if "Hi" == borrowed.to_string() {}
| --------^^^^^^^^^^^^^^^^^^^^
| |
| help: try: `borrowed == "Hi"`
error: this creates an owned instance just for comparison
--> $DIR/asymmetric_partial_eq.rs:89:12
|
LL | if borrowed.to_string() == "Hi" {}
| ^^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
error: aborting due to 6 previous errors

View File

@ -2,6 +2,7 @@
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::map_identity)]
fn main() {
let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();

View File

@ -2,6 +2,7 @@
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::map_identity)]
fn main() {
let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();

View File

@ -1,5 +1,5 @@
error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)`
--> $DIR/map_flatten.rs:7:21
--> $DIR/map_flatten.rs:8:21
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)`
@ -7,7 +7,7 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().colle
= note: `-D clippy::map-flatten` implied by `-D warnings`
error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)`
--> $DIR/map_flatten.rs:8:24
--> $DIR/map_flatten.rs:9:24
|
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)`

View File

@ -0,0 +1,23 @@
// run-rustfix
#![warn(clippy::map_identity)]
#![allow(clippy::needless_return)]
fn main() {
let x: [u16; 3] = [1, 2, 3];
// should lint
let _: Vec<_> = x.iter().map(not_identity).collect();
let _: Vec<_> = x.iter().collect();
let _: Option<u8> = Some(3);
let _: Result<i8, f32> = Ok(-3);
// should not lint
let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
let _: Option<u8> = None.map(|x: u8| x - 1);
let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
return x + 3;
});
}
fn not_identity(x: &u16) -> u16 {
*x
}

25
tests/ui/map_identity.rs Normal file
View File

@ -0,0 +1,25 @@
// run-rustfix
#![warn(clippy::map_identity)]
#![allow(clippy::needless_return)]
fn main() {
let x: [u16; 3] = [1, 2, 3];
// should lint
let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
let _: Option<u8> = Some(3).map(|x| x);
let _: Result<i8, f32> = Ok(-3).map(|x| {
return x;
});
// should not lint
let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
let _: Option<u8> = None.map(|x: u8| x - 1);
let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
return x + 3;
});
}
fn not_identity(x: &u16) -> u16 {
*x
}

View File

@ -0,0 +1,37 @@
error: unnecessary map of the identity function
--> $DIR/map_identity.rs:8:47
|
LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
| ^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
|
= note: `-D clippy::map-identity` implied by `-D warnings`
error: unnecessary map of the identity function
--> $DIR/map_identity.rs:9:57
|
LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
| ^^^^^^^^^^^ help: remove the call to `map`
error: unnecessary map of the identity function
--> $DIR/map_identity.rs:9:29
|
LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
error: unnecessary map of the identity function
--> $DIR/map_identity.rs:10:32
|
LL | let _: Option<u8> = Some(3).map(|x| x);
| ^^^^^^^^^^^ help: remove the call to `map`
error: unnecessary map of the identity function
--> $DIR/map_identity.rs:11:36
|
LL | let _: Result<i8, f32> = Ok(-3).map(|x| {
| ____________________________________^
LL | | return x;
LL | | });
| |______^ help: remove the call to `map`
error: aborting due to 5 previous errors

View File

@ -13,31 +13,6 @@ impl SomeTrait for SomeImpl {}
fn main() {}
fn is_ascii(ch: char) -> bool {
ch.is_ascii()
}
fn clone_on_copy() {
42.clone();
vec![1].clone(); // ok, not a Copy type
Some(vec![1]).clone(); // ok, not a Copy type
(&42).clone();
let rc = RefCell::new(0);
rc.borrow().clone();
// Issue #4348
let mut x = 43;
let _ = &x.clone(); // ok, getting a ref
'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
is_ascii('z'.clone());
// Issue #5436
let mut vec = Vec::new();
vec.push(42.clone());
}
fn clone_on_ref_ptr() {
let rc = Rc::new(true);
let arc = Arc::new(true);

View File

@ -1,37 +1,5 @@
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:21:5
|
LL | 42.clone();
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
|
= note: `-D clippy::clone-on-copy` implied by `-D warnings`
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:25:5
|
LL | (&42).clone();
| ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:28:5
|
LL | rc.borrow().clone();
| ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:34:14
|
LL | is_ascii('z'.clone());
| ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:38:14
|
LL | vec.push(42.clone());
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:48:5
--> $DIR/unnecessary_clone.rs:23:5
|
LL | rc.clone();
| ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)`
@ -39,43 +7,45 @@ LL | rc.clone();
= note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:51:5
--> $DIR/unnecessary_clone.rs:26:5
|
LL | arc.clone();
| ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:54:5
--> $DIR/unnecessary_clone.rs:29:5
|
LL | rcweak.clone();
| ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:57:5
--> $DIR/unnecessary_clone.rs:32:5
|
LL | arc_weak.clone();
| ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:61:33
--> $DIR/unnecessary_clone.rs:36:33
|
LL | let _: Arc<dyn SomeTrait> = x.clone();
| ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)`
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:65:5
--> $DIR/unnecessary_clone.rs:40:5
|
LL | t.clone();
| ^^^^^^^^^ help: try removing the `clone` call: `t`
|
= note: `-D clippy::clone-on-copy` implied by `-D warnings`
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:67:5
--> $DIR/unnecessary_clone.rs:42:5
|
LL | Some(t).clone();
| ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
--> $DIR/unnecessary_clone.rs:73:22
--> $DIR/unnecessary_clone.rs:48:22
|
LL | let z: &Vec<_> = y.clone();
| ^^^^^^^^^
@ -91,13 +61,13 @@ LL | let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: using `clone` on a `Copy` type
--> $DIR/unnecessary_clone.rs:109:20
--> $DIR/unnecessary_clone.rs:84:20
|
LL | let _: E = a.clone();
| ^^^^^^^^^ help: try dereferencing it: `*****a`
error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
--> $DIR/unnecessary_clone.rs:114:22
--> $DIR/unnecessary_clone.rs:89:22
|
LL | let _ = &mut encoded.clone();
| ^^^^^^^^^^^^^^^
@ -112,7 +82,7 @@ LL | let _ = &mut <&[u8]>::clone(encoded);
| ^^^^^^^^^^^^^^^^^^^^^^^
error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
--> $DIR/unnecessary_clone.rs:115:18
--> $DIR/unnecessary_clone.rs:90:18
|
LL | let _ = &encoded.clone();
| ^^^^^^^^^^^^^^^
@ -126,5 +96,5 @@ help: or try being explicit if you are sure, that you want to clone a reference
LL | let _ = &<&[u8]>::clone(encoded);
| ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 16 previous errors
error: aborting due to 11 previous errors

View File

@ -1,7 +0,0 @@
#!/bin/sh
CARGO_TARGET_DIR=$(pwd)/target/
export CARGO_TARGET_DIR
echo 'Deprecated! `util/dev` usage is deprecated, please use `cargo dev` instead.'
cd clippy_dev && cargo run -- "$@"