mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
d037b28025
@ -981,7 +981,7 @@ Released 2021-03-25
|
||||
[#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
|
||||
* [`single_match`] Suggest `if` over `if let` when possible
|
||||
[#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
|
||||
* [`ref_in_deref`] Use parentheses correctly in suggestion
|
||||
* `ref_in_deref` Use parentheses correctly in suggestion
|
||||
[#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
|
||||
* [`stable_sort_primitive`] Clarify error message
|
||||
[#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
|
||||
@ -3227,7 +3227,6 @@ Released 2018-09-13
|
||||
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
|
||||
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
|
||||
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
|
||||
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
|
||||
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
|
||||
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
|
||||
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
|
||||
|
@ -9,9 +9,14 @@ use walkdir::WalkDir;
|
||||
|
||||
use crate::clippy_project_root;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
|
||||
#[cfg(windows)]
|
||||
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
|
||||
|
||||
static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
|
||||
let mut path = std::env::current_exe().unwrap();
|
||||
path.set_file_name("cargo-clippy");
|
||||
path.set_file_name(CARGO_CLIPPY_EXE);
|
||||
fs::metadata(path).ok()?.modified().ok()
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,6 @@ pub fn run(filename: &str) {
|
||||
.args(["-Z", "no-codegen"])
|
||||
.args(["--edition", "2021"])
|
||||
.arg(filename)
|
||||
.env("__CLIPPY_INTERNAL_TESTS", "true")
|
||||
.status()
|
||||
.expect("failed to run cargo")
|
||||
.code();
|
||||
|
@ -94,4 +94,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
@ -23,15 +23,14 @@ pub(super) fn check(
|
||||
|
||||
if_chain! {
|
||||
if let LitKind::Int(n, _) = lit.node;
|
||||
if let Some(src) = snippet_opt(cx, lit.span);
|
||||
if let Some(src) = snippet_opt(cx, cast_expr.span);
|
||||
if cast_to.is_floating_point();
|
||||
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
|
||||
let from_nbits = 128 - n.leading_zeros();
|
||||
let to_nbits = fp_ty_mantissa_nbits(cast_to);
|
||||
if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
|
||||
then {
|
||||
let literal_str = if is_unary_neg(cast_expr) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
|
||||
lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
|
||||
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -48,7 +47,7 @@ pub(super) fn check(
|
||||
| LitKind::Float(_, LitFloatType::Suffixed(_))
|
||||
if cast_from.kind() == cast_to.kind() =>
|
||||
{
|
||||
if let Some(src) = snippet_opt(cx, lit.span) {
|
||||
if let Some(src) = snippet_opt(cx, cast_expr.span) {
|
||||
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
|
||||
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
|
||||
}
|
||||
@ -113,7 +112,3 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unary_neg(expr: &Expr<'_>) -> bool {
|
||||
matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::sugg::has_enclosing_paren;
|
||||
use clippy_utils::ty::peel_mid_ty_refs;
|
||||
use clippy_utils::{get_parent_expr, get_parent_node, is_lint_allowed, path_to_local};
|
||||
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
|
||||
@ -10,11 +11,10 @@ use rustc_hir::{
|
||||
Pat, PatKind, UnOp,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TyS, TypeckResults};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{symbol::sym, Span};
|
||||
use std::iter;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -131,8 +131,6 @@ pub struct Dereferencing {
|
||||
struct StateData {
|
||||
/// Span of the top level expression
|
||||
span: Span,
|
||||
/// The required mutability
|
||||
target_mut: Mutability,
|
||||
}
|
||||
|
||||
enum State {
|
||||
@ -141,9 +139,13 @@ enum State {
|
||||
// The number of calls in a sequence which changed the referenced type
|
||||
ty_changed_count: usize,
|
||||
is_final_ufcs: bool,
|
||||
/// The required mutability
|
||||
target_mut: Mutability,
|
||||
},
|
||||
DerefedBorrow {
|
||||
count: u32,
|
||||
count: usize,
|
||||
required_precedence: i8,
|
||||
msg: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
@ -214,59 +216,98 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
1
|
||||
},
|
||||
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
|
||||
},
|
||||
StateData {
|
||||
span: expr.span,
|
||||
target_mut,
|
||||
},
|
||||
StateData { span: expr.span },
|
||||
));
|
||||
},
|
||||
RefOp::AddrOf => {
|
||||
// Find the number of times the borrow is auto-derefed.
|
||||
let mut iter = find_adjustments(cx.tcx, typeck, expr).iter();
|
||||
if let Some((i, adjust)) = iter.by_ref().enumerate().find_map(|(i, adjust)| {
|
||||
if !matches!(adjust.kind, Adjust::Deref(_)) {
|
||||
Some((i, adjust))
|
||||
} else if !adjust.target.is_ref() {
|
||||
// Add one to the number of references found.
|
||||
Some((i + 1, adjust))
|
||||
let mut deref_count = 0usize;
|
||||
let next_adjust = loop {
|
||||
match iter.next() {
|
||||
Some(adjust) => {
|
||||
if !matches!(adjust.kind, Adjust::Deref(_)) {
|
||||
break Some(adjust);
|
||||
} else if !adjust.target.is_ref() {
|
||||
deref_count += 1;
|
||||
break iter.next();
|
||||
}
|
||||
deref_count += 1;
|
||||
},
|
||||
None => break None,
|
||||
};
|
||||
};
|
||||
|
||||
// Determine the required number of references before any can be removed. In all cases the
|
||||
// reference made by the current expression will be removed. After that there are four cases to
|
||||
// handle.
|
||||
//
|
||||
// 1. Auto-borrow will trigger in the current position, so no further references are required.
|
||||
// 2. Auto-deref ends at a reference, or the underlying type, so one extra needs to be left to
|
||||
// handle the automatically inserted re-borrow.
|
||||
// 3. Auto-deref hits a user-defined `Deref` impl, so at least one reference needs to exist to
|
||||
// start auto-deref.
|
||||
// 4. If the chain of non-user-defined derefs ends with a mutable re-borrow, and re-borrow
|
||||
// adjustments will not be inserted automatically, then leave one further reference to avoid
|
||||
// moving a mutable borrow.
|
||||
// e.g.
|
||||
// fn foo<T>(x: &mut Option<&mut T>, y: &mut T) {
|
||||
// let x = match x {
|
||||
// // Removing the borrow will cause `x` to be moved
|
||||
// Some(x) => &mut *x,
|
||||
// None => y
|
||||
// };
|
||||
// }
|
||||
let deref_msg =
|
||||
"this expression creates a reference which is immediately dereferenced by the compiler";
|
||||
let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
|
||||
|
||||
let (required_refs, required_precedence, msg) = if is_auto_borrow_position(parent, expr.hir_id)
|
||||
{
|
||||
(1, PREC_POSTFIX, if deref_count == 1 { borrow_msg } else { deref_msg })
|
||||
} else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
|
||||
next_adjust.map(|a| &a.kind)
|
||||
{
|
||||
if matches!(mutability, AutoBorrowMutability::Mut { .. })
|
||||
&& !is_auto_reborrow_position(parent)
|
||||
{
|
||||
(3, 0, deref_msg)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
// Found two consecutive derefs. At least one can be removed.
|
||||
if i > 1 {
|
||||
let target_mut = iter::once(adjust)
|
||||
.chain(iter)
|
||||
.find_map(|adjust| match adjust.kind {
|
||||
Adjust::Borrow(AutoBorrow::Ref(_, m)) => Some(m.into()),
|
||||
_ => None,
|
||||
})
|
||||
// This default should never happen. Auto-deref always reborrows.
|
||||
.unwrap_or(Mutability::Not);
|
||||
self.state = Some((
|
||||
// Subtract one for the current borrow expression, and one to cover the last
|
||||
// reference which can't be removed (it's either reborrowed, or needed for
|
||||
// auto-deref to happen).
|
||||
State::DerefedBorrow {
|
||||
count:
|
||||
// Truncation here would require more than a `u32::MAX` level reference. The compiler
|
||||
// does not support this.
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
{ i as u32 - 2 }
|
||||
},
|
||||
StateData {
|
||||
span: expr.span,
|
||||
target_mut,
|
||||
},
|
||||
));
|
||||
(2, 0, deref_msg)
|
||||
}
|
||||
} else {
|
||||
(2, 0, deref_msg)
|
||||
};
|
||||
|
||||
if deref_count >= required_refs {
|
||||
self.state = Some((
|
||||
State::DerefedBorrow {
|
||||
// One of the required refs is for the current borrow expression, the remaining ones
|
||||
// can't be removed without breaking the code. See earlier comment.
|
||||
count: deref_count - required_refs,
|
||||
required_precedence,
|
||||
msg,
|
||||
},
|
||||
StateData { span: expr.span },
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
(Some((State::DerefMethod { ty_changed_count, .. }, data)), RefOp::Method(_)) => {
|
||||
(
|
||||
Some((
|
||||
State::DerefMethod {
|
||||
target_mut,
|
||||
ty_changed_count,
|
||||
..
|
||||
},
|
||||
data,
|
||||
)),
|
||||
RefOp::Method(_),
|
||||
) => {
|
||||
self.state = Some((
|
||||
State::DerefMethod {
|
||||
ty_changed_count: if deref_method_same_type(typeck.expr_ty(expr), typeck.expr_ty(sub_expr)) {
|
||||
@ -275,12 +316,30 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
ty_changed_count + 1
|
||||
},
|
||||
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
|
||||
target_mut,
|
||||
},
|
||||
data,
|
||||
));
|
||||
},
|
||||
(Some((State::DerefedBorrow { count }, data)), RefOp::AddrOf) if count != 0 => {
|
||||
self.state = Some((State::DerefedBorrow { count: count - 1 }, data));
|
||||
(
|
||||
Some((
|
||||
State::DerefedBorrow {
|
||||
count,
|
||||
required_precedence,
|
||||
msg,
|
||||
},
|
||||
data,
|
||||
)),
|
||||
RefOp::AddrOf,
|
||||
) if count != 0 => {
|
||||
self.state = Some((
|
||||
State::DerefedBorrow {
|
||||
count: count - 1,
|
||||
required_precedence,
|
||||
msg,
|
||||
},
|
||||
data,
|
||||
));
|
||||
},
|
||||
|
||||
(Some((state, data)), _) => report(cx, expr, state, data),
|
||||
@ -455,6 +514,30 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given expression is in a position which can be auto-reborrowed.
|
||||
/// Note: This is only correct assuming auto-deref is already occurring.
|
||||
fn is_auto_reborrow_position(parent: Option<Node<'_>>) -> bool {
|
||||
match parent {
|
||||
Some(Node::Expr(parent)) => matches!(parent.kind, ExprKind::MethodCall(..) | ExprKind::Call(..)),
|
||||
Some(Node::Local(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given expression is a position which can auto-borrow.
|
||||
fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool {
|
||||
if let Some(Node::Expr(parent)) = parent {
|
||||
match parent.kind {
|
||||
ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id,
|
||||
ExprKind::Field(..) => true,
|
||||
ExprKind::Call(f, _) => f.hir_id == child_id,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjustments are sometimes made in the parent block rather than the expression itself.
|
||||
fn find_adjustments<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -503,6 +586,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
|
||||
State::DerefMethod {
|
||||
ty_changed_count,
|
||||
is_final_ufcs,
|
||||
target_mut,
|
||||
} => {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
|
||||
@ -517,12 +601,12 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
|
||||
};
|
||||
let addr_of_str = if ty_changed_count < ref_count {
|
||||
// Check if a reborrow from &mut T -> &T is required.
|
||||
if data.target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
|
||||
if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
|
||||
"&*"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} else if data.target_mut == Mutability::Mut {
|
||||
} else if target_mut == Mutability::Mut {
|
||||
"&mut "
|
||||
} else {
|
||||
"&"
|
||||
@ -538,7 +622,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
|
||||
cx,
|
||||
EXPLICIT_DEREF_METHODS,
|
||||
data.span,
|
||||
match data.target_mut {
|
||||
match target_mut {
|
||||
Mutability::Not => "explicit `deref` method call",
|
||||
Mutability::Mut => "explicit `deref_mut` method call",
|
||||
},
|
||||
@ -547,19 +631,24 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
|
||||
app,
|
||||
);
|
||||
},
|
||||
State::DerefedBorrow { .. } => {
|
||||
State::DerefedBorrow {
|
||||
required_precedence,
|
||||
msg,
|
||||
..
|
||||
} => {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_BORROW,
|
||||
data.span,
|
||||
&format!(
|
||||
"this expression borrows a reference (`{}`) that is immediately dereferenced by the compiler",
|
||||
cx.typeck_results().expr_ty(expr),
|
||||
),
|
||||
msg,
|
||||
"change this to",
|
||||
snip.into(),
|
||||
if required_precedence > expr.precedence().order() && !has_enclosing_paren(&snip) {
|
||||
format!("({})", snip)
|
||||
} else {
|
||||
snip.into()
|
||||
},
|
||||
app,
|
||||
);
|
||||
},
|
||||
|
@ -172,6 +172,9 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
|
||||
let name = var.ident.name.as_str();
|
||||
|
||||
let variant_split = camel_case_split(name);
|
||||
if variant_split.len() == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
pre = pre
|
||||
.iter()
|
||||
|
@ -1,12 +1,16 @@
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
|
||||
use clippy_utils::get_enclosing_block;
|
||||
use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::{implements_trait, is_copy};
|
||||
use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
|
||||
use rustc_hir::{
|
||||
def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, Ty, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, TyS};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -146,6 +150,13 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
|
||||
let rty = cx.typeck_results().expr_ty(r);
|
||||
let lcpy = is_copy(cx, lty);
|
||||
let rcpy = is_copy(cx, rty);
|
||||
if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) {
|
||||
if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
|
||||
|| (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))
|
||||
{
|
||||
return; // Don't lint
|
||||
}
|
||||
}
|
||||
// either operator autorefs or both args are copyable
|
||||
if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) {
|
||||
span_lint_and_then(
|
||||
@ -206,6 +217,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
|
||||
// &foo == bar
|
||||
(&ExprKind::AddrOf(BorrowKind::Ref, _, l), _) => {
|
||||
let lty = cx.typeck_results().expr_ty(l);
|
||||
if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) {
|
||||
let rty = cx.typeck_results().expr_ty(right);
|
||||
if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
|
||||
|| (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))
|
||||
{
|
||||
return; // Don't lint
|
||||
}
|
||||
}
|
||||
let lcpy = is_copy(cx, lty);
|
||||
if (requires_ref || lcpy)
|
||||
&& implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
|
||||
@ -230,6 +249,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
|
||||
// foo == &bar
|
||||
(_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => {
|
||||
let rty = cx.typeck_results().expr_ty(r);
|
||||
if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) {
|
||||
let lty = cx.typeck_results().expr_ty(left);
|
||||
if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
|
||||
|| (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))
|
||||
{
|
||||
return; // Don't lint
|
||||
}
|
||||
}
|
||||
let rcpy = is_copy(cx, rty);
|
||||
if (requires_ref || rcpy)
|
||||
&& implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
|
||||
@ -251,3 +278,43 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx Ty<'tcx>, &'tcx Ty<'tcx>)> {
|
||||
if_chain! {
|
||||
if let Some(block) = get_enclosing_block(cx, e.hir_id);
|
||||
if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id());
|
||||
let item = cx.tcx.hir().expect_item(impl_def_id.expect_local());
|
||||
if let ItemKind::Impl(item) = &item.kind;
|
||||
if let Some(of_trait) = &item.of_trait;
|
||||
if let Some(seg) = of_trait.path.segments.last();
|
||||
if let Some(Res::Def(_, trait_id)) = seg.res;
|
||||
if trait_id == bin_op;
|
||||
if let Some(generic_args) = seg.args;
|
||||
if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
|
||||
|
||||
then {
|
||||
Some((item.self_ty, other_ty))
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: &TyS<'_>, hir_ty: &Ty<'_>) -> bool {
|
||||
if_chain! {
|
||||
if let ty::Adt(adt_def, _) = middle_ty.kind();
|
||||
if let Some(local_did) = adt_def.did.as_local();
|
||||
let item = cx.tcx.hir().expect_item(local_did);
|
||||
let middle_ty_id = item.def_id.to_def_id();
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
|
||||
if let Res::Def(_, hir_ty_id) = path.res;
|
||||
|
||||
then {
|
||||
hir_ty_id == middle_ty_id
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
||||
)
|
||||
.and_then(|snip| {
|
||||
let i = snip.find("fn")?;
|
||||
Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
|
||||
Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32))
|
||||
})
|
||||
.expect("failed to create span for type parameters");
|
||||
Span::new(pos, pos, item.span.ctxt(), item.span.parent())
|
||||
|
@ -247,7 +247,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(redundant_slicing::REDUNDANT_SLICING),
|
||||
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
||||
LintId::of(reference::DEREF_ADDROF),
|
||||
LintId::of(reference::REF_IN_DEREF),
|
||||
LintId::of(regex::INVALID_REGEX),
|
||||
LintId::of(repeat_once::REPEAT_ONCE),
|
||||
LintId::of(returns::LET_AND_RETURN),
|
||||
|
@ -71,7 +71,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
|
||||
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
|
||||
LintId::of(redundant_slicing::REDUNDANT_SLICING),
|
||||
LintId::of(reference::DEREF_ADDROF),
|
||||
LintId::of(reference::REF_IN_DEREF),
|
||||
LintId::of(repeat_once::REPEAT_ONCE),
|
||||
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
|
||||
LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
|
||||
|
@ -423,7 +423,6 @@ store.register_lints(&[
|
||||
redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
|
||||
ref_option_ref::REF_OPTION_REF,
|
||||
reference::DEREF_ADDROF,
|
||||
reference::REF_IN_DEREF,
|
||||
regex::INVALID_REGEX,
|
||||
regex::TRIVIAL_REGEX,
|
||||
repeat_once::REPEAT_ONCE,
|
||||
|
@ -581,6 +581,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
|
||||
store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
|
||||
store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
|
||||
store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv)));
|
||||
|
||||
store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
|
||||
store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
|
||||
@ -591,7 +592,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
msrv,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(|| Box::new(map_clone::MapClone));
|
||||
store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
|
||||
store.register_late_pass(|| Box::new(shadow::Shadow::default()));
|
||||
store.register_late_pass(|| Box::new(unit_types::UnitTypes));
|
||||
@ -703,7 +703,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
|
||||
store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic));
|
||||
store.register_early_pass(|| Box::new(reference::DerefAddrOf));
|
||||
store.register_early_pass(|| Box::new(reference::RefInDeref));
|
||||
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
|
||||
store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
|
||||
store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
|
||||
@ -935,6 +934,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
|
||||
ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
|
||||
ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types");
|
||||
ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods");
|
||||
ls.register_renamed("clippy::ref_in_deref", "clippy::needless_borrow");
|
||||
|
||||
// uplifted lints
|
||||
ls.register_renamed("clippy::invalid_ref", "invalid_value");
|
||||
|
@ -13,7 +13,7 @@ use rustc_hir::{
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -83,7 +83,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
|
||||
impl<'tcx> LateLintPass<'tcx> for Lifetimes {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
|
||||
check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true);
|
||||
check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,6 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
|
||||
cx,
|
||||
sig.decl,
|
||||
Some(id),
|
||||
None,
|
||||
&item.generics,
|
||||
item.span,
|
||||
report_extra_lifetimes,
|
||||
@ -103,11 +104,11 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
|
||||
if let TraitItemKind::Fn(ref sig, ref body) = item.kind {
|
||||
let body = match *body {
|
||||
TraitFn::Required(_) => None,
|
||||
TraitFn::Provided(id) => Some(id),
|
||||
let (body, trait_sig) = match *body {
|
||||
TraitFn::Required(sig) => (None, Some(sig)),
|
||||
TraitFn::Provided(id) => (Some(id), None),
|
||||
};
|
||||
check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true);
|
||||
check_fn_inner(cx, sig.decl, body, trait_sig, &item.generics, item.span, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,6 +125,7 @@ fn check_fn_inner<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
decl: &'tcx FnDecl<'_>,
|
||||
body: Option<BodyId>,
|
||||
trait_sig: Option<&[Ident]>,
|
||||
generics: &'tcx Generics<'_>,
|
||||
span: Span,
|
||||
report_extra_lifetimes: bool,
|
||||
@ -165,7 +167,7 @@ fn check_fn_inner<'tcx>(
|
||||
}
|
||||
}
|
||||
}
|
||||
if could_use_elision(cx, decl, body, generics.params) {
|
||||
if could_use_elision(cx, decl, body, trait_sig, generics.params) {
|
||||
span_lint(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
@ -179,10 +181,31 @@ fn check_fn_inner<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
// elision doesn't work for explicit self types, see rust-lang/rust#69064
|
||||
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
|
||||
if_chain! {
|
||||
if let Some(ident) = ident;
|
||||
if ident.name == kw::SelfLower;
|
||||
if !func.implicit_self.has_implicit_self();
|
||||
|
||||
if let Some(self_ty) = func.inputs.first();
|
||||
then {
|
||||
let mut visitor = RefVisitor::new(cx);
|
||||
visitor.visit_ty(self_ty);
|
||||
|
||||
!visitor.all_lts().is_empty()
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn could_use_elision<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
func: &'tcx FnDecl<'_>,
|
||||
body: Option<BodyId>,
|
||||
trait_sig: Option<&[Ident]>,
|
||||
named_generics: &'tcx [GenericParam<'_>],
|
||||
) -> bool {
|
||||
// There are two scenarios where elision works:
|
||||
@ -233,11 +256,24 @@ fn could_use_elision<'tcx>(
|
||||
let input_lts = input_visitor.lts;
|
||||
let output_lts = output_visitor.lts;
|
||||
|
||||
if let Some(trait_sig) = trait_sig {
|
||||
if explicit_self_type(cx, func, trait_sig.first().copied()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(body_id) = body {
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
|
||||
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
|
||||
if explicit_self_type(cx, func, first_ident) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut checker = BodyLifetimeChecker {
|
||||
lifetimes_used_in_body: false,
|
||||
};
|
||||
checker.visit_expr(&cx.tcx.hir().body(body_id).value);
|
||||
checker.visit_expr(&body.value);
|
||||
if checker.lifetimes_used_in_body {
|
||||
return false;
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ struct PathAndSpan {
|
||||
span: Span,
|
||||
}
|
||||
|
||||
/// `MacroRefData` includes the name of the macro.
|
||||
/// `MacroRefData` includes the name of the macro
|
||||
/// and the path from `SourceMap::span_to_filename`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MacroRefData {
|
||||
name: String,
|
||||
|
@ -6,8 +6,8 @@ use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
Term, AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
|
||||
IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
|
||||
AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
|
||||
IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
@ -72,6 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn get_one_size_of_ty<'tcx>(
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::{is_trait_method, peel_blocks};
|
||||
use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -9,7 +9,8 @@ use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
@ -42,7 +43,17 @@ declare_clippy_lint! {
|
||||
"using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
|
||||
}
|
||||
|
||||
declare_lint_pass!(MapClone => [MAP_CLONE]);
|
||||
pub struct MapClone {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
|
||||
impl_lint_pass!(MapClone => [MAP_CLONE]);
|
||||
|
||||
impl MapClone {
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
|
||||
@ -65,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
hir::BindingAnnotation::Unannotated, .., name, None
|
||||
) = inner.kind {
|
||||
if ident_eq(name, closure_expr) {
|
||||
lint(cx, e.span, args[0].span, true);
|
||||
self.lint_explicit_closure(cx, e.span, args[0].span, true);
|
||||
}
|
||||
},
|
||||
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
|
||||
@ -73,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
|
||||
if ident_eq(name, inner) {
|
||||
if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
|
||||
lint(cx, e.span, args[0].span, true);
|
||||
self.lint_explicit_closure(cx, e.span, args[0].span, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -90,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
|
||||
if matches!(mutability, Mutability::Not) {
|
||||
let copy = is_copy(cx, ty);
|
||||
lint(cx, e.span, args[0].span, copy);
|
||||
self.lint_explicit_closure(cx, e.span, args[0].span, copy);
|
||||
}
|
||||
} else {
|
||||
lint_needless_cloning(cx, e.span, args[0].span);
|
||||
@ -105,6 +116,8 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
|
||||
@ -127,31 +140,30 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
|
||||
);
|
||||
}
|
||||
|
||||
fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
if copied {
|
||||
impl MapClone {
|
||||
fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let message = if is_copy {
|
||||
"you are using an explicit closure for copying elements"
|
||||
} else {
|
||||
"you are using an explicit closure for cloning elements"
|
||||
};
|
||||
let sugg_method = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) {
|
||||
"copied"
|
||||
} else {
|
||||
"cloned"
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_CLONE,
|
||||
replace,
|
||||
"you are using an explicit closure for copying elements",
|
||||
"consider calling the dedicated `copied` method",
|
||||
message,
|
||||
&format!("consider calling the dedicated `{}` method", sugg_method),
|
||||
format!(
|
||||
"{}.copied()",
|
||||
snippet_with_applicability(cx, root, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
} else {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_CLONE,
|
||||
replace,
|
||||
"you are using an explicit closure for cloning elements",
|
||||
"consider calling the dedicated `cloned` method",
|
||||
format!(
|
||||
"{}.cloned()",
|
||||
snippet_with_applicability(cx, root, "..", &mut applicability)
|
||||
"{}.{}()",
|
||||
snippet_with_applicability(cx, root, "..", &mut applicability),
|
||||
sugg_method,
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
|
@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Ty, TyS, VariantDef};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::{sym, symbol::kw};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
@ -961,13 +961,13 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
|
||||
let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
|
||||
if path_str == "Err" {
|
||||
let mut matching_wild = inner.iter().any(is_wild);
|
||||
let mut ident_bind_name = String::from("_");
|
||||
let mut ident_bind_name = kw::Underscore;
|
||||
if !matching_wild {
|
||||
// Looking for unused bindings (i.e.: `_e`)
|
||||
for pat in inner.iter() {
|
||||
if let PatKind::Binding(_, id, ident, None) = pat.kind {
|
||||
if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
|
||||
ident_bind_name = ident.name.as_str().to_string();
|
||||
ident_bind_name = ident.name;
|
||||
matching_wild = true;
|
||||
}
|
||||
}
|
||||
@ -982,7 +982,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
|
||||
span_lint_and_note(cx,
|
||||
MATCH_WILD_ERR_ARM,
|
||||
arm.pat.span,
|
||||
&format!("`Err({})` matches all errors", &ident_bind_name),
|
||||
&format!("`Err({})` matches all errors", ident_bind_name),
|
||||
None,
|
||||
"match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
|
||||
);
|
||||
|
@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
|
||||
hir::ExprKind::MethodCall(method_name, call_args, _) => {
|
||||
if call_args.len() == 1
|
||||
&& (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref))
|
||||
&& (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
|
||||
&& {
|
||||
let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
|
||||
let base_type = arg_type.peel_refs();
|
||||
|
@ -2180,8 +2180,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
|
||||
let assoc_ty = match projection_predicate.term {
|
||||
ty::Term::Ty(ty) => ty,
|
||||
ty::Term::Const(_c) => continue,
|
||||
ty::Term::Ty(ty) => ty,
|
||||
ty::Term::Const(_c) => continue,
|
||||
};
|
||||
// walk the associated type and check for Self
|
||||
if let Some(self_adt) = self_ty.ty_adt_def() {
|
||||
|
@ -7,7 +7,8 @@
|
||||
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::ast;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty;
|
||||
@ -57,6 +58,20 @@ impl MissingDoc {
|
||||
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
|
||||
}
|
||||
|
||||
fn has_include(meta: Option<MetaItem>) -> bool {
|
||||
if_chain! {
|
||||
if let Some(meta) = meta;
|
||||
if let MetaItemKind::List(list) = meta.kind;
|
||||
if let Some(meta) = list.get(0);
|
||||
if let Some(name) = meta.ident();
|
||||
then {
|
||||
name.name == sym::include
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_missing_docs_attrs(
|
||||
&self,
|
||||
cx: &LateContext<'_>,
|
||||
@ -80,7 +95,9 @@ impl MissingDoc {
|
||||
return;
|
||||
}
|
||||
|
||||
let has_doc = attrs.iter().any(|a| a.doc_str().is_some());
|
||||
let has_doc = attrs
|
||||
.iter()
|
||||
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
|
||||
if !has_doc {
|
||||
span_lint(
|
||||
cx,
|
||||
|
@ -92,10 +92,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::If(..) => {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::Path(_) => {
|
||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||
if adj
|
||||
|
@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionSome, ResultOk};
|
||||
use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||
use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyS;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -88,7 +88,26 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
|
||||
}
|
||||
|
||||
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
|
||||
check(cx, body.value.peel_blocks());
|
||||
if let Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) = body.generator_kind {
|
||||
if let ExprKind::Block(
|
||||
Block {
|
||||
expr:
|
||||
Some(Expr {
|
||||
kind: ExprKind::DropTemps(async_body),
|
||||
..
|
||||
}),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) = body.value.kind
|
||||
{
|
||||
if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind {
|
||||
check(cx, expr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
check(cx, body.value.peel_blocks());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
|
||||
// construct a replacement escape
|
||||
// the maximum value is \077, or \x3f, so u8 is sufficient here
|
||||
if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) {
|
||||
write!(&mut suggest_1, "\\x{:02x}", n).unwrap();
|
||||
write!(suggest_1, "\\x{:02x}", n).unwrap();
|
||||
}
|
||||
|
||||
// append the null byte as \x00 and the following digits literally
|
||||
|
@ -1,30 +1,36 @@
|
||||
//! Checks for usage of `&Vec[_]` and `&String`.
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::ptr::get_spans;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::walk_ptrs_hir_ty;
|
||||
use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
|
||||
use clippy_utils::ty::expr_sig;
|
||||
use clippy_utils::{
|
||||
expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, match_any_diagnostic_items, path_to_local, paths,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::hir_id::HirIdMap;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{
|
||||
BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
|
||||
Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
|
||||
self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArg,
|
||||
ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
|
||||
TraitItem, TraitItemKind, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::{self, AssocItems, AssocKind, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{sym, MultiSpan};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// This lint checks for function arguments of type `&String`
|
||||
/// or `&Vec` unless the references are mutable. It will also suggest you
|
||||
/// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
|
||||
/// calls.
|
||||
/// This lint checks for function arguments of type `&String`, `&Vec`,
|
||||
/// `&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls
|
||||
/// with the appropriate `.to_owned()`/`to_string()` calls.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Requiring the argument to be of the specific size
|
||||
@ -32,28 +38,7 @@ declare_clippy_lint! {
|
||||
/// or `&str` usually suffice and can be obtained from other types, too.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// The lint does not follow data. So if you have an
|
||||
/// argument `x` and write `let y = x; y.clone()` the lint will not suggest
|
||||
/// changing that `.clone()` to `.to_owned()`.
|
||||
///
|
||||
/// Other functions called from this function taking a `&String` or `&Vec`
|
||||
/// argument may also fail to compile if you change the argument. Applying
|
||||
/// this lint on them will fix the problem, but they may be in other crates.
|
||||
///
|
||||
/// One notable example of a function that may cause issues, and which cannot
|
||||
/// easily be changed due to being in the standard library is `Vec::contains`.
|
||||
/// when called on a `Vec<Vec<T>>`. If a `&Vec` is passed to that method then
|
||||
/// it will compile, but if a `&[T]` is passed then it will not compile.
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn cannot_take_a_slice(v: &Vec<u8>) -> bool {
|
||||
/// let vec_of_vecs: Vec<Vec<u8>> = some_other_fn();
|
||||
///
|
||||
/// vec_of_vecs.contains(v)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Also there may be `fn(&Vec)`-typed references pointing to your function.
|
||||
/// There may be `fn(&Vec)`-typed references pointing to your function.
|
||||
/// If you have them, you will get a compiler error after applying this lint's
|
||||
/// suggestions. You then have the choice to undo your changes or change the
|
||||
/// type of the reference.
|
||||
@ -155,32 +140,86 @@ declare_clippy_lint! {
|
||||
declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USAGE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Ptr {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
|
||||
check_fn(cx, sig.decl, Some(body_id));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
|
||||
if let ImplItemKind::Fn(ref sig, body_id) = item.kind {
|
||||
let parent_item = cx.tcx.hir().get_parent_item(item.hir_id());
|
||||
if let Some(Node::Item(it)) = cx.tcx.hir().find_by_def_id(parent_item) {
|
||||
if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = it.kind {
|
||||
return; // ignore trait impls
|
||||
}
|
||||
}
|
||||
check_fn(cx, sig.decl, Some(body_id));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
|
||||
if let TraitItemKind::Fn(ref sig, ref trait_method) = item.kind {
|
||||
let body_id = if let TraitFn::Provided(b) = *trait_method {
|
||||
Some(b)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
check_fn(cx, sig.decl, body_id);
|
||||
if let TraitItemKind::Fn(sig, trait_method) = &item.kind {
|
||||
if matches!(trait_method, TraitFn::Provided(_)) {
|
||||
// Handled by check body.
|
||||
return;
|
||||
}
|
||||
|
||||
check_mut_from_ref(cx, sig.decl);
|
||||
for arg in check_fn_args(
|
||||
cx,
|
||||
cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
|
||||
sig.decl.inputs,
|
||||
&[],
|
||||
) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
&arg.build_msg(),
|
||||
"change this to",
|
||||
format!("{}{}", arg.ref_prefix, arg.deref_ty.display(cx)),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
|
||||
let hir = cx.tcx.hir();
|
||||
let mut parents = hir.parent_iter(body.value.hir_id);
|
||||
let (item_id, decl) = match parents.next() {
|
||||
Some((_, Node::Item(i))) => {
|
||||
if let ItemKind::Fn(sig, ..) = &i.kind {
|
||||
(i.def_id, sig.decl)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
Some((_, Node::ImplItem(i))) => {
|
||||
if !matches!(parents.next(),
|
||||
Some((_, Node::Item(i))) if matches!(&i.kind, ItemKind::Impl(i) if i.of_trait.is_none())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if let ImplItemKind::Fn(sig, _) = &i.kind {
|
||||
(i.def_id, sig.decl)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
Some((_, Node::TraitItem(i))) => {
|
||||
if let TraitItemKind::Fn(sig, _) = &i.kind {
|
||||
(i.def_id, sig.decl)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
check_mut_from_ref(cx, decl);
|
||||
let sig = cx.tcx.fn_sig(item_id).skip_binder();
|
||||
let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params).collect();
|
||||
let results = check_ptr_arg_usage(cx, body, &lint_args);
|
||||
|
||||
for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) {
|
||||
span_lint_and_then(cx, PTR_ARG, args.span, &args.build_msg(), |diag| {
|
||||
diag.multipart_suggestion(
|
||||
"change this to",
|
||||
iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx))))
|
||||
.chain(result.replacements.iter().map(|r| {
|
||||
(
|
||||
r.expr_span,
|
||||
format!("{}{}", snippet_opt(cx, r.self_span).unwrap(), r.replacement),
|
||||
)
|
||||
}))
|
||||
.collect(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,154 +286,206 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
|
||||
let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
|
||||
#[derive(Default)]
|
||||
struct PtrArgResult {
|
||||
skip: bool,
|
||||
replacements: Vec<PtrArgReplacement>,
|
||||
}
|
||||
|
||||
for (idx, arg) in decl.inputs.iter().enumerate() {
|
||||
// Honor the allow attribute on parameters. See issue 5644.
|
||||
if let Some(body) = &body {
|
||||
if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
|
||||
continue;
|
||||
}
|
||||
struct PtrArgReplacement {
|
||||
expr_span: Span,
|
||||
self_span: Span,
|
||||
replacement: &'static str,
|
||||
}
|
||||
|
||||
struct PtrArg<'tcx> {
|
||||
idx: usize,
|
||||
span: Span,
|
||||
ty_did: DefId,
|
||||
ty_name: Symbol,
|
||||
method_renames: &'static [(&'static str, &'static str)],
|
||||
ref_prefix: RefPrefix,
|
||||
deref_ty: DerefTy<'tcx>,
|
||||
deref_assoc_items: Option<(DefId, &'tcx AssocItems<'tcx>)>,
|
||||
}
|
||||
impl PtrArg<'_> {
|
||||
fn build_msg(&self) -> String {
|
||||
format!(
|
||||
"writing `&{}{}` instead of `&{}{}` involves a new object where a slice will do",
|
||||
self.ref_prefix.mutability.prefix_str(),
|
||||
self.ty_name,
|
||||
self.ref_prefix.mutability.prefix_str(),
|
||||
self.deref_ty.argless_str(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct RefPrefix {
|
||||
lt: LifetimeName,
|
||||
mutability: Mutability,
|
||||
}
|
||||
impl fmt::Display for RefPrefix {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use fmt::Write;
|
||||
f.write_char('&')?;
|
||||
match self.lt {
|
||||
LifetimeName::Param(ParamName::Plain(name)) => {
|
||||
name.fmt(f)?;
|
||||
f.write_char(' ')?;
|
||||
},
|
||||
LifetimeName::Underscore => f.write_str("'_ ")?,
|
||||
LifetimeName::Static => f.write_str("'static ")?,
|
||||
_ => (),
|
||||
}
|
||||
f.write_str(self.mutability.prefix_str())
|
||||
}
|
||||
}
|
||||
|
||||
let (item_name, path) = if_chain! {
|
||||
if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
|
||||
if let Res::Def(_, did) = path.res;
|
||||
if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
|
||||
then {
|
||||
(item_name, path)
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
};
|
||||
struct DerefTyDisplay<'a, 'tcx>(&'a LateContext<'tcx>, &'a DerefTy<'tcx>);
|
||||
impl fmt::Display for DerefTyDisplay<'_, '_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use std::fmt::Write;
|
||||
match self.1 {
|
||||
DerefTy::Str => f.write_str("str"),
|
||||
DerefTy::Path => f.write_str("Path"),
|
||||
DerefTy::Slice(hir_ty, ty) => {
|
||||
f.write_char('[')?;
|
||||
match hir_ty.and_then(|s| snippet_opt(self.0, s)) {
|
||||
Some(s) => f.write_str(&s)?,
|
||||
None => ty.fmt(f)?,
|
||||
}
|
||||
f.write_char(']')
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match item_name {
|
||||
sym::Vec => {
|
||||
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
|
||||
with non-Vec-based slices",
|
||||
|diag| {
|
||||
if let Some(ref snippet) = get_only_generic_arg_snippet(cx, arg) {
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", snippet),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
for (clonespan, suggestion) in spans {
|
||||
diag.span_suggestion(
|
||||
clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
|
||||
Cow::Owned(format!("change `{}` to", x))
|
||||
}),
|
||||
suggestion.into(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
sym::String => {
|
||||
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&String` instead of `&str` involves a new object where a slice will do",
|
||||
|diag| {
|
||||
diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified);
|
||||
for (clonespan, suggestion) in spans {
|
||||
diag.span_suggestion_short(
|
||||
clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
|
||||
Cow::Owned(format!("change `{}` to", x))
|
||||
}),
|
||||
suggestion.into(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
sym::PathBuf => {
|
||||
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"writing `&PathBuf` instead of `&Path` involves a new object where a slice will do",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"change this to",
|
||||
"&Path".into(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
for (clonespan, suggestion) in spans {
|
||||
diag.span_suggestion_short(
|
||||
clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
|
||||
Cow::Owned(format!("change `{}` to", x))
|
||||
}),
|
||||
suggestion.into(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
sym::Cow => {
|
||||
if_chain! {
|
||||
if let [ref bx] = *path.segments;
|
||||
if let Some(params) = bx.args;
|
||||
if !params.parenthesized;
|
||||
if let Some(inner) = params.args.iter().find_map(|arg| match arg {
|
||||
GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
});
|
||||
let replacement = snippet_opt(cx, inner.span);
|
||||
if let Some(r) = replacement;
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
arg.span,
|
||||
"using a reference to `Cow` is not recommended",
|
||||
"change this to",
|
||||
"&".to_owned() + &r,
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
enum DerefTy<'tcx> {
|
||||
Str,
|
||||
Path,
|
||||
Slice(Option<Span>, Ty<'tcx>),
|
||||
}
|
||||
impl<'tcx> DerefTy<'tcx> {
|
||||
fn argless_str(&self) -> &'static str {
|
||||
match *self {
|
||||
Self::Str => "str",
|
||||
Self::Path => "Path",
|
||||
Self::Slice(..) => "[_]",
|
||||
}
|
||||
}
|
||||
|
||||
fn display<'a>(&'a self, cx: &'a LateContext<'tcx>) -> DerefTyDisplay<'a, 'tcx> {
|
||||
DerefTyDisplay(cx, self)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn_args<'cx, 'tcx: 'cx>(
|
||||
cx: &'cx LateContext<'tcx>,
|
||||
tys: &'tcx [Ty<'_>],
|
||||
hir_tys: &'tcx [hir::Ty<'_>],
|
||||
params: &'tcx [Param<'_>],
|
||||
) -> impl Iterator<Item = PtrArg<'tcx>> + 'cx {
|
||||
tys.iter()
|
||||
.zip(hir_tys.iter())
|
||||
.enumerate()
|
||||
.filter_map(|(i, (ty, hir_ty))| {
|
||||
if_chain! {
|
||||
if let ty::Ref(_, ty, mutability) = *ty.kind();
|
||||
if let ty::Adt(adt, substs) = *ty.kind();
|
||||
|
||||
if let TyKind::Rptr(lt, ref ty) = hir_ty.kind;
|
||||
if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind;
|
||||
|
||||
// Check that the name as typed matches the actual name of the type.
|
||||
// e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec`
|
||||
if let [.., name] = path.segments;
|
||||
if cx.tcx.item_name(adt.did) == name.ident.name;
|
||||
|
||||
if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id);
|
||||
if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id));
|
||||
|
||||
then {
|
||||
let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did) {
|
||||
Some(sym::Vec) => (
|
||||
[("clone", ".to_owned()")].as_slice(),
|
||||
DerefTy::Slice(
|
||||
name.args
|
||||
.and_then(|args| args.args.first())
|
||||
.and_then(|arg| if let GenericArg::Type(ty) = arg {
|
||||
Some(ty.span)
|
||||
} else {
|
||||
None
|
||||
}),
|
||||
substs.type_at(0),
|
||||
),
|
||||
cx.tcx.lang_items().slice_impl()
|
||||
),
|
||||
Some(sym::String) => (
|
||||
[("clone", ".to_owned()"), ("as_str", "")].as_slice(),
|
||||
DerefTy::Str,
|
||||
cx.tcx.lang_items().str_impl()
|
||||
),
|
||||
Some(sym::PathBuf) => (
|
||||
[("clone", ".to_path_buf()"), ("as_path", "")].as_slice(),
|
||||
DerefTy::Path,
|
||||
None,
|
||||
),
|
||||
Some(sym::Cow) => {
|
||||
let ty_name = name.args
|
||||
.and_then(|args| {
|
||||
args.args.iter().find_map(|a| match a {
|
||||
GenericArg::Type(x) => Some(x),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
.and_then(|arg| snippet_opt(cx, arg.span))
|
||||
.unwrap_or_else(|| substs.type_at(1).to_string());
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PTR_ARG,
|
||||
hir_ty.span,
|
||||
"using a reference to `Cow` is not recommended",
|
||||
"change this to",
|
||||
format!("&{}{}", mutability.prefix_str(), ty_name),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
return None;
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
return Some(PtrArg {
|
||||
idx: i,
|
||||
span: hir_ty.span,
|
||||
ty_did: adt.did,
|
||||
ty_name: name.ident.name,
|
||||
method_renames,
|
||||
ref_prefix: RefPrefix {
|
||||
lt: lt.name,
|
||||
mutability,
|
||||
},
|
||||
deref_ty,
|
||||
deref_assoc_items: deref_impl_id.map(|id| (id, cx.tcx.associated_items(id))),
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
fn check_mut_from_ref(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
|
||||
if let FnRetTy::Return(ty) = decl.output {
|
||||
if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
|
||||
let mut immutables = vec![];
|
||||
for (_, ref mutbl, ref argspan) in decl
|
||||
for (_, mutbl, argspan) in decl
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(get_rptr_lm)
|
||||
.filter(|&(lt, _, _)| lt.name == out.name)
|
||||
{
|
||||
if *mutbl == Mutability::Mut {
|
||||
if mutbl == Mutability::Mut {
|
||||
return;
|
||||
}
|
||||
immutables.push(*argspan);
|
||||
immutables.push(argspan);
|
||||
}
|
||||
if immutables.is_empty() {
|
||||
return;
|
||||
@ -413,24 +504,158 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>
|
||||
}
|
||||
}
|
||||
|
||||
fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option<String> {
|
||||
if_chain! {
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = walk_ptrs_hir_ty(arg).kind;
|
||||
if let Some(&PathSegment{args: Some(parameters), ..}) = path.segments.last();
|
||||
let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
|
||||
GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
}).collect();
|
||||
if types.len() == 1;
|
||||
then {
|
||||
snippet_opt(cx, types[0].span)
|
||||
} else {
|
||||
None
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> {
|
||||
struct V<'cx, 'tcx> {
|
||||
cx: &'cx LateContext<'tcx>,
|
||||
/// Map from a local id to which argument it came from (index into `Self::args` and
|
||||
/// `Self::results`)
|
||||
bindings: HirIdMap<usize>,
|
||||
/// The arguments being checked.
|
||||
args: &'cx [PtrArg<'tcx>],
|
||||
/// The results for each argument (len should match args.len)
|
||||
results: Vec<PtrArgResult>,
|
||||
/// The number of arguments which can't be linted. Used to return early.
|
||||
skip_count: usize,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
|
||||
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
if self.skip_count == self.args.len() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is local we care about
|
||||
let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) {
|
||||
Some(&i) => i,
|
||||
None => return walk_expr(self, e),
|
||||
};
|
||||
let args = &self.args[args_idx];
|
||||
let result = &mut self.results[args_idx];
|
||||
|
||||
// Helper function to handle early returns.
|
||||
let mut set_skip_flag = || {
|
||||
if result.skip {
|
||||
self.skip_count += 1;
|
||||
}
|
||||
result.skip = true;
|
||||
};
|
||||
|
||||
match get_expr_use_or_unification_node(self.cx.tcx, e) {
|
||||
Some((Node::Stmt(_), _)) => (),
|
||||
Some((Node::Local(l), _)) => {
|
||||
// Only trace simple bindings. e.g `let x = y;`
|
||||
if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
|
||||
self.bindings.insert(id, args_idx);
|
||||
} else {
|
||||
set_skip_flag();
|
||||
}
|
||||
},
|
||||
Some((Node::Expr(e), child_id)) => match e.kind {
|
||||
ExprKind::Call(f, expr_args) => {
|
||||
let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
|
||||
if expr_sig(self.cx, f)
|
||||
.map(|sig| sig.input(i).skip_binder().peel_refs())
|
||||
.map_or(true, |ty| match *ty.kind() {
|
||||
ty::Param(_) => true,
|
||||
ty::Adt(def, _) => def.did == args.ty_did,
|
||||
_ => false,
|
||||
})
|
||||
{
|
||||
// Passed to a function taking the non-dereferenced type.
|
||||
set_skip_flag();
|
||||
}
|
||||
},
|
||||
ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
|
||||
let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
|
||||
if i == 0 {
|
||||
// Check if the method can be renamed.
|
||||
let name = name.ident.as_str();
|
||||
if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
|
||||
result.replacements.push(PtrArgReplacement {
|
||||
expr_span: e.span,
|
||||
self_span: self_arg.span,
|
||||
replacement,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) {
|
||||
x
|
||||
} else {
|
||||
set_skip_flag();
|
||||
return;
|
||||
};
|
||||
|
||||
match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
|
||||
ty::Param(_) => {
|
||||
set_skip_flag();
|
||||
},
|
||||
// If the types match check for methods which exist on both types. e.g. `Vec::len` and
|
||||
// `slice::len`
|
||||
ty::Adt(def, _)
|
||||
if def.did == args.ty_did
|
||||
&& (i != 0
|
||||
|| self.cx.tcx.trait_of_item(id).is_some()
|
||||
|| !args.deref_assoc_items.map_or(false, |(id, items)| {
|
||||
items
|
||||
.find_by_name_and_kind(self.cx.tcx, name.ident, AssocKind::Fn, id)
|
||||
.is_some()
|
||||
})) =>
|
||||
{
|
||||
set_skip_flag();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
// Indexing is fine for currently supported types.
|
||||
ExprKind::Index(e, _) if e.hir_id == child_id => (),
|
||||
_ => set_skip_flag(),
|
||||
},
|
||||
_ => set_skip_flag(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut skip_count = 0;
|
||||
let mut results = args.iter().map(|_| PtrArgResult::default()).collect::<Vec<_>>();
|
||||
let mut v = V {
|
||||
cx,
|
||||
bindings: args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, arg)| {
|
||||
let param = &body.params[arg.idx];
|
||||
match param.pat.kind {
|
||||
PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
|
||||
if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
|
||||
{
|
||||
Some((id, i))
|
||||
},
|
||||
_ => {
|
||||
skip_count += 1;
|
||||
results[arg.idx].skip = true;
|
||||
None
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
args,
|
||||
results,
|
||||
skip_count,
|
||||
};
|
||||
v.visit_expr(&body.value);
|
||||
v.results
|
||||
}
|
||||
|
||||
fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
|
||||
fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
|
||||
if let TyKind::Rptr(ref lt, ref m) = ty.kind {
|
||||
Some((lt, m.mutbl, ty.span))
|
||||
} else {
|
||||
|
@ -342,7 +342,7 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args:
|
||||
// `.iter()` and `.len()` called on same `Path`
|
||||
if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
|
||||
if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
|
||||
if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
|
||||
if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
|
||||
then {
|
||||
span_lint(cx,
|
||||
RANGE_ZIP_WITH_LEN,
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
|
||||
use rustc_errors::Applicability;
|
||||
@ -104,59 +103,3 @@ impl EarlyLintPass for DerefAddrOf {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for references in expressions that use
|
||||
/// auto dereference.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The reference is a no-op and is automatically
|
||||
/// dereferenced by the compiler and makes the code less clear.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// struct Point(u32, u32);
|
||||
/// let point = Point(30, 20);
|
||||
/// let x = (&point).0;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # struct Point(u32, u32);
|
||||
/// # let point = Point(30, 20);
|
||||
/// let x = point.0;
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub REF_IN_DEREF,
|
||||
complexity,
|
||||
"Use of reference in auto dereference expression."
|
||||
}
|
||||
|
||||
declare_lint_pass!(RefInDeref => [REF_IN_DEREF]);
|
||||
|
||||
impl EarlyLintPass for RefInDeref {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
|
||||
if_chain! {
|
||||
if let ExprKind::Field(ref object, _) = e.kind;
|
||||
if let ExprKind::Paren(ref parened) = object.kind;
|
||||
if let ExprKind::AddrOf(_, _, ref inner) = parened.kind;
|
||||
then {
|
||||
let applicability = if inner.span.from_expansion() {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
let sugg = Sugg::ast(cx, inner, "_").maybe_par();
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REF_IN_DEREF,
|
||||
object.span,
|
||||
"creating a reference that is immediately dereferenced",
|
||||
"try this",
|
||||
sugg.to_string(),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::{SpanlessEq, SpanlessHash};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unhash::UnhashMap;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
|
||||
let Generics { where_clause, .. } = &item.generics;
|
||||
let mut self_bounds_set = FxHashSet::default();
|
||||
let mut self_bounds_map = FxHashMap::default();
|
||||
|
||||
for predicate in where_clause.predicates {
|
||||
if_chain! {
|
||||
@ -108,27 +108,29 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
|
||||
)
|
||||
) = cx.tcx.hir().get_if_local(*def_id);
|
||||
then {
|
||||
if self_bounds_set.is_empty() {
|
||||
if self_bounds_map.is_empty() {
|
||||
for bound in self_bounds.iter() {
|
||||
let Some((self_res, _)) = get_trait_res_span_from_bound(bound) else { continue };
|
||||
self_bounds_set.insert(self_res);
|
||||
let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue };
|
||||
self_bounds_map.insert(self_res, self_segments);
|
||||
}
|
||||
}
|
||||
|
||||
bound_predicate
|
||||
.bounds
|
||||
.iter()
|
||||
.filter_map(get_trait_res_span_from_bound)
|
||||
.for_each(|(trait_item_res, span)| {
|
||||
if self_bounds_set.get(&trait_item_res).is_some() {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
TRAIT_DUPLICATION_IN_BOUNDS,
|
||||
span,
|
||||
"this trait bound is already specified in trait declaration",
|
||||
None,
|
||||
"consider removing this trait bound",
|
||||
);
|
||||
.filter_map(get_trait_info_from_bound)
|
||||
.for_each(|(trait_item_res, trait_item_segments, span)| {
|
||||
if let Some(self_segments) = self_bounds_map.get(&trait_item_res) {
|
||||
if SpanlessEq::new(cx).eq_path_segments(self_segments, trait_item_segments) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
TRAIT_DUPLICATION_IN_BOUNDS,
|
||||
span,
|
||||
"this trait bound is already specified in trait declaration",
|
||||
None,
|
||||
"consider removing this trait bound",
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -137,14 +139,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
|
||||
if let GenericBound::Trait(t, _) = bound {
|
||||
Some((t.trait_ref.path.res, t.span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl TraitBounds {
|
||||
fn check_type_repetition<'tcx>(self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
|
||||
struct SpanlessTy<'cx, 'tcx> {
|
||||
@ -231,7 +225,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
|
||||
let res = param
|
||||
.bounds
|
||||
.iter()
|
||||
.filter_map(get_trait_res_span_from_bound)
|
||||
.filter_map(get_trait_info_from_bound)
|
||||
.collect::<Vec<_>>();
|
||||
map.insert(*ident, res);
|
||||
}
|
||||
@ -245,10 +239,10 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
|
||||
if let Some(segment) = segments.first();
|
||||
if let Some(trait_resolutions_direct) = map.get(&segment.ident);
|
||||
then {
|
||||
for (res_where, _) in bound_predicate.bounds.iter().filter_map(get_trait_res_span_from_bound) {
|
||||
if let Some((_, span_direct)) = trait_resolutions_direct
|
||||
for (res_where, _, _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
|
||||
if let Some((_, _, span_direct)) = trait_resolutions_direct
|
||||
.iter()
|
||||
.find(|(res_direct, _)| *res_direct == res_where) {
|
||||
.find(|(res_direct, _, _)| *res_direct == res_where) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
TRAIT_DUPLICATION_IN_BOUNDS,
|
||||
@ -263,3 +257,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
|
||||
if let GenericBound::Trait(t, _) = bound {
|
||||
Some((t.trait_ref.path.res, t.trait_ref.path.segments, t.span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -98,10 +98,11 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
|
||||
if trait_pred.self_ty() == inp;
|
||||
if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
|
||||
then {
|
||||
if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
|
||||
return_ty_pred.term.ty()) {
|
||||
if ord_preds.iter().any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) {
|
||||
args_to_check.push((i, "Ord".to_string()));
|
||||
} else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
|
||||
} else if partial_ord_preds.iter().any(|pord| {
|
||||
pord.self_ty() == return_ty_pred.term.ty().unwrap()
|
||||
}) {
|
||||
args_to_check.push((i, "PartialOrd".to_string()));
|
||||
}
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
|
||||
fn extend_with_struct_pat(
|
||||
qself1: &Option<ast::QSelf>,
|
||||
path1: &ast::Path,
|
||||
fps1: &mut Vec<ast::PatField>,
|
||||
fps1: &mut [ast::PatField],
|
||||
rest1: bool,
|
||||
start: usize,
|
||||
alternatives: &mut Vec<P<Pat>>,
|
||||
@ -332,7 +332,7 @@ fn extend_with_struct_pat(
|
||||
/// while also requiring `ps1[..n] ~ ps2[..n]` (pre) and `ps1[n + 1..] ~ ps2[n + 1..]` (post),
|
||||
/// where `~` denotes semantic equality.
|
||||
fn extend_with_matching_product(
|
||||
targets: &mut Vec<P<Pat>>,
|
||||
targets: &mut [P<Pat>],
|
||||
start: usize,
|
||||
alternatives: &mut Vec<P<Pat>>,
|
||||
predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool,
|
||||
|
@ -156,7 +156,7 @@ define_Conf! {
|
||||
///
|
||||
/// Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
(avoid_breaking_exported_api: bool = true),
|
||||
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE.
|
||||
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS.
|
||||
///
|
||||
/// The minimum rust version that the project supports
|
||||
(msrv: Option<String> = None),
|
||||
|
@ -23,6 +23,7 @@ use rustc_hir::{
|
||||
UnOp,
|
||||
};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::mir::interpret::ConstValue;
|
||||
use rustc_middle::ty;
|
||||
use rustc_semver::RustcVersion;
|
||||
|
@ -19,7 +19,9 @@ use rustc_hir::{
|
||||
self as hir, def::DefKind, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath,
|
||||
};
|
||||
use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Loc, Span, Symbol};
|
||||
use serde::{ser::SerializeStruct, Serialize, Serializer};
|
||||
use std::collections::BinaryHeap;
|
||||
@ -578,9 +580,11 @@ fn get_lint_group_and_level_or_lint(
|
||||
lint_name: &str,
|
||||
item: &Item<'_>,
|
||||
) -> Option<(String, &'static str)> {
|
||||
let result = cx
|
||||
.lint_store
|
||||
.check_lint_name(lint_name, Some(sym::clippy), &[]);
|
||||
let result = cx.lint_store.check_lint_name(
|
||||
lint_name,
|
||||
Some(sym::clippy),
|
||||
&[Ident::with_dummy_span(sym::clippy)].into_iter().collect(),
|
||||
);
|
||||
if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
|
||||
if let Some(group) = get_lint_group(cx, lint_lst[0]) {
|
||||
if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) {
|
||||
|
@ -646,11 +646,11 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
|
||||
}
|
||||
|
||||
fn eq_term(l: &Term, r: &Term) -> bool {
|
||||
match (l, r) {
|
||||
(Term::Ty(l), Term::Ty(r)) => eq_ty(l,r),
|
||||
(Term::Const(l), Term::Const(r)) => eq_anon_const(l,r),
|
||||
_ => false,
|
||||
}
|
||||
match (l, r) {
|
||||
(Term::Ty(l), Term::Ty(r)) => eq_ty(l, r),
|
||||
(Term::Const(l), Term::Const(r)) => eq_anon_const(l, r),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
|
||||
|
@ -1827,7 +1827,8 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
|
||||
}
|
||||
|
||||
/// Gets the node where an expression is either used, or it's type is unified with another branch.
|
||||
pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
|
||||
/// Returns both the node and the `HirId` of the closest child node.
|
||||
pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {
|
||||
let mut child_id = expr.hir_id;
|
||||
let mut iter = tcx.hir().parent_iter(child_id);
|
||||
loop {
|
||||
@ -1839,9 +1840,9 @@ pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>
|
||||
ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
|
||||
ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
|
||||
ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
|
||||
_ => break Some(Node::Expr(expr)),
|
||||
_ => break Some((Node::Expr(expr), child_id)),
|
||||
},
|
||||
Some((_, node)) => break Some(node),
|
||||
Some((_, node)) => break Some((node, child_id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1850,18 +1851,21 @@ pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>
|
||||
pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
|
||||
!matches!(
|
||||
get_expr_use_or_unification_node(tcx, expr),
|
||||
None | Some(Node::Stmt(Stmt {
|
||||
kind: StmtKind::Expr(_)
|
||||
| StmtKind::Semi(_)
|
||||
| StmtKind::Local(Local {
|
||||
pat: Pat {
|
||||
kind: PatKind::Wild,
|
||||
None | Some((
|
||||
Node::Stmt(Stmt {
|
||||
kind: StmtKind::Expr(_)
|
||||
| StmtKind::Semi(_)
|
||||
| StmtKind::Local(Local {
|
||||
pat: Pat {
|
||||
kind: PatKind::Wild,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
..
|
||||
}),
|
||||
..
|
||||
}))
|
||||
}),
|
||||
..
|
||||
}),
|
||||
_
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,14 @@ impl<'a> NumericLiteral<'a> {
|
||||
}
|
||||
|
||||
pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
|
||||
if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
|
||||
let unsigned_src = src.strip_prefix('-').map_or(src, |s| s);
|
||||
if lit_kind.is_numeric()
|
||||
&& unsigned_src
|
||||
.trim_start()
|
||||
.chars()
|
||||
.next()
|
||||
.map_or(false, |c| c.is_digit(10))
|
||||
{
|
||||
let (unsuffixed, suffix) = split_suffix(src, lit_kind);
|
||||
let float = matches!(lit_kind, LitKind::Float(..));
|
||||
Some(NumericLiteral::new(unsuffixed, suffix, float))
|
||||
|
@ -386,7 +386,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
|
||||
}
|
||||
|
||||
/// Return `true` if `sugg` is enclosed in parenthesis.
|
||||
fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
|
||||
pub fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
|
||||
let mut chars = sugg.as_ref().chars();
|
||||
if chars.next() == Some('(') {
|
||||
let mut depth = 1;
|
||||
|
@ -5,19 +5,22 @@
|
||||
use rustc_ast::ast::Mutability;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{TyKind, Unsafety};
|
||||
use rustc_hir::{Expr, TyKind, Unsafety};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
||||
use rustc_middle::ty::{self, AdtDef, IntTy, Predicate, Ty, TyCtxt, TypeFoldable, UintTy};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy,
|
||||
};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use std::iter;
|
||||
|
||||
use crate::{match_def_path, must_use_attr};
|
||||
use crate::{expr_path_res, match_def_path, must_use_attr};
|
||||
|
||||
// Checks if the given type implements copy.
|
||||
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
@ -410,3 +413,105 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// A signature for a function like type.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ExprFnSig<'tcx> {
|
||||
Sig(Binder<'tcx, FnSig<'tcx>>),
|
||||
Closure(Binder<'tcx, FnSig<'tcx>>),
|
||||
Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>),
|
||||
}
|
||||
impl<'tcx> ExprFnSig<'tcx> {
|
||||
/// Gets the argument type at the given offset.
|
||||
pub fn input(self, i: usize) -> Binder<'tcx, Ty<'tcx>> {
|
||||
match self {
|
||||
Self::Sig(sig) => sig.input(i),
|
||||
Self::Closure(sig) => sig.input(0).map_bound(|ty| ty.tuple_element_ty(i).unwrap()),
|
||||
Self::Trait(inputs, _) => inputs.map_bound(|ty| ty.tuple_element_ty(i).unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the result type, if one could be found. Note that the result type of a trait may not be
|
||||
/// specified.
|
||||
pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
|
||||
match self {
|
||||
Self::Sig(sig) | Self::Closure(sig) => Some(sig.output()),
|
||||
Self::Trait(_, output) => output,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If the expression is function like, get the signature for it.
|
||||
pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
|
||||
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = expr_path_res(cx, expr) {
|
||||
Some(ExprFnSig::Sig(cx.tcx.fn_sig(id)))
|
||||
} else {
|
||||
let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs();
|
||||
match *ty.kind() {
|
||||
ty::Closure(_, subs) => Some(ExprFnSig::Closure(subs.as_closure().sig())),
|
||||
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs))),
|
||||
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig)),
|
||||
ty::Dynamic(bounds, _) => {
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
match bounds.principal() {
|
||||
Some(bound)
|
||||
if Some(bound.def_id()) == lang_items.fn_trait()
|
||||
|| Some(bound.def_id()) == lang_items.fn_once_trait()
|
||||
|| Some(bound.def_id()) == lang_items.fn_mut_trait() =>
|
||||
{
|
||||
let output = bounds
|
||||
.projection_bounds()
|
||||
.find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
|
||||
.map(|p| p.map_bound(|p| p.term.ty().expect("return type was a const")));
|
||||
Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
ty::Param(_) | ty::Projection(..) => {
|
||||
let mut inputs = None;
|
||||
let mut output = None;
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
|
||||
for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) {
|
||||
let mut is_input = false;
|
||||
if let Some(ty) = pred
|
||||
.kind()
|
||||
.map_bound(|pred| match pred {
|
||||
PredicateKind::Trait(p)
|
||||
if (lang_items.fn_trait() == Some(p.def_id())
|
||||
|| lang_items.fn_mut_trait() == Some(p.def_id())
|
||||
|| lang_items.fn_once_trait() == Some(p.def_id()))
|
||||
&& p.self_ty() == ty =>
|
||||
{
|
||||
is_input = true;
|
||||
Some(p.trait_ref.substs.type_at(1))
|
||||
},
|
||||
PredicateKind::Projection(p)
|
||||
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
|
||||
&& p.projection_ty.self_ty() == ty =>
|
||||
{
|
||||
is_input = false;
|
||||
p.term.ty()
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.transpose()
|
||||
{
|
||||
if is_input && inputs.is_none() {
|
||||
inputs = Some(ty);
|
||||
} else if !is_input && output.is_none() {
|
||||
output = Some(ty);
|
||||
} else {
|
||||
// Multiple different fn trait impls. Is this even allowed?
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputs.map(|ty| ExprFnSig::Trait(ty, output))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,11 +331,10 @@ pub fn main() {
|
||||
// - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
|
||||
// - IF `--no-deps` is not set (`!no_deps`) OR
|
||||
// - IF `--no-deps` is set and Clippy is run on the specified primary package
|
||||
let clippy_tests_set = env::var("__CLIPPY_INTERNAL_TESTS").map_or(false, |val| val == "true");
|
||||
let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some();
|
||||
let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
|
||||
|
||||
let clippy_enabled = clippy_tests_set || (!cap_lints_allow && (!no_deps || in_primary_package));
|
||||
let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
|
||||
if clippy_enabled {
|
||||
args.extend(clippy_args);
|
||||
}
|
||||
|
@ -328,15 +328,9 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_env() {
|
||||
set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
|
||||
set_var("__CLIPPY_INTERNAL_TESTS", "true");
|
||||
//set_var("RUST_BACKTRACE", "0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_test() {
|
||||
prepare_env();
|
||||
set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
|
||||
let mut config = default_config();
|
||||
run_ui(&mut config);
|
||||
run_ui_test(&mut config);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![allow(clippy::redundant_clone)]
|
||||
#![warn(clippy::manual_non_exhaustive)]
|
||||
#![allow(clippy::redundant_clone, clippy::unnecessary_operation)]
|
||||
#![warn(clippy::manual_non_exhaustive, clippy::borrow_as_ptr, clippy::manual_bits)]
|
||||
|
||||
use std::mem::{size_of, size_of_val};
|
||||
use std::ops::Deref;
|
||||
|
||||
mod enums {
|
||||
@ -68,6 +69,24 @@ fn check_index_refutable_slice() {
|
||||
}
|
||||
}
|
||||
|
||||
fn map_clone_suggest_copied() {
|
||||
// This should still trigger the lint but suggest `cloned()` instead of `copied()`
|
||||
let _: Option<u64> = Some(&16).map(|b| *b);
|
||||
}
|
||||
|
||||
fn borrow_as_ptr() {
|
||||
let val = 1;
|
||||
let _p = &val as *const i32;
|
||||
|
||||
let mut val_mut = 1;
|
||||
let _p_mut = &mut val_mut as *mut i32;
|
||||
}
|
||||
|
||||
fn manual_bits() {
|
||||
size_of::<i8>() * 8;
|
||||
size_of_val(&0u32) * 8;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
option_as_ref_deref();
|
||||
match_like_matches();
|
||||
@ -75,4 +94,5 @@ fn main() {
|
||||
match_same_arms2();
|
||||
manual_strip_msrv();
|
||||
check_index_refutable_slice();
|
||||
borrow_as_ptr();
|
||||
}
|
||||
|
10
tests/ui-toml/min_rust_version/min_rust_version.stderr
Normal file
10
tests/ui-toml/min_rust_version/min_rust_version.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error: you are using an explicit closure for copying elements
|
||||
--> $DIR/min_rust_version.rs:74:26
|
||||
|
|
||||
LL | let _: Option<u64> = Some(&16).map(|b| *b);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `Some(&16).cloned()`
|
||||
|
|
||||
= note: `-D clippy::map-clone` implied by `-D warnings`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,9 +1,5 @@
|
||||
#![warn(clippy::borrow_interior_mutable_const)]
|
||||
#![allow(
|
||||
clippy::declare_interior_mutable_const,
|
||||
clippy::ref_in_deref,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)]
|
||||
#![allow(const_item_mutation)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:58:5
|
||||
--> $DIR/others.rs:54:5
|
||||
|
|
||||
LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
| ^^^^^^
|
||||
@ -8,7 +8,7 @@ LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:59:16
|
||||
--> $DIR/others.rs:55:16
|
||||
|
|
||||
LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
|
||||
| ^^^^^^
|
||||
@ -16,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:62:22
|
||||
--> $DIR/others.rs:58:22
|
||||
|
|
||||
LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -24,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:63:25
|
||||
--> $DIR/others.rs:59:25
|
||||
|
|
||||
LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -32,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:64:27
|
||||
--> $DIR/others.rs:60:27
|
||||
|
|
||||
LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -40,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:65:26
|
||||
--> $DIR/others.rs:61:26
|
||||
|
|
||||
LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -48,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:76:14
|
||||
--> $DIR/others.rs:72:14
|
||||
|
|
||||
LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -56,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:77:14
|
||||
--> $DIR/others.rs:73:14
|
||||
|
|
||||
LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -64,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:78:19
|
||||
--> $DIR/others.rs:74:19
|
||||
|
|
||||
LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -72,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:79:14
|
||||
--> $DIR/others.rs:75:14
|
||||
|
|
||||
LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -80,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:80:13
|
||||
--> $DIR/others.rs:76:13
|
||||
|
|
||||
LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -88,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:86:13
|
||||
--> $DIR/others.rs:82:13
|
||||
|
|
||||
LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -96,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:91:5
|
||||
--> $DIR/others.rs:87:5
|
||||
|
|
||||
LL | CELL.set(2); //~ ERROR interior mutability
|
||||
| ^^^^
|
||||
@ -104,7 +104,7 @@ LL | CELL.set(2); //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/others.rs:92:16
|
||||
--> $DIR/others.rs:88:16
|
||||
|
|
||||
LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
|
||||
| ^^^^
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![allow(clippy::needless_borrow)]
|
||||
|
||||
#[deny(clippy::naive_bytecount)]
|
||||
fn main() {
|
||||
let x = vec![0_u8; 16];
|
||||
|
@ -1,23 +1,23 @@
|
||||
error: you appear to be counting bytes the naive way
|
||||
--> $DIR/bytecount.rs:5:13
|
||||
--> $DIR/bytecount.rs:7:13
|
||||
|
|
||||
LL | let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, 0)`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/bytecount.rs:1:8
|
||||
--> $DIR/bytecount.rs:3:8
|
||||
|
|
||||
LL | #[deny(clippy::naive_bytecount)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you appear to be counting bytes the naive way
|
||||
--> $DIR/bytecount.rs:7:13
|
||||
--> $DIR/bytecount.rs:9:13
|
||||
|
|
||||
LL | let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count((&x[..]), 0)`
|
||||
|
||||
error: you appear to be counting bytes the naive way
|
||||
--> $DIR/bytecount.rs:19:13
|
||||
--> $DIR/bytecount.rs:21:13
|
||||
|
|
||||
LL | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, b + 1)`
|
||||
|
@ -7,7 +7,8 @@
|
||||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::vec_init_then_push,
|
||||
clippy::toplevel_ref_arg
|
||||
clippy::toplevel_ref_arg,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
@ -7,7 +7,8 @@
|
||||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::vec_init_then_push,
|
||||
clippy::toplevel_ref_arg
|
||||
clippy::toplevel_ref_arg,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: using `clone` on type `i32` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:24:5
|
||||
--> $DIR/clone_on_copy.rs:25:5
|
||||
|
|
||||
LL | 42.clone();
|
||||
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
|
||||
@ -7,43 +7,43 @@ LL | 42.clone();
|
||||
= note: `-D clippy::clone-on-copy` implied by `-D warnings`
|
||||
|
||||
error: using `clone` on type `i32` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:28:5
|
||||
--> $DIR/clone_on_copy.rs:29:5
|
||||
|
|
||||
LL | (&42).clone();
|
||||
| ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
|
||||
|
||||
error: using `clone` on type `i32` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:31:5
|
||||
--> $DIR/clone_on_copy.rs:32:5
|
||||
|
|
||||
LL | rc.borrow().clone();
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
|
||||
|
||||
error: using `clone` on type `u32` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:34:5
|
||||
--> $DIR/clone_on_copy.rs:35:5
|
||||
|
|
||||
LL | x.clone().rotate_left(1);
|
||||
| ^^^^^^^^^ help: try removing the `clone` call: `x`
|
||||
|
||||
error: using `clone` on type `i32` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:48:5
|
||||
--> $DIR/clone_on_copy.rs:49:5
|
||||
|
|
||||
LL | m!(42).clone();
|
||||
| ^^^^^^^^^^^^^^ help: try removing the `clone` call: `m!(42)`
|
||||
|
||||
error: using `clone` on type `[u32; 2]` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:58:5
|
||||
--> $DIR/clone_on_copy.rs:59:5
|
||||
|
|
||||
LL | x.clone()[0];
|
||||
| ^^^^^^^^^ help: try dereferencing it: `(*x)`
|
||||
|
||||
error: using `clone` on type `char` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:68:14
|
||||
--> $DIR/clone_on_copy.rs:69:14
|
||||
|
|
||||
LL | is_ascii('z'.clone());
|
||||
| ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
|
||||
|
||||
error: using `clone` on type `i32` which implements the `Copy` trait
|
||||
--> $DIR/clone_on_copy.rs:72:14
|
||||
--> $DIR/clone_on_copy.rs:73:14
|
||||
|
|
||||
LL | vec.push(42.clone());
|
||||
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
|
||||
|
@ -1,5 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, clippy::needless_borrow)]
|
||||
#![warn(clippy::duration_subsec)]
|
||||
|
||||
use std::time::Duration;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, clippy::needless_borrow)]
|
||||
#![warn(clippy::duration_subsec)]
|
||||
|
||||
use std::time::Duration;
|
||||
|
@ -151,4 +151,11 @@ enum North {
|
||||
NoRight,
|
||||
}
|
||||
|
||||
// #8324
|
||||
enum Phase {
|
||||
PreLookup,
|
||||
Lookup,
|
||||
PostLookup,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -5,13 +5,10 @@
|
||||
clippy::no_effect,
|
||||
clippy::redundant_closure_call,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::option_map_unit_fn
|
||||
)]
|
||||
#![warn(
|
||||
clippy::redundant_closure,
|
||||
clippy::redundant_closure_for_method_calls,
|
||||
clippy::option_map_unit_fn,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@ -34,7 +31,7 @@ fn main() {
|
||||
Some(1).map(closure_mac!()); // don't lint closure in macro expansion
|
||||
let _: Option<Vec<u8>> = true.then(std::vec::Vec::new); // special case vec!
|
||||
let d = Some(1u8).map(|a| foo(foo2(a))); //is adjusted?
|
||||
all(&[1, 2, 3], &2, below); //is adjusted
|
||||
all(&[1, 2, 3], &&2, below); //is adjusted
|
||||
unsafe {
|
||||
Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
|
||||
}
|
||||
|
@ -5,13 +5,10 @@
|
||||
clippy::no_effect,
|
||||
clippy::redundant_closure_call,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::option_map_unit_fn
|
||||
)]
|
||||
#![warn(
|
||||
clippy::redundant_closure,
|
||||
clippy::redundant_closure_for_method_calls,
|
||||
clippy::option_map_unit_fn,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:31:27
|
||||
--> $DIR/eta.rs:28:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| foo(a));
|
||||
| ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
|
||||
@ -7,45 +7,37 @@ LL | let a = Some(1u8).map(|a| foo(a));
|
||||
= note: `-D clippy::redundant-closure` implied by `-D warnings`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:35:40
|
||||
--> $DIR/eta.rs:32:40
|
||||
|
|
||||
LL | let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
|
||||
| ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:36:35
|
||||
--> $DIR/eta.rs:33:35
|
||||
|
|
||||
LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
|
||||
| ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
|
||||
|
||||
error: this expression borrows a reference (`&u8`) that is immediately dereferenced by the compiler
|
||||
--> $DIR/eta.rs:37:21
|
||||
|
|
||||
LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
|
||||
| ^^^ help: change this to: `&2`
|
||||
|
|
||||
= note: `-D clippy::needless-borrow` implied by `-D warnings`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:37:26
|
||||
--> $DIR/eta.rs:34:26
|
||||
|
|
||||
LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
|
||||
| ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:43:27
|
||||
--> $DIR/eta.rs:40:27
|
||||
|
|
||||
LL | let e = Some(1u8).map(|a| divergent(a));
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `divergent`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:44:27
|
||||
--> $DIR/eta.rs:41:27
|
||||
|
|
||||
LL | let e = Some(1u8).map(|a| generic(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:90:51
|
||||
--> $DIR/eta.rs:87:51
|
||||
|
|
||||
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
|
||||
| ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
|
||||
@ -53,82 +45,82 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
|
||||
= note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:91:51
|
||||
--> $DIR/eta.rs:88:51
|
||||
|
|
||||
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:93:42
|
||||
--> $DIR/eta.rs:90:42
|
||||
|
|
||||
LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
|
||||
| ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:97:29
|
||||
--> $DIR/eta.rs:94:29
|
||||
|
|
||||
LL | let e = Some("str").map(|s| s.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:98:27
|
||||
--> $DIR/eta.rs:95:27
|
||||
|
|
||||
LL | let e = Some('a').map(|s| s.to_uppercase());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:100:65
|
||||
--> $DIR/eta.rs:97:65
|
||||
|
|
||||
LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:163:22
|
||||
--> $DIR/eta.rs:160:22
|
||||
|
|
||||
LL | requires_fn_once(|| x());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `x`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:170:27
|
||||
--> $DIR/eta.rs:167:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| foo_ptr(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:175:27
|
||||
--> $DIR/eta.rs:172:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| closure(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:207:28
|
||||
--> $DIR/eta.rs:204:28
|
||||
|
|
||||
LL | x.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:208:28
|
||||
--> $DIR/eta.rs:205:28
|
||||
|
|
||||
LL | y.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:209:28
|
||||
--> $DIR/eta.rs:206:28
|
||||
|
|
||||
LL | z.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:216:21
|
||||
--> $DIR/eta.rs:213:21
|
||||
|
|
||||
LL | Some(1).map(|n| closure(n));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:235:21
|
||||
--> $DIR/eta.rs:232:21
|
||||
|
|
||||
LL | map_str_to_path(|s| s.as_ref());
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::convert::AsRef::as_ref`
|
||||
|
||||
error: aborting due to 21 previous errors
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused_variables, clippy::clone_double_ref)]
|
||||
#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)]
|
||||
#![warn(clippy::explicit_deref_methods)]
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
@ -1,6 +1,6 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused_variables, clippy::clone_double_ref)]
|
||||
#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)]
|
||||
#![warn(clippy::explicit_deref_methods)]
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
@ -23,7 +23,12 @@ impl Unrelated {
|
||||
clippy::iter_next_loop,
|
||||
clippy::for_kv_map
|
||||
)]
|
||||
#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
|
||||
#[allow(
|
||||
clippy::linkedlist,
|
||||
clippy::unnecessary_mut_passed,
|
||||
clippy::similar_names,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
#[allow(unused_variables)]
|
||||
fn main() {
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
|
@ -23,7 +23,12 @@ impl Unrelated {
|
||||
clippy::iter_next_loop,
|
||||
clippy::for_kv_map
|
||||
)]
|
||||
#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
|
||||
#[allow(
|
||||
clippy::linkedlist,
|
||||
clippy::unnecessary_mut_passed,
|
||||
clippy::similar_names,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
#[allow(unused_variables)]
|
||||
fn main() {
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:38:15
|
||||
--> $DIR/for_loop_fixable.rs:43:15
|
||||
|
|
||||
LL | for _v in vec.iter() {}
|
||||
| ^^^^^^^^^^ help: to write this more concisely, try: `&vec`
|
||||
@ -7,13 +7,13 @@ LL | for _v in vec.iter() {}
|
||||
= note: `-D clippy::explicit-iter-loop` implied by `-D warnings`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:40:15
|
||||
--> $DIR/for_loop_fixable.rs:45:15
|
||||
|
|
||||
LL | for _v in vec.iter_mut() {}
|
||||
| ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec`
|
||||
|
||||
error: it is more concise to loop over containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:43:15
|
||||
--> $DIR/for_loop_fixable.rs:48:15
|
||||
|
|
||||
LL | for _v in out_vec.into_iter() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec`
|
||||
@ -21,73 +21,73 @@ LL | for _v in out_vec.into_iter() {}
|
||||
= note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:48:15
|
||||
--> $DIR/for_loop_fixable.rs:53:15
|
||||
|
|
||||
LL | for _v in [1, 2, 3].iter() {}
|
||||
| ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:52:15
|
||||
--> $DIR/for_loop_fixable.rs:57:15
|
||||
|
|
||||
LL | for _v in [0; 32].iter() {}
|
||||
| ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:57:15
|
||||
--> $DIR/for_loop_fixable.rs:62:15
|
||||
|
|
||||
LL | for _v in ll.iter() {}
|
||||
| ^^^^^^^^^ help: to write this more concisely, try: `&ll`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:60:15
|
||||
--> $DIR/for_loop_fixable.rs:65:15
|
||||
|
|
||||
LL | for _v in vd.iter() {}
|
||||
| ^^^^^^^^^ help: to write this more concisely, try: `&vd`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:63:15
|
||||
--> $DIR/for_loop_fixable.rs:68:15
|
||||
|
|
||||
LL | for _v in bh.iter() {}
|
||||
| ^^^^^^^^^ help: to write this more concisely, try: `&bh`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:66:15
|
||||
--> $DIR/for_loop_fixable.rs:71:15
|
||||
|
|
||||
LL | for _v in hm.iter() {}
|
||||
| ^^^^^^^^^ help: to write this more concisely, try: `&hm`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:69:15
|
||||
--> $DIR/for_loop_fixable.rs:74:15
|
||||
|
|
||||
LL | for _v in bt.iter() {}
|
||||
| ^^^^^^^^^ help: to write this more concisely, try: `&bt`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:72:15
|
||||
--> $DIR/for_loop_fixable.rs:77:15
|
||||
|
|
||||
LL | for _v in hs.iter() {}
|
||||
| ^^^^^^^^^ help: to write this more concisely, try: `&hs`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:75:15
|
||||
--> $DIR/for_loop_fixable.rs:80:15
|
||||
|
|
||||
LL | for _v in bs.iter() {}
|
||||
| ^^^^^^^^^ help: to write this more concisely, try: `&bs`
|
||||
|
||||
error: it is more concise to loop over containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:250:18
|
||||
--> $DIR/for_loop_fixable.rs:255:18
|
||||
|
|
||||
LL | for i in iterator.into_iter() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator`
|
||||
|
||||
error: it is more concise to loop over references to containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:270:18
|
||||
--> $DIR/for_loop_fixable.rs:275:18
|
||||
|
|
||||
LL | for _ in t.into_iter() {}
|
||||
| ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t`
|
||||
|
||||
error: it is more concise to loop over containers instead of using explicit iteration methods
|
||||
--> $DIR/for_loop_fixable.rs:272:18
|
||||
--> $DIR/for_loop_fixable.rs:277:18
|
||||
|
|
||||
LL | for _ in r.into_iter() {}
|
||||
| ^^^^^^^^^^^^^ help: to write this more concisely, try: `r`
|
||||
|
@ -1,6 +1,11 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
|
||||
#![allow(
|
||||
clippy::print_literal,
|
||||
clippy::redundant_clone,
|
||||
clippy::to_string_in_format_args,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
#![warn(clippy::useless_format)]
|
||||
|
||||
struct Foo(pub String);
|
||||
|
@ -1,6 +1,11 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
|
||||
#![allow(
|
||||
clippy::print_literal,
|
||||
clippy::redundant_clone,
|
||||
clippy::to_string_in_format_args,
|
||||
clippy::needless_borrow
|
||||
)]
|
||||
#![warn(clippy::useless_format)]
|
||||
|
||||
struct Foo(pub String);
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:13:5
|
||||
--> $DIR/format.rs:18:5
|
||||
|
|
||||
LL | format!("foo");
|
||||
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
@ -7,19 +7,19 @@ LL | format!("foo");
|
||||
= note: `-D clippy::useless-format` implied by `-D warnings`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:14:5
|
||||
--> $DIR/format.rs:19:5
|
||||
|
|
||||
LL | format!("{{}}");
|
||||
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:15:5
|
||||
--> $DIR/format.rs:20:5
|
||||
|
|
||||
LL | format!("{{}} abc {{}}");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:16:5
|
||||
--> $DIR/format.rs:21:5
|
||||
|
|
||||
LL | / format!(
|
||||
LL | | r##"foo {{}}
|
||||
@ -34,79 +34,79 @@ LL ~ " bar"##.to_string();
|
||||
|
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:21:13
|
||||
--> $DIR/format.rs:26:13
|
||||
|
|
||||
LL | let _ = format!("");
|
||||
| ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:23:5
|
||||
--> $DIR/format.rs:28:5
|
||||
|
|
||||
LL | format!("{}", "foo");
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:27:5
|
||||
--> $DIR/format.rs:32:5
|
||||
|
|
||||
LL | format!("{:+}", "foo"); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:28:5
|
||||
--> $DIR/format.rs:33:5
|
||||
|
|
||||
LL | format!("{:<}", "foo"); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:33:5
|
||||
--> $DIR/format.rs:38:5
|
||||
|
|
||||
LL | format!("{}", arg);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:37:5
|
||||
--> $DIR/format.rs:42:5
|
||||
|
|
||||
LL | format!("{:+}", arg); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:38:5
|
||||
--> $DIR/format.rs:43:5
|
||||
|
|
||||
LL | format!("{:<}", arg); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:65:5
|
||||
--> $DIR/format.rs:70:5
|
||||
|
|
||||
LL | format!("{}", 42.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:67:5
|
||||
--> $DIR/format.rs:72:5
|
||||
|
|
||||
LL | format!("{}", x.display().to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:71:18
|
||||
--> $DIR/format.rs:76:18
|
||||
|
|
||||
LL | let _ = Some(format!("{}", a + "bar"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:75:22
|
||||
--> $DIR/format.rs:80:22
|
||||
|
|
||||
LL | let _s: String = format!("{}", &*v.join("/n"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:81:13
|
||||
--> $DIR/format.rs:86:13
|
||||
|
|
||||
LL | let _ = format!("{x}");
|
||||
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:83:13
|
||||
--> $DIR/format.rs:88:13
|
||||
|
|
||||
LL | let _ = format!("{y}", y = x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||
|
@ -45,6 +45,33 @@ fn main() {
|
||||
let b = &mut b;
|
||||
x(b);
|
||||
}
|
||||
|
||||
// Issue #8191
|
||||
let mut x = 5;
|
||||
let mut x = &mut x;
|
||||
|
||||
mut_ref(x);
|
||||
mut_ref(x);
|
||||
let y: &mut i32 = x;
|
||||
let y: &mut i32 = x;
|
||||
|
||||
let y = match 0 {
|
||||
// Don't lint. Removing the borrow would move 'x'
|
||||
0 => &mut x,
|
||||
_ => &mut *x,
|
||||
};
|
||||
|
||||
*x = 5;
|
||||
|
||||
let s = String::new();
|
||||
let _ = s.len();
|
||||
let _ = s.capacity();
|
||||
let _ = s.capacity();
|
||||
|
||||
let x = (1, 2);
|
||||
let _ = x.0;
|
||||
let x = &x as *const (i32, i32);
|
||||
let _ = unsafe { (*x).0 };
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_borrowed_reference)]
|
||||
|
@ -45,6 +45,33 @@ fn main() {
|
||||
let b = &mut b;
|
||||
x(&b);
|
||||
}
|
||||
|
||||
// Issue #8191
|
||||
let mut x = 5;
|
||||
let mut x = &mut x;
|
||||
|
||||
mut_ref(&mut x);
|
||||
mut_ref(&mut &mut x);
|
||||
let y: &mut i32 = &mut x;
|
||||
let y: &mut i32 = &mut &mut x;
|
||||
|
||||
let y = match 0 {
|
||||
// Don't lint. Removing the borrow would move 'x'
|
||||
0 => &mut x,
|
||||
_ => &mut *x,
|
||||
};
|
||||
|
||||
*x = 5;
|
||||
|
||||
let s = String::new();
|
||||
let _ = (&s).len();
|
||||
let _ = (&s).capacity();
|
||||
let _ = (&&s).capacity();
|
||||
|
||||
let x = (1, 2);
|
||||
let _ = (&x).0;
|
||||
let x = &x as *const (i32, i32);
|
||||
let _ = unsafe { (&*x).0 };
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_borrowed_reference)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:9:15
|
||||
|
|
||||
LL | let _ = x(&&a); // warn
|
||||
@ -6,59 +6,113 @@ LL | let _ = x(&&a); // warn
|
||||
|
|
||||
= note: `-D clippy::needless-borrow` implied by `-D warnings`
|
||||
|
||||
error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:13:13
|
||||
|
|
||||
LL | mut_ref(&mut &mut b); // warn
|
||||
| ^^^^^^^^^^^ help: change this to: `&mut b`
|
||||
|
||||
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:25:13
|
||||
|
|
||||
LL | &&a
|
||||
| ^^^ help: change this to: `&a`
|
||||
|
||||
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:27:15
|
||||
|
|
||||
LL | 46 => &&a,
|
||||
| ^^^ help: change this to: `&a`
|
||||
|
||||
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:33:27
|
||||
|
|
||||
LL | break &ref_a;
|
||||
| ^^^^^^ help: change this to: `ref_a`
|
||||
|
||||
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:40:15
|
||||
|
|
||||
LL | let _ = x(&&&a);
|
||||
| ^^^^ help: change this to: `&a`
|
||||
|
||||
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:41:15
|
||||
|
|
||||
LL | let _ = x(&mut &&a);
|
||||
| ^^^^^^^^ help: change this to: `&a`
|
||||
|
||||
error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:42:15
|
||||
|
|
||||
LL | let _ = x(&&&mut b);
|
||||
| ^^^^^^^^ help: change this to: `&mut b`
|
||||
|
||||
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:43:15
|
||||
|
|
||||
LL | let _ = x(&&ref_a);
|
||||
| ^^^^^^^ help: change this to: `ref_a`
|
||||
|
||||
error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:46:11
|
||||
|
|
||||
LL | x(&b);
|
||||
| ^^ help: change this to: `b`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:53:13
|
||||
|
|
||||
LL | mut_ref(&mut x);
|
||||
| ^^^^^^ help: change this to: `x`
|
||||
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:54:13
|
||||
|
|
||||
LL | mut_ref(&mut &mut x);
|
||||
| ^^^^^^^^^^^ help: change this to: `x`
|
||||
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:55:23
|
||||
|
|
||||
LL | let y: &mut i32 = &mut x;
|
||||
| ^^^^^^ help: change this to: `x`
|
||||
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:56:23
|
||||
|
|
||||
LL | let y: &mut i32 = &mut &mut x;
|
||||
| ^^^^^^^^^^^ help: change this to: `x`
|
||||
|
||||
error: this expression borrows a value the compiler would automatically borrow
|
||||
--> $DIR/needless_borrow.rs:67:13
|
||||
|
|
||||
LL | let _ = (&s).len();
|
||||
| ^^^^ help: change this to: `s`
|
||||
|
||||
error: this expression borrows a value the compiler would automatically borrow
|
||||
--> $DIR/needless_borrow.rs:68:13
|
||||
|
|
||||
LL | let _ = (&s).capacity();
|
||||
| ^^^^ help: change this to: `s`
|
||||
|
||||
error: this expression creates a reference which is immediately dereferenced by the compiler
|
||||
--> $DIR/needless_borrow.rs:69:13
|
||||
|
|
||||
LL | let _ = (&&s).capacity();
|
||||
| ^^^^^ help: change this to: `s`
|
||||
|
||||
error: this expression borrows a value the compiler would automatically borrow
|
||||
--> $DIR/needless_borrow.rs:72:13
|
||||
|
|
||||
LL | let _ = (&x).0;
|
||||
| ^^^^ help: change this to: `x`
|
||||
|
||||
error: this expression borrows a value the compiler would automatically borrow
|
||||
--> $DIR/needless_borrow.rs:74:22
|
||||
|
|
||||
LL | let _ = unsafe { (&*x).0 };
|
||||
| ^^^^^ help: change this to: `(*x)`
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
#![warn(clippy::needless_lifetimes)]
|
||||
#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)]
|
||||
#![allow(
|
||||
dead_code,
|
||||
clippy::boxed_local,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::unnecessary_wraps,
|
||||
dyn_drop
|
||||
)]
|
||||
|
||||
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
|
||||
|
||||
@ -369,4 +375,47 @@ mod issue6159 {
|
||||
}
|
||||
}
|
||||
|
||||
mod issue7296 {
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn implicit<'a>(&'a self) -> &'a () {
|
||||
&()
|
||||
}
|
||||
fn implicit_mut<'a>(&'a mut self) -> &'a () {
|
||||
&()
|
||||
}
|
||||
|
||||
fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
|
||||
&()
|
||||
}
|
||||
fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
|
||||
&()
|
||||
}
|
||||
|
||||
fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
|
||||
&()
|
||||
}
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn implicit<'a>(&'a self) -> &'a ();
|
||||
fn implicit_provided<'a>(&'a self) -> &'a () {
|
||||
&()
|
||||
}
|
||||
|
||||
fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
|
||||
fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
|
||||
&()
|
||||
}
|
||||
|
||||
fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
|
||||
fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
|
||||
&()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:4:1
|
||||
--> $DIR/needless_lifetimes.rs:10:1
|
||||
|
|
||||
LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -7,148 +7,190 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
|
||||
= note: `-D clippy::needless-lifetimes` implied by `-D warnings`
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:6:1
|
||||
--> $DIR/needless_lifetimes.rs:12:1
|
||||
|
|
||||
LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:16:1
|
||||
--> $DIR/needless_lifetimes.rs:22:1
|
||||
|
|
||||
LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:50:1
|
||||
--> $DIR/needless_lifetimes.rs:56:1
|
||||
|
|
||||
LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:55:1
|
||||
--> $DIR/needless_lifetimes.rs:61:1
|
||||
|
|
||||
LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:67:1
|
||||
--> $DIR/needless_lifetimes.rs:73:1
|
||||
|
|
||||
LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:91:1
|
||||
--> $DIR/needless_lifetimes.rs:97:1
|
||||
|
|
||||
LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:121:5
|
||||
--> $DIR/needless_lifetimes.rs:127:5
|
||||
|
|
||||
LL | fn self_and_out<'s>(&'s self) -> &'s u8 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:130:5
|
||||
--> $DIR/needless_lifetimes.rs:136:5
|
||||
|
|
||||
LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:149:1
|
||||
--> $DIR/needless_lifetimes.rs:155:1
|
||||
|
|
||||
LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:179:1
|
||||
--> $DIR/needless_lifetimes.rs:185:1
|
||||
|
|
||||
LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:185:1
|
||||
--> $DIR/needless_lifetimes.rs:191:1
|
||||
|
|
||||
LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:204:1
|
||||
--> $DIR/needless_lifetimes.rs:210:1
|
||||
|
|
||||
LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:212:1
|
||||
--> $DIR/needless_lifetimes.rs:218:1
|
||||
|
|
||||
LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:248:1
|
||||
--> $DIR/needless_lifetimes.rs:254:1
|
||||
|
|
||||
LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:255:9
|
||||
--> $DIR/needless_lifetimes.rs:261:9
|
||||
|
|
||||
LL | fn needless_lt<'a>(x: &'a u8) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:259:9
|
||||
--> $DIR/needless_lifetimes.rs:265:9
|
||||
|
|
||||
LL | fn needless_lt<'a>(_x: &'a u8) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:272:9
|
||||
--> $DIR/needless_lifetimes.rs:278:9
|
||||
|
|
||||
LL | fn baz<'a>(&'a self) -> impl Foo + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:301:5
|
||||
--> $DIR/needless_lifetimes.rs:307:5
|
||||
|
|
||||
LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:304:5
|
||||
--> $DIR/needless_lifetimes.rs:310:5
|
||||
|
|
||||
LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:313:5
|
||||
--> $DIR/needless_lifetimes.rs:319:5
|
||||
|
|
||||
LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:325:5
|
||||
--> $DIR/needless_lifetimes.rs:331:5
|
||||
|
|
||||
LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:340:5
|
||||
--> $DIR/needless_lifetimes.rs:346:5
|
||||
|
|
||||
LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:353:5
|
||||
--> $DIR/needless_lifetimes.rs:359:5
|
||||
|
|
||||
LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:356:5
|
||||
--> $DIR/needless_lifetimes.rs:362:5
|
||||
|
|
||||
LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:384:9
|
||||
|
|
||||
LL | fn implicit<'a>(&'a self) -> &'a () {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:387:9
|
||||
|
|
||||
LL | fn implicit_mut<'a>(&'a mut self) -> &'a () {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:398:9
|
||||
|
|
||||
LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:404:9
|
||||
|
|
||||
LL | fn implicit<'a>(&'a self) -> &'a ();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:405:9
|
||||
|
|
||||
LL | fn implicit_provided<'a>(&'a self) -> &'a () {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:414:9
|
||||
|
|
||||
LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:415:9
|
||||
|
|
||||
LL | fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 32 previous errors
|
||||
|
||||
|
@ -125,3 +125,16 @@ pub fn test2() {
|
||||
let x = Some(3);
|
||||
let _x = some_and_qmark_in_macro!(x?);
|
||||
}
|
||||
|
||||
async fn async_option_bad(to: TO) -> Option<usize> {
|
||||
let _ = Some(3);
|
||||
to.magic
|
||||
}
|
||||
|
||||
async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
|
||||
Some(s?)
|
||||
}
|
||||
|
||||
async fn async_result_bad(s: TR) -> Result<usize, bool> {
|
||||
s.magic
|
||||
}
|
||||
|
@ -125,3 +125,16 @@ pub fn test2() {
|
||||
let x = Some(3);
|
||||
let _x = some_and_qmark_in_macro!(x?);
|
||||
}
|
||||
|
||||
async fn async_option_bad(to: TO) -> Option<usize> {
|
||||
let _ = Some(3);
|
||||
Some(to.magic?)
|
||||
}
|
||||
|
||||
async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
|
||||
Some(s?)
|
||||
}
|
||||
|
||||
async fn async_result_bad(s: TR) -> Result<usize, bool> {
|
||||
Ok(s.magic?)
|
||||
}
|
||||
|
@ -77,5 +77,17 @@ LL | let _x = some_and_qmark_in_macro!(x?);
|
||||
|
|
||||
= note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:131:5
|
||||
|
|
||||
LL | Some(to.magic?)
|
||||
| ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
|
||||
|
||||
error: question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:139:5
|
||||
|
|
||||
LL | Ok(s.magic?)
|
||||
| ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![allow(unused_variables, clippy::blacklisted_name)]
|
||||
#![warn(clippy::op_ref)]
|
||||
use std::collections::HashSet;
|
||||
use std::ops::BitAnd;
|
||||
use std::ops::{BitAnd, Mul};
|
||||
|
||||
fn main() {
|
||||
let tracked_fds: HashSet<i32> = HashSet::new();
|
||||
@ -55,3 +55,40 @@ fn main() {
|
||||
let y = Y(2);
|
||||
let z = x & &y;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct A(i32);
|
||||
#[derive(Clone, Copy)]
|
||||
struct B(i32);
|
||||
|
||||
impl Mul<&A> for B {
|
||||
type Output = i32;
|
||||
fn mul(self, rhs: &A) -> Self::Output {
|
||||
self.0 * rhs.0
|
||||
}
|
||||
}
|
||||
impl Mul<A> for B {
|
||||
type Output = i32;
|
||||
fn mul(self, rhs: A) -> Self::Output {
|
||||
// Should not lint because removing the reference would lead to unconditional recursion
|
||||
self * &rhs
|
||||
}
|
||||
}
|
||||
impl Mul<&A> for A {
|
||||
type Output = i32;
|
||||
fn mul(self, rhs: &A) -> Self::Output {
|
||||
self.0 * rhs.0
|
||||
}
|
||||
}
|
||||
impl Mul<A> for A {
|
||||
type Output = i32;
|
||||
fn mul(self, rhs: A) -> Self::Output {
|
||||
let one = B(1);
|
||||
let two = 2;
|
||||
let three = 3;
|
||||
let _ = one * &self;
|
||||
let _ = two + &three;
|
||||
// Removing the reference would lead to unconditional recursion
|
||||
self * &rhs
|
||||
}
|
||||
}
|
||||
|
@ -18,5 +18,21 @@ LL | let z = x & &y;
|
||||
| |
|
||||
| help: use the right value directly: `y`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: taken reference of right operand
|
||||
--> $DIR/op_ref.rs:89:17
|
||||
|
|
||||
LL | let _ = one * &self;
|
||||
| ^^^^^^-----
|
||||
| |
|
||||
| help: use the right value directly: `self`
|
||||
|
||||
error: taken reference of right operand
|
||||
--> $DIR/op_ref.rs:90:17
|
||||
|
|
||||
LL | let _ = two + &three;
|
||||
| ^^^^^^------
|
||||
| |
|
||||
| help: use the right value directly: `three`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -9,7 +9,6 @@ fn do_vec(x: &Vec<i64>) {
|
||||
}
|
||||
|
||||
fn do_vec_mut(x: &mut Vec<i64>) {
|
||||
// no error here
|
||||
//Nothing here
|
||||
}
|
||||
|
||||
@ -18,7 +17,6 @@ fn do_str(x: &String) {
|
||||
}
|
||||
|
||||
fn do_str_mut(x: &mut String) {
|
||||
// no error here
|
||||
//Nothing here either
|
||||
}
|
||||
|
||||
@ -27,7 +25,6 @@ fn do_path(x: &PathBuf) {
|
||||
}
|
||||
|
||||
fn do_path_mut(x: &mut PathBuf) {
|
||||
// no error here
|
||||
//Nothing here either
|
||||
}
|
||||
|
||||
@ -52,7 +49,7 @@ fn cloned(x: &Vec<u8>) -> Vec<u8> {
|
||||
let e = x.clone();
|
||||
let f = e.clone(); // OK
|
||||
let g = x;
|
||||
let h = g.clone(); // Alas, we cannot reliably detect this without following data.
|
||||
let h = g.clone();
|
||||
let i = (e).clone();
|
||||
x.clone()
|
||||
}
|
||||
@ -156,6 +153,30 @@ mod issue6509 {
|
||||
}
|
||||
}
|
||||
|
||||
fn mut_vec_slice_methods(v: &mut Vec<u32>) {
|
||||
v.copy_within(1..5, 10);
|
||||
}
|
||||
|
||||
fn mut_vec_vec_methods(v: &mut Vec<u32>) {
|
||||
v.clear();
|
||||
}
|
||||
|
||||
fn vec_contains(v: &Vec<u32>) -> bool {
|
||||
[vec![], vec![0]].as_slice().contains(v)
|
||||
}
|
||||
|
||||
fn fn_requires_vec(v: &Vec<u32>) -> bool {
|
||||
vec_contains(v)
|
||||
}
|
||||
|
||||
fn impl_fn_requires_vec(v: &Vec<u32>, f: impl Fn(&Vec<u32>)) {
|
||||
f(v);
|
||||
}
|
||||
|
||||
fn dyn_fn_requires_vec(v: &Vec<u32>, f: &dyn Fn(&Vec<u32>)) {
|
||||
f(v);
|
||||
}
|
||||
|
||||
// No error for types behind an alias (#7699)
|
||||
type A = Vec<u8>;
|
||||
fn aliased(a: &A) {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
|
||||
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:7:14
|
||||
|
|
||||
LL | fn do_vec(x: &Vec<i64>) {
|
||||
@ -6,170 +6,154 @@ LL | fn do_vec(x: &Vec<i64>) {
|
||||
|
|
||||
= note: `-D clippy::ptr-arg` implied by `-D warnings`
|
||||
|
||||
error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:11:18
|
||||
|
|
||||
LL | fn do_vec_mut(x: &mut Vec<i64>) {
|
||||
| ^^^^^^^^^^^^^ help: change this to: `&mut [i64]`
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:16:14
|
||||
--> $DIR/ptr_arg.rs:15:14
|
||||
|
|
||||
LL | fn do_str(x: &String) {
|
||||
| ^^^^^^^ help: change this to: `&str`
|
||||
|
||||
error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:19:18
|
||||
|
|
||||
LL | fn do_str_mut(x: &mut String) {
|
||||
| ^^^^^^^^^^^ help: change this to: `&mut str`
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:25:15
|
||||
--> $DIR/ptr_arg.rs:23:15
|
||||
|
|
||||
LL | fn do_path(x: &PathBuf) {
|
||||
| ^^^^^^^^ help: change this to: `&Path`
|
||||
|
||||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
|
||||
--> $DIR/ptr_arg.rs:38:18
|
||||
error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:27:19
|
||||
|
|
||||
LL | fn do_path_mut(x: &mut PathBuf) {
|
||||
| ^^^^^^^^^^^^ help: change this to: `&mut Path`
|
||||
|
||||
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:35:18
|
||||
|
|
||||
LL | fn do_vec(x: &Vec<i64>);
|
||||
| ^^^^^^^^^ help: change this to: `&[i64]`
|
||||
|
||||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
|
||||
--> $DIR/ptr_arg.rs:51:14
|
||||
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:48:14
|
||||
|
|
||||
LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn cloned(x: &[u8]) -> Vec<u8> {
|
||||
| ~~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | let e = x.to_owned();
|
||||
| ~~~~~~~~~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | x.to_owned()
|
||||
|
|
||||
LL ~ fn cloned(x: &[u8]) -> Vec<u8> {
|
||||
LL ~ let e = x.to_owned();
|
||||
LL | let f = e.clone(); // OK
|
||||
LL | let g = x;
|
||||
LL ~ let h = g.to_owned();
|
||||
LL | let i = (e).clone();
|
||||
...
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:60:18
|
||||
--> $DIR/ptr_arg.rs:57:18
|
||||
|
|
||||
LL | fn str_cloned(x: &String) -> String {
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn str_cloned(x: &str) -> String {
|
||||
| ~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | let a = x.to_string();
|
||||
| ~~~~~~~~~~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | let b = x.to_string();
|
||||
| ~~~~~~~~~~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | x.to_string()
|
||||
LL ~ fn str_cloned(x: &str) -> String {
|
||||
LL ~ let a = x.to_owned();
|
||||
LL ~ let b = x.to_owned();
|
||||
LL | let c = b.clone();
|
||||
LL | let d = a.clone().clone().clone();
|
||||
LL ~ x.to_owned()
|
||||
|
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:68:19
|
||||
--> $DIR/ptr_arg.rs:65:19
|
||||
|
|
||||
LL | fn path_cloned(x: &PathBuf) -> PathBuf {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn path_cloned(x: &Path) -> PathBuf {
|
||||
| ~~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | let a = x.to_path_buf();
|
||||
| ~~~~~~~~~~~~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | let b = x.to_path_buf();
|
||||
| ~~~~~~~~~~~~~~~
|
||||
help: change `x.clone()` to
|
||||
|
|
||||
LL | x.to_path_buf()
|
||||
LL ~ fn path_cloned(x: &Path) -> PathBuf {
|
||||
LL ~ let a = x.to_path_buf();
|
||||
LL ~ let b = x.to_path_buf();
|
||||
LL | let c = b.clone();
|
||||
LL | let d = a.clone().clone().clone();
|
||||
LL ~ x.to_path_buf()
|
||||
|
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:76:44
|
||||
--> $DIR/ptr_arg.rs:73:44
|
||||
|
|
||||
LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn false_positive_capacity(x: &Vec<u8>, y: &str) {
|
||||
| ~~~~
|
||||
help: change `y.clone()` to
|
||||
LL ~ fn false_positive_capacity(x: &Vec<u8>, y: &str) {
|
||||
LL | let a = x.capacity();
|
||||
LL ~ let b = y.to_owned();
|
||||
LL ~ let c = y;
|
||||
|
|
||||
LL | let b = y.to_string();
|
||||
| ~~~~~~~~~~~~~
|
||||
help: change `y.as_str()` to
|
||||
|
|
||||
LL | let c = y;
|
||||
| ~
|
||||
|
||||
error: using a reference to `Cow` is not recommended
|
||||
--> $DIR/ptr_arg.rs:90:25
|
||||
--> $DIR/ptr_arg.rs:87:25
|
||||
|
|
||||
LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
|
||||
| ^^^^^^^^^^^ help: change this to: `&[i32]`
|
||||
|
||||
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
|
||||
--> $DIR/ptr_arg.rs:143:21
|
||||
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:140:21
|
||||
|
|
||||
LL | fn foo_vec(vec: &Vec<u8>) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn foo_vec(vec: &[u8]) {
|
||||
| ~~~~~
|
||||
help: change `vec.clone()` to
|
||||
LL ~ fn foo_vec(vec: &[u8]) {
|
||||
LL ~ let _ = vec.to_owned().pop();
|
||||
LL ~ let _ = vec.to_owned().clone();
|
||||
|
|
||||
LL | let _ = vec.to_owned().pop();
|
||||
| ~~~~~~~~~~~~~~
|
||||
help: change `vec.clone()` to
|
||||
|
|
||||
LL | let _ = vec.to_owned().clone();
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:148:23
|
||||
--> $DIR/ptr_arg.rs:145:23
|
||||
|
|
||||
LL | fn foo_path(path: &PathBuf) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn foo_path(path: &Path) {
|
||||
| ~~~~~
|
||||
help: change `path.clone()` to
|
||||
LL ~ fn foo_path(path: &Path) {
|
||||
LL ~ let _ = path.to_path_buf().pop();
|
||||
LL ~ let _ = path.to_path_buf().clone();
|
||||
|
|
||||
LL | let _ = path.to_path_buf().pop();
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
help: change `path.clone()` to
|
||||
|
|
||||
LL | let _ = path.to_path_buf().clone();
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:153:21
|
||||
--> $DIR/ptr_arg.rs:150:21
|
||||
|
|
||||
LL | fn foo_str(str: &PathBuf) {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
help: change this to
|
||||
|
|
||||
LL | fn foo_str(str: &Path) {
|
||||
| ~~~~~
|
||||
help: change `str.clone()` to
|
||||
LL ~ fn foo_str(str: &Path) {
|
||||
LL ~ let _ = str.to_path_buf().pop();
|
||||
LL ~ let _ = str.to_path_buf().clone();
|
||||
|
|
||||
LL | let _ = str.to_path_buf().pop();
|
||||
| ~~~~~~~~~~~~~~~~~
|
||||
help: change `str.clone()` to
|
||||
|
||||
error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
|
||||
--> $DIR/ptr_arg.rs:156:29
|
||||
|
|
||||
LL | let _ = str.to_path_buf().clone();
|
||||
| ~~~~~~~~~~~~~~~~~
|
||||
LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) {
|
||||
| ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
|
@ -81,7 +81,7 @@ const fn issue6067() {
|
||||
None::<()>.is_none();
|
||||
}
|
||||
|
||||
#[allow(clippy::deref_addrof, dead_code)]
|
||||
#[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)]
|
||||
fn issue7921() {
|
||||
if (&None::<()>).is_none() {}
|
||||
if (&None::<()>).is_none() {}
|
||||
|
@ -96,7 +96,7 @@ const fn issue6067() {
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(clippy::deref_addrof, dead_code)]
|
||||
#[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)]
|
||||
fn issue7921() {
|
||||
if let None = *(&None::<()>) {}
|
||||
if let None = *&None::<()> {}
|
||||
|
@ -54,6 +54,7 @@
|
||||
#![warn(clippy::match_result_ok)]
|
||||
#![warn(clippy::disallowed_types)]
|
||||
#![warn(clippy::disallowed_methods)]
|
||||
#![warn(clippy::needless_borrow)]
|
||||
// uplifted lints
|
||||
#![warn(invalid_value)]
|
||||
#![warn(array_into_iter)]
|
||||
|
@ -54,6 +54,7 @@
|
||||
#![warn(clippy::if_let_some_result)]
|
||||
#![warn(clippy::disallowed_type)]
|
||||
#![warn(clippy::disallowed_method)]
|
||||
#![warn(clippy::ref_in_deref)]
|
||||
// uplifted lints
|
||||
#![warn(clippy::invalid_ref)]
|
||||
#![warn(clippy::into_iter_on_array)]
|
||||
|
@ -138,59 +138,65 @@ error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_
|
||||
LL | #![warn(clippy::disallowed_method)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
|
||||
|
||||
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
|
||||
--> $DIR/rename.rs:57:9
|
||||
|
|
||||
LL | #![warn(clippy::ref_in_deref)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
|
||||
|
||||
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
|
||||
--> $DIR/rename.rs:58:9
|
||||
--> $DIR/rename.rs:59:9
|
||||
|
|
||||
LL | #![warn(clippy::invalid_ref)]
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
|
||||
|
||||
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
|
||||
--> $DIR/rename.rs:59:9
|
||||
--> $DIR/rename.rs:60:9
|
||||
|
|
||||
LL | #![warn(clippy::into_iter_on_array)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
|
||||
|
||||
error: lint `clippy::unused_label` has been renamed to `unused_labels`
|
||||
--> $DIR/rename.rs:60:9
|
||||
--> $DIR/rename.rs:61:9
|
||||
|
|
||||
LL | #![warn(clippy::unused_label)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
|
||||
|
||||
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
|
||||
--> $DIR/rename.rs:61:9
|
||||
--> $DIR/rename.rs:62:9
|
||||
|
|
||||
LL | #![warn(clippy::drop_bounds)]
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
|
||||
|
||||
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
|
||||
--> $DIR/rename.rs:62:9
|
||||
--> $DIR/rename.rs:63:9
|
||||
|
|
||||
LL | #![warn(clippy::temporary_cstring_as_ptr)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
|
||||
|
||||
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
|
||||
--> $DIR/rename.rs:63:9
|
||||
--> $DIR/rename.rs:64:9
|
||||
|
|
||||
LL | #![warn(clippy::panic_params)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
|
||||
|
||||
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
|
||||
--> $DIR/rename.rs:64:9
|
||||
--> $DIR/rename.rs:65:9
|
||||
|
|
||||
LL | #![warn(clippy::unknown_clippy_lints)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
|
||||
|
||||
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
|
||||
--> $DIR/rename.rs:65:9
|
||||
--> $DIR/rename.rs:66:9
|
||||
|
|
||||
LL | #![warn(clippy::invalid_atomic_ordering)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
|
||||
|
||||
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
|
||||
--> $DIR/rename.rs:66:9
|
||||
--> $DIR/rename.rs:67:9
|
||||
|
|
||||
LL | #![warn(clippy::mem_discriminant_non_enum)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
|
||||
|
||||
error: aborting due to 32 previous errors
|
||||
error: aborting due to 33 previous errors
|
||||
|
||||
|
@ -189,7 +189,7 @@ mod issue7392 {
|
||||
let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
|
||||
}
|
||||
|
||||
fn test_string_1(s: &String) -> bool {
|
||||
fn test_string_1(s: &str) -> bool {
|
||||
s.is_empty()
|
||||
}
|
||||
|
||||
|
@ -251,14 +251,6 @@ error: called `is_none()` after searching an `Iterator` with `find`
|
||||
LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do
|
||||
--> $DIR/search_is_some_fixable_none.rs:192:25
|
||||
|
|
||||
LL | fn test_string_1(s: &String) -> bool {
|
||||
| ^^^^^^^ help: change this to: `&str`
|
||||
|
|
||||
= note: `-D clippy::ptr-arg` implied by `-D warnings`
|
||||
|
||||
error: called `is_none()` after searching an `Iterator` with `find`
|
||||
--> $DIR/search_is_some_fixable_none.rs:208:17
|
||||
|
|
||||
@ -289,5 +281,5 @@ error: called `is_none()` after searching an `Iterator` with `find`
|
||||
LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))`
|
||||
|
||||
error: aborting due to 44 previous errors
|
||||
error: aborting due to 43 previous errors
|
||||
|
||||
|
@ -188,7 +188,7 @@ mod issue7392 {
|
||||
let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
|
||||
}
|
||||
|
||||
fn test_string_1(s: &String) -> bool {
|
||||
fn test_string_1(s: &str) -> bool {
|
||||
s.is_empty()
|
||||
}
|
||||
|
||||
|
@ -234,14 +234,6 @@ error: called `is_some()` after searching an `Iterator` with `find`
|
||||
LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)`
|
||||
|
||||
error: writing `&String` instead of `&str` involves a new object where a slice will do
|
||||
--> $DIR/search_is_some_fixable_some.rs:191:25
|
||||
|
|
||||
LL | fn test_string_1(s: &String) -> bool {
|
||||
| ^^^^^^^ help: change this to: `&str`
|
||||
|
|
||||
= note: `-D clippy::ptr-arg` implied by `-D warnings`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with `find`
|
||||
--> $DIR/search_is_some_fixable_some.rs:207:26
|
||||
|
|
||||
@ -272,5 +264,5 @@ error: called `is_some()` after searching an `Iterator` with `find`
|
||||
LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))`
|
||||
|
||||
error: aborting due to 44 previous errors
|
||||
error: aborting due to 43 previous errors
|
||||
|
||||
|
@ -53,7 +53,7 @@ fn resize_vector() {
|
||||
vec1.resize(10, 0);
|
||||
}
|
||||
|
||||
fn do_stuff(vec: &mut Vec<u8>) {}
|
||||
fn do_stuff(vec: &mut [u8]) {}
|
||||
|
||||
fn extend_vector_with_manipulations_between() {
|
||||
let len = 300;
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![warn(clippy::temporary_assignment)]
|
||||
#![allow(const_item_mutation)]
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:48:5
|
||||
--> $DIR/temporary_assignment.rs:47:5
|
||||
|
|
||||
LL | Struct { field: 0 }.field = 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -7,7 +7,7 @@ LL | Struct { field: 0 }.field = 1;
|
||||
= note: `-D clippy::temporary-assignment` implied by `-D warnings`
|
||||
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:49:5
|
||||
--> $DIR/temporary_assignment.rs:48:5
|
||||
|
|
||||
LL | / MultiStruct {
|
||||
LL | | structure: Struct { field: 0 },
|
||||
@ -17,13 +17,13 @@ LL | | .field = 1;
|
||||
| |______________^
|
||||
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:54:5
|
||||
--> $DIR/temporary_assignment.rs:53:5
|
||||
|
|
||||
LL | ArrayStruct { array: [0] }.array[0] = 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:55:5
|
||||
--> $DIR/temporary_assignment.rs:54:5
|
||||
|
|
||||
LL | (0, 0).0 = 1;
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![deny(clippy::trait_duplication_in_bounds)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
|
||||
|
||||
fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
|
||||
@ -73,4 +74,25 @@ impl U for Life {
|
||||
fn f() {}
|
||||
}
|
||||
|
||||
// should not warn
|
||||
trait Iter: Iterator {
|
||||
fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
|
||||
where
|
||||
Self: Iterator<Item = (K, V)> + Sized,
|
||||
K: Ord + Eq,
|
||||
{
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo {}
|
||||
|
||||
trait FooIter: Iterator<Item = Foo> {
|
||||
fn bar()
|
||||
where
|
||||
Self: Iterator<Item = Foo>,
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: this trait bound is already specified in the where clause
|
||||
--> $DIR/trait_duplication_in_bounds.rs:5:15
|
||||
--> $DIR/trait_duplication_in_bounds.rs:6:15
|
||||
|
|
||||
LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
|
||||
| ^^^^^
|
||||
@ -12,7 +12,7 @@ LL | #![deny(clippy::trait_duplication_in_bounds)]
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: this trait bound is already specified in the where clause
|
||||
--> $DIR/trait_duplication_in_bounds.rs:5:23
|
||||
--> $DIR/trait_duplication_in_bounds.rs:6:23
|
||||
|
|
||||
LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
|
||||
| ^^^^^^^
|
||||
@ -20,7 +20,7 @@ LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: this trait bound is already specified in trait declaration
|
||||
--> $DIR/trait_duplication_in_bounds.rs:34:15
|
||||
--> $DIR/trait_duplication_in_bounds.rs:35:15
|
||||
|
|
||||
LL | Self: Default;
|
||||
| ^^^^^^^
|
||||
@ -28,7 +28,7 @@ LL | Self: Default;
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: this trait bound is already specified in trait declaration
|
||||
--> $DIR/trait_duplication_in_bounds.rs:48:15
|
||||
--> $DIR/trait_duplication_in_bounds.rs:49:15
|
||||
|
|
||||
LL | Self: Default + Clone;
|
||||
| ^^^^^^^
|
||||
@ -36,7 +36,7 @@ LL | Self: Default + Clone;
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: this trait bound is already specified in trait declaration
|
||||
--> $DIR/trait_duplication_in_bounds.rs:54:15
|
||||
--> $DIR/trait_duplication_in_bounds.rs:55:15
|
||||
|
|
||||
LL | Self: Default + Clone;
|
||||
| ^^^^^^^
|
||||
@ -44,7 +44,7 @@ LL | Self: Default + Clone;
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: this trait bound is already specified in trait declaration
|
||||
--> $DIR/trait_duplication_in_bounds.rs:54:25
|
||||
--> $DIR/trait_duplication_in_bounds.rs:55:25
|
||||
|
|
||||
LL | Self: Default + Clone;
|
||||
| ^^^^^
|
||||
@ -52,12 +52,20 @@ LL | Self: Default + Clone;
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: this trait bound is already specified in trait declaration
|
||||
--> $DIR/trait_duplication_in_bounds.rs:57:15
|
||||
--> $DIR/trait_duplication_in_bounds.rs:58:15
|
||||
|
|
||||
LL | Self: Default;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: this trait bound is already specified in trait declaration
|
||||
--> $DIR/trait_duplication_in_bounds.rs:93:15
|
||||
|
|
||||
LL | Self: Iterator<Item = Foo>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider removing this trait bound
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![warn(clippy::unnecessary_cast)]
|
||||
#![allow(clippy::no_effect)]
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
// Test cast_unnecessary
|
||||
1i32 as i32;
|
||||
@ -8,6 +9,12 @@ fn main() {
|
||||
false as bool;
|
||||
&1i32 as &i32;
|
||||
|
||||
-1_i32 as i32;
|
||||
- 1_i32 as i32;
|
||||
-1f32 as f32;
|
||||
1_i32 as i32;
|
||||
1_f32 as f32;
|
||||
|
||||
// macro version
|
||||
macro_rules! foo {
|
||||
($a:ident, $b:ident) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: casting integer literal to `i32` is unnecessary
|
||||
--> $DIR/unnecessary_cast.rs:6:5
|
||||
--> $DIR/unnecessary_cast.rs:7:5
|
||||
|
|
||||
LL | 1i32 as i32;
|
||||
| ^^^^^^^^^^^ help: try: `1_i32`
|
||||
@ -7,16 +7,46 @@ LL | 1i32 as i32;
|
||||
= note: `-D clippy::unnecessary-cast` implied by `-D warnings`
|
||||
|
||||
error: casting float literal to `f32` is unnecessary
|
||||
--> $DIR/unnecessary_cast.rs:7:5
|
||||
--> $DIR/unnecessary_cast.rs:8:5
|
||||
|
|
||||
LL | 1f32 as f32;
|
||||
| ^^^^^^^^^^^ help: try: `1_f32`
|
||||
|
||||
error: casting to the same type is unnecessary (`bool` -> `bool`)
|
||||
--> $DIR/unnecessary_cast.rs:8:5
|
||||
--> $DIR/unnecessary_cast.rs:9:5
|
||||
|
|
||||
LL | false as bool;
|
||||
| ^^^^^^^^^^^^^ help: try: `false`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: casting integer literal to `i32` is unnecessary
|
||||
--> $DIR/unnecessary_cast.rs:12:5
|
||||
|
|
||||
LL | -1_i32 as i32;
|
||||
| ^^^^^^^^^^^^^ help: try: `-1_i32`
|
||||
|
||||
error: casting integer literal to `i32` is unnecessary
|
||||
--> $DIR/unnecessary_cast.rs:13:5
|
||||
|
|
||||
LL | - 1_i32 as i32;
|
||||
| ^^^^^^^^^^^^^^ help: try: `- 1_i32`
|
||||
|
||||
error: casting float literal to `f32` is unnecessary
|
||||
--> $DIR/unnecessary_cast.rs:14:5
|
||||
|
|
||||
LL | -1f32 as f32;
|
||||
| ^^^^^^^^^^^^ help: try: `-1_f32`
|
||||
|
||||
error: casting integer literal to `i32` is unnecessary
|
||||
--> $DIR/unnecessary_cast.rs:15:5
|
||||
|
|
||||
LL | 1_i32 as i32;
|
||||
| ^^^^^^^^^^^^ help: try: `1_i32`
|
||||
|
||||
error: casting float literal to `f32` is unnecessary
|
||||
--> $DIR/unnecessary_cast.rs:16:5
|
||||
|
|
||||
LL | 1_f32 as f32;
|
||||
| ^^^^^^^^^^^^ help: try: `1_f32`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
// run-rustfix
|
||||
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![allow(unused_variables, dead_code)]
|
||||
|
||||
struct Outer {
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
#[deny(clippy::ref_in_deref)]
|
||||
fn main() {
|
||||
let outer = Outer { inner: 0 };
|
||||
let inner = outer.inner;
|
||||
}
|
||||
|
||||
struct Apple;
|
||||
impl Apple {
|
||||
fn hello(&self) {}
|
||||
}
|
||||
struct Package(pub *const Apple);
|
||||
fn foobar(package: *const Package) {
|
||||
unsafe { &*(*package).0 }.hello();
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
// run-rustfix
|
||||
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![allow(unused_variables, dead_code)]
|
||||
|
||||
struct Outer {
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
#[deny(clippy::ref_in_deref)]
|
||||
fn main() {
|
||||
let outer = Outer { inner: 0 };
|
||||
let inner = (&outer).inner;
|
||||
}
|
||||
|
||||
struct Apple;
|
||||
impl Apple {
|
||||
fn hello(&self) {}
|
||||
}
|
||||
struct Package(pub *const Apple);
|
||||
fn foobar(package: *const Package) {
|
||||
unsafe { &*(&*package).0 }.hello();
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
error: creating a reference that is immediately dereferenced
|
||||
--> $DIR/unnecessary_ref.rs:13:17
|
||||
|
|
||||
LL | let inner = (&outer).inner;
|
||||
| ^^^^^^^^ help: try this: `outer`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unnecessary_ref.rs:10:8
|
||||
|
|
||||
LL | #[deny(clippy::ref_in_deref)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: creating a reference that is immediately dereferenced
|
||||
--> $DIR/unnecessary_ref.rs:22:16
|
||||
|
|
||||
LL | unsafe { &*(&*package).0 }.hello();
|
||||
| ^^^^^^^^^^^ help: try this: `(*package)`
|
||||
|
|
||||
= note: `-D clippy::ref-in-deref` implied by `-D warnings`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -67,7 +67,7 @@ fn not_ok() {
|
||||
foo_rslice(mrrrrrslice);
|
||||
foo_rslice(mrrrrrslice);
|
||||
}
|
||||
#[allow(unused_parens, clippy::double_parens)]
|
||||
#[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)]
|
||||
foo_rrrrmr((&&&&MoreRef));
|
||||
|
||||
generic_not_ok(mrslice);
|
||||
|
@ -67,7 +67,7 @@ fn not_ok() {
|
||||
foo_rslice(mrrrrrslice.as_ref());
|
||||
foo_rslice(mrrrrrslice);
|
||||
}
|
||||
#[allow(unused_parens, clippy::double_parens)]
|
||||
#[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)]
|
||||
foo_rrrrmr((&&&&MoreRef).as_ref());
|
||||
|
||||
generic_not_ok(mrslice);
|
||||
|
@ -7,37 +7,37 @@ fn main() {
|
||||
let mut v = Vec::new();
|
||||
|
||||
// these should be fine
|
||||
write!(&mut v, "Hello");
|
||||
writeln!(&mut v, "Hello");
|
||||
write!(v, "Hello");
|
||||
writeln!(v, "Hello");
|
||||
let world = "world";
|
||||
writeln!(&mut v, "Hello {}", world);
|
||||
writeln!(&mut v, "Hello {world}", world = world);
|
||||
writeln!(&mut v, "3 in hex is {:X}", 3);
|
||||
writeln!(&mut v, "2 + 1 = {:.4}", 3);
|
||||
writeln!(&mut v, "2 + 1 = {:5.4}", 3);
|
||||
writeln!(&mut v, "Debug test {:?}", "hello, world");
|
||||
writeln!(&mut v, "{0:8} {1:>8}", "hello", "world");
|
||||
writeln!(&mut v, "{1:8} {0:>8}", "hello", "world");
|
||||
writeln!(&mut v, "{foo:8} {bar:>8}", foo = "hello", bar = "world");
|
||||
writeln!(&mut v, "{bar:8} {foo:>8}", foo = "hello", bar = "world");
|
||||
writeln!(&mut v, "{number:>width$}", number = 1, width = 6);
|
||||
writeln!(&mut v, "{number:>0width$}", number = 1, width = 6);
|
||||
writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
|
||||
writeln!(&mut v, "10 / 4 is {}", 2.5);
|
||||
writeln!(&mut v, "2 + 1 = {}", 3);
|
||||
writeln!(v, "Hello {}", world);
|
||||
writeln!(v, "Hello {world}", world = world);
|
||||
writeln!(v, "3 in hex is {:X}", 3);
|
||||
writeln!(v, "2 + 1 = {:.4}", 3);
|
||||
writeln!(v, "2 + 1 = {:5.4}", 3);
|
||||
writeln!(v, "Debug test {:?}", "hello, world");
|
||||
writeln!(v, "{0:8} {1:>8}", "hello", "world");
|
||||
writeln!(v, "{1:8} {0:>8}", "hello", "world");
|
||||
writeln!(v, "{foo:8} {bar:>8}", foo = "hello", bar = "world");
|
||||
writeln!(v, "{bar:8} {foo:>8}", foo = "hello", bar = "world");
|
||||
writeln!(v, "{number:>width$}", number = 1, width = 6);
|
||||
writeln!(v, "{number:>0width$}", number = 1, width = 6);
|
||||
writeln!(v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
|
||||
writeln!(v, "10 / 4 is {}", 2.5);
|
||||
writeln!(v, "2 + 1 = {}", 3);
|
||||
|
||||
// these should throw warnings
|
||||
write!(&mut v, "Hello {}", "world");
|
||||
writeln!(&mut v, "Hello {} {}", world, "world");
|
||||
writeln!(&mut v, "Hello {}", "world");
|
||||
write!(v, "Hello {}", "world");
|
||||
writeln!(v, "Hello {} {}", world, "world");
|
||||
writeln!(v, "Hello {}", "world");
|
||||
|
||||
// positional args don't change the fact
|
||||
// that we're using a literal -- this should
|
||||
// throw a warning
|
||||
writeln!(&mut v, "{0} {1}", "hello", "world");
|
||||
writeln!(&mut v, "{1} {0}", "hello", "world");
|
||||
writeln!(v, "{0} {1}", "hello", "world");
|
||||
writeln!(v, "{1} {0}", "hello", "world");
|
||||
|
||||
// named args shouldn't change anything either
|
||||
writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
}
|
||||
|
@ -1,134 +1,134 @@
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:30:32
|
||||
--> $DIR/write_literal.rs:30:27
|
||||
|
|
||||
LL | write!(&mut v, "Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
LL | write!(v, "Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::write-literal` implied by `-D warnings`
|
||||
help: try this
|
||||
|
|
||||
LL - write!(&mut v, "Hello {}", "world");
|
||||
LL + write!(&mut v, "Hello world");
|
||||
LL - write!(v, "Hello {}", "world");
|
||||
LL + write!(v, "Hello world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:31:44
|
||||
--> $DIR/write_literal.rs:31:39
|
||||
|
|
||||
LL | writeln!(&mut v, "Hello {} {}", world, "world");
|
||||
| ^^^^^^^
|
||||
LL | writeln!(v, "Hello {} {}", world, "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "Hello {} {}", world, "world");
|
||||
LL + writeln!(&mut v, "Hello {} world", world);
|
||||
LL - writeln!(v, "Hello {} {}", world, "world");
|
||||
LL + writeln!(v, "Hello {} world", world);
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:32:34
|
||||
--> $DIR/write_literal.rs:32:29
|
||||
|
|
||||
LL | writeln!(&mut v, "Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
LL | writeln!(v, "Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "Hello {}", "world");
|
||||
LL + writeln!(&mut v, "Hello world");
|
||||
LL - writeln!(v, "Hello {}", "world");
|
||||
LL + writeln!(v, "Hello world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:37:33
|
||||
--> $DIR/write_literal.rs:37:28
|
||||
|
|
||||
LL | writeln!(&mut v, "{0} {1}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
LL | writeln!(v, "{0} {1}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{0} {1}", "hello", "world");
|
||||
LL + writeln!(&mut v, "hello {1}", "world");
|
||||
LL - writeln!(v, "{0} {1}", "hello", "world");
|
||||
LL + writeln!(v, "hello {1}", "world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:37:42
|
||||
--> $DIR/write_literal.rs:37:37
|
||||
|
|
||||
LL | writeln!(&mut v, "{0} {1}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
LL | writeln!(v, "{0} {1}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{0} {1}", "hello", "world");
|
||||
LL + writeln!(&mut v, "{0} world", "hello");
|
||||
LL - writeln!(v, "{0} {1}", "hello", "world");
|
||||
LL + writeln!(v, "{0} world", "hello");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:38:33
|
||||
--> $DIR/write_literal.rs:38:28
|
||||
|
|
||||
LL | writeln!(&mut v, "{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
LL | writeln!(v, "{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{1} {0}", "hello", "world");
|
||||
LL + writeln!(&mut v, "{1} hello", "world");
|
||||
LL - writeln!(v, "{1} {0}", "hello", "world");
|
||||
LL + writeln!(v, "{1} hello", "world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:38:42
|
||||
--> $DIR/write_literal.rs:38:37
|
||||
|
|
||||
LL | writeln!(&mut v, "{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
LL | writeln!(v, "{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{1} {0}", "hello", "world");
|
||||
LL + writeln!(&mut v, "world {0}", "hello");
|
||||
LL - writeln!(v, "{1} {0}", "hello", "world");
|
||||
LL + writeln!(v, "world {0}", "hello");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:41:37
|
||||
--> $DIR/write_literal.rs:41:32
|
||||
|
|
||||
LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
LL + writeln!(&mut v, "hello {bar}", bar = "world");
|
||||
LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
LL + writeln!(v, "hello {bar}", bar = "world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:41:52
|
||||
--> $DIR/write_literal.rs:41:47
|
||||
|
|
||||
LL | writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
LL + writeln!(&mut v, "{foo} world", foo = "hello");
|
||||
LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
|
||||
LL + writeln!(v, "{foo} world", foo = "hello");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:42:37
|
||||
--> $DIR/write_literal.rs:42:32
|
||||
|
|
||||
LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
LL + writeln!(&mut v, "{bar} hello", bar = "world");
|
||||
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
LL + writeln!(v, "{bar} hello", bar = "world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/write_literal.rs:42:52
|
||||
--> $DIR/write_literal.rs:42:47
|
||||
|
|
||||
LL | writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
LL + writeln!(&mut v, "world {foo}", foo = "hello");
|
||||
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
|
||||
LL + writeln!(v, "world {foo}", foo = "hello");
|
||||
|
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
@ -6,20 +6,20 @@ use std::io::Write;
|
||||
fn main() {
|
||||
let mut v = Vec::new();
|
||||
|
||||
writeln!(&mut v, "{}", "{hello}");
|
||||
writeln!(&mut v, r"{}", r"{hello}");
|
||||
writeln!(&mut v, "{}", '\'');
|
||||
writeln!(&mut v, "{}", '"');
|
||||
writeln!(&mut v, r"{}", '"'); // don't lint
|
||||
writeln!(&mut v, r"{}", '\'');
|
||||
writeln!(v, "{}", "{hello}");
|
||||
writeln!(v, r"{}", r"{hello}");
|
||||
writeln!(v, "{}", '\'');
|
||||
writeln!(v, "{}", '"');
|
||||
writeln!(v, r"{}", '"'); // don't lint
|
||||
writeln!(v, r"{}", '\'');
|
||||
writeln!(
|
||||
&mut v,
|
||||
v,
|
||||
"some {}",
|
||||
"hello \
|
||||
world!"
|
||||
);
|
||||
writeln!(
|
||||
&mut v,
|
||||
v,
|
||||
"some {}\
|
||||
{} \\ {}",
|
||||
"1", "2", "3",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user