Auto merge of #7516 - lf-:unwrap-or-default, r=xFrednet
Add `unwrap_or_else_default` lint --- *Please write a short comment explaining your change (or "none" for internal only changes)* changelog: Add a new [`unwrap_or_else_default`] style lint. This will catch `unwrap_or_else(Default::default)` on Result and Option and suggest `unwrap_or_default()` instead.
This commit is contained in:
commit
e62a6cad1e
@ -2999,6 +2999,7 @@ Released 2018-09-13
|
||||
[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
|
||||
[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
|
||||
[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
|
||||
[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
|
||||
[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
|
||||
[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
|
||||
[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
|
||||
|
@ -797,6 +797,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
methods::UNNECESSARY_FILTER_MAP,
|
||||
methods::UNNECESSARY_FOLD,
|
||||
methods::UNNECESSARY_LAZY_EVALUATIONS,
|
||||
methods::UNWRAP_OR_ELSE_DEFAULT,
|
||||
methods::UNWRAP_USED,
|
||||
methods::USELESS_ASREF,
|
||||
methods::WRONG_SELF_CONVENTION,
|
||||
@ -1341,6 +1342,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::USELESS_ASREF),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(methods::ZST_OFFSET),
|
||||
@ -1535,6 +1537,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(methods::STRING_EXTEND_CHARS),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(misc::TOPLEVEL_REF_ARG),
|
||||
LintId::of(misc::ZERO_PTR),
|
||||
|
@ -56,6 +56,7 @@
|
||||
mod unnecessary_filter_map;
|
||||
mod unnecessary_fold;
|
||||
mod unnecessary_lazy_eval;
|
||||
mod unwrap_or_else_default;
|
||||
mod unwrap_used;
|
||||
mod useless_asref;
|
||||
mod utils;
|
||||
@ -310,6 +311,31 @@
|
||||
"using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
|
||||
/// `Result` values.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Readability, these can be written as `_.unwrap_or_default`, which is
|
||||
/// simpler and more concise.
|
||||
///
|
||||
/// ### Examples
|
||||
/// ```rust
|
||||
/// # let x = Some(1);
|
||||
///
|
||||
/// // Bad
|
||||
/// x.unwrap_or_else(Default::default);
|
||||
/// x.unwrap_or_else(u32::default);
|
||||
///
|
||||
/// // Good
|
||||
/// x.unwrap_or_default();
|
||||
/// ```
|
||||
pub UNWRAP_OR_ELSE_DEFAULT,
|
||||
style,
|
||||
"using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
|
||||
@ -1766,6 +1792,7 @@ pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Sel
|
||||
SHOULD_IMPLEMENT_TRAIT,
|
||||
WRONG_SELF_CONVENTION,
|
||||
OK_EXPECT,
|
||||
UNWRAP_OR_ELSE_DEFAULT,
|
||||
MAP_UNWRAP_OR,
|
||||
RESULT_MAP_OR_INTO_OPTION,
|
||||
OPTION_MAP_OR_NONE,
|
||||
@ -2172,7 +2199,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
|
||||
},
|
||||
("unwrap_or_else", [u_arg]) => match method_call!(recv) {
|
||||
Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
|
||||
_ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"),
|
||||
_ => {
|
||||
unwrap_or_else_default::check(cx, expr, recv, u_arg);
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
|
||||
},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::eager_or_lazy::is_lazyness_candidate;
|
||||
use clippy_utils::is_trait_item;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite};
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
|
||||
use clippy_utils::{contains_return, last_path_segment, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
@ -34,15 +36,23 @@ fn check_unwrap_or_default(
|
||||
or_has_args: bool,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
let is_default_default = || is_trait_item(cx, fun, sym::Default);
|
||||
|
||||
let implements_default = |arg, default_trait_id| {
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
implements_trait(cx, arg_ty, default_trait_id, &[])
|
||||
};
|
||||
|
||||
if_chain! {
|
||||
if !or_has_args;
|
||||
if name == "unwrap_or";
|
||||
if let hir::ExprKind::Path(ref qpath) = fun.kind;
|
||||
let path = last_path_segment(qpath).ident.name;
|
||||
if matches!(path, kw::Default | sym::new);
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
|
||||
if implements_trait(cx, arg_ty, default_trait_id, &[]);
|
||||
let path = last_path_segment(qpath).ident.name;
|
||||
// needs to target Default::default in particular or be *::new and have a Default impl
|
||||
// available
|
||||
if (matches!(path, kw::Default) && is_default_default())
|
||||
|| (matches!(path, sym::new) && implements_default(arg, default_trait_id));
|
||||
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
45
clippy_lints/src/methods/unwrap_or_else_default.rs
Normal file
45
clippy_lints/src/methods/unwrap_or_else_default.rs
Normal file
@ -0,0 +1,45 @@
|
||||
//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
|
||||
|
||||
use super::UNWRAP_OR_ELSE_DEFAULT;
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
recv: &'tcx hir::Expr<'_>,
|
||||
u_arg: &'tcx hir::Expr<'_>,
|
||||
) {
|
||||
// something.unwrap_or_else(Default::default)
|
||||
// ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
|
||||
let recv_ty = cx.typeck_results().expr_ty(recv);
|
||||
let is_option = is_type_diagnostic_item(cx, recv_ty, sym::option_type);
|
||||
let is_result = is_type_diagnostic_item(cx, recv_ty, sym::result_type);
|
||||
|
||||
if_chain! {
|
||||
if is_option || is_result;
|
||||
if is_trait_item(cx, u_arg, sym::Default);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNWRAP_OR_ELSE_DEFAULT,
|
||||
expr.span,
|
||||
"use of `.unwrap_or_else(..)` to construct default value",
|
||||
"try",
|
||||
format!(
|
||||
"{}.unwrap_or_default()",
|
||||
snippet_with_applicability(cx, recv.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -422,7 +422,7 @@ fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) {
|
||||
///
|
||||
/// is transformed to
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// {
|
||||
/// let x = 5;
|
||||
/// ```
|
||||
|
@ -122,7 +122,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
/// 2. Detect use of `return` in `Loop` in the closure body.
|
||||
///
|
||||
/// NOTE: The functionality of this type is similar to
|
||||
/// [`crate::utilts::visitors::find_all_ret_expressions`], but we can't use
|
||||
/// [`clippy_utils::visitors::find_all_ret_expressions`], but we can't use
|
||||
/// `find_all_ret_expressions` instead of this type. The reasons are:
|
||||
/// 1. `find_all_ret_expressions` passes the argument of `ExprKind::Ret` to a callback, but what we
|
||||
/// need here is `ExprKind::Ret` itself.
|
||||
|
@ -65,7 +65,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// error: constant division of 0.0 with 0.0 will always result in NaN
|
||||
/// --> $DIR/zero_div_zero.rs:6:25
|
||||
/// |
|
||||
@ -103,7 +103,7 @@ pub fn span_lint_and_help<'a, T: LintContext>(
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
/// --> $DIR/drop_forget_ref.rs:10:5
|
||||
/// |
|
||||
@ -189,7 +189,7 @@ pub fn span_lint_hir_and_then(
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// error: This `.fold` can be more succinctly expressed as `.any`
|
||||
/// --> $DIR/methods.rs:390:13
|
||||
/// |
|
||||
|
@ -195,8 +195,8 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve
|
||||
/// - `assert!`, `assert_eq!` and `assert_ne!`
|
||||
/// - `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!`
|
||||
/// For example:
|
||||
/// `assert!(expr)` will return Some([expr])
|
||||
/// `debug_assert_eq!(a, b)` will return Some([a, b])
|
||||
/// `assert!(expr)` will return `Some([expr])`
|
||||
/// `debug_assert_eq!(a, b)` will return `Some([a, b])`
|
||||
pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx Expr<'tcx>>> {
|
||||
/// Try to match the AST for a pattern that contains a match, for example when two args are
|
||||
/// compared
|
||||
@ -283,7 +283,7 @@ pub struct FormatArgsExpn<'tcx> {
|
||||
|
||||
/// String literal expressions which represent the format string split by "{}"
|
||||
pub format_string_parts: &'tcx [Expr<'tcx>],
|
||||
/// Symbols corresponding to [`format_string_parts`]
|
||||
/// Symbols corresponding to [`Self::format_string_parts`]
|
||||
pub format_string_symbols: Vec<Symbol>,
|
||||
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
|
||||
pub args: &'tcx [Expr<'tcx>],
|
||||
|
@ -326,6 +326,25 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
|
||||
.map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
|
||||
}
|
||||
|
||||
/// Checks if the given expression is a path referring an item on the trait
|
||||
/// that is marked with the given diagnostic item.
|
||||
///
|
||||
/// For checking method call expressions instead of path expressions, use
|
||||
/// [`is_trait_method`].
|
||||
///
|
||||
/// For example, this can be used to find if an expression like `u64::default`
|
||||
/// refers to an item of the trait `Default`, which is associated with the
|
||||
/// `diag_item` of `sym::Default`.
|
||||
pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
|
||||
if let hir::ExprKind::Path(ref qpath) = expr.kind {
|
||||
cx.qpath_res(qpath, expr.hir_id)
|
||||
.opt_def_id()
|
||||
.map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
|
||||
match *path {
|
||||
QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
|
||||
|
@ -168,7 +168,7 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<
|
||||
snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
|
||||
}
|
||||
|
||||
/// Same as `snippet`, but it adapts the applicability level by following rules:
|
||||
/// Same as [`snippet`], but it adapts the applicability level by following rules:
|
||||
///
|
||||
/// - Applicability level `Unspecified` will never be changed.
|
||||
/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
|
||||
|
@ -114,7 +114,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
|
||||
|
||||
/// Checks whether a type implements a trait.
|
||||
/// The function returns false in case the type contains an inference variable.
|
||||
/// See also `get_trait_def_id`.
|
||||
/// See also [`get_trait_def_id`](super::get_trait_def_id).
|
||||
pub fn implements_trait<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
|
@ -18,6 +18,19 @@ fn or_fun_call() {
|
||||
}
|
||||
}
|
||||
|
||||
struct FakeDefault;
|
||||
impl FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(i32),
|
||||
}
|
||||
@ -53,6 +66,12 @@ fn or_fun_call() {
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_default();
|
||||
|
||||
let self_default = None::<FakeDefault>;
|
||||
self_default.unwrap_or_else(<FakeDefault>::default);
|
||||
|
||||
let real_default = None::<FakeDefault>;
|
||||
real_default.unwrap_or_default();
|
||||
|
||||
let with_vec = Some(vec![1]);
|
||||
with_vec.unwrap_or_default();
|
||||
|
||||
|
@ -18,6 +18,19 @@ fn new() -> Foo {
|
||||
}
|
||||
}
|
||||
|
||||
struct FakeDefault;
|
||||
impl FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(i32),
|
||||
}
|
||||
@ -53,6 +66,12 @@ fn make<T>() -> T {
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or(u64::default());
|
||||
|
||||
let self_default = None::<FakeDefault>;
|
||||
self_default.unwrap_or(<FakeDefault>::default());
|
||||
|
||||
let real_default = None::<FakeDefault>;
|
||||
real_default.unwrap_or(<FakeDefault as Default>::default());
|
||||
|
||||
let with_vec = Some(vec![1]);
|
||||
with_vec.unwrap_or(vec![]);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:33:19
|
||||
--> $DIR/or_fun_call.rs:46:19
|
||||
|
|
||||
LL | with_const_fn.unwrap_or(Duration::from_secs(5));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))`
|
||||
@ -7,130 +7,142 @@ LL | with_const_fn.unwrap_or(Duration::from_secs(5));
|
||||
= note: `-D clippy::or-fun-call` implied by `-D warnings`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:36:22
|
||||
--> $DIR/or_fun_call.rs:49:22
|
||||
|
|
||||
LL | with_constructor.unwrap_or(make());
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `new`
|
||||
--> $DIR/or_fun_call.rs:39:5
|
||||
--> $DIR/or_fun_call.rs:52:5
|
||||
|
|
||||
LL | with_new.unwrap_or(Vec::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:42:21
|
||||
--> $DIR/or_fun_call.rs:55:21
|
||||
|
|
||||
LL | with_const_args.unwrap_or(Vec::with_capacity(12));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:45:14
|
||||
--> $DIR/or_fun_call.rs:58:14
|
||||
|
|
||||
LL | with_err.unwrap_or(make());
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:48:19
|
||||
--> $DIR/or_fun_call.rs:61:19
|
||||
|
|
||||
LL | with_err_args.unwrap_or(Vec::with_capacity(12));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `default`
|
||||
--> $DIR/or_fun_call.rs:51:5
|
||||
--> $DIR/or_fun_call.rs:64:5
|
||||
|
|
||||
LL | with_default_trait.unwrap_or(Default::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `default`
|
||||
--> $DIR/or_fun_call.rs:54:5
|
||||
--> $DIR/or_fun_call.rs:67:5
|
||||
|
|
||||
LL | with_default_type.unwrap_or(u64::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:70:18
|
||||
|
|
||||
LL | self_default.unwrap_or(<FakeDefault>::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(<FakeDefault>::default)`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `default`
|
||||
--> $DIR/or_fun_call.rs:73:5
|
||||
|
|
||||
LL | real_default.unwrap_or(<FakeDefault as Default>::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `real_default.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `new`
|
||||
--> $DIR/or_fun_call.rs:57:5
|
||||
--> $DIR/or_fun_call.rs:76:5
|
||||
|
|
||||
LL | with_vec.unwrap_or(vec![]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:60:21
|
||||
--> $DIR/or_fun_call.rs:79:21
|
||||
|
|
||||
LL | without_default.unwrap_or(Foo::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:63:19
|
||||
--> $DIR/or_fun_call.rs:82:19
|
||||
|
|
||||
LL | map.entry(42).or_insert(String::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:66:23
|
||||
--> $DIR/or_fun_call.rs:85:23
|
||||
|
|
||||
LL | map_vec.entry(42).or_insert(vec![]);
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:69:21
|
||||
--> $DIR/or_fun_call.rs:88:21
|
||||
|
|
||||
LL | btree.entry(42).or_insert(String::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:72:25
|
||||
--> $DIR/or_fun_call.rs:91:25
|
||||
|
|
||||
LL | btree_vec.entry(42).or_insert(vec![]);
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:75:21
|
||||
--> $DIR/or_fun_call.rs:94:21
|
||||
|
|
||||
LL | let _ = stringy.unwrap_or("".to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:83:21
|
||||
--> $DIR/or_fun_call.rs:102:21
|
||||
|
|
||||
LL | let _ = Some(1).unwrap_or(map[&1]);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:85:21
|
||||
--> $DIR/or_fun_call.rs:104:21
|
||||
|
|
||||
LL | let _ = Some(1).unwrap_or(map[&1]);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
|
||||
|
||||
error: use of `or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:109:35
|
||||
--> $DIR/or_fun_call.rs:128:35
|
||||
|
|
||||
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
|
||||
|
||||
error: use of `or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:113:10
|
||||
--> $DIR/or_fun_call.rs:132:10
|
||||
|
|
||||
LL | .or(Some(Bar(b, Duration::from_secs(2))));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:141:14
|
||||
--> $DIR/or_fun_call.rs:160:14
|
||||
|
|
||||
LL | None.unwrap_or(s.as_mut_vec());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:146:14
|
||||
--> $DIR/or_fun_call.rs:165:14
|
||||
|
|
||||
LL | None.unwrap_or(unsafe { s.as_mut_vec() });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:148:14
|
||||
--> $DIR/or_fun_call.rs:167:14
|
||||
|
|
||||
LL | None.unwrap_or( unsafe { s.as_mut_vec() } );
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })`
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
error: aborting due to 24 previous errors
|
||||
|
||||
|
71
tests/ui/unwrap_or_else_default.fixed
Normal file
71
tests/ui/unwrap_or_else_default.fixed
Normal file
@ -0,0 +1,71 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::unwrap_or_else_default)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
|
||||
fn unwrap_or_else_default() {
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn new() -> Foo {
|
||||
Foo
|
||||
}
|
||||
|
||||
// fake default, we should not trigger on this
|
||||
fn default() -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
struct HasDefaultAndDuplicate;
|
||||
|
||||
impl HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(),
|
||||
}
|
||||
|
||||
fn make<T, V>(_: V) -> T {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
let with_enum = Some(Enum::A());
|
||||
with_enum.unwrap_or_else(Enum::A);
|
||||
|
||||
let with_new = Some(vec![1]);
|
||||
with_new.unwrap_or_else(Vec::new);
|
||||
|
||||
let with_err: Result<_, ()> = Ok(vec![1]);
|
||||
with_err.unwrap_or_else(make);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default = None::<Foo>;
|
||||
with_fake_default.unwrap_or_else(Foo::default);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default2 = None::<HasDefaultAndDuplicate>;
|
||||
with_fake_default2.unwrap_or_else(<HasDefaultAndDuplicate>::default);
|
||||
|
||||
let with_real_default = None::<HasDefaultAndDuplicate>;
|
||||
with_real_default.unwrap_or_default();
|
||||
|
||||
let with_default_trait = Some(1);
|
||||
with_default_trait.unwrap_or_default();
|
||||
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_default();
|
||||
}
|
||||
|
||||
fn main() {}
|
71
tests/ui/unwrap_or_else_default.rs
Normal file
71
tests/ui/unwrap_or_else_default.rs
Normal file
@ -0,0 +1,71 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::unwrap_or_else_default)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
|
||||
fn unwrap_or_else_default() {
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn new() -> Foo {
|
||||
Foo
|
||||
}
|
||||
|
||||
// fake default, we should not trigger on this
|
||||
fn default() -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
struct HasDefaultAndDuplicate;
|
||||
|
||||
impl HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(),
|
||||
}
|
||||
|
||||
fn make<T, V>(_: V) -> T {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
let with_enum = Some(Enum::A());
|
||||
with_enum.unwrap_or_else(Enum::A);
|
||||
|
||||
let with_new = Some(vec![1]);
|
||||
with_new.unwrap_or_else(Vec::new);
|
||||
|
||||
let with_err: Result<_, ()> = Ok(vec![1]);
|
||||
with_err.unwrap_or_else(make);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default = None::<Foo>;
|
||||
with_fake_default.unwrap_or_else(Foo::default);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default2 = None::<HasDefaultAndDuplicate>;
|
||||
with_fake_default2.unwrap_or_else(<HasDefaultAndDuplicate>::default);
|
||||
|
||||
let with_real_default = None::<HasDefaultAndDuplicate>;
|
||||
with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
|
||||
|
||||
let with_default_trait = Some(1);
|
||||
with_default_trait.unwrap_or_else(Default::default);
|
||||
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_else(u64::default);
|
||||
}
|
||||
|
||||
fn main() {}
|
22
tests/ui/unwrap_or_else_default.stderr
Normal file
22
tests/ui/unwrap_or_else_default.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:62:5
|
||||
|
|
||||
LL | with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
|
||||
|
|
||||
= note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:65:5
|
||||
|
|
||||
LL | with_default_trait.unwrap_or_else(Default::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:68:5
|
||||
|
|
||||
LL | with_default_type.unwrap_or_else(u64::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user