mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Merge commit '23d11428de3e973b34a5090a78d62887f821c90e' into clippyup
This commit is contained in:
parent
b2f8a27ff2
commit
ece0946d7f
4
.gitignore
vendored
4
.gitignore
vendored
@ -27,9 +27,11 @@ out
|
||||
# Generated by dogfood
|
||||
/target_recur/
|
||||
|
||||
# Generated by lintcheck
|
||||
/lintcheck-logs
|
||||
|
||||
# gh pages docs
|
||||
util/gh-pages/lints.json
|
||||
**/metadata_collection.json
|
||||
|
||||
# rustfmt backups
|
||||
*.rs.bk
|
||||
|
@ -3118,6 +3118,7 @@ Released 2018-09-13
|
||||
[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
|
||||
[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
|
||||
[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
|
||||
[`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
|
||||
[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
|
||||
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
|
||||
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
|
||||
@ -3209,6 +3210,7 @@ Released 2018-09-13
|
||||
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
|
||||
[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
|
||||
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
|
||||
[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
|
||||
[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
|
||||
[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
|
||||
[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
|
||||
|
@ -162,7 +162,8 @@ define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
|
||||
|
||||
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
|
||||
|
||||
* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`)
|
||||
* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
|
||||
Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
|
||||
|
||||
* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
|
||||
`#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
|
||||
|
@ -65,6 +65,7 @@ declare_clippy_lint! {
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// # use std::arch::asm;
|
||||
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
|
||||
/// # }
|
||||
/// ```
|
||||
@ -72,6 +73,7 @@ declare_clippy_lint! {
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// # use std::arch::asm;
|
||||
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
|
||||
/// # }
|
||||
/// ```
|
||||
@ -102,6 +104,7 @@ declare_clippy_lint! {
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// # use std::arch::asm;
|
||||
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
|
||||
/// # }
|
||||
/// ```
|
||||
@ -109,6 +112,7 @@ declare_clippy_lint! {
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// # use std::arch::asm;
|
||||
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
|
||||
/// # }
|
||||
/// ```
|
||||
|
@ -2,7 +2,7 @@ use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
|
||||
use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call, peel_blocks};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -122,15 +122,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
|
||||
if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
|
||||
// bind the first argument of the `assert!` macro
|
||||
if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
|
||||
// block
|
||||
if let ExprKind::Block(block, _) = then.kind;
|
||||
if block.stmts.is_empty();
|
||||
if let Some(block_expr) = &block.expr;
|
||||
// inner block is optional. unwrap it if it exists, or use the expression as is otherwise.
|
||||
if let Some(begin_panic_call) = match block_expr.kind {
|
||||
ExprKind::Block(inner_block, _) => &inner_block.expr,
|
||||
_ => &block.expr,
|
||||
};
|
||||
let begin_panic_call = peel_blocks(then);
|
||||
// function call
|
||||
if let Some(arg) = match_panic_call(cx, begin_panic_call);
|
||||
// bind the second argument of the `assert!` macro if it exists
|
||||
|
@ -73,9 +73,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
|
||||
|
||||
let body = self.cx.tcx.hir().body(eid);
|
||||
let ex = &body.value;
|
||||
if matches!(ex.kind, ExprKind::Block(_, _)) && !body.value.span.from_expansion() {
|
||||
self.found_block = Some(ex);
|
||||
return;
|
||||
if let ExprKind::Block(block, _) = ex.kind {
|
||||
if !body.value.span.from_expansion() && !block.stmts.is_empty() {
|
||||
self.found_block = Some(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
walk_expr(self, expr);
|
||||
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::match_type;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{path_to_local_id, paths, peel_ref_operators, remove_blocks, strip_pat_refs};
|
||||
use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
|
||||
@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(count, _, [count_recv], _) = expr.kind;
|
||||
if count.ident.name == sym!(count);
|
||||
if count.ident.name == sym::count;
|
||||
if let ExprKind::MethodCall(filter, _, [filter_recv, filter_arg], _) = count_recv.kind;
|
||||
if filter.ident.name == sym!(filter);
|
||||
if let ExprKind::Closure(_, _, body_id, _, _) = filter_arg.kind;
|
||||
@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
|
||||
cx.typeck_results().expr_ty(filter_recv).peel_refs(),
|
||||
&paths::SLICE_ITER);
|
||||
let operand_is_arg = |expr| {
|
||||
let expr = peel_ref_operators(cx, remove_blocks(expr));
|
||||
let expr = peel_ref_operators(cx, peel_blocks(expr));
|
||||
path_to_local_id(expr, arg_id)
|
||||
};
|
||||
let needle = if operand_is_arg(l) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLetOrMatch;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_ref_operators, SpanlessEq};
|
||||
use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::LangItem::OptionNone;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind};
|
||||
use rustc_hir::{Arm, Expr, Guard, HirId, Pat, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
@ -75,7 +75,7 @@ fn check_arm<'tcx>(
|
||||
outer_guard: Option<&'tcx Guard<'tcx>>,
|
||||
outer_else_body: Option<&'tcx Expr<'tcx>>,
|
||||
) {
|
||||
let inner_expr = strip_singleton_blocks(outer_then_body);
|
||||
let inner_expr = peel_blocks_with_stmt(outer_then_body);
|
||||
if_chain! {
|
||||
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr);
|
||||
if let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
|
||||
@ -138,20 +138,6 @@ fn check_arm<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
|
||||
while let ExprKind::Block(block, _) = expr.kind {
|
||||
match (block.stmts, block.expr) {
|
||||
([stmt], None) => match stmt.kind {
|
||||
StmtKind::Expr(e) | StmtKind::Semi(e) => expr = e,
|
||||
_ => break,
|
||||
},
|
||||
([], Some(e)) => expr = e,
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
||||
/// A "wild-like" arm has a wild (`_`) or `None` pattern and no guard. Such arms can be "collapsed"
|
||||
/// into a single wild arm without any significant loss in semantics or readability.
|
||||
fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::{is_automatically_derived, is_default_equivalent, remove_blocks};
|
||||
use clippy_utils::{is_automatically_derived, is_default_equivalent, peel_blocks};
|
||||
use rustc_hir::{
|
||||
def::{DefKind, Res},
|
||||
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
|
||||
@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
||||
}
|
||||
}
|
||||
}
|
||||
let should_emit = match remove_blocks(func_expr).kind {
|
||||
let should_emit = match peel_blocks(func_expr).kind {
|
||||
ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
|
||||
ExprKind::Call(callee, args)
|
||||
if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
|
||||
|
@ -4,7 +4,7 @@ use clippy_utils::consts::{
|
||||
};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, sugg};
|
||||
use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
|
||||
@ -546,13 +546,9 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a
|
||||
|
||||
fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
|
||||
if let ExprKind::Block(block, _) = then.kind;
|
||||
if block.stmts.is_empty();
|
||||
if let Some(if_body_expr) = block.expr;
|
||||
if let Some(ExprKind::Block(else_block, _)) = r#else.map(|el| &el.kind);
|
||||
if else_block.stmts.is_empty();
|
||||
if let Some(else_body_expr) = else_block.expr;
|
||||
if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr);
|
||||
let if_body_expr = peel_blocks(then);
|
||||
let else_body_expr = peel_blocks(r#else);
|
||||
if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr);
|
||||
then {
|
||||
let positive_abs_sugg = (
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet_with_macro_callsite;
|
||||
use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs};
|
||||
use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
|
||||
@ -77,10 +77,7 @@ impl LateLintPass<'_> for IfThenSomeElseNone {
|
||||
if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
|
||||
if let ExprKind::Path(ref then_call_qpath) = then_call.kind;
|
||||
if is_lang_ctor(cx, then_call_qpath, OptionSome);
|
||||
if let ExprKind::Block(els_block, _) = els.kind;
|
||||
if els_block.stmts.is_empty();
|
||||
if let Some(els_expr) = els_block.expr;
|
||||
if let ExprKind::Path(ref qpath) = els_expr.kind;
|
||||
if let ExprKind::Path(ref qpath) = peel_blocks(els).kind;
|
||||
if is_lang_ctor(cx, qpath, OptionNone);
|
||||
if !stmts_contains_early_return(then_block.stmts);
|
||||
then {
|
||||
|
@ -1,10 +1,9 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::SpanlessEq;
|
||||
use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath, StmtKind};
|
||||
use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -52,13 +51,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
||||
// Ensure that the binary operator is >, != and <
|
||||
if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node;
|
||||
|
||||
// Check if the true condition block has only one statement
|
||||
if let ExprKind::Block(block, _) = then.kind;
|
||||
if block.stmts.len() == 1 && block.expr.is_none();
|
||||
|
||||
// Check if assign operation is done
|
||||
if let StmtKind::Semi(e) = block.stmts[0].kind;
|
||||
if let Some(target) = subtracts_one(cx, e);
|
||||
if let Some(target) = subtracts_one(cx, then);
|
||||
|
||||
// Extracting out the variable name
|
||||
if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind;
|
||||
@ -138,8 +132,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
||||
}
|
||||
}
|
||||
|
||||
fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<'a>> {
|
||||
match expr.kind {
|
||||
fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
|
||||
match peel_blocks_with_stmt(expr).kind {
|
||||
ExprKind::AssignOp(ref op1, target, value) => {
|
||||
if_chain! {
|
||||
if BinOpKind::Sub == op1.node;
|
||||
|
@ -181,6 +181,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNNECESSARY_TO_OWNED),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::USELESS_ASREF),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
@ -220,7 +221,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
|
||||
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
|
||||
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
|
||||
LintId::of(octal_escapes::OCTAL_ESCAPES),
|
||||
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
|
||||
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
|
||||
@ -246,6 +246,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(reference::REF_IN_DEREF),
|
||||
LintId::of(regex::INVALID_REGEX),
|
||||
LintId::of(repeat_once::REPEAT_ONCE),
|
||||
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
|
||||
LintId::of(returns::LET_AND_RETURN),
|
||||
LintId::of(returns::NEEDLESS_RETURN),
|
||||
LintId::of(self_assignment::SELF_ASSIGNMENT),
|
||||
|
@ -315,6 +315,7 @@ store.register_lints(&[
|
||||
methods::UNNECESSARY_FILTER_MAP,
|
||||
methods::UNNECESSARY_FOLD,
|
||||
methods::UNNECESSARY_LAZY_EVALUATIONS,
|
||||
methods::UNNECESSARY_TO_OWNED,
|
||||
methods::UNWRAP_OR_ELSE_DEFAULT,
|
||||
methods::UNWRAP_USED,
|
||||
methods::USELESS_ASREF,
|
||||
@ -422,6 +423,7 @@ store.register_lints(&[
|
||||
regex::INVALID_REGEX,
|
||||
regex::TRIVIAL_REGEX,
|
||||
repeat_once::REPEAT_ONCE,
|
||||
return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
|
||||
returns::LET_AND_RETURN,
|
||||
returns::NEEDLESS_RETURN,
|
||||
same_name_method::SAME_NAME_METHOD,
|
||||
|
@ -18,6 +18,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
|
||||
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
|
||||
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
|
||||
LintId::of(mutex_atomic::MUTEX_INTEGER),
|
||||
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
|
||||
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
|
||||
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
|
||||
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
|
||||
|
@ -17,6 +17,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
|
||||
LintId::of(methods::MANUAL_STR_REPEAT),
|
||||
LintId::of(methods::OR_FUN_CALL),
|
||||
LintId::of(methods::SINGLE_CHAR_PATTERN),
|
||||
LintId::of(methods::UNNECESSARY_TO_OWNED),
|
||||
LintId::of(misc::CMP_OWNED),
|
||||
LintId::of(mutex_atomic::MUTEX_ATOMIC),
|
||||
LintId::of(redundant_clone::REDUNDANT_CLONE),
|
||||
|
@ -15,8 +15,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
|
||||
LintId::of(loops::MUT_RANGE_BOUND),
|
||||
LintId::of(methods::SUSPICIOUS_MAP),
|
||||
LintId::of(mut_key::MUTABLE_KEY_TYPE),
|
||||
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
|
||||
LintId::of(octal_escapes::OCTAL_ESCAPES),
|
||||
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
|
||||
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
|
||||
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
|
||||
])
|
||||
|
@ -340,6 +340,7 @@ mod ref_option_ref;
|
||||
mod reference;
|
||||
mod regex;
|
||||
mod repeat_once;
|
||||
mod return_self_not_must_use;
|
||||
mod returns;
|
||||
mod same_name_method;
|
||||
mod self_assignment;
|
||||
@ -852,6 +853,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
|
||||
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
|
||||
store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
|
||||
store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ declare_clippy_lint! {
|
||||
///
|
||||
/// ### Known problems
|
||||
/// - We bail out if the function has a `where` clause where lifetimes
|
||||
/// are mentioned due to potenial false positives.
|
||||
/// are mentioned due to potential false positives.
|
||||
/// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
|
||||
/// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
|
||||
///
|
||||
|
@ -3,11 +3,11 @@ use super::MANUAL_FLATTEN;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{is_lang_ctor, path_to_local_id};
|
||||
use clippy_utils::{is_lang_ctor, path_to_local_id, peel_blocks_with_stmt};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionSome, ResultOk};
|
||||
use rustc_hir::{Expr, ExprKind, Pat, PatKind, StmtKind};
|
||||
use rustc_hir::{Expr, Pat, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::source_map::Span;
|
||||
@ -21,71 +21,55 @@ pub(super) fn check<'tcx>(
|
||||
body: &'tcx Expr<'_>,
|
||||
span: Span,
|
||||
) {
|
||||
if let ExprKind::Block(block, _) = body.kind {
|
||||
// Ensure the `if let` statement is the only expression or statement in the for-loop
|
||||
let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() {
|
||||
let match_stmt = &block.stmts[0];
|
||||
if let StmtKind::Semi(inner_expr) = match_stmt.kind {
|
||||
Some(inner_expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if block.stmts.is_empty() {
|
||||
block.expr
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let inner_expr = peel_blocks_with_stmt(body);
|
||||
if_chain! {
|
||||
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
|
||||
= higher::IfLet::hir(cx, inner_expr);
|
||||
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
|
||||
if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
|
||||
if path_to_local_id(let_expr, pat_hir_id);
|
||||
// Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
|
||||
if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
|
||||
let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
|
||||
let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
|
||||
if some_ctor || ok_ctor;
|
||||
// Ensure expr in `if let` is not used afterwards
|
||||
if !is_local_used(cx, if_then, pat_hir_id);
|
||||
then {
|
||||
let if_let_type = if some_ctor { "Some" } else { "Ok" };
|
||||
// Prepare the error message
|
||||
let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
|
||||
|
||||
if_chain! {
|
||||
if let Some(inner_expr) = inner_expr;
|
||||
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
|
||||
= higher::IfLet::hir(cx, inner_expr);
|
||||
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
|
||||
if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
|
||||
if path_to_local_id(let_expr, pat_hir_id);
|
||||
// Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
|
||||
if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
|
||||
let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
|
||||
let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
|
||||
if some_ctor || ok_ctor;
|
||||
// Ensure epxr in `if let` is not used afterwards
|
||||
if !is_local_used(cx, if_then, pat_hir_id);
|
||||
then {
|
||||
let if_let_type = if some_ctor { "Some" } else { "Ok" };
|
||||
// Prepare the error message
|
||||
let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
|
||||
|
||||
// Prepare the help message
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
|
||||
let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
|
||||
ty::Ref(_, inner, _) => match inner.kind() {
|
||||
ty::Ref(..) => ".copied()",
|
||||
_ => ""
|
||||
}
|
||||
// Prepare the help message
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
|
||||
let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
|
||||
ty::Ref(_, inner, _) => match inner.kind() {
|
||||
ty::Ref(..) => ".copied()",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
_ => ""
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_FLATTEN,
|
||||
span,
|
||||
&msg,
|
||||
|diag| {
|
||||
let sugg = format!("{}{}.flatten()", arg_snippet, copied);
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"try",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.span_help(
|
||||
inner_expr.span,
|
||||
"...and remove the `if let` statement in the for loop",
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_FLATTEN,
|
||||
span,
|
||||
&msg,
|
||||
|diag| {
|
||||
let sugg = format!("{}{}.flatten()", arg_snippet, copied);
|
||||
diag.span_suggestion(
|
||||
arg.span,
|
||||
"try",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.span_help(
|
||||
inner_expr.span,
|
||||
"...and remove the `if let` statement in the for loop",
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,9 +92,7 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
|
||||
}
|
||||
|
||||
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
let stmts = block.stmts.iter().map(stmt_to_expr);
|
||||
let expr = once(block.expr);
|
||||
let mut iter = stmts.chain(expr).flatten();
|
||||
let mut iter = block.stmts.iter().filter_map(stmt_to_expr).chain(block.expr);
|
||||
never_loop_expr_seq(&mut iter, main_loop_id)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
|
||||
use clippy_utils::{
|
||||
can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id,
|
||||
peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
|
||||
peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
|
||||
};
|
||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||
use rustc_errors::Applicability;
|
||||
@ -307,16 +307,5 @@ fn get_some_expr(
|
||||
|
||||
// Checks for the `None` value.
|
||||
fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
|
||||
ExprKind::Block(
|
||||
Block {
|
||||
stmts: [],
|
||||
expr: Some(expr),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) => is_none_expr(cx, expr),
|
||||
_ => false,
|
||||
}
|
||||
matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::remove_blocks;
|
||||
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 if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -60,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
|
||||
then {
|
||||
let closure_body = cx.tcx.hir().body(body_id);
|
||||
let closure_expr = remove_blocks(&closure_body.value);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
match closure_body.params[0].pat.kind {
|
||||
hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
|
||||
hir::BindingAnnotation::Unannotated, .., name, None
|
||||
|
@ -9,7 +9,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, pe
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{
|
||||
get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
|
||||
path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks,
|
||||
path_to_local, path_to_local_id, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
|
||||
strip_pat_refs,
|
||||
};
|
||||
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
|
||||
@ -658,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||
QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
|
||||
if args.len() == 1;
|
||||
if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
|
||||
let body = remove_blocks(arms[0].body);
|
||||
let body = peel_blocks(arms[0].body);
|
||||
if path_to_local_id(body, arg);
|
||||
|
||||
then {
|
||||
@ -723,7 +723,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
|
||||
return;
|
||||
}
|
||||
let els = arms[1].body;
|
||||
let els = if is_unit_expr(remove_blocks(els)) {
|
||||
let els = if is_unit_expr(peel_blocks(els)) {
|
||||
None
|
||||
} else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
|
||||
if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
|
||||
@ -1481,7 +1481,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
|
||||
|
||||
let matched_vars = ex.span;
|
||||
let bind_names = arms[0].pat.span;
|
||||
let match_body = remove_blocks(arms[0].body);
|
||||
let match_body = peel_blocks(arms[0].body);
|
||||
let mut snippet_body = if match_body.span.from_expansion() {
|
||||
Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
|
||||
} else {
|
||||
@ -1678,7 +1678,7 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotat
|
||||
if is_lang_ctor(cx, qpath, OptionSome);
|
||||
if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
|
||||
if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
|
||||
if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind;
|
||||
if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
|
||||
if let ExprKind::Path(ref some_path) = e.kind;
|
||||
if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
|
||||
if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{contains_return, BIND_INSTEAD_OF_MAP};
|
||||
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
|
||||
use clippy_utils::{remove_blocks, visitors::find_all_ret_expressions};
|
||||
use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -152,7 +152,7 @@ pub(crate) trait BindInsteadOfMap {
|
||||
match arg.kind {
|
||||
hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
|
||||
let closure_body = cx.tcx.hir().body(body_id);
|
||||
let closure_expr = remove_blocks(&closure_body.value);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
|
||||
if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
|
||||
true
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, SpanlessEq};
|
||||
use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -25,7 +25,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
|
||||
},
|
||||
hir::ExprKind::Closure(_, _, c, _, _) => {
|
||||
let body = cx.tcx.hir().body(*c);
|
||||
let closure_expr = remove_blocks(&body.value);
|
||||
let closure_expr = peel_blocks(&body.value);
|
||||
let arg_id = body.params[0].pat.hir_id;
|
||||
match closure_expr.kind {
|
||||
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, args, _) => {
|
||||
|
@ -12,15 +12,7 @@ use super::IMPLICIT_CLONE;
|
||||
pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) {
|
||||
if_chain! {
|
||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
||||
if match method_name {
|
||||
"to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
|
||||
"to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
|
||||
"to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
|
||||
"to_vec" => cx.tcx.impl_of_method(method_def_id)
|
||||
.map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl())
|
||||
== Some(true),
|
||||
_ => false,
|
||||
};
|
||||
if is_clone_like(cx, method_name, method_def_id);
|
||||
let return_type = cx.typeck_results().expr_ty(expr);
|
||||
let input_type = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did));
|
||||
@ -38,3 +30,22 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the named method can be used to clone the receiver.
|
||||
/// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
|
||||
/// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
|
||||
/// `is_to_owned_like` in `unnecessary_to_owned.rs`.
|
||||
pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool {
|
||||
match method_name {
|
||||
"to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
|
||||
"to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
|
||||
"to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
|
||||
"to_vec" => {
|
||||
cx.tcx
|
||||
.impl_of_method(method_def_id)
|
||||
.map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl())
|
||||
== Some(true)
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,9 @@ mod suspicious_splitn;
|
||||
mod uninit_assumed_init;
|
||||
mod unnecessary_filter_map;
|
||||
mod unnecessary_fold;
|
||||
mod unnecessary_iter_cloned;
|
||||
mod unnecessary_lazy_eval;
|
||||
mod unnecessary_to_owned;
|
||||
mod unwrap_or_else_default;
|
||||
mod unwrap_used;
|
||||
mod useless_asref;
|
||||
@ -1885,6 +1887,32 @@ declare_clippy_lint! {
|
||||
"usages of `str::splitn` that can be replaced with `str::split`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
|
||||
/// and other `to_owned`-like functions.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The unnecessary calls result in useless allocations.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let path = std::path::Path::new("x");
|
||||
/// foo(&path.to_string_lossy().to_string());
|
||||
/// fn foo(s: &str) {}
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let path = std::path::Path::new("x");
|
||||
/// foo(&path.to_string_lossy());
|
||||
/// fn foo(s: &str) {}
|
||||
/// ```
|
||||
#[clippy::version = "1.58.0"]
|
||||
pub UNNECESSARY_TO_OWNED,
|
||||
perf,
|
||||
"unnecessary calls to `to_owned`-like functions"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Option<RustcVersion>,
|
||||
@ -1964,7 +1992,8 @@ impl_lint_pass!(Methods => [
|
||||
MANUAL_STR_REPEAT,
|
||||
EXTEND_WITH_DRAIN,
|
||||
MANUAL_SPLIT_ONCE,
|
||||
NEEDLESS_SPLITN
|
||||
NEEDLESS_SPLITN,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
@ -2007,6 +2036,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
single_char_add_str::check(cx, expr, args);
|
||||
into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args);
|
||||
single_char_pattern::check(cx, expr, method_call.ident.name, args);
|
||||
unnecessary_to_owned::check(cx, expr, method_call.ident.name, args);
|
||||
},
|
||||
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
|
||||
let mut info = BinaryExprInfo {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, remove_blocks};
|
||||
use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -53,7 +53,7 @@ pub(super) fn check<'tcx>(
|
||||
}),
|
||||
hir::ExprKind::Closure(_, _, body_id, _, _) => {
|
||||
let closure_body = cx.tcx.hir().body(body_id);
|
||||
let closure_expr = remove_blocks(&closure_body.value);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
|
||||
match &closure_expr.kind {
|
||||
hir::ExprKind::MethodCall(_, _, args, _) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs};
|
||||
use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
@ -31,7 +31,7 @@ pub(super) fn check(
|
||||
// Extract the body of the closure passed to fold
|
||||
if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind;
|
||||
let closure_body = cx.tcx.hir().body(body_id);
|
||||
let closure_expr = remove_blocks(&closure_body.value);
|
||||
let closure_expr = peel_blocks(&closure_body.value);
|
||||
|
||||
// Check if the closure body is of the form `acc <op> some_expr(x)`
|
||||
if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
|
||||
|
177
clippy_lints/src/methods/unnecessary_iter_cloned.rs
Normal file
177
clippy_lints/src/methods/unnecessary_iter_cloned.rs
Normal file
@ -0,0 +1,177 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::ForLoop;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait};
|
||||
use clippy_utils::{fn_def_id, get_parent_expr, path_to_local_id, usage};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, HirId, LangItem, Mutability, Pat};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::{hir::map::Map, ty};
|
||||
use rustc_span::{sym, Symbol};
|
||||
|
||||
use super::UNNECESSARY_TO_OWNED;
|
||||
|
||||
pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) -> bool {
|
||||
if_chain! {
|
||||
if let Some(parent) = get_parent_expr(cx, expr);
|
||||
if let Some(callee_def_id) = fn_def_id(cx, parent);
|
||||
if is_into_iter(cx, callee_def_id);
|
||||
then {
|
||||
check_for_loop_iter(cx, parent, method_name, receiver)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether `expr` is an iterator in a `for` loop and, if so, determines whether the
|
||||
/// iterated-over items could be iterated over by reference. The reason why `check` above does not
|
||||
/// include this code directly is so that it can be called from
|
||||
/// `unnecessary_into_owned::check_into_iter_call_arg`.
|
||||
pub fn check_for_loop_iter(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
method_name: Symbol,
|
||||
receiver: &'tcx Expr<'tcx>,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent));
|
||||
if let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent);
|
||||
let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body);
|
||||
if !clone_or_copy_needed;
|
||||
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
||||
then {
|
||||
let snippet = if_chain! {
|
||||
if let ExprKind::MethodCall(maybe_iter_method_name, _, [collection], _) = receiver.kind;
|
||||
if maybe_iter_method_name.ident.name == sym::iter;
|
||||
|
||||
if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||
if implements_trait(cx, receiver_ty, iterator_trait_id, &[]);
|
||||
if let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty);
|
||||
|
||||
if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator);
|
||||
let collection_ty = cx.typeck_results().expr_ty(collection);
|
||||
if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]);
|
||||
if let Some(into_iter_item_ty) = get_associated_type(cx, collection_ty, into_iterator_trait_id, "Item");
|
||||
|
||||
if iter_item_ty == into_iter_item_ty;
|
||||
if let Some(collection_snippet) = snippet_opt(cx, collection.span);
|
||||
then {
|
||||
collection_snippet
|
||||
} else {
|
||||
receiver_snippet
|
||||
}
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
expr.span,
|
||||
&format!("unnecessary use of `{}`", method_name),
|
||||
|diag| {
|
||||
diag.span_suggestion(expr.span, "use", snippet, Applicability::MachineApplicable);
|
||||
for addr_of_expr in addr_of_exprs {
|
||||
match addr_of_expr.kind {
|
||||
ExprKind::AddrOf(_, _, referent) => {
|
||||
let span = addr_of_expr.span.with_hi(referent.span.lo());
|
||||
diag.span_suggestion(span, "remove this `&`", String::new(), Applicability::MachineApplicable);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// The core logic of `check_for_loop_iter` above, this function wraps a use of
|
||||
/// `CloneOrCopyVisitor`.
|
||||
fn clone_or_copy_needed(
|
||||
cx: &LateContext<'tcx>,
|
||||
pat: &Pat<'tcx>,
|
||||
body: &'tcx Expr<'tcx>,
|
||||
) -> (bool, Vec<&'tcx Expr<'tcx>>) {
|
||||
let mut visitor = CloneOrCopyVisitor {
|
||||
cx,
|
||||
binding_hir_ids: pat_bindings(pat),
|
||||
clone_or_copy_needed: false,
|
||||
addr_of_exprs: Vec::new(),
|
||||
};
|
||||
visitor.visit_expr(body);
|
||||
(visitor.clone_or_copy_needed, visitor.addr_of_exprs)
|
||||
}
|
||||
|
||||
/// Returns a vector of all `HirId`s bound by the pattern.
|
||||
fn pat_bindings(pat: &Pat<'_>) -> Vec<HirId> {
|
||||
let mut collector = usage::ParamBindingIdCollector {
|
||||
binding_hir_ids: Vec::new(),
|
||||
};
|
||||
collector.visit_pat(pat);
|
||||
collector.binding_hir_ids
|
||||
}
|
||||
|
||||
/// `clone_or_copy_needed` will be false when `CloneOrCopyVisitor` is done visiting if the only
|
||||
/// operations performed on `binding_hir_ids` are:
|
||||
/// * to take non-mutable references to them
|
||||
/// * to use them as non-mutable `&self` in method calls
|
||||
/// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true
|
||||
/// when `CloneOrCopyVisitor` is done visiting.
|
||||
struct CloneOrCopyVisitor<'cx, 'tcx> {
|
||||
cx: &'cx LateContext<'tcx>,
|
||||
binding_hir_ids: Vec<HirId>,
|
||||
clone_or_copy_needed: bool,
|
||||
addr_of_exprs: Vec<&'tcx Expr<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
walk_expr(self, expr);
|
||||
if self.is_binding(expr) {
|
||||
if let Some(parent) = get_parent_expr(self.cx, expr) {
|
||||
match parent.kind {
|
||||
ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => {
|
||||
self.addr_of_exprs.push(parent);
|
||||
return;
|
||||
},
|
||||
ExprKind::MethodCall(_, _, args, _) => {
|
||||
if_chain! {
|
||||
if args.iter().skip(1).all(|arg| !self.is_binding(arg));
|
||||
if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
|
||||
let method_ty = self.cx.tcx.type_of(method_def_id);
|
||||
let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
|
||||
if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not));
|
||||
then {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
self.clone_or_copy_needed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> {
|
||||
fn is_binding(&self, expr: &Expr<'tcx>) -> bool {
|
||||
self.binding_hir_ids
|
||||
.iter()
|
||||
.any(|hir_id| path_to_local_id(expr, *hir_id))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the named method is `IntoIterator::into_iter`.
|
||||
pub fn is_into_iter(cx: &LateContext<'_>, callee_def_id: DefId) -> bool {
|
||||
cx.tcx.lang_items().require(LangItem::IntoIterIntoIter) == Ok(callee_def_id)
|
||||
}
|
397
clippy_lints/src/methods/unnecessary_to_owned.rs
Normal file
397
clippy_lints/src/methods/unnecessary_to_owned.rs
Normal file
@ -0,0 +1,397 @@
|
||||
use super::implicit_clone::is_clone_like;
|
||||
use super::unnecessary_iter_cloned::{self, is_into_iter};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
|
||||
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
|
||||
use rustc_span::{sym, Symbol};
|
||||
use std::cmp::max;
|
||||
|
||||
use super::UNNECESSARY_TO_OWNED;
|
||||
|
||||
pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) {
|
||||
if_chain! {
|
||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
||||
if let [receiver] = args;
|
||||
then {
|
||||
if is_cloned_or_copied(cx, method_name, method_def_id) {
|
||||
unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
|
||||
} else if is_to_owned_like(cx, method_name, method_def_id) {
|
||||
// At this point, we know the call is of a `to_owned`-like function. The functions
|
||||
// `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
|
||||
// based on its context, that is, whether it is a referent in an `AddrOf` expression, an
|
||||
// argument in a `into_iter` call, or an argument in the call of some other function.
|
||||
if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) {
|
||||
return;
|
||||
}
|
||||
if check_into_iter_call_arg(cx, expr, method_name, receiver) {
|
||||
return;
|
||||
}
|
||||
check_other_call_arg(cx, expr, method_name, receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether `expr` is a referent in an `AddrOf` expression and, if so, determines whether its
|
||||
/// call of a `to_owned`-like function is unnecessary.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_addr_of_expr(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
method_name: Symbol,
|
||||
method_def_id: DefId,
|
||||
receiver: &'tcx Expr<'tcx>,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(parent) = get_parent_expr(cx, expr);
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind;
|
||||
let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::<Vec<_>>();
|
||||
if let Some(target_ty) = match adjustments[..]
|
||||
{
|
||||
// For matching uses of `Cow::from`
|
||||
[
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Borrow(_),
|
||||
target: target_ty,
|
||||
},
|
||||
]
|
||||
// For matching uses of arrays
|
||||
| [
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Borrow(_),
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Pointer(_),
|
||||
target: target_ty,
|
||||
},
|
||||
]
|
||||
// For matching everything else
|
||||
| [
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Deref(Some(OverloadedDeref { .. })),
|
||||
..
|
||||
},
|
||||
Adjustment {
|
||||
kind: Adjust::Borrow(_),
|
||||
target: target_ty,
|
||||
},
|
||||
] => Some(target_ty),
|
||||
_ => None,
|
||||
};
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||
// Only flag cases where the receiver is copyable or the method is `Cow::into_owned`. This
|
||||
// restriction is to ensure there is not overlap between `redundant_clone` and this lint.
|
||||
if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id);
|
||||
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
||||
then {
|
||||
let (target_ty, n_target_refs) = peel_mid_ty_refs(target_ty);
|
||||
let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
|
||||
if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
parent.span,
|
||||
&format!("unnecessary use of `{}`", method_name),
|
||||
"use",
|
||||
format!("{:&>width$}{}", "", receiver_snippet, width = n_target_refs - n_receiver_refs),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
if_chain! {
|
||||
if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
|
||||
if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
|
||||
if get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(target_ty);
|
||||
then {
|
||||
if n_receiver_refs > 0 {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
parent.span,
|
||||
&format!("unnecessary use of `{}`", method_name),
|
||||
"use",
|
||||
receiver_snippet,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
expr.span.with_lo(receiver.span.hi()),
|
||||
&format!("unnecessary use of `{}`", method_name),
|
||||
"remove this",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if_chain! {
|
||||
if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
|
||||
if implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)]);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
parent.span,
|
||||
&format!("unnecessary use of `{}`", method_name),
|
||||
"use",
|
||||
format!("{}.as_ref()", receiver_snippet),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
|
||||
/// call of a `to_owned`-like function is unnecessary.
|
||||
fn check_into_iter_call_arg(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
method_name: Symbol,
|
||||
receiver: &'tcx Expr<'tcx>,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(parent) = get_parent_expr(cx, expr);
|
||||
if let Some(callee_def_id) = fn_def_id(cx, parent);
|
||||
if is_into_iter(cx, callee_def_id);
|
||||
if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||
let parent_ty = cx.typeck_results().expr_ty(parent);
|
||||
if implements_trait(cx, parent_ty, iterator_trait_id, &[]);
|
||||
if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty);
|
||||
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
||||
then {
|
||||
if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver) {
|
||||
return true;
|
||||
}
|
||||
let cloned_or_copied = if is_copy(cx, item_ty) {
|
||||
"copied"
|
||||
} else {
|
||||
"cloned"
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
parent.span,
|
||||
&format!("unnecessary use of `{}`", method_name),
|
||||
"use",
|
||||
format!("{}.iter().{}()", receiver_snippet, cloned_or_copied),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks whether `expr` is an argument in a function call and, if so, determines whether its call
|
||||
/// of a `to_owned`-like function is unnecessary.
|
||||
fn check_other_call_arg(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
method_name: Symbol,
|
||||
receiver: &'tcx Expr<'tcx>,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
|
||||
if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
|
||||
if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
|
||||
if let Some(input) = fn_sig.inputs().get(i);
|
||||
let (input, n_refs) = peel_mid_ty_refs(input);
|
||||
if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
|
||||
if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
|
||||
if let [trait_predicate] = trait_predicates
|
||||
.iter()
|
||||
.filter(|trait_predicate| trait_predicate.def_id() != sized_def_id)
|
||||
.collect::<Vec<_>>()[..];
|
||||
if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
|
||||
if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||
// If the callee has type parameters, they could appear in `projection_predicate.ty` or the
|
||||
// types of `trait_predicate.trait_ref.substs`.
|
||||
if if trait_predicate.def_id() == deref_trait_id {
|
||||
if let [projection_predicate] = projection_predicates[..] {
|
||||
let normalized_ty =
|
||||
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty);
|
||||
implements_trait(cx, receiver_ty, deref_trait_id, &[])
|
||||
&& get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if trait_predicate.def_id() == as_ref_trait_id {
|
||||
let composed_substs = compose_substs(
|
||||
cx,
|
||||
&trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
|
||||
call_substs
|
||||
);
|
||||
implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
|
||||
// `Target = T`.
|
||||
if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
|
||||
let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
|
||||
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_TO_OWNED,
|
||||
maybe_arg.span,
|
||||
&format!("unnecessary use of `{}`", method_name),
|
||||
"use",
|
||||
format!("{:&>width$}{}", "", receiver_snippet, width = n_refs),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Walks an expression's ancestors until it finds a non-`AddrOf` expression. Returns the first such
|
||||
/// expression found (if any) along with the immediately prior expression.
|
||||
fn skip_addr_of_ancestors(
|
||||
cx: &LateContext<'tcx>,
|
||||
mut expr: &'tcx Expr<'tcx>,
|
||||
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
|
||||
while let Some(parent) = get_parent_expr(cx, expr) {
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind {
|
||||
expr = parent;
|
||||
} else {
|
||||
return Some((parent, expr));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
|
||||
/// `Substs`, and arguments.
|
||||
fn get_callee_substs_and_args(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
|
||||
if_chain! {
|
||||
if let ExprKind::Call(callee, args) = expr.kind;
|
||||
let callee_ty = cx.typeck_results().expr_ty(callee);
|
||||
if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
|
||||
then {
|
||||
let substs = cx.typeck_results().node_substs(callee.hir_id);
|
||||
return Some((*callee_def_id, substs, args));
|
||||
}
|
||||
}
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(_, _, args, _) = expr.kind;
|
||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
||||
then {
|
||||
let substs = cx.typeck_results().node_substs(expr.hir_id);
|
||||
return Some((method_def_id, substs, args));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the `TraitPredicate`s and `ProjectionPredicate`s for a function's input type.
|
||||
fn get_input_traits_and_projections(
|
||||
cx: &LateContext<'tcx>,
|
||||
callee_def_id: DefId,
|
||||
input: Ty<'tcx>,
|
||||
) -> (Vec<TraitPredicate<'tcx>>, Vec<ProjectionPredicate<'tcx>>) {
|
||||
let mut trait_predicates = Vec::new();
|
||||
let mut projection_predicates = Vec::new();
|
||||
for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() {
|
||||
// `substs` should have 1 + n elements. The first is the type on the left hand side of an
|
||||
// `as`. The remaining n are trait parameters.
|
||||
let is_input_substs = |substs: SubstsRef<'tcx>| {
|
||||
if_chain! {
|
||||
if let Some(arg) = substs.iter().next();
|
||||
if let GenericArgKind::Type(arg_ty) = arg.unpack();
|
||||
if arg_ty == input;
|
||||
then {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
match predicate.kind().skip_binder() {
|
||||
PredicateKind::Trait(trait_predicate) => {
|
||||
if is_input_substs(trait_predicate.trait_ref.substs) {
|
||||
trait_predicates.push(trait_predicate);
|
||||
}
|
||||
},
|
||||
PredicateKind::Projection(projection_predicate) => {
|
||||
if is_input_substs(projection_predicate.projection_ty.substs) {
|
||||
projection_predicates.push(projection_predicate);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
(trait_predicates, projection_predicates)
|
||||
}
|
||||
|
||||
/// Composes two substitutions by applying the latter to the types of the former.
|
||||
fn compose_substs(cx: &LateContext<'tcx>, left: &[GenericArg<'tcx>], right: SubstsRef<'tcx>) -> Vec<GenericArg<'tcx>> {
|
||||
left.iter()
|
||||
.map(|arg| {
|
||||
if let GenericArgKind::Type(arg_ty) = arg.unpack() {
|
||||
let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty);
|
||||
GenericArg::from(normalized_ty)
|
||||
} else {
|
||||
*arg
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
|
||||
fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
|
||||
(method_name.as_str() == "cloned" || method_name.as_str() == "copied")
|
||||
&& is_diag_trait_item(cx, method_def_id, sym::Iterator)
|
||||
}
|
||||
|
||||
/// Returns true if the named method can be used to convert the receiver to its "owned"
|
||||
/// representation.
|
||||
fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
|
||||
is_clone_like(cx, &*method_name.as_str(), method_def_id)
|
||||
|| is_cow_into_owned(cx, method_name, method_def_id)
|
||||
|| is_to_string(cx, method_name, method_def_id)
|
||||
}
|
||||
|
||||
/// Returns true if the named method is `Cow::into_owned`.
|
||||
fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
|
||||
method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
|
||||
}
|
||||
|
||||
/// Returns true if the named method is `ToString::to_string`.
|
||||
fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
|
||||
method_name.as_str() == "to_string" && is_diag_trait_item(cx, method_def_id, sym::ToString)
|
||||
}
|
@ -6,10 +6,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{is_else_clause, is_expn_of};
|
||||
use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Spanned;
|
||||
@ -74,6 +74,36 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
|
||||
|
||||
fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
|
||||
let mut inner = e;
|
||||
while let ExprKind::Binary(_, i, _)
|
||||
| ExprKind::Call(i, _)
|
||||
| ExprKind::Cast(i, _)
|
||||
| ExprKind::Type(i, _)
|
||||
| ExprKind::Index(i, _) = inner.kind
|
||||
{
|
||||
if matches!(
|
||||
i.kind,
|
||||
ExprKind::Block(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
inner = i;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
|
||||
matches!(
|
||||
get_parent_node(cx.tcx, id),
|
||||
Some(Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }))
|
||||
)
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
use self::Expression::{Bool, RetBool};
|
||||
@ -99,6 +129,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
||||
snip = snip.blockify();
|
||||
}
|
||||
|
||||
if condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id) {
|
||||
snip = snip.maybe_par();
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_BOOL,
|
||||
@ -109,8 +143,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
if let ExprKind::Block(then, _) = then.kind {
|
||||
match (fetch_bool_block(then), fetch_bool_expr(r#else)) {
|
||||
if let Some((a, b)) = fetch_bool_block(then).and_then(|a| Some((a, fetch_bool_block(r#else)?))) {
|
||||
match (a, b) {
|
||||
(RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
|
||||
span_lint(
|
||||
cx,
|
||||
@ -133,8 +167,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
||||
(Bool(false), Bool(true)) => reduce(false, true),
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
panic!("IfExpr `then` node is not an `ExprKind::Block`");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,8 +269,6 @@ fn check_comparison<'a, 'tcx>(
|
||||
right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
|
||||
no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>,
|
||||
) {
|
||||
use self::Expression::{Bool, Other};
|
||||
|
||||
if let ExprKind::Binary(op, left_side, right_side) = e.kind {
|
||||
let (l_ty, r_ty) = (
|
||||
cx.typeck_results().expr_ty(left_side),
|
||||
@ -270,19 +300,19 @@ fn check_comparison<'a, 'tcx>(
|
||||
}
|
||||
|
||||
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
|
||||
(Bool(true), Other) => left_true.map_or((), |(h, m)| {
|
||||
(Some(true), None) => left_true.map_or((), |(h, m)| {
|
||||
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
|
||||
}),
|
||||
(Other, Bool(true)) => right_true.map_or((), |(h, m)| {
|
||||
(None, Some(true)) => right_true.map_or((), |(h, m)| {
|
||||
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
|
||||
}),
|
||||
(Bool(false), Other) => left_false.map_or((), |(h, m)| {
|
||||
(Some(false), None) => left_false.map_or((), |(h, m)| {
|
||||
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
|
||||
}),
|
||||
(Other, Bool(false)) => right_false.map_or((), |(h, m)| {
|
||||
(None, Some(false)) => right_false.map_or((), |(h, m)| {
|
||||
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
|
||||
}),
|
||||
(Other, Other) => no_literal.map_or((), |(h, m)| {
|
||||
(None, None) => no_literal.map_or((), |(h, m)| {
|
||||
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
|
||||
let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
@ -331,41 +361,20 @@ fn suggest_bool_comparison<'a, 'tcx>(
|
||||
enum Expression {
|
||||
Bool(bool),
|
||||
RetBool(bool),
|
||||
Other,
|
||||
}
|
||||
|
||||
fn fetch_bool_block(block: &Block<'_>) -> Expression {
|
||||
match (&*block.stmts, block.expr.as_ref()) {
|
||||
(&[], Some(e)) => fetch_bool_expr(&**e),
|
||||
(&[ref e], None) => {
|
||||
if let StmtKind::Semi(e) = e.kind {
|
||||
if let ExprKind::Ret(_) = e.kind {
|
||||
fetch_bool_expr(e)
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
},
|
||||
_ => Expression::Other,
|
||||
fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
|
||||
match peel_blocks_with_stmt(expr).kind {
|
||||
ExprKind::Ret(Some(ret)) => Some(Expression::RetBool(fetch_bool_expr(ret)?)),
|
||||
_ => Some(Expression::Bool(fetch_bool_expr(expr)?)),
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_bool_expr(expr: &Expr<'_>) -> Expression {
|
||||
match expr.kind {
|
||||
ExprKind::Block(block, _) => fetch_bool_block(block),
|
||||
ExprKind::Lit(ref lit_ptr) => {
|
||||
if let LitKind::Bool(value) = lit_ptr.node {
|
||||
Expression::Bool(value)
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
},
|
||||
ExprKind::Ret(Some(expr)) => match fetch_bool_expr(expr) {
|
||||
Expression::Bool(value) => Expression::RetBool(value),
|
||||
_ => Expression::Other,
|
||||
},
|
||||
_ => Expression::Other,
|
||||
fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
|
||||
if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
|
||||
if let LitKind::Bool(value) = lit_ptr.node {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) ->
|
||||
seen
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
struct LocalAssign {
|
||||
lhs_id: HirId,
|
||||
lhs_span: Span,
|
||||
@ -154,14 +154,15 @@ fn assignment_suggestions<'tcx>(
|
||||
assignments.push(assign);
|
||||
}
|
||||
|
||||
let suggestions = assignments.clone()
|
||||
.into_iter()
|
||||
let suggestions = assignments
|
||||
.iter()
|
||||
.map(|assignment| Some((assignment.span.until(assignment.rhs_span), String::new())))
|
||||
.chain(
|
||||
assignments
|
||||
.into_iter()
|
||||
.map(|assignment| Some((assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()), String::new())))
|
||||
)
|
||||
.chain(assignments.iter().map(|assignment| {
|
||||
Some((
|
||||
assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()),
|
||||
String::new(),
|
||||
))
|
||||
}))
|
||||
.collect::<Option<Vec<(Span, String)>>>()?;
|
||||
|
||||
let applicability = if suggestions.len() > 1 {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use clippy_utils::peel_blocks;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::has_drop;
|
||||
use rustc_errors::Applicability;
|
||||
@ -114,7 +115,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
if expr.span.from_expansion() {
|
||||
return false;
|
||||
}
|
||||
match expr.kind {
|
||||
match peel_blocks(expr).kind {
|
||||
ExprKind::Lit(..) | ExprKind::Closure(..) => true,
|
||||
ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
|
||||
ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
|
||||
@ -150,9 +151,6 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
false
|
||||
}
|
||||
},
|
||||
ExprKind::Block(block, _) => {
|
||||
block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| has_no_effect(cx, expr))
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -13,24 +13,28 @@ use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Warns about fields in struct implementing `Send` that are neither `Send` nor `Copy`.
|
||||
/// This lint warns about a `Send` implementation for a type that
|
||||
/// contains fields that are not safe to be sent across threads.
|
||||
/// It tries to detect fields that can cause a soundness issue
|
||||
/// when sent to another thread (e.g., `Rc`) while allowing `!Send` fields
|
||||
/// that are expected to exist in a `Send` type, such as raw pointers.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Sending the struct to another thread will transfer the ownership to
|
||||
/// the new thread by dropping in the current thread during the transfer.
|
||||
/// This causes soundness issues for non-`Send` fields, as they are also
|
||||
/// dropped and might not be set up to handle this.
|
||||
/// Sending the struct to another thread effectively sends all of its fields,
|
||||
/// and the fields that do not implement `Send` can lead to soundness bugs
|
||||
/// such as data races when accessed in a thread
|
||||
/// that is different from the thread that created it.
|
||||
///
|
||||
/// See:
|
||||
/// * [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html)
|
||||
/// * [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)
|
||||
///
|
||||
/// ### Known Problems
|
||||
/// Data structures that contain raw pointers may cause false positives.
|
||||
/// They are sometimes safe to be sent across threads but do not implement
|
||||
/// the `Send` trait. This lint has a heuristic to filter out basic cases
|
||||
/// such as `Vec<*const T>`, but it's not perfect. Feel free to create an
|
||||
/// issue if you have a suggestion on how this heuristic can be improved.
|
||||
/// This lint relies on heuristics to distinguish types that are actually
|
||||
/// unsafe to be sent across threads and `!Send` types that are expected to
|
||||
/// exist in `Send` type. Its rule can filter out basic cases such as
|
||||
/// `Vec<*const T>`, but it's not perfect. Feel free to create an issue if
|
||||
/// you have a suggestion on how this heuristic can be improved.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust,ignore
|
||||
@ -46,8 +50,8 @@ declare_clippy_lint! {
|
||||
/// or specify correct bounds on generic type parameters (`T: Send`).
|
||||
#[clippy::version = "1.57.0"]
|
||||
pub NON_SEND_FIELDS_IN_SEND_TY,
|
||||
suspicious,
|
||||
"there is field that does not implement `Send` in a `Send` struct"
|
||||
nursery,
|
||||
"there is a field that is not safe to be sent to another thread in a `Send` struct"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -120,14 +124,14 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
|
||||
NON_SEND_FIELDS_IN_SEND_TY,
|
||||
item.span,
|
||||
&format!(
|
||||
"this implementation is unsound, as some fields in `{}` are `!Send`",
|
||||
"some fields in `{}` are not safe to be sent to another thread",
|
||||
snippet(cx, hir_impl.self_ty.span, "Unknown")
|
||||
),
|
||||
|diag| {
|
||||
for field in non_send_fields {
|
||||
diag.span_note(
|
||||
field.def.span,
|
||||
&format!("the type of field `{}` is `!Send`", field.def.ident.name),
|
||||
&format!("it is not safe to send field `{}` to another thread", field.def.ident.name),
|
||||
);
|
||||
|
||||
match field.generic_params.len() {
|
||||
|
@ -1,15 +1,14 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{
|
||||
can_move_expr_to_closure, eager_or_lazy, in_constant, is_else_clause, is_lang_ctor, peel_hir_expr_while,
|
||||
CaptureKind,
|
||||
can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks,
|
||||
peel_hir_expr_while, CaptureKind,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::OptionSome;
|
||||
use rustc_hir::{def::Res, BindingAnnotation, Block, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
|
||||
use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
@ -86,28 +85,6 @@ struct OptionIfLetElseOccurence {
|
||||
none_expr: String,
|
||||
}
|
||||
|
||||
/// Extracts the body of a given arm. If the arm contains only an expression,
|
||||
/// then it returns the expression. Otherwise, it returns the entire block
|
||||
fn extract_body_from_expr<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
|
||||
if let ExprKind::Block(
|
||||
Block {
|
||||
stmts: block_stmts,
|
||||
expr: Some(block_expr),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) = expr.kind
|
||||
{
|
||||
if let [] = block_stmts {
|
||||
Some(block_expr)
|
||||
} else {
|
||||
Some(expr)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
|
||||
format!(
|
||||
"{}{}",
|
||||
@ -135,7 +112,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
|
||||
if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already
|
||||
if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind;
|
||||
if is_lang_ctor(cx, struct_qpath, OptionSome);
|
||||
if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
|
||||
if let PatKind::Binding(bind_annotation, _, id, None) = &inner_pat.kind;
|
||||
if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
|
||||
if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
|
||||
if some_captures
|
||||
@ -145,8 +122,8 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
|
||||
|
||||
then {
|
||||
let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
|
||||
let some_body = extract_body_from_expr(if_then)?;
|
||||
let none_body = extract_body_from_expr(if_else)?;
|
||||
let some_body = peel_blocks(if_then);
|
||||
let none_body = peel_blocks(if_else);
|
||||
let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
|
||||
let capture_name = id.name.to_ident_string();
|
||||
let (as_ref, as_mut) = match &let_expr.kind {
|
||||
|
@ -1,14 +1,13 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::is_lang_ctor;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id};
|
||||
use clippy_utils::{eq_expr_value, is_lang_ctor, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk};
|
||||
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind};
|
||||
use rustc_hir::{BindingAnnotation, Expr, ExprKind, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
@ -68,14 +67,8 @@ impl QuestionMark {
|
||||
let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
|
||||
let mut replacement: Option<String> = None;
|
||||
if let Some(else_inner) = r#else {
|
||||
if_chain! {
|
||||
if let ExprKind::Block(block, None) = &else_inner.kind;
|
||||
if block.stmts.is_empty();
|
||||
if let Some(block_expr) = &block.expr;
|
||||
if eq_expr_value(cx, subject, block_expr);
|
||||
then {
|
||||
replacement = Some(format!("Some({}?)", receiver_str));
|
||||
}
|
||||
if eq_expr_value(cx, subject, peel_blocks(else_inner)) {
|
||||
replacement = Some(format!("Some({}?)", receiver_str));
|
||||
}
|
||||
} else if Self::moves_by_default(cx, subject)
|
||||
&& !matches!(subject.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
|
||||
@ -110,10 +103,7 @@ impl QuestionMark {
|
||||
|
||||
if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
|
||||
let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
|
||||
if let ExprKind::Block(block, None) = if_then.kind;
|
||||
if block.stmts.is_empty();
|
||||
if let Some(trailing_expr) = &block.expr;
|
||||
if path_to_local_id(trailing_expr, bind_id);
|
||||
if path_to_local_id(peel_blocks(if_then), bind_id);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
|
||||
@ -159,14 +149,7 @@ impl QuestionMark {
|
||||
}
|
||||
|
||||
fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
|
||||
match expression.kind {
|
||||
ExprKind::Block(block, _) => {
|
||||
if let Some(return_expression) = Self::return_expression(block) {
|
||||
return Self::expression_returns_none(cx, return_expression);
|
||||
}
|
||||
|
||||
false
|
||||
},
|
||||
match peel_blocks_with_stmt(expression).kind {
|
||||
ExprKind::Ret(Some(expr)) => Self::expression_returns_none(cx, expr),
|
||||
ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
|
||||
_ => false,
|
||||
@ -174,44 +157,12 @@ impl QuestionMark {
|
||||
}
|
||||
|
||||
fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Block(block, _) => {
|
||||
if let Some(return_expression) = Self::return_expression(block) {
|
||||
return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
|
||||
}
|
||||
|
||||
false
|
||||
},
|
||||
match peel_blocks_with_stmt(expr).kind {
|
||||
ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
|
||||
ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
|
||||
ExprKind::Path(_) => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||
// Check if last expression is a return statement. Then, return the expression
|
||||
if_chain! {
|
||||
if block.stmts.len() == 1;
|
||||
if let Some(expr) = block.stmts.iter().last();
|
||||
if let StmtKind::Semi(expr) = expr.kind;
|
||||
if let ExprKind::Ret(Some(ret_expr)) = expr.kind;
|
||||
|
||||
then {
|
||||
return Some(ret_expr);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for `return` without a semicolon.
|
||||
if_chain! {
|
||||
if block.stmts.is_empty();
|
||||
if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.kind);
|
||||
then {
|
||||
return Some(ret_expr);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
|
||||
|
105
clippy_lints/src/return_self_not_must_use.rs
Normal file
105
clippy_lints/src/return_self_not_must_use.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use clippy_utils::{diagnostics::span_lint, must_use_attr, nth_arg, return_ty};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It prevents to "forget" to use the newly created value.
|
||||
///
|
||||
/// ### Limitations
|
||||
/// This lint is only applied on methods taking a `self` argument. It would be mostly noise
|
||||
/// if it was added on constructors for example.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// pub struct Bar;
|
||||
///
|
||||
/// impl Bar {
|
||||
/// // Bad
|
||||
/// pub fn bar(&self) -> Self {
|
||||
/// Self
|
||||
/// }
|
||||
///
|
||||
/// // Good
|
||||
/// #[must_use]
|
||||
/// pub fn foo(&self) -> Self {
|
||||
/// Self
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.59.0"]
|
||||
pub RETURN_SELF_NOT_MUST_USE,
|
||||
suspicious,
|
||||
"missing `#[must_use]` annotation on a method returning `Self`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
|
||||
|
||||
fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
|
||||
if_chain! {
|
||||
// If it comes from an external macro, better ignore it.
|
||||
if !in_external_macro(cx.sess(), span);
|
||||
if decl.implicit_self.has_implicit_self();
|
||||
// We only show this warning for public exported methods.
|
||||
if cx.access_levels.is_exported(fn_def);
|
||||
if cx.tcx.visibility(fn_def.to_def_id()).is_public();
|
||||
// No need to warn if the attribute is already present.
|
||||
if must_use_attr(cx.tcx.hir().attrs(hir_id)).is_none();
|
||||
let ret_ty = return_ty(cx, hir_id);
|
||||
let self_arg = nth_arg(cx, hir_id, 0);
|
||||
// If `Self` has the same type as the returned type, then we want to warn.
|
||||
//
|
||||
// For this check, we don't want to remove the reference on the returned type because if
|
||||
// there is one, we shouldn't emit a warning!
|
||||
if self_arg.peel_refs() == ret_ty;
|
||||
|
||||
then {
|
||||
span_lint(
|
||||
cx,
|
||||
RETURN_SELF_NOT_MUST_USE,
|
||||
span,
|
||||
"missing `#[must_use]` attribute on a method returning `Self`",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
kind: FnKind<'tcx>,
|
||||
decl: &'tcx FnDecl<'tcx>,
|
||||
_: &'tcx Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
if_chain! {
|
||||
// We are only interested in methods, not in functions or associated functions.
|
||||
if matches!(kind, FnKind::Method(_, _, _));
|
||||
if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
|
||||
if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
|
||||
// We don't want this method to be te implementation of a trait because the
|
||||
// `#[must_use]` should be put on the trait definition directly.
|
||||
if cx.tcx.trait_id_of_impl(impl_def).is_none();
|
||||
|
||||
then {
|
||||
check_method(cx, decl, fn_def, span, hir_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
|
||||
if let TraitItemKind::Fn(ref sig, _) = item.kind {
|
||||
check_method(cx, sig.decl, item.def_id, item.span, item.hir_id());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::SpanlessEq;
|
||||
use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
|
||||
use clippy_utils::{peel_blocks, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
|
||||
@ -201,7 +201,7 @@ fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
}
|
||||
|
||||
fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
|
||||
match src.kind {
|
||||
match peel_blocks(src).kind {
|
||||
ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Add, ..
|
||||
@ -209,9 +209,6 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
|
||||
left,
|
||||
_,
|
||||
) => SpanlessEq::new(cx).eq_expr(target, left),
|
||||
ExprKind::Block(block, _) => {
|
||||
block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -350,16 +350,28 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
||||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
|
||||
match item.kind {
|
||||
ImplItemKind::Const(ty, _) | ImplItemKind::TyAlias(ty) => self.check_ty(
|
||||
cx,
|
||||
ty,
|
||||
CheckTyContext {
|
||||
is_in_trait_impl: true,
|
||||
..CheckTyContext::default()
|
||||
},
|
||||
),
|
||||
// methods are covered by check_fn
|
||||
ImplItemKind::Fn(..) => (),
|
||||
ImplItemKind::Const(ty, _) => {
|
||||
let is_in_trait_impl = if let Some(hir::Node::Item(item)) =
|
||||
cx.tcx.hir().find(cx.tcx.hir().get_parent_item(item.hir_id()))
|
||||
{
|
||||
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
self.check_ty(
|
||||
cx,
|
||||
ty,
|
||||
CheckTyContext {
|
||||
is_in_trait_impl,
|
||||
..CheckTyContext::default()
|
||||
},
|
||||
);
|
||||
},
|
||||
// Methods are covered by check_fn.
|
||||
// Type aliases are ignored because oftentimes it's impossible to
|
||||
// make type alias declaration in trait simpler, see #1013
|
||||
ImplItemKind::Fn(..) | ImplItemKind::TyAlias(..) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,6 +429,14 @@ impl Types {
|
||||
}
|
||||
|
||||
fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, context: CheckTyContext) {
|
||||
// Ignore functions in trait implementations as they are usually forced by the trait definition.
|
||||
//
|
||||
// FIXME: idially we would like to warn *if the compicated type can be simplified*, but it's hard to
|
||||
// check.
|
||||
if context.is_in_trait_impl {
|
||||
return;
|
||||
}
|
||||
|
||||
for input in decl.inputs {
|
||||
self.check_ty(cx, input, context);
|
||||
}
|
||||
@ -435,12 +455,12 @@ impl Types {
|
||||
return;
|
||||
}
|
||||
|
||||
if !context.is_nested_call && type_complexity::check(cx, hir_ty, self.type_complexity_threshold) {
|
||||
// Skip trait implementations; see issue #605.
|
||||
if context.is_in_trait_impl {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip trait implementations; see issue #605.
|
||||
if context.is_in_trait_impl {
|
||||
if !context.is_nested_call && type_complexity::check(cx, hir_ty, self.type_complexity_threshold) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
|
||||
trait_name
|
||||
),
|
||||
Some(last_semi),
|
||||
&"probably caused by this trailing semicolon".to_string(),
|
||||
"probably caused by this trailing semicolon",
|
||||
);
|
||||
},
|
||||
None => {},
|
||||
|
@ -1,11 +1,10 @@
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::match_type;
|
||||
use clippy_utils::{
|
||||
is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls, path_to_res,
|
||||
paths, SpanlessEq,
|
||||
higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls,
|
||||
path_to_res, paths, peel_blocks_with_stmt, SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast as ast;
|
||||
@ -662,10 +661,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
|
||||
if and_then_args.len() == 5;
|
||||
if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
|
||||
let body = cx.tcx.hir().body(*body_id);
|
||||
if let ExprKind::Block(block, _) = &body.value.kind;
|
||||
let stmts = &block.stmts;
|
||||
if stmts.len() == 1 && block.expr.is_none();
|
||||
if let StmtKind::Semi(only_expr) = &stmts[0].kind;
|
||||
let only_expr = peel_blocks_with_stmt(&body.value);
|
||||
if let ExprKind::MethodCall(ps, _, span_call_args, _) = &only_expr.kind;
|
||||
then {
|
||||
let and_then_snippets = get_and_then_snippets(cx, and_then_args);
|
||||
|
@ -8,6 +8,11 @@
|
||||
//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
|
||||
//! a simple mistake)
|
||||
|
||||
use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
|
||||
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
|
||||
use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -25,12 +30,6 @@ use std::fs::{self, OpenOptions};
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type,
|
||||
ty::walk_ptrs_ty_depth,
|
||||
};
|
||||
|
||||
/// This is the output file of the lint collector.
|
||||
const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
|
||||
/// These lints are excluded from the export.
|
||||
|
@ -41,6 +41,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Consider expressions containing potential side effects as not equal.
|
||||
#[must_use]
|
||||
pub fn deny_side_effects(self) -> Self {
|
||||
Self {
|
||||
allow_side_effects: false,
|
||||
@ -48,6 +49,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
|
||||
Self {
|
||||
expr_fallback: Some(Box::new(expr_fallback)),
|
||||
|
@ -72,10 +72,10 @@ use rustc_hir::intravisit::{walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visi
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs,
|
||||
HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
|
||||
Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
|
||||
UnOp,
|
||||
def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
|
||||
ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
|
||||
MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem,
|
||||
TraitItemKind, TraitRef, TyKind, UnOp,
|
||||
};
|
||||
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||
use rustc_middle::hir::exports::Export;
|
||||
@ -1223,6 +1223,70 @@ pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes blocks around an expression, only if the block contains just one expression
|
||||
/// and no statements. Unsafe blocks are not removed.
|
||||
///
|
||||
/// Examples:
|
||||
/// * `{}` -> `{}`
|
||||
/// * `{ x }` -> `x`
|
||||
/// * `{{ x }}` -> `x`
|
||||
/// * `{ x; }` -> `{ x; }`
|
||||
/// * `{ x; y }` -> `{ x; y }`
|
||||
/// * `{ unsafe { x } }` -> `unsafe { x }`
|
||||
pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
|
||||
while let ExprKind::Block(
|
||||
Block {
|
||||
stmts: [],
|
||||
expr: Some(inner),
|
||||
rules: BlockCheckMode::DefaultBlock,
|
||||
..
|
||||
},
|
||||
_,
|
||||
) = expr.kind
|
||||
{
|
||||
expr = inner;
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
||||
/// Removes blocks around an expression, only if the block contains just one expression
|
||||
/// or just one expression statement with a semicolon. Unsafe blocks are not removed.
|
||||
///
|
||||
/// Examples:
|
||||
/// * `{}` -> `{}`
|
||||
/// * `{ x }` -> `x`
|
||||
/// * `{ x; }` -> `x`
|
||||
/// * `{{ x; }}` -> `x`
|
||||
/// * `{ x; y }` -> `{ x; y }`
|
||||
/// * `{ unsafe { x } }` -> `unsafe { x }`
|
||||
pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
|
||||
while let ExprKind::Block(
|
||||
Block {
|
||||
stmts: [],
|
||||
expr: Some(inner),
|
||||
rules: BlockCheckMode::DefaultBlock,
|
||||
..
|
||||
}
|
||||
| Block {
|
||||
stmts:
|
||||
[
|
||||
Stmt {
|
||||
kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),
|
||||
..
|
||||
},
|
||||
],
|
||||
expr: None,
|
||||
rules: BlockCheckMode::DefaultBlock,
|
||||
..
|
||||
},
|
||||
_,
|
||||
) = expr.kind
|
||||
{
|
||||
expr = inner;
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
||||
/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
|
||||
pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
|
||||
let mut iter = tcx.hir().parent_iter(expr.hir_id);
|
||||
@ -1328,6 +1392,13 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx>
|
||||
cx.tcx.erase_late_bound_regions(ret_ty)
|
||||
}
|
||||
|
||||
/// Convenience function to get the nth argument type of a function.
|
||||
pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> {
|
||||
let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
|
||||
let arg = cx.tcx.fn_sig(fn_def_id).input(nth);
|
||||
cx.tcx.erase_late_bound_regions(arg)
|
||||
}
|
||||
|
||||
/// Checks if an expression is constructing a tuple-like enum variant or struct
|
||||
pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
if let ExprKind::Call(fun, _) = expr.kind {
|
||||
@ -1404,20 +1475,6 @@ pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
|
||||
has_attr(attrs, sym::automatically_derived)
|
||||
}
|
||||
|
||||
/// Remove blocks around an expression.
|
||||
///
|
||||
/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
|
||||
/// themselves.
|
||||
pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
|
||||
while let ExprKind::Block(block, ..) = expr.kind {
|
||||
match (block.stmts.is_empty(), block.expr.as_ref()) {
|
||||
(true, Some(e)) => expr = e,
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
||||
pub fn is_self(slf: &Param<'_>) -> bool {
|
||||
if let PatKind::Binding(.., name, _) = slf.pat.kind {
|
||||
name.name == kw::SelfLower
|
||||
|
@ -294,6 +294,7 @@ impl<'a> Sugg<'a> {
|
||||
/// Adds parentheses to any expression that might need them. Suitable to the
|
||||
/// `self` argument of a method call
|
||||
/// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
|
||||
#[must_use]
|
||||
pub fn maybe_par(self) -> Self {
|
||||
match self {
|
||||
Sugg::NonParen(..) => self,
|
||||
|
@ -58,14 +58,20 @@ pub fn contains_adt_constructor<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, adt: &'tc
|
||||
pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
cx.tcx
|
||||
.get_diagnostic_item(sym::Iterator)
|
||||
.and_then(|iter_did| {
|
||||
cx.tcx.associated_items(iter_did).find_by_name_and_kind(
|
||||
cx.tcx,
|
||||
Ident::from_str("Item"),
|
||||
ty::AssocKind::Type,
|
||||
iter_did,
|
||||
)
|
||||
})
|
||||
.and_then(|iter_did| get_associated_type(cx, ty, iter_did, "Item"))
|
||||
}
|
||||
|
||||
/// Returns the associated type `name` for `ty` as an implementation of `trait_id`.
|
||||
/// Do not invoke without first verifying that the type implements the trait.
|
||||
pub fn get_associated_type<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
trait_id: DefId,
|
||||
name: &str,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
cx.tcx
|
||||
.associated_items(trait_id)
|
||||
.find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
|
||||
.map(|assoc| {
|
||||
let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, &[]));
|
||||
cx.tcx.normalize_erasing_regions(cx.param_env, proj)
|
||||
|
@ -78,7 +78,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
|
||||
}
|
||||
|
||||
pub struct ParamBindingIdCollector {
|
||||
binding_hir_ids: Vec<hir::HirId>,
|
||||
pub binding_hir_ids: Vec<hir::HirId>,
|
||||
}
|
||||
impl<'tcx> ParamBindingIdCollector {
|
||||
fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@ use std::process::Command;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::{collections::HashMap, io::ErrorKind};
|
||||
use std::{
|
||||
env, fmt,
|
||||
env,
|
||||
fs::write,
|
||||
path::{Path, PathBuf},
|
||||
thread,
|
||||
@ -101,13 +101,28 @@ struct ClippyWarning {
|
||||
is_ice: bool,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ClippyWarning {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
r#"target/lintcheck/sources/{}-{}/{}:{}:{} {} "{}""#,
|
||||
&self.crate_name, &self.crate_version, &self.file, &self.line, &self.column, &self.linttype, &self.message
|
||||
)
|
||||
#[allow(unused)]
|
||||
impl ClippyWarning {
|
||||
fn to_output(&self, markdown: bool) -> String {
|
||||
let file = format!("{}-{}/{}", &self.crate_name, &self.crate_version, &self.file);
|
||||
let file_with_pos = format!("{}:{}:{}", &file, &self.line, &self.column);
|
||||
if markdown {
|
||||
let lint = format!("`{}`", self.linttype);
|
||||
|
||||
let mut output = String::from("| ");
|
||||
output.push_str(&format!(
|
||||
"[`{}`](../target/lintcheck/sources/{}#L{})",
|
||||
file_with_pos, file, self.line
|
||||
));
|
||||
output.push_str(&format!(r#" | {:<50} | "{}" |"#, lint, self.message));
|
||||
output.push('\n');
|
||||
output
|
||||
} else {
|
||||
format!(
|
||||
"target/lintcheck/sources/{} {} \"{}\"\n",
|
||||
file_with_pos, self.linttype, self.message
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,6 +279,7 @@ impl Crate {
|
||||
thread_limit: usize,
|
||||
total_crates_to_lint: usize,
|
||||
fix: bool,
|
||||
lint_filter: &Vec<String>,
|
||||
) -> Vec<ClippyWarning> {
|
||||
// advance the atomic index by one
|
||||
let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
|
||||
@ -288,9 +304,9 @@ impl Crate {
|
||||
let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
|
||||
|
||||
let mut args = if fix {
|
||||
vec!["--fix", "--allow-no-vcs", "--", "--cap-lints=warn"]
|
||||
vec!["--fix", "--allow-no-vcs", "--"]
|
||||
} else {
|
||||
vec!["--", "--message-format=json", "--", "--cap-lints=warn"]
|
||||
vec!["--", "--message-format=json", "--"]
|
||||
};
|
||||
|
||||
if let Some(options) = &self.options {
|
||||
@ -301,6 +317,13 @@ impl Crate {
|
||||
args.extend(&["-Wclippy::pedantic", "-Wclippy::cargo"])
|
||||
}
|
||||
|
||||
if lint_filter.is_empty() {
|
||||
args.push("--cap-lints=warn");
|
||||
} else {
|
||||
args.push("--cap-lints=allow");
|
||||
args.extend(lint_filter.iter().map(|filter| filter.as_str()))
|
||||
}
|
||||
|
||||
let all_output = std::process::Command::new(&cargo_clippy_path)
|
||||
// use the looping index to create individual target dirs
|
||||
.env(
|
||||
@ -360,14 +383,18 @@ impl Crate {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LintcheckConfig {
|
||||
// max number of jobs to spawn (default 1)
|
||||
/// max number of jobs to spawn (default 1)
|
||||
max_jobs: usize,
|
||||
// we read the sources to check from here
|
||||
/// we read the sources to check from here
|
||||
sources_toml_path: PathBuf,
|
||||
// we save the clippy lint results here
|
||||
/// we save the clippy lint results here
|
||||
lintcheck_results_path: PathBuf,
|
||||
// whether to just run --fix and not collect all the warnings
|
||||
/// whether to just run --fix and not collect all the warnings
|
||||
fix: bool,
|
||||
/// A list of lint that this lintcheck run shound focus on
|
||||
lint_filter: Vec<String>,
|
||||
/// Indicate if the output should support markdown syntax
|
||||
markdown: bool,
|
||||
}
|
||||
|
||||
impl LintcheckConfig {
|
||||
@ -383,12 +410,17 @@ impl LintcheckConfig {
|
||||
.to_string()
|
||||
});
|
||||
|
||||
let markdown = clap_config.is_present("markdown");
|
||||
let sources_toml_path = PathBuf::from(sources_toml);
|
||||
|
||||
// for the path where we save the lint results, get the filename without extension (so for
|
||||
// wasd.toml, use "wasd"...)
|
||||
let filename: PathBuf = sources_toml_path.file_stem().unwrap().into();
|
||||
let lintcheck_results_path = PathBuf::from(format!("lintcheck-logs/{}_logs.txt", filename.display()));
|
||||
let lintcheck_results_path = PathBuf::from(format!(
|
||||
"lintcheck-logs/{}_logs.{}",
|
||||
filename.display(),
|
||||
if markdown { "md" } else { "txt" }
|
||||
));
|
||||
|
||||
// look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
|
||||
// use half of that for the physical core count
|
||||
@ -410,12 +442,27 @@ impl LintcheckConfig {
|
||||
None => 1,
|
||||
};
|
||||
let fix: bool = clap_config.is_present("fix");
|
||||
let lint_filter: Vec<String> = clap_config
|
||||
.values_of("filter")
|
||||
.map(|iter| {
|
||||
iter.map(|lint_name| {
|
||||
let mut filter = lint_name.replace('_', "-");
|
||||
if !filter.starts_with("clippy::") {
|
||||
filter.insert_str(0, "clippy::");
|
||||
}
|
||||
filter
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
LintcheckConfig {
|
||||
max_jobs,
|
||||
sources_toml_path,
|
||||
lintcheck_results_path,
|
||||
fix,
|
||||
lint_filter,
|
||||
markdown,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -577,10 +624,15 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
|
||||
// to not have a lint with 200 and 2 warnings take the same spot
|
||||
stats.sort_by_key(|(lint, count)| format!("{:0>4}, {}", count, lint));
|
||||
|
||||
let mut header = String::from("| lint | count |\n");
|
||||
header.push_str("| -------------------------------------------------- | ----- |\n");
|
||||
let stats_string = stats
|
||||
.iter()
|
||||
.map(|(lint, count)| format!("{} {}\n", lint, count))
|
||||
.collect::<String>();
|
||||
.map(|(lint, count)| format!("| {:<50} | {:>4} |\n", lint, count))
|
||||
.fold(header, |mut table, line| {
|
||||
table.push_str(&line);
|
||||
table
|
||||
});
|
||||
|
||||
(stats_string, counter)
|
||||
}
|
||||
@ -682,6 +734,15 @@ pub fn main() {
|
||||
let old_stats = read_stats_from_file(&config.lintcheck_results_path);
|
||||
|
||||
let counter = AtomicUsize::new(1);
|
||||
let lint_filter: Vec<String> = config
|
||||
.lint_filter
|
||||
.iter()
|
||||
.map(|filter| {
|
||||
let mut filter = filter.clone();
|
||||
filter.insert_str(0, "--force-warn=");
|
||||
filter
|
||||
})
|
||||
.collect();
|
||||
|
||||
let clippy_warnings: Vec<ClippyWarning> = if let Some(only_one_crate) = clap_config.value_of("only") {
|
||||
// if we don't have the specified crate in the .toml, throw an error
|
||||
@ -705,7 +766,9 @@ pub fn main() {
|
||||
.into_iter()
|
||||
.map(|krate| krate.download_and_extract())
|
||||
.filter(|krate| krate.name == only_one_crate)
|
||||
.flat_map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &AtomicUsize::new(0), 1, 1, config.fix))
|
||||
.flat_map(|krate| {
|
||||
krate.run_clippy_lints(&cargo_clippy_path, &AtomicUsize::new(0), 1, 1, config.fix, &lint_filter)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
if config.max_jobs > 1 {
|
||||
@ -729,7 +792,14 @@ pub fn main() {
|
||||
.into_par_iter()
|
||||
.map(|krate| krate.download_and_extract())
|
||||
.flat_map(|krate| {
|
||||
krate.run_clippy_lints(&cargo_clippy_path, &counter, num_cpus, num_crates, config.fix)
|
||||
krate.run_clippy_lints(
|
||||
&cargo_clippy_path,
|
||||
&counter,
|
||||
num_cpus,
|
||||
num_crates,
|
||||
config.fix,
|
||||
&lint_filter,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
@ -738,7 +808,9 @@ pub fn main() {
|
||||
crates
|
||||
.into_iter()
|
||||
.map(|krate| krate.download_and_extract())
|
||||
.flat_map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &counter, 1, num_crates, config.fix))
|
||||
.flat_map(|krate| {
|
||||
krate.run_clippy_lints(&cargo_clippy_path, &counter, 1, num_crates, config.fix, &lint_filter)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
};
|
||||
@ -758,22 +830,31 @@ pub fn main() {
|
||||
.map(|w| (&w.crate_name, &w.message))
|
||||
.collect();
|
||||
|
||||
let mut all_msgs: Vec<String> = clippy_warnings.iter().map(ToString::to_string).collect();
|
||||
let mut all_msgs: Vec<String> = clippy_warnings
|
||||
.iter()
|
||||
.map(|warn| warn.to_output(config.markdown))
|
||||
.collect();
|
||||
all_msgs.sort();
|
||||
all_msgs.push("\n\n\n\nStats:\n".into());
|
||||
all_msgs.push("\n\n### Stats:\n\n".into());
|
||||
all_msgs.push(stats_formatted);
|
||||
|
||||
// save the text into lintcheck-logs/logs.txt
|
||||
let mut text = clippy_ver; // clippy version number on top
|
||||
text.push_str(&format!("\n{}", all_msgs.join("")));
|
||||
text.push_str("ICEs:\n");
|
||||
text.push_str("\n### Reports\n\n");
|
||||
if config.markdown {
|
||||
text.push_str("| file | lint | message |\n");
|
||||
text.push_str("| --- | --- | --- |\n");
|
||||
}
|
||||
text.push_str(&format!("{}", all_msgs.join("")));
|
||||
text.push_str("\n\n### ICEs:\n");
|
||||
ices.iter()
|
||||
.for_each(|(cratename, msg)| text.push_str(&format!("{}: '{}'", cratename, msg)));
|
||||
|
||||
println!("Writing logs to {}", config.lintcheck_results_path.display());
|
||||
std::fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap();
|
||||
write(&config.lintcheck_results_path, text).unwrap();
|
||||
|
||||
print_stats(old_stats, new_stats);
|
||||
print_stats(old_stats, new_stats, &config.lint_filter);
|
||||
}
|
||||
|
||||
/// read the previous stats from the lintcheck-log file
|
||||
@ -787,26 +868,27 @@ fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
|
||||
|
||||
let lines: Vec<String> = file_content.lines().map(ToString::to_string).collect();
|
||||
|
||||
// search for the beginning "Stats:" and the end "ICEs:" of the section we want
|
||||
let start = lines.iter().position(|line| line == "Stats:").unwrap();
|
||||
let end = lines.iter().position(|line| line == "ICEs:").unwrap();
|
||||
|
||||
let stats_lines = &lines[start + 1..end];
|
||||
|
||||
stats_lines
|
||||
lines
|
||||
.iter()
|
||||
.map(|line| {
|
||||
let mut spl = line.split(' ');
|
||||
(
|
||||
spl.next().unwrap().to_string(),
|
||||
spl.next().unwrap().parse::<usize>().unwrap(),
|
||||
)
|
||||
.skip_while(|line| line.as_str() != "### Stats:")
|
||||
// Skipping the table header and the `Stats:` label
|
||||
.skip(4)
|
||||
.take_while(|line| line.starts_with("| "))
|
||||
.filter_map(|line| {
|
||||
let mut spl = line.split('|');
|
||||
// Skip the first `|` symbol
|
||||
spl.next();
|
||||
if let (Some(lint), Some(count)) = (spl.next(), spl.next()) {
|
||||
Some((lint.trim().to_string(), count.trim().parse::<usize>().unwrap()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<HashMap<String, usize>>()
|
||||
}
|
||||
|
||||
/// print how lint counts changed between runs
|
||||
fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>) {
|
||||
fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &Vec<String>) {
|
||||
let same_in_both_hashmaps = old_stats
|
||||
.iter()
|
||||
.filter(|(old_key, old_val)| new_stats.get::<&String>(&old_key) == Some(old_val))
|
||||
@ -845,6 +927,7 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
|
||||
old_stats_deduped
|
||||
.iter()
|
||||
.filter(|(old_key, _)| new_stats_deduped.get::<&String>(&old_key).is_none())
|
||||
.filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
|
||||
.for_each(|(old_key, old_value)| {
|
||||
println!("{} {} => 0", old_key, old_value);
|
||||
});
|
||||
@ -903,6 +986,19 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
|
||||
.long("--fix")
|
||||
.help("runs cargo clippy --fix and checks if all suggestions apply"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("filter")
|
||||
.long("--filter")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.value_name("clippy_lint_name")
|
||||
.help("apply a filter to only collect specified lints, this also overrides `allow` attributes"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("markdown")
|
||||
.long("--markdown")
|
||||
.help("change the reports table to use markdown links"),
|
||||
)
|
||||
.get_matches()
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2021-12-02"
|
||||
channel = "nightly-2021-12-17"
|
||||
components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
|
@ -1,86 +1,86 @@
|
||||
error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
|
||||
error: some fields in `NoGeneric` are not safe to be sent to another thread
|
||||
--> $DIR/test.rs:11:1
|
||||
|
|
||||
LL | unsafe impl Send for NoGeneric {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
|
||||
note: the type of field `rc_is_not_send` is `!Send`
|
||||
note: it is not safe to send field `rc_is_not_send` to another thread
|
||||
--> $DIR/test.rs:8:5
|
||||
|
|
||||
LL | rc_is_not_send: Rc<String>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: use a thread-safe type that implements `Send`
|
||||
|
||||
error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
|
||||
error: some fields in `MultiField<T>` are not safe to be sent to another thread
|
||||
--> $DIR/test.rs:19:1
|
||||
|
|
||||
LL | unsafe impl<T> Send for MultiField<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `field1` is `!Send`
|
||||
note: it is not safe to send field `field1` to another thread
|
||||
--> $DIR/test.rs:14:5
|
||||
|
|
||||
LL | field1: T,
|
||||
| ^^^^^^^^^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
note: the type of field `field2` is `!Send`
|
||||
note: it is not safe to send field `field2` to another thread
|
||||
--> $DIR/test.rs:15:5
|
||||
|
|
||||
LL | field2: T,
|
||||
| ^^^^^^^^^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
note: the type of field `field3` is `!Send`
|
||||
note: it is not safe to send field `field3` to another thread
|
||||
--> $DIR/test.rs:16:5
|
||||
|
|
||||
LL | field3: T,
|
||||
| ^^^^^^^^^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
|
||||
error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
|
||||
error: some fields in `MyOption<T>` are not safe to be sent to another thread
|
||||
--> $DIR/test.rs:26:1
|
||||
|
|
||||
LL | unsafe impl<T> Send for MyOption<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `0` is `!Send`
|
||||
note: it is not safe to send field `0` to another thread
|
||||
--> $DIR/test.rs:22:12
|
||||
|
|
||||
LL | MySome(T),
|
||||
| ^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
|
||||
error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
|
||||
error: some fields in `HeuristicTest` are not safe to be sent to another thread
|
||||
--> $DIR/test.rs:41:1
|
||||
|
|
||||
LL | unsafe impl Send for HeuristicTest {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `field1` is `!Send`
|
||||
note: it is not safe to send field `field1` to another thread
|
||||
--> $DIR/test.rs:34:5
|
||||
|
|
||||
LL | field1: Vec<*const NonSend>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: use a thread-safe type that implements `Send`
|
||||
note: the type of field `field2` is `!Send`
|
||||
note: it is not safe to send field `field2` to another thread
|
||||
--> $DIR/test.rs:35:5
|
||||
|
|
||||
LL | field2: [*const NonSend; 3],
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: use a thread-safe type that implements `Send`
|
||||
note: the type of field `field3` is `!Send`
|
||||
note: it is not safe to send field `field3` to another thread
|
||||
--> $DIR/test.rs:36:5
|
||||
|
|
||||
LL | field3: (*const NonSend, *const NonSend, *const NonSend),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: use a thread-safe type that implements `Send`
|
||||
note: the type of field `field4` is `!Send`
|
||||
note: it is not safe to send field `field4` to another thread
|
||||
--> $DIR/test.rs:37:5
|
||||
|
|
||||
LL | field4: (*const NonSend, Rc<u8>),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: use a thread-safe type that implements `Send`
|
||||
note: the type of field `field5` is `!Send`
|
||||
note: it is not safe to send field `field5` to another thread
|
||||
--> $DIR/test.rs:38:5
|
||||
|
|
||||
LL | field5: Vec<Vec<*const NonSend>>,
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![allow(dead_code, unused_variables)]
|
||||
#![allow(dead_code, unused_variables, clippy::return_self_not_must_use)]
|
||||
|
||||
/// Utility macro to test linting behavior in `option_methods()`
|
||||
/// The lints included in `option_methods()` should not lint if the call to map is partially
|
||||
|
@ -44,6 +44,14 @@ fn macro_in_closure() {
|
||||
}
|
||||
}
|
||||
|
||||
fn closure(_: impl FnMut()) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn function_with_empty_closure() {
|
||||
if closure(|| {}) {}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
let mut range = 0..10;
|
||||
|
@ -1,4 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(clippy::return_self_not_must_use)]
|
||||
#![warn(clippy::deref_addrof)]
|
||||
|
||||
fn get_number() -> usize {
|
||||
|
@ -1,4 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(clippy::return_self_not_must_use)]
|
||||
#![warn(clippy::deref_addrof)]
|
||||
|
||||
fn get_number() -> usize {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:18:13
|
||||
--> $DIR/deref_addrof.rs:19:13
|
||||
|
|
||||
LL | let b = *&a;
|
||||
| ^^^ help: try this: `a`
|
||||
@ -7,49 +7,49 @@ LL | let b = *&a;
|
||||
= note: `-D clippy::deref-addrof` implied by `-D warnings`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:20:13
|
||||
--> $DIR/deref_addrof.rs:21:13
|
||||
|
|
||||
LL | let b = *&get_number();
|
||||
| ^^^^^^^^^^^^^^ help: try this: `get_number()`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:25:13
|
||||
--> $DIR/deref_addrof.rs:26:13
|
||||
|
|
||||
LL | let b = *&bytes[1..2][0];
|
||||
| ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:29:13
|
||||
--> $DIR/deref_addrof.rs:30:13
|
||||
|
|
||||
LL | let b = *&(a);
|
||||
| ^^^^^ help: try this: `(a)`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:31:13
|
||||
--> $DIR/deref_addrof.rs:32:13
|
||||
|
|
||||
LL | let b = *(&a);
|
||||
| ^^^^^ help: try this: `a`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:34:13
|
||||
--> $DIR/deref_addrof.rs:35:13
|
||||
|
|
||||
LL | let b = *((&a));
|
||||
| ^^^^^^^ help: try this: `a`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:36:13
|
||||
--> $DIR/deref_addrof.rs:37:13
|
||||
|
|
||||
LL | let b = *&&a;
|
||||
| ^^^^ help: try this: `&a`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:38:14
|
||||
--> $DIR/deref_addrof.rs:39:14
|
||||
|
|
||||
LL | let b = **&aref;
|
||||
| ^^^^^^ help: try this: `aref`
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:44:9
|
||||
--> $DIR/deref_addrof.rs:45:9
|
||||
|
|
||||
LL | *& $visitor
|
||||
| ^^^^^^^^^^^ help: try this: `$visitor`
|
||||
@ -60,7 +60,7 @@ LL | m!(self)
|
||||
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:51:9
|
||||
--> $DIR/deref_addrof.rs:52:9
|
||||
|
|
||||
LL | *& mut $visitor
|
||||
| ^^^^^^^^^^^^^^^ help: try this: `$visitor`
|
||||
|
@ -53,6 +53,7 @@ fn main() {
|
||||
needless_bool(x);
|
||||
needless_bool2(x);
|
||||
needless_bool3(x);
|
||||
needless_bool_condition();
|
||||
}
|
||||
|
||||
fn bool_ret3(x: bool) -> bool {
|
||||
@ -98,3 +99,19 @@ fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_b
|
||||
true
|
||||
} else { !returns_bool() };
|
||||
}
|
||||
|
||||
unsafe fn no(v: u8) -> u8 {
|
||||
v
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_operation)]
|
||||
fn needless_bool_condition() -> bool {
|
||||
(unsafe { no(4) } & 1 != 0);
|
||||
let _brackets_unneeded = unsafe { no(4) } & 1 != 0;
|
||||
fn foo() -> bool {
|
||||
// parentheses are needed here
|
||||
(unsafe { no(4) } & 1 != 0)
|
||||
}
|
||||
|
||||
foo()
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ fn main() {
|
||||
needless_bool(x);
|
||||
needless_bool2(x);
|
||||
needless_bool3(x);
|
||||
needless_bool_condition();
|
||||
}
|
||||
|
||||
fn bool_ret3(x: bool) -> bool {
|
||||
@ -130,3 +131,23 @@ fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_b
|
||||
true
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn no(v: u8) -> u8 {
|
||||
v
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_operation)]
|
||||
fn needless_bool_condition() -> bool {
|
||||
if unsafe { no(4) } & 1 != 0 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
|
||||
fn foo() -> bool {
|
||||
// parentheses are needed here
|
||||
if unsafe { no(4) } & 1 != 0 { true } else { false }
|
||||
}
|
||||
|
||||
foo()
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ LL | | };
|
||||
| |_____^ help: you can reduce it to: `!(x && y)`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:71:5
|
||||
--> $DIR/fixable.rs:72:5
|
||||
|
|
||||
LL | / if x {
|
||||
LL | | return true;
|
||||
@ -41,7 +41,7 @@ LL | | };
|
||||
| |_____^ help: you can reduce it to: `return x`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:79:5
|
||||
--> $DIR/fixable.rs:80:5
|
||||
|
|
||||
LL | / if x {
|
||||
LL | | return false;
|
||||
@ -51,7 +51,7 @@ LL | | };
|
||||
| |_____^ help: you can reduce it to: `return !x`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:87:5
|
||||
--> $DIR/fixable.rs:88:5
|
||||
|
|
||||
LL | / if x && y {
|
||||
LL | | return true;
|
||||
@ -61,7 +61,7 @@ LL | | };
|
||||
| |_____^ help: you can reduce it to: `return x && y`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:95:5
|
||||
--> $DIR/fixable.rs:96:5
|
||||
|
|
||||
LL | / if x && y {
|
||||
LL | | return false;
|
||||
@ -71,7 +71,7 @@ LL | | };
|
||||
| |_____^ help: you can reduce it to: `return !(x && y)`
|
||||
|
||||
error: equality checks against true are unnecessary
|
||||
--> $DIR/fixable.rs:103:8
|
||||
--> $DIR/fixable.rs:104:8
|
||||
|
|
||||
LL | if x == true {};
|
||||
| ^^^^^^^^^ help: try simplifying it as shown: `x`
|
||||
@ -79,25 +79,25 @@ LL | if x == true {};
|
||||
= note: `-D clippy::bool-comparison` implied by `-D warnings`
|
||||
|
||||
error: equality checks against false can be replaced by a negation
|
||||
--> $DIR/fixable.rs:107:8
|
||||
--> $DIR/fixable.rs:108:8
|
||||
|
|
||||
LL | if x == false {};
|
||||
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
|
||||
|
||||
error: equality checks against true are unnecessary
|
||||
--> $DIR/fixable.rs:117:8
|
||||
--> $DIR/fixable.rs:118:8
|
||||
|
|
||||
LL | if x == true {};
|
||||
| ^^^^^^^^^ help: try simplifying it as shown: `x`
|
||||
|
||||
error: equality checks against false can be replaced by a negation
|
||||
--> $DIR/fixable.rs:118:8
|
||||
--> $DIR/fixable.rs:119:8
|
||||
|
|
||||
LL | if x == false {};
|
||||
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:127:12
|
||||
--> $DIR/fixable.rs:128:12
|
||||
|
|
||||
LL | } else if returns_bool() {
|
||||
| ____________^
|
||||
@ -107,5 +107,27 @@ LL | | true
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `{ !returns_bool() }`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:141:5
|
||||
|
|
||||
LL | / if unsafe { no(4) } & 1 != 0 {
|
||||
LL | | true
|
||||
LL | | } else {
|
||||
LL | | false
|
||||
LL | | };
|
||||
| |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:146:30
|
||||
|
|
||||
LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
|
||||
|
||||
error: this if-then-else expression returns a bool literal
|
||||
--> $DIR/fixable.rs:149:9
|
||||
|
|
||||
LL | if unsafe { no(4) } & 1 != 0 { true } else { false }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
|
@ -39,6 +39,19 @@ fn main() {
|
||||
e = format!("{}", c);
|
||||
}
|
||||
|
||||
let f;
|
||||
match 1 {
|
||||
1 => f = "three",
|
||||
_ => return,
|
||||
}; // has semi
|
||||
|
||||
let g: usize;
|
||||
if true {
|
||||
g = 5;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
println!("{}", a);
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,43 @@ LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:50:5
|
||||
--> $DIR/needless_late_init.rs:42:5
|
||||
|
|
||||
LL | let f;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `f` here
|
||||
|
|
||||
LL | let f = match 1 {
|
||||
| +++++++
|
||||
help: remove the assignments from the `match` arms
|
||||
|
|
||||
LL - 1 => f = "three",
|
||||
LL + 1 => "three",
|
||||
|
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:48:5
|
||||
|
|
||||
LL | let g: usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: declare `g` here
|
||||
|
|
||||
LL | let g: usize = if true {
|
||||
| ++++++++++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL - g = 5;
|
||||
LL + 5
|
||||
|
|
||||
help: add a semicolon after the `if` expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:63:5
|
||||
|
|
||||
LL | let a;
|
||||
| ^^^^^^
|
||||
@ -126,7 +162,7 @@ LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init.rs:67:5
|
||||
--> $DIR/needless_late_init.rs:80:5
|
||||
|
|
||||
LL | let a;
|
||||
| ^^^^^^
|
||||
@ -146,5 +182,5 @@ help: add a semicolon after the `match` expression
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
25
tests/ui/needless_late_init_fixable.fixed
Normal file
25
tests/ui/needless_late_init_fixable.fixed
Normal file
@ -0,0 +1,25 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused, clippy::assign_op_pattern)]
|
||||
|
||||
fn main() {
|
||||
|
||||
let a = "zero";
|
||||
|
||||
|
||||
|
||||
let b = 1;
|
||||
let c = 2;
|
||||
|
||||
|
||||
let d: usize = 1;
|
||||
|
||||
|
||||
let mut e = 1;
|
||||
e = 2;
|
||||
|
||||
|
||||
let h = format!("{}", e);
|
||||
|
||||
println!("{}", a);
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused, clippy::assign_op_pattern)]
|
||||
|
||||
fn main() {
|
||||
@ -16,19 +18,6 @@ fn main() {
|
||||
e = 1;
|
||||
e = 2;
|
||||
|
||||
let f;
|
||||
match 1 {
|
||||
1 => f = "three",
|
||||
_ => return,
|
||||
}; // has semi
|
||||
|
||||
let g: usize;
|
||||
if true {
|
||||
g = 5;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
let h;
|
||||
h = format!("{}", e);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:4:5
|
||||
--> $DIR/needless_late_init_fixable.rs:6:5
|
||||
|
|
||||
LL | let a;
|
||||
| ^^^^^^
|
||||
@ -11,7 +11,7 @@ LL | let a = "zero";
|
||||
| ~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:7:5
|
||||
--> $DIR/needless_late_init_fixable.rs:9:5
|
||||
|
|
||||
LL | let b;
|
||||
| ^^^^^^
|
||||
@ -22,7 +22,7 @@ LL | let b = 1;
|
||||
| ~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:8:5
|
||||
--> $DIR/needless_late_init_fixable.rs:10:5
|
||||
|
|
||||
LL | let c;
|
||||
| ^^^^^^
|
||||
@ -33,7 +33,7 @@ LL | let c = 2;
|
||||
| ~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:12:5
|
||||
--> $DIR/needless_late_init_fixable.rs:14:5
|
||||
|
|
||||
LL | let d: usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
@ -44,7 +44,7 @@ LL | let d: usize = 1;
|
||||
| ~~~~~~~~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:15:5
|
||||
--> $DIR/needless_late_init_fixable.rs:17:5
|
||||
|
|
||||
LL | let mut e;
|
||||
| ^^^^^^^^^^
|
||||
@ -55,43 +55,7 @@ LL | let mut e = 1;
|
||||
| ~~~~~~~~~
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:19:5
|
||||
|
|
||||
LL | let f;
|
||||
| ^^^^^^
|
||||
|
|
||||
help: declare `f` here
|
||||
|
|
||||
LL | let f = match 1 {
|
||||
| +++++++
|
||||
help: remove the assignments from the `match` arms
|
||||
|
|
||||
LL - 1 => f = "three",
|
||||
LL + 1 => "three",
|
||||
|
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:25:5
|
||||
|
|
||||
LL | let g: usize;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: declare `g` here
|
||||
|
|
||||
LL | let g: usize = if true {
|
||||
| ++++++++++++++
|
||||
help: remove the assignments from the branches
|
||||
|
|
||||
LL - g = 5;
|
||||
LL + 5
|
||||
|
|
||||
help: add a semicolon after the `if` expression
|
||||
|
|
||||
LL | };
|
||||
| +
|
||||
|
||||
error: unneeded late initalization
|
||||
--> $DIR/needless_late_init_fixable.rs:32:5
|
||||
--> $DIR/needless_late_init_fixable.rs:21:5
|
||||
|
|
||||
LL | let h;
|
||||
| ^^^^^^
|
||||
@ -101,5 +65,5 @@ help: declare `h` here
|
||||
LL | let h = format!("{}", e);
|
||||
| ~~~~~
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -1,166 +1,166 @@
|
||||
error: this implementation is unsound, as some fields in `RingBuffer<T>` are `!Send`
|
||||
error: some fields in `RingBuffer<T>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:16:1
|
||||
|
|
||||
LL | unsafe impl<T> Send for RingBuffer<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
|
||||
note: the type of field `data` is `!Send`
|
||||
note: it is not safe to send field `data` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:11:5
|
||||
|
|
||||
LL | data: Vec<UnsafeCell<T>>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: add bounds on type parameter `T` that satisfy `Vec<UnsafeCell<T>>: Send`
|
||||
|
||||
error: this implementation is unsound, as some fields in `MvccRwLock<T>` are `!Send`
|
||||
error: some fields in `MvccRwLock<T>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:24:1
|
||||
|
|
||||
LL | unsafe impl<T> Send for MvccRwLock<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `lock` is `!Send`
|
||||
note: it is not safe to send field `lock` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:21:5
|
||||
|
|
||||
LL | lock: Mutex<Box<T>>,
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= help: add bounds on type parameter `T` that satisfy `Mutex<Box<T>>: Send`
|
||||
|
||||
error: this implementation is unsound, as some fields in `ArcGuard<RC, T>` are `!Send`
|
||||
error: some fields in `ArcGuard<RC, T>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:32:1
|
||||
|
|
||||
LL | unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `head` is `!Send`
|
||||
note: it is not safe to send field `head` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:29:5
|
||||
|
|
||||
LL | head: Arc<RC>,
|
||||
| ^^^^^^^^^^^^^
|
||||
= help: add bounds on type parameter `RC` that satisfy `Arc<RC>: Send`
|
||||
|
||||
error: this implementation is unsound, as some fields in `DeviceHandle<T>` are `!Send`
|
||||
error: some fields in `DeviceHandle<T>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:48:1
|
||||
|
|
||||
LL | unsafe impl<T: UsbContext> Send for DeviceHandle<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `context` is `!Send`
|
||||
note: it is not safe to send field `context` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:44:5
|
||||
|
|
||||
LL | context: T,
|
||||
| ^^^^^^^^^^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
|
||||
error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
|
||||
error: some fields in `NoGeneric` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:55:1
|
||||
|
|
||||
LL | unsafe impl Send for NoGeneric {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `rc_is_not_send` is `!Send`
|
||||
note: it is not safe to send field `rc_is_not_send` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:52:5
|
||||
|
|
||||
LL | rc_is_not_send: Rc<String>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: use a thread-safe type that implements `Send`
|
||||
|
||||
error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
|
||||
error: some fields in `MultiField<T>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:63:1
|
||||
|
|
||||
LL | unsafe impl<T> Send for MultiField<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `field1` is `!Send`
|
||||
note: it is not safe to send field `field1` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:58:5
|
||||
|
|
||||
LL | field1: T,
|
||||
| ^^^^^^^^^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
note: the type of field `field2` is `!Send`
|
||||
note: it is not safe to send field `field2` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:59:5
|
||||
|
|
||||
LL | field2: T,
|
||||
| ^^^^^^^^^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
note: the type of field `field3` is `!Send`
|
||||
note: it is not safe to send field `field3` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:60:5
|
||||
|
|
||||
LL | field3: T,
|
||||
| ^^^^^^^^^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
|
||||
error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
|
||||
error: some fields in `MyOption<T>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:70:1
|
||||
|
|
||||
LL | unsafe impl<T> Send for MyOption<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `0` is `!Send`
|
||||
note: it is not safe to send field `0` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:66:12
|
||||
|
|
||||
LL | MySome(T),
|
||||
| ^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
|
||||
error: this implementation is unsound, as some fields in `MultiParam<A, B>` are `!Send`
|
||||
error: some fields in `MultiParam<A, B>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:82:1
|
||||
|
|
||||
LL | unsafe impl<A, B> Send for MultiParam<A, B> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `vec` is `!Send`
|
||||
note: it is not safe to send field `vec` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:79:5
|
||||
|
|
||||
LL | vec: Vec<(A, B)>,
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
= help: add bounds on type parameters `A, B` that satisfy `Vec<(A, B)>: Send`
|
||||
|
||||
error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
|
||||
error: some fields in `HeuristicTest` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:100:1
|
||||
|
|
||||
LL | unsafe impl Send for HeuristicTest {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `field4` is `!Send`
|
||||
note: it is not safe to send field `field4` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:95:5
|
||||
|
|
||||
LL | field4: (*const NonSend, Rc<u8>),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: use a thread-safe type that implements `Send`
|
||||
|
||||
error: this implementation is unsound, as some fields in `AttrTest3<T>` are `!Send`
|
||||
error: some fields in `AttrTest3<T>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:119:1
|
||||
|
|
||||
LL | unsafe impl<T> Send for AttrTest3<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `0` is `!Send`
|
||||
note: it is not safe to send field `0` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:114:11
|
||||
|
|
||||
LL | Enum2(T),
|
||||
| ^
|
||||
= help: add `T: Send` bound in `Send` impl
|
||||
|
||||
error: this implementation is unsound, as some fields in `Complex<P, u32>` are `!Send`
|
||||
error: some fields in `Complex<P, u32>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:127:1
|
||||
|
|
||||
LL | unsafe impl<P> Send for Complex<P, u32> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `field1` is `!Send`
|
||||
note: it is not safe to send field `field1` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:123:5
|
||||
|
|
||||
LL | field1: A,
|
||||
| ^^^^^^^^^
|
||||
= help: add `P: Send` bound in `Send` impl
|
||||
|
||||
error: this implementation is unsound, as some fields in `Complex<Q, MutexGuard<'static, bool>>` are `!Send`
|
||||
error: some fields in `Complex<Q, MutexGuard<'static, bool>>` are not safe to be sent to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:130:1
|
||||
|
|
||||
LL | unsafe impl<Q: Send> Send for Complex<Q, MutexGuard<'static, bool>> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the type of field `field2` is `!Send`
|
||||
note: it is not safe to send field `field2` to another thread
|
||||
--> $DIR/non_send_fields_in_send_ty.rs:124:5
|
||||
|
|
||||
LL | field2: B,
|
||||
|
@ -86,6 +86,19 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> {
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
enum DummyEnum {
|
||||
One(u8),
|
||||
Two,
|
||||
}
|
||||
|
||||
// should not warn since there is a compled complex subpat
|
||||
// see #7991
|
||||
fn complex_subpat() -> DummyEnum {
|
||||
let x = Some(DummyEnum::One(1));
|
||||
let _ = if let Some(_one @ DummyEnum::One(..)) = x { 1 } else { 2 };
|
||||
DummyEnum::Two
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let optional = Some(5);
|
||||
let _ = optional.map_or(5, |x| x + 2);
|
||||
@ -159,4 +172,5 @@ fn main() {
|
||||
}
|
||||
|
||||
let _ = pattern_to_vec("hello world");
|
||||
let _ = complex_subpat();
|
||||
}
|
||||
|
@ -109,6 +109,19 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> {
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
enum DummyEnum {
|
||||
One(u8),
|
||||
Two,
|
||||
}
|
||||
|
||||
// should not warn since there is a compled complex subpat
|
||||
// see #7991
|
||||
fn complex_subpat() -> DummyEnum {
|
||||
let x = Some(DummyEnum::One(1));
|
||||
let _ = if let Some(_one @ DummyEnum::One(..)) = x { 1 } else { 2 };
|
||||
DummyEnum::Two
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let optional = Some(5);
|
||||
let _ = if let Some(x) = optional { x + 2 } else { 5 };
|
||||
@ -188,4 +201,5 @@ fn main() {
|
||||
}
|
||||
|
||||
let _ = pattern_to_vec("hello world");
|
||||
let _ = complex_subpat();
|
||||
}
|
||||
|
@ -153,13 +153,13 @@ LL | | }
|
||||
| |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:114:13
|
||||
--> $DIR/option_if_let_else.rs:127:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:123:13
|
||||
--> $DIR/option_if_let_else.rs:136:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = Some(0) {
|
||||
| _____________^
|
||||
@ -181,13 +181,13 @@ LL ~ });
|
||||
|
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:151:13
|
||||
--> $DIR/option_if_let_else.rs:164:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:155:13
|
||||
--> $DIR/option_if_let_else.rs:168:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = Some(0) {
|
||||
| _____________^
|
||||
|
@ -136,6 +136,24 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
|
||||
Ok(y)
|
||||
}
|
||||
|
||||
// see issue #8019
|
||||
pub enum NotOption {
|
||||
None,
|
||||
First,
|
||||
AfterFirst,
|
||||
}
|
||||
|
||||
fn obj(_: i32) -> Result<(), NotOption> {
|
||||
Err(NotOption::First)
|
||||
}
|
||||
|
||||
fn f() -> NotOption {
|
||||
if obj(2).is_err() {
|
||||
return NotOption::None;
|
||||
}
|
||||
NotOption::First
|
||||
}
|
||||
|
||||
fn main() {
|
||||
some_func(Some(42));
|
||||
some_func(None);
|
||||
@ -157,4 +175,5 @@ fn main() {
|
||||
func();
|
||||
|
||||
let _ = result_func(Ok(42));
|
||||
let _ = f();
|
||||
}
|
||||
|
@ -168,6 +168,24 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
|
||||
Ok(y)
|
||||
}
|
||||
|
||||
// see issue #8019
|
||||
pub enum NotOption {
|
||||
None,
|
||||
First,
|
||||
AfterFirst,
|
||||
}
|
||||
|
||||
fn obj(_: i32) -> Result<(), NotOption> {
|
||||
Err(NotOption::First)
|
||||
}
|
||||
|
||||
fn f() -> NotOption {
|
||||
if obj(2).is_err() {
|
||||
return NotOption::None;
|
||||
}
|
||||
NotOption::First
|
||||
}
|
||||
|
||||
fn main() {
|
||||
some_func(Some(42));
|
||||
some_func(None);
|
||||
@ -189,4 +207,5 @@ fn main() {
|
||||
func();
|
||||
|
||||
let _ = result_func(Ok(42));
|
||||
let _ = f();
|
||||
}
|
||||
|
42
tests/ui/return_self_not_must_use.rs
Normal file
42
tests/ui/return_self_not_must_use.rs
Normal file
@ -0,0 +1,42 @@
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Bar;
|
||||
|
||||
pub trait Whatever {
|
||||
fn what(&self) -> Self;
|
||||
// There should be no warning here!
|
||||
fn what2(&self) -> &Self;
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
// There should be no warning here!
|
||||
pub fn not_new() -> Self {
|
||||
Self
|
||||
}
|
||||
pub fn foo(&self) -> Self {
|
||||
Self
|
||||
}
|
||||
pub fn bar(self) -> Self {
|
||||
self
|
||||
}
|
||||
// There should be no warning here!
|
||||
fn foo2(&self) -> Self {
|
||||
Self
|
||||
}
|
||||
// There should be no warning here!
|
||||
pub fn foo3(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Whatever for Bar {
|
||||
// There should be no warning here!
|
||||
fn what(&self) -> Self {
|
||||
self.foo2()
|
||||
}
|
||||
// There should be no warning here!
|
||||
fn what2(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
26
tests/ui/return_self_not_must_use.stderr
Normal file
26
tests/ui/return_self_not_must_use.stderr
Normal file
@ -0,0 +1,26 @@
|
||||
error: missing `#[must_use]` attribute on a method returning `Self`
|
||||
--> $DIR/return_self_not_must_use.rs:7:5
|
||||
|
|
||||
LL | fn what(&self) -> Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::return-self-not-must-use` implied by `-D warnings`
|
||||
|
||||
error: missing `#[must_use]` attribute on a method returning `Self`
|
||||
--> $DIR/return_self_not_must_use.rs:17:5
|
||||
|
|
||||
LL | / pub fn foo(&self) -> Self {
|
||||
LL | | Self
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: missing `#[must_use]` attribute on a method returning `Self`
|
||||
--> $DIR/return_self_not_must_use.rs:20:5
|
||||
|
|
||||
LL | / pub fn bar(self) -> Self {
|
||||
LL | | self
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -7,7 +7,8 @@
|
||||
clippy::needless_lifetimes,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::wrong_self_convention,
|
||||
clippy::missing_panics_doc
|
||||
clippy::missing_panics_doc,
|
||||
clippy::return_self_not_must_use
|
||||
)]
|
||||
|
||||
use std::ops::Mul;
|
||||
|
@ -7,7 +7,8 @@
|
||||
clippy::needless_lifetimes,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::wrong_self_convention,
|
||||
clippy::missing_panics_doc
|
||||
clippy::missing_panics_doc,
|
||||
clippy::return_self_not_must_use
|
||||
)]
|
||||
|
||||
use std::ops::Mul;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: method `add` can be confused for the standard trait method `std::ops::Add::add`
|
||||
--> $DIR/method_list_1.rs:24:5
|
||||
--> $DIR/method_list_1.rs:25:5
|
||||
|
|
||||
LL | / pub fn add(self, other: T) -> T {
|
||||
LL | | unimplemented!()
|
||||
@ -10,7 +10,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
|
||||
|
||||
error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
|
||||
--> $DIR/method_list_1.rs:28:5
|
||||
--> $DIR/method_list_1.rs:29:5
|
||||
|
|
||||
LL | / pub fn as_mut(&mut self) -> &mut T {
|
||||
LL | | unimplemented!()
|
||||
@ -20,7 +20,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
|
||||
--> $DIR/method_list_1.rs:32:5
|
||||
--> $DIR/method_list_1.rs:33:5
|
||||
|
|
||||
LL | / pub fn as_ref(&self) -> &T {
|
||||
LL | | unimplemented!()
|
||||
@ -30,7 +30,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
|
||||
|
||||
error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
|
||||
--> $DIR/method_list_1.rs:36:5
|
||||
--> $DIR/method_list_1.rs:37:5
|
||||
|
|
||||
LL | / pub fn bitand(self, rhs: T) -> T {
|
||||
LL | | unimplemented!()
|
||||
@ -40,7 +40,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
|
||||
|
||||
error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
|
||||
--> $DIR/method_list_1.rs:40:5
|
||||
--> $DIR/method_list_1.rs:41:5
|
||||
|
|
||||
LL | / pub fn bitor(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -50,7 +50,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
|
||||
|
||||
error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
|
||||
--> $DIR/method_list_1.rs:44:5
|
||||
--> $DIR/method_list_1.rs:45:5
|
||||
|
|
||||
LL | / pub fn bitxor(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -60,7 +60,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
|
||||
|
||||
error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
|
||||
--> $DIR/method_list_1.rs:48:5
|
||||
--> $DIR/method_list_1.rs:49:5
|
||||
|
|
||||
LL | / pub fn borrow(&self) -> &str {
|
||||
LL | | unimplemented!()
|
||||
@ -70,7 +70,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
|
||||
|
||||
error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
|
||||
--> $DIR/method_list_1.rs:52:5
|
||||
--> $DIR/method_list_1.rs:53:5
|
||||
|
|
||||
LL | / pub fn borrow_mut(&mut self) -> &mut str {
|
||||
LL | | unimplemented!()
|
||||
@ -80,7 +80,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
|
||||
--> $DIR/method_list_1.rs:56:5
|
||||
--> $DIR/method_list_1.rs:57:5
|
||||
|
|
||||
LL | / pub fn clone(&self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -90,7 +90,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
|
||||
|
||||
error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
|
||||
--> $DIR/method_list_1.rs:60:5
|
||||
--> $DIR/method_list_1.rs:61:5
|
||||
|
|
||||
LL | / pub fn cmp(&self, other: &Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -100,7 +100,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
|
||||
|
||||
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
|
||||
--> $DIR/method_list_1.rs:68:5
|
||||
--> $DIR/method_list_1.rs:69:5
|
||||
|
|
||||
LL | / pub fn deref(&self) -> &Self {
|
||||
LL | | unimplemented!()
|
||||
@ -110,7 +110,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
|
||||
|
||||
error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
|
||||
--> $DIR/method_list_1.rs:72:5
|
||||
--> $DIR/method_list_1.rs:73:5
|
||||
|
|
||||
LL | / pub fn deref_mut(&mut self) -> &mut Self {
|
||||
LL | | unimplemented!()
|
||||
@ -120,7 +120,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `div` can be confused for the standard trait method `std::ops::Div::div`
|
||||
--> $DIR/method_list_1.rs:76:5
|
||||
--> $DIR/method_list_1.rs:77:5
|
||||
|
|
||||
LL | / pub fn div(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -130,7 +130,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
|
||||
|
||||
error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
|
||||
--> $DIR/method_list_1.rs:80:5
|
||||
--> $DIR/method_list_1.rs:81:5
|
||||
|
|
||||
LL | / pub fn drop(&mut self) {
|
||||
LL | | unimplemented!()
|
||||
|
@ -7,7 +7,8 @@
|
||||
clippy::needless_lifetimes,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::wrong_self_convention,
|
||||
clippy::missing_panics_doc
|
||||
clippy::missing_panics_doc,
|
||||
clippy::return_self_not_must_use
|
||||
)]
|
||||
|
||||
use std::ops::Mul;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
|
||||
--> $DIR/method_list_2.rs:25:5
|
||||
--> $DIR/method_list_2.rs:26:5
|
||||
|
|
||||
LL | / pub fn eq(&self, other: &Self) -> bool {
|
||||
LL | | unimplemented!()
|
||||
@ -10,7 +10,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
|
||||
|
||||
error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
|
||||
--> $DIR/method_list_2.rs:29:5
|
||||
--> $DIR/method_list_2.rs:30:5
|
||||
|
|
||||
LL | / pub fn from_iter<T>(iter: T) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -20,7 +20,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
|
||||
|
||||
error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
|
||||
--> $DIR/method_list_2.rs:33:5
|
||||
--> $DIR/method_list_2.rs:34:5
|
||||
|
|
||||
LL | / pub fn from_str(s: &str) -> Result<Self, Self> {
|
||||
LL | | unimplemented!()
|
||||
@ -30,7 +30,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
|
||||
|
||||
error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
|
||||
--> $DIR/method_list_2.rs:37:5
|
||||
--> $DIR/method_list_2.rs:38:5
|
||||
|
|
||||
LL | / pub fn hash(&self, state: &mut T) {
|
||||
LL | | unimplemented!()
|
||||
@ -40,7 +40,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
|
||||
|
||||
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
|
||||
--> $DIR/method_list_2.rs:41:5
|
||||
--> $DIR/method_list_2.rs:42:5
|
||||
|
|
||||
LL | / pub fn index(&self, index: usize) -> &Self {
|
||||
LL | | unimplemented!()
|
||||
@ -50,7 +50,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
|
||||
|
||||
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
|
||||
--> $DIR/method_list_2.rs:45:5
|
||||
--> $DIR/method_list_2.rs:46:5
|
||||
|
|
||||
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
|
||||
LL | | unimplemented!()
|
||||
@ -60,7 +60,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
|
||||
|
||||
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
|
||||
--> $DIR/method_list_2.rs:49:5
|
||||
--> $DIR/method_list_2.rs:50:5
|
||||
|
|
||||
LL | / pub fn into_iter(self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -70,7 +70,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
|
||||
|
||||
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
|
||||
--> $DIR/method_list_2.rs:53:5
|
||||
--> $DIR/method_list_2.rs:54:5
|
||||
|
|
||||
LL | / pub fn mul(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -80,7 +80,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
|
||||
|
||||
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
|
||||
--> $DIR/method_list_2.rs:57:5
|
||||
--> $DIR/method_list_2.rs:58:5
|
||||
|
|
||||
LL | / pub fn neg(self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -90,7 +90,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
|
||||
|
||||
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
|
||||
--> $DIR/method_list_2.rs:61:5
|
||||
--> $DIR/method_list_2.rs:62:5
|
||||
|
|
||||
LL | / pub fn next(&mut self) -> Option<Self> {
|
||||
LL | | unimplemented!()
|
||||
@ -100,7 +100,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
|
||||
|
||||
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
|
||||
--> $DIR/method_list_2.rs:65:5
|
||||
--> $DIR/method_list_2.rs:66:5
|
||||
|
|
||||
LL | / pub fn not(self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -110,7 +110,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
|
||||
|
||||
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
|
||||
--> $DIR/method_list_2.rs:69:5
|
||||
--> $DIR/method_list_2.rs:70:5
|
||||
|
|
||||
LL | / pub fn rem(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -120,7 +120,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
|
||||
|
||||
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
|
||||
--> $DIR/method_list_2.rs:73:5
|
||||
--> $DIR/method_list_2.rs:74:5
|
||||
|
|
||||
LL | / pub fn shl(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -130,7 +130,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
|
||||
|
||||
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
|
||||
--> $DIR/method_list_2.rs:77:5
|
||||
--> $DIR/method_list_2.rs:78:5
|
||||
|
|
||||
LL | / pub fn shr(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
@ -140,7 +140,7 @@ LL | | }
|
||||
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
|
||||
|
||||
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
|
||||
--> $DIR/method_list_2.rs:81:5
|
||||
--> $DIR/method_list_2.rs:82:5
|
||||
|
|
||||
LL | / pub fn sub(self, rhs: Self) -> Self {
|
||||
LL | | unimplemented!()
|
||||
|
@ -30,6 +30,15 @@ trait T {
|
||||
fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
|
||||
}
|
||||
|
||||
// Should not warn since there is likely no way to simplify this (#1013)
|
||||
impl T for () {
|
||||
const A: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
|
||||
|
||||
type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
|
||||
|
||||
fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
|
||||
}
|
||||
|
||||
fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
|
||||
vec![]
|
||||
}
|
||||
|
@ -73,19 +73,19 @@ LL | fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: very complex type used. Consider factoring parts into `type` definitions
|
||||
--> $DIR/type_complexity.rs:33:15
|
||||
--> $DIR/type_complexity.rs:42:15
|
||||
|
|
||||
LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: very complex type used. Consider factoring parts into `type` definitions
|
||||
--> $DIR/type_complexity.rs:37:14
|
||||
--> $DIR/type_complexity.rs:46:14
|
||||
|
|
||||
LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: very complex type used. Consider factoring parts into `type` definitions
|
||||
--> $DIR/type_complexity.rs:40:13
|
||||
--> $DIR/type_complexity.rs:49:13
|
||||
|
|
||||
LL | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
142
tests/ui/unnecessary_iter_cloned.fixed
Normal file
142
tests/ui/unnecessary_iter_cloned.fixed
Normal file
@ -0,0 +1,142 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused_assignments)]
|
||||
#![warn(clippy::unnecessary_to_owned)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
enum FileType {
|
||||
Account,
|
||||
PrivateKey,
|
||||
Certificate,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let path = std::path::Path::new("x");
|
||||
|
||||
let _ = check_files(&[(FileType::Account, path)]);
|
||||
let _ = check_files_vec(vec![(FileType::Account, path)]);
|
||||
|
||||
// negative tests
|
||||
let _ = check_files_ref(&[(FileType::Account, path)]);
|
||||
let _ = check_files_mut(&[(FileType::Account, path)]);
|
||||
let _ = check_files_ref_mut(&[(FileType::Account, path)]);
|
||||
let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
|
||||
let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
|
||||
}
|
||||
|
||||
// `check_files` and its variants are based on:
|
||||
// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
|
||||
fn check_files(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (t, path) in files {
|
||||
let other = match get_file_path(t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool {
|
||||
for (t, path) in files.iter() {
|
||||
let other = match get_file_path(t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (ref t, path) in files.iter().copied() {
|
||||
let other = match get_file_path(t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (mut t, path) in files.iter().copied() {
|
||||
t = FileType::PrivateKey;
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (ref mut t, path) in files.iter().copied() {
|
||||
*t = FileType::PrivateKey;
|
||||
let other = match get_file_path(t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (t, path) in files.iter().copied() {
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.join(path).is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool {
|
||||
for (mut t, path) in files.iter().cloned() {
|
||||
t = FileType::PrivateKey;
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
|
||||
Ok(std::path::PathBuf::new())
|
||||
}
|
142
tests/ui/unnecessary_iter_cloned.rs
Normal file
142
tests/ui/unnecessary_iter_cloned.rs
Normal file
@ -0,0 +1,142 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused_assignments)]
|
||||
#![warn(clippy::unnecessary_to_owned)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
enum FileType {
|
||||
Account,
|
||||
PrivateKey,
|
||||
Certificate,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let path = std::path::Path::new("x");
|
||||
|
||||
let _ = check_files(&[(FileType::Account, path)]);
|
||||
let _ = check_files_vec(vec![(FileType::Account, path)]);
|
||||
|
||||
// negative tests
|
||||
let _ = check_files_ref(&[(FileType::Account, path)]);
|
||||
let _ = check_files_mut(&[(FileType::Account, path)]);
|
||||
let _ = check_files_ref_mut(&[(FileType::Account, path)]);
|
||||
let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
|
||||
let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
|
||||
}
|
||||
|
||||
// `check_files` and its variants are based on:
|
||||
// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
|
||||
fn check_files(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (t, path) in files.iter().copied() {
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool {
|
||||
for (t, path) in files.iter().copied() {
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (ref t, path) in files.iter().copied() {
|
||||
let other = match get_file_path(t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (mut t, path) in files.iter().copied() {
|
||||
t = FileType::PrivateKey;
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (ref mut t, path) in files.iter().copied() {
|
||||
*t = FileType::PrivateKey;
|
||||
let other = match get_file_path(t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool {
|
||||
for (t, path) in files.iter().copied() {
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.join(path).is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool {
|
||||
for (mut t, path) in files.iter().cloned() {
|
||||
t = FileType::PrivateKey;
|
||||
let other = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() || !other.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
|
||||
Ok(std::path::PathBuf::new())
|
||||
}
|
35
tests/ui/unnecessary_iter_cloned.stderr
Normal file
35
tests/ui/unnecessary_iter_cloned.stderr
Normal file
@ -0,0 +1,35 @@
|
||||
error: unnecessary use of `copied`
|
||||
--> $DIR/unnecessary_iter_cloned.rs:31:22
|
||||
|
|
||||
LL | for (t, path) in files.iter().copied() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::unnecessary-to-owned` implied by `-D warnings`
|
||||
help: use
|
||||
|
|
||||
LL | for (t, path) in files {
|
||||
| ~~~~~
|
||||
help: remove this `&`
|
||||
|
|
||||
LL - let other = match get_file_path(&t) {
|
||||
LL + let other = match get_file_path(t) {
|
||||
|
|
||||
|
||||
error: unnecessary use of `copied`
|
||||
--> $DIR/unnecessary_iter_cloned.rs:46:22
|
||||
|
|
||||
LL | for (t, path) in files.iter().copied() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use
|
||||
|
|
||||
LL | for (t, path) in files.iter() {
|
||||
| ~~~~~~~~~~~~
|
||||
help: remove this `&`
|
||||
|
|
||||
LL - let other = match get_file_path(&t) {
|
||||
LL + let other = match get_file_path(t) {
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
214
tests/ui/unnecessary_to_owned.fixed
Normal file
214
tests/ui/unnecessary_to_owned.fixed
Normal file
@ -0,0 +1,214 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(clippy::ptr_arg)]
|
||||
#![warn(clippy::unnecessary_to_owned)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::{CStr, CString, OsStr, OsString};
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct X(String);
|
||||
|
||||
impl Deref for X {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for X {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for X {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl X {
|
||||
fn join(&self, other: impl AsRef<str>) -> Self {
|
||||
let mut s = self.0.clone();
|
||||
s.push_str(other.as_ref());
|
||||
Self(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
enum FileType {
|
||||
Account,
|
||||
PrivateKey,
|
||||
Certificate,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c_str = CStr::from_bytes_with_nul(&[0]).unwrap();
|
||||
let os_str = OsStr::new("x");
|
||||
let path = std::path::Path::new("x");
|
||||
let s = "x";
|
||||
let array = ["x"];
|
||||
let array_ref = &["x"];
|
||||
let slice = &["x"][..];
|
||||
let x = X(String::from("x"));
|
||||
let x_ref = &x;
|
||||
|
||||
require_c_str(&Cow::from(c_str));
|
||||
require_c_str(c_str);
|
||||
|
||||
require_os_str(os_str);
|
||||
require_os_str(&Cow::from(os_str));
|
||||
require_os_str(os_str);
|
||||
|
||||
require_path(path);
|
||||
require_path(&Cow::from(path));
|
||||
require_path(path);
|
||||
|
||||
require_str(s);
|
||||
require_str(&Cow::from(s));
|
||||
require_str(s);
|
||||
require_str(x_ref.as_ref());
|
||||
|
||||
require_slice(slice);
|
||||
require_slice(&Cow::from(slice));
|
||||
require_slice(array.as_ref());
|
||||
require_slice(array_ref.as_ref());
|
||||
require_slice(slice);
|
||||
require_slice(x_ref);
|
||||
|
||||
require_x(&Cow::<X>::Owned(x.clone()));
|
||||
require_x(x_ref);
|
||||
|
||||
require_deref_c_str(c_str);
|
||||
require_deref_os_str(os_str);
|
||||
require_deref_path(path);
|
||||
require_deref_str(s);
|
||||
require_deref_slice(slice);
|
||||
|
||||
require_impl_deref_c_str(c_str);
|
||||
require_impl_deref_os_str(os_str);
|
||||
require_impl_deref_path(path);
|
||||
require_impl_deref_str(s);
|
||||
require_impl_deref_slice(slice);
|
||||
|
||||
require_deref_str_slice(s, slice);
|
||||
require_deref_slice_str(slice, s);
|
||||
|
||||
require_as_ref_c_str(c_str);
|
||||
require_as_ref_os_str(os_str);
|
||||
require_as_ref_path(path);
|
||||
require_as_ref_str(s);
|
||||
require_as_ref_str(&x);
|
||||
require_as_ref_slice(array);
|
||||
require_as_ref_slice(array_ref);
|
||||
require_as_ref_slice(slice);
|
||||
|
||||
require_impl_as_ref_c_str(c_str);
|
||||
require_impl_as_ref_os_str(os_str);
|
||||
require_impl_as_ref_path(path);
|
||||
require_impl_as_ref_str(s);
|
||||
require_impl_as_ref_str(&x);
|
||||
require_impl_as_ref_slice(array);
|
||||
require_impl_as_ref_slice(array_ref);
|
||||
require_impl_as_ref_slice(slice);
|
||||
|
||||
require_as_ref_str_slice(s, array);
|
||||
require_as_ref_str_slice(s, array_ref);
|
||||
require_as_ref_str_slice(s, slice);
|
||||
require_as_ref_slice_str(array, s);
|
||||
require_as_ref_slice_str(array_ref, s);
|
||||
require_as_ref_slice_str(slice, s);
|
||||
|
||||
let _ = x.join(x_ref);
|
||||
|
||||
let _ = slice.iter().copied();
|
||||
let _ = slice.iter().copied();
|
||||
let _ = [std::path::PathBuf::new()][..].iter().cloned();
|
||||
let _ = [std::path::PathBuf::new()][..].iter().cloned();
|
||||
|
||||
let _ = slice.iter().copied();
|
||||
let _ = slice.iter().copied();
|
||||
let _ = [std::path::PathBuf::new()][..].iter().cloned();
|
||||
let _ = [std::path::PathBuf::new()][..].iter().cloned();
|
||||
|
||||
let _ = check_files(&[FileType::Account]);
|
||||
|
||||
// negative tests
|
||||
require_string(&s.to_string());
|
||||
require_string(&Cow::from(s).into_owned());
|
||||
require_string(&s.to_owned());
|
||||
require_string(&x_ref.to_string());
|
||||
|
||||
// `X` isn't copy.
|
||||
require_slice(&x.to_owned());
|
||||
require_deref_slice(x.to_owned());
|
||||
|
||||
// The following should be flagged by `redundant_clone`, but not by this lint.
|
||||
require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap());
|
||||
require_os_str(&OsString::from("x"));
|
||||
require_path(&std::path::PathBuf::from("x"));
|
||||
require_str(&String::from("x"));
|
||||
}
|
||||
|
||||
fn require_c_str(_: &CStr) {}
|
||||
fn require_os_str(_: &OsStr) {}
|
||||
fn require_path(_: &std::path::Path) {}
|
||||
fn require_str(_: &str) {}
|
||||
fn require_slice<T>(_: &[T]) {}
|
||||
fn require_x(_: &X) {}
|
||||
|
||||
fn require_deref_c_str<T: Deref<Target = CStr>>(_: T) {}
|
||||
fn require_deref_os_str<T: Deref<Target = OsStr>>(_: T) {}
|
||||
fn require_deref_path<T: Deref<Target = std::path::Path>>(_: T) {}
|
||||
fn require_deref_str<T: Deref<Target = str>>(_: T) {}
|
||||
fn require_deref_slice<T, U: Deref<Target = [T]>>(_: U) {}
|
||||
|
||||
fn require_impl_deref_c_str(_: impl Deref<Target = CStr>) {}
|
||||
fn require_impl_deref_os_str(_: impl Deref<Target = OsStr>) {}
|
||||
fn require_impl_deref_path(_: impl Deref<Target = std::path::Path>) {}
|
||||
fn require_impl_deref_str(_: impl Deref<Target = str>) {}
|
||||
fn require_impl_deref_slice<T>(_: impl Deref<Target = [T]>) {}
|
||||
|
||||
fn require_deref_str_slice<T: Deref<Target = str>, U, V: Deref<Target = [U]>>(_: T, _: V) {}
|
||||
fn require_deref_slice_str<T, U: Deref<Target = [T]>, V: Deref<Target = str>>(_: U, _: V) {}
|
||||
|
||||
fn require_as_ref_c_str<T: AsRef<CStr>>(_: T) {}
|
||||
fn require_as_ref_os_str<T: AsRef<OsStr>>(_: T) {}
|
||||
fn require_as_ref_path<T: AsRef<std::path::Path>>(_: T) {}
|
||||
fn require_as_ref_str<T: AsRef<str>>(_: T) {}
|
||||
fn require_as_ref_slice<T, U: AsRef<[T]>>(_: U) {}
|
||||
|
||||
fn require_impl_as_ref_c_str(_: impl AsRef<CStr>) {}
|
||||
fn require_impl_as_ref_os_str(_: impl AsRef<OsStr>) {}
|
||||
fn require_impl_as_ref_path(_: impl AsRef<std::path::Path>) {}
|
||||
fn require_impl_as_ref_str(_: impl AsRef<str>) {}
|
||||
fn require_impl_as_ref_slice<T>(_: impl AsRef<[T]>) {}
|
||||
|
||||
fn require_as_ref_str_slice<T: AsRef<str>, U, V: AsRef<[U]>>(_: T, _: V) {}
|
||||
fn require_as_ref_slice_str<T, U: AsRef<[T]>, V: AsRef<str>>(_: U, _: V) {}
|
||||
|
||||
// `check_files` is based on:
|
||||
// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
|
||||
fn check_files(file_types: &[FileType]) -> bool {
|
||||
for t in file_types {
|
||||
let path = match get_file_path(t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
|
||||
Ok(std::path::PathBuf::new())
|
||||
}
|
||||
|
||||
fn require_string(_: &String) {}
|
214
tests/ui/unnecessary_to_owned.rs
Normal file
214
tests/ui/unnecessary_to_owned.rs
Normal file
@ -0,0 +1,214 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(clippy::ptr_arg)]
|
||||
#![warn(clippy::unnecessary_to_owned)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::{CStr, CString, OsStr, OsString};
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct X(String);
|
||||
|
||||
impl Deref for X {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for X {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for X {
|
||||
fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl X {
|
||||
fn join(&self, other: impl AsRef<str>) -> Self {
|
||||
let mut s = self.0.clone();
|
||||
s.push_str(other.as_ref());
|
||||
Self(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
enum FileType {
|
||||
Account,
|
||||
PrivateKey,
|
||||
Certificate,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c_str = CStr::from_bytes_with_nul(&[0]).unwrap();
|
||||
let os_str = OsStr::new("x");
|
||||
let path = std::path::Path::new("x");
|
||||
let s = "x";
|
||||
let array = ["x"];
|
||||
let array_ref = &["x"];
|
||||
let slice = &["x"][..];
|
||||
let x = X(String::from("x"));
|
||||
let x_ref = &x;
|
||||
|
||||
require_c_str(&Cow::from(c_str).into_owned());
|
||||
require_c_str(&c_str.to_owned());
|
||||
|
||||
require_os_str(&os_str.to_os_string());
|
||||
require_os_str(&Cow::from(os_str).into_owned());
|
||||
require_os_str(&os_str.to_owned());
|
||||
|
||||
require_path(&path.to_path_buf());
|
||||
require_path(&Cow::from(path).into_owned());
|
||||
require_path(&path.to_owned());
|
||||
|
||||
require_str(&s.to_string());
|
||||
require_str(&Cow::from(s).into_owned());
|
||||
require_str(&s.to_owned());
|
||||
require_str(&x_ref.to_string());
|
||||
|
||||
require_slice(&slice.to_vec());
|
||||
require_slice(&Cow::from(slice).into_owned());
|
||||
require_slice(&array.to_owned());
|
||||
require_slice(&array_ref.to_owned());
|
||||
require_slice(&slice.to_owned());
|
||||
require_slice(&x_ref.to_owned());
|
||||
|
||||
require_x(&Cow::<X>::Owned(x.clone()).into_owned());
|
||||
require_x(&x_ref.to_owned());
|
||||
|
||||
require_deref_c_str(c_str.to_owned());
|
||||
require_deref_os_str(os_str.to_owned());
|
||||
require_deref_path(path.to_owned());
|
||||
require_deref_str(s.to_owned());
|
||||
require_deref_slice(slice.to_owned());
|
||||
|
||||
require_impl_deref_c_str(c_str.to_owned());
|
||||
require_impl_deref_os_str(os_str.to_owned());
|
||||
require_impl_deref_path(path.to_owned());
|
||||
require_impl_deref_str(s.to_owned());
|
||||
require_impl_deref_slice(slice.to_owned());
|
||||
|
||||
require_deref_str_slice(s.to_owned(), slice.to_owned());
|
||||
require_deref_slice_str(slice.to_owned(), s.to_owned());
|
||||
|
||||
require_as_ref_c_str(c_str.to_owned());
|
||||
require_as_ref_os_str(os_str.to_owned());
|
||||
require_as_ref_path(path.to_owned());
|
||||
require_as_ref_str(s.to_owned());
|
||||
require_as_ref_str(x.to_owned());
|
||||
require_as_ref_slice(array.to_owned());
|
||||
require_as_ref_slice(array_ref.to_owned());
|
||||
require_as_ref_slice(slice.to_owned());
|
||||
|
||||
require_impl_as_ref_c_str(c_str.to_owned());
|
||||
require_impl_as_ref_os_str(os_str.to_owned());
|
||||
require_impl_as_ref_path(path.to_owned());
|
||||
require_impl_as_ref_str(s.to_owned());
|
||||
require_impl_as_ref_str(x.to_owned());
|
||||
require_impl_as_ref_slice(array.to_owned());
|
||||
require_impl_as_ref_slice(array_ref.to_owned());
|
||||
require_impl_as_ref_slice(slice.to_owned());
|
||||
|
||||
require_as_ref_str_slice(s.to_owned(), array.to_owned());
|
||||
require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
|
||||
require_as_ref_str_slice(s.to_owned(), slice.to_owned());
|
||||
require_as_ref_slice_str(array.to_owned(), s.to_owned());
|
||||
require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
|
||||
require_as_ref_slice_str(slice.to_owned(), s.to_owned());
|
||||
|
||||
let _ = x.join(&x_ref.to_string());
|
||||
|
||||
let _ = slice.to_vec().into_iter();
|
||||
let _ = slice.to_owned().into_iter();
|
||||
let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
|
||||
let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
|
||||
|
||||
let _ = IntoIterator::into_iter(slice.to_vec());
|
||||
let _ = IntoIterator::into_iter(slice.to_owned());
|
||||
let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
|
||||
let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
|
||||
|
||||
let _ = check_files(&[FileType::Account]);
|
||||
|
||||
// negative tests
|
||||
require_string(&s.to_string());
|
||||
require_string(&Cow::from(s).into_owned());
|
||||
require_string(&s.to_owned());
|
||||
require_string(&x_ref.to_string());
|
||||
|
||||
// `X` isn't copy.
|
||||
require_slice(&x.to_owned());
|
||||
require_deref_slice(x.to_owned());
|
||||
|
||||
// The following should be flagged by `redundant_clone`, but not by this lint.
|
||||
require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
|
||||
require_os_str(&OsString::from("x").to_os_string());
|
||||
require_path(&std::path::PathBuf::from("x").to_path_buf());
|
||||
require_str(&String::from("x").to_string());
|
||||
}
|
||||
|
||||
fn require_c_str(_: &CStr) {}
|
||||
fn require_os_str(_: &OsStr) {}
|
||||
fn require_path(_: &std::path::Path) {}
|
||||
fn require_str(_: &str) {}
|
||||
fn require_slice<T>(_: &[T]) {}
|
||||
fn require_x(_: &X) {}
|
||||
|
||||
fn require_deref_c_str<T: Deref<Target = CStr>>(_: T) {}
|
||||
fn require_deref_os_str<T: Deref<Target = OsStr>>(_: T) {}
|
||||
fn require_deref_path<T: Deref<Target = std::path::Path>>(_: T) {}
|
||||
fn require_deref_str<T: Deref<Target = str>>(_: T) {}
|
||||
fn require_deref_slice<T, U: Deref<Target = [T]>>(_: U) {}
|
||||
|
||||
fn require_impl_deref_c_str(_: impl Deref<Target = CStr>) {}
|
||||
fn require_impl_deref_os_str(_: impl Deref<Target = OsStr>) {}
|
||||
fn require_impl_deref_path(_: impl Deref<Target = std::path::Path>) {}
|
||||
fn require_impl_deref_str(_: impl Deref<Target = str>) {}
|
||||
fn require_impl_deref_slice<T>(_: impl Deref<Target = [T]>) {}
|
||||
|
||||
fn require_deref_str_slice<T: Deref<Target = str>, U, V: Deref<Target = [U]>>(_: T, _: V) {}
|
||||
fn require_deref_slice_str<T, U: Deref<Target = [T]>, V: Deref<Target = str>>(_: U, _: V) {}
|
||||
|
||||
fn require_as_ref_c_str<T: AsRef<CStr>>(_: T) {}
|
||||
fn require_as_ref_os_str<T: AsRef<OsStr>>(_: T) {}
|
||||
fn require_as_ref_path<T: AsRef<std::path::Path>>(_: T) {}
|
||||
fn require_as_ref_str<T: AsRef<str>>(_: T) {}
|
||||
fn require_as_ref_slice<T, U: AsRef<[T]>>(_: U) {}
|
||||
|
||||
fn require_impl_as_ref_c_str(_: impl AsRef<CStr>) {}
|
||||
fn require_impl_as_ref_os_str(_: impl AsRef<OsStr>) {}
|
||||
fn require_impl_as_ref_path(_: impl AsRef<std::path::Path>) {}
|
||||
fn require_impl_as_ref_str(_: impl AsRef<str>) {}
|
||||
fn require_impl_as_ref_slice<T>(_: impl AsRef<[T]>) {}
|
||||
|
||||
fn require_as_ref_str_slice<T: AsRef<str>, U, V: AsRef<[U]>>(_: T, _: V) {}
|
||||
fn require_as_ref_slice_str<T, U: AsRef<[T]>, V: AsRef<str>>(_: U, _: V) {}
|
||||
|
||||
// `check_files` is based on:
|
||||
// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
|
||||
fn check_files(file_types: &[FileType]) -> bool {
|
||||
for t in file_types.to_vec() {
|
||||
let path = match get_file_path(&t) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if !path.is_file() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
|
||||
Ok(std::path::PathBuf::new())
|
||||
}
|
||||
|
||||
fn require_string(_: &String) {}
|
495
tests/ui/unnecessary_to_owned.stderr
Normal file
495
tests/ui/unnecessary_to_owned.stderr
Normal file
@ -0,0 +1,495 @@
|
||||
error: redundant clone
|
||||
--> $DIR/unnecessary_to_owned.rs:150:64
|
||||
|
|
||||
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
|
||||
| ^^^^^^^^^^^ help: remove this
|
||||
|
|
||||
= note: `-D clippy::redundant-clone` implied by `-D warnings`
|
||||
note: this value is dropped without further use
|
||||
--> $DIR/unnecessary_to_owned.rs:150:20
|
||||
|
|
||||
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: redundant clone
|
||||
--> $DIR/unnecessary_to_owned.rs:151:40
|
||||
|
|
||||
LL | require_os_str(&OsString::from("x").to_os_string());
|
||||
| ^^^^^^^^^^^^^^^ help: remove this
|
||||
|
|
||||
note: this value is dropped without further use
|
||||
--> $DIR/unnecessary_to_owned.rs:151:21
|
||||
|
|
||||
LL | require_os_str(&OsString::from("x").to_os_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: redundant clone
|
||||
--> $DIR/unnecessary_to_owned.rs:152:48
|
||||
|
|
||||
LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
|
||||
| ^^^^^^^^^^^^^^ help: remove this
|
||||
|
|
||||
note: this value is dropped without further use
|
||||
--> $DIR/unnecessary_to_owned.rs:152:19
|
||||
|
|
||||
LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: redundant clone
|
||||
--> $DIR/unnecessary_to_owned.rs:153:35
|
||||
|
|
||||
LL | require_str(&String::from("x").to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
|
||||
note: this value is dropped without further use
|
||||
--> $DIR/unnecessary_to_owned.rs:153:18
|
||||
|
|
||||
LL | require_str(&String::from("x").to_string());
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unnecessary use of `into_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:59:36
|
||||
|
|
||||
LL | require_c_str(&Cow::from(c_str).into_owned());
|
||||
| ^^^^^^^^^^^^^ help: remove this
|
||||
|
|
||||
= note: `-D clippy::unnecessary-to-owned` implied by `-D warnings`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:60:19
|
||||
|
|
||||
LL | require_c_str(&c_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `c_str`
|
||||
|
||||
error: unnecessary use of `to_os_string`
|
||||
--> $DIR/unnecessary_to_owned.rs:62:20
|
||||
|
|
||||
LL | require_os_str(&os_str.to_os_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str`
|
||||
|
||||
error: unnecessary use of `into_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:63:38
|
||||
|
|
||||
LL | require_os_str(&Cow::from(os_str).into_owned());
|
||||
| ^^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:64:20
|
||||
|
|
||||
LL | require_os_str(&os_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^ help: use: `os_str`
|
||||
|
||||
error: unnecessary use of `to_path_buf`
|
||||
--> $DIR/unnecessary_to_owned.rs:66:18
|
||||
|
|
||||
LL | require_path(&path.to_path_buf());
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: use: `path`
|
||||
|
||||
error: unnecessary use of `into_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:67:34
|
||||
|
|
||||
LL | require_path(&Cow::from(path).into_owned());
|
||||
| ^^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:68:18
|
||||
|
|
||||
LL | require_path(&path.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `path`
|
||||
|
||||
error: unnecessary use of `to_string`
|
||||
--> $DIR/unnecessary_to_owned.rs:70:17
|
||||
|
|
||||
LL | require_str(&s.to_string());
|
||||
| ^^^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `into_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:71:30
|
||||
|
|
||||
LL | require_str(&Cow::from(s).into_owned());
|
||||
| ^^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:72:17
|
||||
|
|
||||
LL | require_str(&s.to_owned());
|
||||
| ^^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_string`
|
||||
--> $DIR/unnecessary_to_owned.rs:73:17
|
||||
|
|
||||
LL | require_str(&x_ref.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()`
|
||||
|
||||
error: unnecessary use of `to_vec`
|
||||
--> $DIR/unnecessary_to_owned.rs:75:19
|
||||
|
|
||||
LL | require_slice(&slice.to_vec());
|
||||
| ^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `into_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:76:36
|
||||
|
|
||||
LL | require_slice(&Cow::from(slice).into_owned());
|
||||
| ^^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:77:19
|
||||
|
|
||||
LL | require_slice(&array.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:78:19
|
||||
|
|
||||
LL | require_slice(&array_ref.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:79:19
|
||||
|
|
||||
LL | require_slice(&slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:80:19
|
||||
|
|
||||
LL | require_slice(&x_ref.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `x_ref`
|
||||
|
||||
error: unnecessary use of `into_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:82:42
|
||||
|
|
||||
LL | require_x(&Cow::<X>::Owned(x.clone()).into_owned());
|
||||
| ^^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:83:15
|
||||
|
|
||||
LL | require_x(&x_ref.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `x_ref`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:85:25
|
||||
|
|
||||
LL | require_deref_c_str(c_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:86:26
|
||||
|
|
||||
LL | require_deref_os_str(os_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:87:24
|
||||
|
|
||||
LL | require_deref_path(path.to_owned());
|
||||
| ^^^^^^^^^^^^^^^ help: use: `path`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:88:23
|
||||
|
|
||||
LL | require_deref_str(s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:89:25
|
||||
|
|
||||
LL | require_deref_slice(slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:91:30
|
||||
|
|
||||
LL | require_impl_deref_c_str(c_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:92:31
|
||||
|
|
||||
LL | require_impl_deref_os_str(os_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:93:29
|
||||
|
|
||||
LL | require_impl_deref_path(path.to_owned());
|
||||
| ^^^^^^^^^^^^^^^ help: use: `path`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:94:28
|
||||
|
|
||||
LL | require_impl_deref_str(s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:95:30
|
||||
|
|
||||
LL | require_impl_deref_slice(slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:97:29
|
||||
|
|
||||
LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:97:43
|
||||
|
|
||||
LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:98:29
|
||||
|
|
||||
LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:98:47
|
||||
|
|
||||
LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:100:26
|
||||
|
|
||||
LL | require_as_ref_c_str(c_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:101:27
|
||||
|
|
||||
LL | require_as_ref_os_str(os_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:102:25
|
||||
|
|
||||
LL | require_as_ref_path(path.to_owned());
|
||||
| ^^^^^^^^^^^^^^^ help: use: `path`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:103:24
|
||||
|
|
||||
LL | require_as_ref_str(s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:104:24
|
||||
|
|
||||
LL | require_as_ref_str(x.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `&x`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:105:26
|
||||
|
|
||||
LL | require_as_ref_slice(array.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `array`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:106:26
|
||||
|
|
||||
LL | require_as_ref_slice(array_ref.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:107:26
|
||||
|
|
||||
LL | require_as_ref_slice(slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:109:31
|
||||
|
|
||||
LL | require_impl_as_ref_c_str(c_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:110:32
|
||||
|
|
||||
LL | require_impl_as_ref_os_str(os_str.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:111:30
|
||||
|
|
||||
LL | require_impl_as_ref_path(path.to_owned());
|
||||
| ^^^^^^^^^^^^^^^ help: use: `path`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:112:29
|
||||
|
|
||||
LL | require_impl_as_ref_str(s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:113:29
|
||||
|
|
||||
LL | require_impl_as_ref_str(x.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `&x`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:114:31
|
||||
|
|
||||
LL | require_impl_as_ref_slice(array.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `array`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:115:31
|
||||
|
|
||||
LL | require_impl_as_ref_slice(array_ref.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:116:31
|
||||
|
|
||||
LL | require_impl_as_ref_slice(slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:118:30
|
||||
|
|
||||
LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:118:44
|
||||
|
|
||||
LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `array`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:119:30
|
||||
|
|
||||
LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:119:44
|
||||
|
|
||||
LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:120:30
|
||||
|
|
||||
LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:120:44
|
||||
|
|
||||
LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:121:30
|
||||
|
|
||||
LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `array`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:121:48
|
||||
|
|
||||
LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:122:30
|
||||
|
|
||||
LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:122:52
|
||||
|
|
||||
LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:123:30
|
||||
|
|
||||
LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `slice`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:123:48
|
||||
|
|
||||
LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
|
||||
| ^^^^^^^^^^^^ help: use: `s`
|
||||
|
||||
error: unnecessary use of `to_string`
|
||||
--> $DIR/unnecessary_to_owned.rs:125:20
|
||||
|
|
||||
LL | let _ = x.join(&x_ref.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^ help: use: `x_ref`
|
||||
|
||||
error: unnecessary use of `to_vec`
|
||||
--> $DIR/unnecessary_to_owned.rs:127:13
|
||||
|
|
||||
LL | let _ = slice.to_vec().into_iter();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:128:13
|
||||
|
|
||||
LL | let _ = slice.to_owned().into_iter();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
|
||||
|
||||
error: unnecessary use of `to_vec`
|
||||
--> $DIR/unnecessary_to_owned.rs:129:13
|
||||
|
|
||||
LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:130:13
|
||||
|
|
||||
LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
|
||||
|
||||
error: unnecessary use of `to_vec`
|
||||
--> $DIR/unnecessary_to_owned.rs:132:13
|
||||
|
|
||||
LL | let _ = IntoIterator::into_iter(slice.to_vec());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:133:13
|
||||
|
|
||||
LL | let _ = IntoIterator::into_iter(slice.to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
|
||||
|
||||
error: unnecessary use of `to_vec`
|
||||
--> $DIR/unnecessary_to_owned.rs:134:13
|
||||
|
|
||||
LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
|
||||
|
||||
error: unnecessary use of `to_owned`
|
||||
--> $DIR/unnecessary_to_owned.rs:135:13
|
||||
|
|
||||
LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
|
||||
|
||||
error: unnecessary use of `to_vec`
|
||||
--> $DIR/unnecessary_to_owned.rs:196:14
|
||||
|
|
||||
LL | for t in file_types.to_vec() {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use
|
||||
|
|
||||
LL | for t in file_types {
|
||||
| ~~~~~~~~~~
|
||||
help: remove this `&`
|
||||
|
|
||||
LL - let path = match get_file_path(&t) {
|
||||
LL + let path = match get_file_path(t) {
|
||||
|
|
||||
|
||||
error: aborting due to 76 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user