mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-31 17:12:53 +00:00
Auto merge of #5937 - montrivo:option_if_let_else, r=flip1995
option_if_let_else - distinguish pure from impure else expressions Addresses partially #5821. changelog: improve the lint `option_if_let_else`. Suggest `map_or` or `map_or_else` based on the else expression purity.
This commit is contained in:
commit
06f1902878
@ -12,6 +12,7 @@ use rustc_middle::hir::map::Map;
|
||||
use rustc_span::Span;
|
||||
|
||||
pub(crate) struct OptionAndThenSome;
|
||||
|
||||
impl BindInsteadOfMap for OptionAndThenSome {
|
||||
const TYPE_NAME: &'static str = "Option";
|
||||
const TYPE_QPATH: &'static [&'static str] = &paths::OPTION;
|
||||
@ -24,6 +25,7 @@ impl BindInsteadOfMap for OptionAndThenSome {
|
||||
}
|
||||
|
||||
pub(crate) struct ResultAndThenOk;
|
||||
|
||||
impl BindInsteadOfMap for ResultAndThenOk {
|
||||
const TYPE_NAME: &'static str = "Result";
|
||||
const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
|
||||
@ -36,6 +38,7 @@ impl BindInsteadOfMap for ResultAndThenOk {
|
||||
}
|
||||
|
||||
pub(crate) struct ResultOrElseErrInfo;
|
||||
|
||||
impl BindInsteadOfMap for ResultOrElseErrInfo {
|
||||
const TYPE_NAME: &'static str = "Result";
|
||||
const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;
|
||||
@ -120,9 +123,9 @@ pub(crate) trait BindInsteadOfMap {
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) {
|
||||
fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
|
||||
let mut suggs = Vec::new();
|
||||
let can_sugg = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
|
||||
let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
|
||||
if_chain! {
|
||||
if !in_macro(ret_expr.span);
|
||||
if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind;
|
||||
@ -153,12 +156,13 @@ pub(crate) trait BindInsteadOfMap {
|
||||
)
|
||||
});
|
||||
}
|
||||
can_sugg
|
||||
}
|
||||
|
||||
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
|
||||
fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||
fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool {
|
||||
if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
match args[1].kind {
|
||||
@ -166,8 +170,10 @@ pub(crate) trait BindInsteadOfMap {
|
||||
let closure_body = cx.tcx.hir().body(body_id);
|
||||
let closure_expr = remove_blocks(&closure_body.value);
|
||||
|
||||
if !Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
|
||||
Self::lint_closure(cx, expr, closure_expr);
|
||||
if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
|
||||
true
|
||||
} else {
|
||||
Self::lint_closure(cx, expr, closure_expr)
|
||||
}
|
||||
},
|
||||
// `_.and_then(Some)` case, which is no-op.
|
||||
@ -181,8 +187,9 @@ pub(crate) trait BindInsteadOfMap {
|
||||
snippet(cx, args[0].span, "..").into(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
true
|
||||
},
|
||||
_ => {},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,14 +25,15 @@ use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{sym, SymbolStr};
|
||||
|
||||
use crate::consts::{constant, Constant};
|
||||
use crate::utils::eager_or_lazy::is_lazyness_candidate;
|
||||
use crate::utils::usage::mutated_variables;
|
||||
use crate::utils::{
|
||||
contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
|
||||
is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats,
|
||||
last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls,
|
||||
method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability,
|
||||
snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
|
||||
span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
|
||||
is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
|
||||
match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty,
|
||||
single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
|
||||
span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty,
|
||||
walk_ptrs_ty_depth, SpanlessEq,
|
||||
};
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -1454,18 +1455,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
|
||||
["unwrap_or_else", "map"] => {
|
||||
if !lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]) {
|
||||
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or");
|
||||
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or");
|
||||
}
|
||||
},
|
||||
["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]),
|
||||
["and_then", ..] => {
|
||||
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "and");
|
||||
bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
|
||||
bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
|
||||
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]);
|
||||
let biom_result_linted = bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]);
|
||||
if !biom_option_linted && !biom_result_linted {
|
||||
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "and");
|
||||
}
|
||||
},
|
||||
["or_else", ..] => {
|
||||
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], false, "or");
|
||||
bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]);
|
||||
if !bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]) {
|
||||
unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "or");
|
||||
}
|
||||
},
|
||||
["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
|
||||
["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
|
||||
@ -1508,9 +1512,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
|
||||
["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
|
||||
["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
|
||||
["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "unwrap_or"),
|
||||
["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "get_or_insert"),
|
||||
["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], true, "ok_or"),
|
||||
["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
|
||||
["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
|
||||
["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
@ -1714,37 +1718,6 @@ fn lint_or_fun_call<'tcx>(
|
||||
name: &str,
|
||||
args: &'tcx [hir::Expr<'_>],
|
||||
) {
|
||||
// Searches an expression for method calls or function calls that aren't ctors
|
||||
struct FunCallFinder<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
|
||||
let call_found = match &expr.kind {
|
||||
// ignore enum and struct constructors
|
||||
hir::ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
|
||||
hir::ExprKind::MethodCall(..) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if call_found {
|
||||
self.found |= true;
|
||||
}
|
||||
|
||||
if !self.found {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::None
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
|
||||
fn check_unwrap_or_default(
|
||||
cx: &LateContext<'_>,
|
||||
@ -1825,8 +1798,7 @@ fn lint_or_fun_call<'tcx>(
|
||||
if_chain! {
|
||||
if know_types.iter().any(|k| k.2.contains(&name));
|
||||
|
||||
let mut finder = FunCallFinder { cx: &cx, found: false };
|
||||
if { finder.visit_expr(&arg); finder.found };
|
||||
if is_lazyness_candidate(cx, arg);
|
||||
if !contains_return(&arg);
|
||||
|
||||
let self_ty = cx.typeck_results().expr_ty(self_expr);
|
||||
|
@ -1,78 +1,17 @@
|
||||
use crate::utils::{is_type_diagnostic_item, match_qpath, snippet, span_lint_and_sugg};
|
||||
use if_chain::if_chain;
|
||||
use crate::utils::{eager_or_lazy, usage};
|
||||
use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::UNNECESSARY_LAZY_EVALUATIONS;
|
||||
|
||||
// Return true if the expression is an accessor of any of the arguments
|
||||
fn expr_uses_argument(expr: &hir::Expr<'_>, params: &[hir::Param<'_>]) -> bool {
|
||||
params.iter().any(|arg| {
|
||||
if_chain! {
|
||||
if let hir::PatKind::Binding(_, _, ident, _) = arg.pat.kind;
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind;
|
||||
if let [p, ..] = path.segments;
|
||||
then {
|
||||
ident.name == p.ident.name
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn match_any_qpath(path: &hir::QPath<'_>, paths: &[&[&str]]) -> bool {
|
||||
paths.iter().any(|candidate| match_qpath(path, candidate))
|
||||
}
|
||||
|
||||
fn can_simplify(expr: &hir::Expr<'_>, params: &[hir::Param<'_>], variant_calls: bool) -> bool {
|
||||
match expr.kind {
|
||||
// Closures returning literals can be unconditionally simplified
|
||||
hir::ExprKind::Lit(_) => true,
|
||||
|
||||
hir::ExprKind::Index(ref object, ref index) => {
|
||||
// arguments are not being indexed into
|
||||
if expr_uses_argument(object, params) {
|
||||
false
|
||||
} else {
|
||||
// arguments are not used as index
|
||||
!expr_uses_argument(index, params)
|
||||
}
|
||||
},
|
||||
|
||||
// Reading fields can be simplified if the object is not an argument of the closure
|
||||
hir::ExprKind::Field(ref object, _) => !expr_uses_argument(object, params),
|
||||
|
||||
// Paths can be simplified if the root is not the argument, this also covers None
|
||||
hir::ExprKind::Path(_) => !expr_uses_argument(expr, params),
|
||||
|
||||
// Calls to Some, Ok, Err can be considered literals if they don't derive an argument
|
||||
hir::ExprKind::Call(ref func, ref args) => if_chain! {
|
||||
if variant_calls; // Disable lint when rules conflict with bind_instead_of_map
|
||||
if let hir::ExprKind::Path(ref path) = func.kind;
|
||||
if match_any_qpath(path, &[&["Some"], &["Ok"], &["Err"]]);
|
||||
then {
|
||||
// Recursively check all arguments
|
||||
args.iter().all(|arg| can_simplify(arg, params, variant_calls))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
|
||||
// For anything more complex than the above, a closure is probably the right solution,
|
||||
// or the case is handled by an other lint
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `<fn>_else(simple closure)` for `Option`s and `Result`s that can be
|
||||
/// replaced with `<fn>(return value of simple closure)`
|
||||
pub(super) fn lint<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
args: &'tcx [hir::Expr<'_>],
|
||||
allow_variant_calls: bool,
|
||||
simplify_using: &str,
|
||||
) {
|
||||
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type));
|
||||
@ -81,10 +20,13 @@ pub(super) fn lint<'tcx>(
|
||||
if is_option || is_result {
|
||||
if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
|
||||
let body = cx.tcx.hir().body(eid);
|
||||
let ex = &body.value;
|
||||
let params = &body.params;
|
||||
let body_expr = &body.value;
|
||||
|
||||
if can_simplify(ex, params, allow_variant_calls) {
|
||||
if usage::BindingUsageFinder::are_params_used(cx, body) {
|
||||
return;
|
||||
}
|
||||
|
||||
if eager_or_lazy::is_eagerness_candidate(cx, body_expr) {
|
||||
let msg = if is_option {
|
||||
"unnecessary closure used to substitute value for `Option::None`"
|
||||
} else {
|
||||
@ -101,7 +43,7 @@ pub(super) fn lint<'tcx>(
|
||||
"{0}.{1}({2})",
|
||||
snippet(cx, args[0].span, ".."),
|
||||
simplify_using,
|
||||
snippet(cx, ex.span, ".."),
|
||||
snippet(cx, body_expr.span, ".."),
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::utils;
|
||||
use crate::utils::eager_or_lazy;
|
||||
use crate::utils::sugg::Sugg;
|
||||
use crate::utils::{is_type_diagnostic_item, paths, span_lint_and_sugg};
|
||||
use if_chain::if_chain;
|
||||
@ -13,22 +14,16 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:**
|
||||
/// Lints usage of `if let Some(v) = ... { y } else { x }` which is more
|
||||
/// idiomatically done with `Option::map_or` (if the else bit is a simple
|
||||
/// expression) or `Option::map_or_else` (if the else bit is a longer
|
||||
/// block).
|
||||
/// idiomatically done with `Option::map_or` (if the else bit is a pure
|
||||
/// expression) or `Option::map_or_else` (if the else bit is an impure
|
||||
/// expresion).
|
||||
///
|
||||
/// **Why is this bad?**
|
||||
/// Using the dedicated functions of the Option type is clearer and
|
||||
/// more concise than an if let expression.
|
||||
///
|
||||
/// **Known problems:**
|
||||
/// This lint uses whether the block is just an expression or if it has
|
||||
/// more statements to decide whether to use `Option::map_or` or
|
||||
/// `Option::map_or_else`. If you have a single expression which calls
|
||||
/// an expensive function, then it would be more efficient to use
|
||||
/// `Option::map_or_else`, but this lint would suggest `Option::map_or`.
|
||||
///
|
||||
/// Also, this lint uses a deliberately conservative metric for checking
|
||||
/// This lint uses a deliberately conservative metric for checking
|
||||
/// if the inside of either body contains breaks or continues which will
|
||||
/// cause it to not suggest a fix if either block contains a loop with
|
||||
/// continues or breaks contained within the loop.
|
||||
@ -92,6 +87,7 @@ struct OptionIfLetElseOccurence {
|
||||
struct ReturnBreakContinueMacroVisitor {
|
||||
seen_return_break_continue: bool,
|
||||
}
|
||||
|
||||
impl ReturnBreakContinueMacroVisitor {
|
||||
fn new() -> ReturnBreakContinueMacroVisitor {
|
||||
ReturnBreakContinueMacroVisitor {
|
||||
@ -99,6 +95,7 @@ impl ReturnBreakContinueMacroVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
|
||||
type Map = Map<'tcx>;
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
@ -157,7 +154,7 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
|
||||
}
|
||||
|
||||
/// If this is the else body of an if/else expression, then we need to wrap
|
||||
/// it in curcly braces. Otherwise, we don't.
|
||||
/// it in curly braces. Otherwise, we don't.
|
||||
fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
|
||||
if let Some(Expr {
|
||||
@ -199,7 +196,10 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
|
||||
/// If this expression is the option if let/else construct we're detecting, then
|
||||
/// this function returns an `OptionIfLetElseOccurence` struct with details if
|
||||
/// this construct is found, or None if this construct is not found.
|
||||
fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OptionIfLetElseOccurence> {
|
||||
fn detect_option_if_let_else<'tcx>(
|
||||
cx: &'_ LateContext<'tcx>,
|
||||
expr: &'_ Expr<'tcx>,
|
||||
) -> Option<OptionIfLetElseOccurence> {
|
||||
if_chain! {
|
||||
if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly
|
||||
if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
|
||||
@ -214,10 +214,7 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Op
|
||||
let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
|
||||
let some_body = extract_body_from_arm(&arms[0])?;
|
||||
let none_body = extract_body_from_arm(&arms[1])?;
|
||||
let method_sugg = match &none_body.kind {
|
||||
ExprKind::Block(..) => "map_or_else",
|
||||
_ => "map_or",
|
||||
};
|
||||
let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
|
||||
let capture_name = id.name.to_ident_string();
|
||||
let wrap_braces = should_wrap_in_braces(cx, expr);
|
||||
let (as_ref, as_mut) = match &cond_expr.kind {
|
||||
@ -243,8 +240,8 @@ fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Op
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LateLintPass<'a> for OptionIfLetElse {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) {
|
||||
impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
if let Some(detection) = detect_option_if_let_else(cx, expr) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
128
clippy_lints/src/utils/eager_or_lazy.rs
Normal file
128
clippy_lints/src/utils/eager_or_lazy.rs
Normal file
@ -0,0 +1,128 @@
|
||||
//! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa.
|
||||
//!
|
||||
//! Things to consider:
|
||||
//! - has the expression side-effects?
|
||||
//! - is the expression computationally expensive?
|
||||
//!
|
||||
//! See lints:
|
||||
//! - unnecessary-lazy-evaluations
|
||||
//! - or-fun-call
|
||||
//! - option-if-let-else
|
||||
|
||||
use crate::utils::is_ctor_or_promotable_const_function;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
|
||||
|
||||
use rustc_hir::{Block, Expr, ExprKind, Path, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::hir::map::Map;
|
||||
|
||||
/// Is the expr pure (is it free from side-effects)?
|
||||
/// This function is named so to stress that it isn't exhaustive and returns FNs.
|
||||
fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
|
||||
ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr),
|
||||
ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)),
|
||||
ExprKind::Struct(_, fields, expr) => {
|
||||
fields.iter().all(|f| identify_some_pure_patterns(f.expr))
|
||||
&& expr.map_or(true, |e| identify_some_pure_patterns(e))
|
||||
},
|
||||
ExprKind::Call(
|
||||
&Expr {
|
||||
kind:
|
||||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
Path {
|
||||
res: Res::Def(DefKind::Ctor(..) | DefKind::Variant, ..),
|
||||
..
|
||||
},
|
||||
)),
|
||||
..
|
||||
},
|
||||
args,
|
||||
) => args.iter().all(|expr| identify_some_pure_patterns(expr)),
|
||||
ExprKind::Block(
|
||||
&Block {
|
||||
stmts,
|
||||
expr: Some(expr),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) => stmts.is_empty() && identify_some_pure_patterns(expr),
|
||||
ExprKind::Box(..)
|
||||
| ExprKind::Array(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::Binary(..)
|
||||
| ExprKind::Unary(..)
|
||||
| ExprKind::Cast(..)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::DropTemps(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::Closure(..)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Assign(..)
|
||||
| ExprKind::AssignOp(..)
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::LlvmInlineAsm(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Err => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Identify some potentially computationally expensive patterns.
|
||||
/// This function is named so to stress that its implementation is non-exhaustive.
|
||||
/// It returns FNs and FPs.
|
||||
fn identify_some_potentially_expensive_patterns<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
|
||||
// Searches an expression for method calls or function calls that aren't ctors
|
||||
struct FunCallFinder<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
let call_found = match &expr.kind {
|
||||
// ignore enum and struct constructors
|
||||
ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
|
||||
ExprKind::MethodCall(..) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if call_found {
|
||||
self.found |= true;
|
||||
}
|
||||
|
||||
if !self.found {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
}
|
||||
|
||||
let mut finder = FunCallFinder { cx, found: false };
|
||||
finder.visit_expr(expr);
|
||||
finder.found
|
||||
}
|
||||
|
||||
pub fn is_eagerness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
|
||||
!identify_some_potentially_expensive_patterns(cx, expr) && identify_some_pure_patterns(expr)
|
||||
}
|
||||
|
||||
pub fn is_lazyness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
|
||||
identify_some_potentially_expensive_patterns(cx, expr)
|
||||
}
|
@ -10,6 +10,7 @@ pub mod comparisons;
|
||||
pub mod conf;
|
||||
pub mod constants;
|
||||
mod diagnostics;
|
||||
pub mod eager_or_lazy;
|
||||
pub mod higher;
|
||||
mod hir_utils;
|
||||
pub mod inspector;
|
||||
|
@ -49,7 +49,7 @@ impl<'a> Sugg<'a> {
|
||||
/// Convenience function around `hir_opt` for suggestions with a default
|
||||
/// text.
|
||||
pub fn hir(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
|
||||
Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default)))
|
||||
Self::hir_opt(cx, expr).unwrap_or(Sugg::NonParen(Cow::Borrowed(default)))
|
||||
}
|
||||
|
||||
/// Same as `hir`, but it adapts the applicability level by following rules:
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::utils::match_var;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{Expr, HirId, Path};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
@ -108,3 +110,67 @@ pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool {
|
||||
walk_expr(&mut visitor, body);
|
||||
!visitor.used
|
||||
}
|
||||
|
||||
pub struct ParamBindingIdCollector {
|
||||
binding_hir_ids: Vec<hir::HirId>,
|
||||
}
|
||||
impl<'tcx> ParamBindingIdCollector {
|
||||
fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
|
||||
let mut finder = ParamBindingIdCollector {
|
||||
binding_hir_ids: Vec::new(),
|
||||
};
|
||||
finder.visit_body(body);
|
||||
finder.binding_hir_ids
|
||||
}
|
||||
}
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
||||
if let hir::PatKind::Binding(_, hir_id, ..) = param.pat.kind {
|
||||
self.binding_hir_ids.push(hir_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BindingUsageFinder<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
binding_ids: Vec<hir::HirId>,
|
||||
usage_found: bool,
|
||||
}
|
||||
impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
|
||||
pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool {
|
||||
let mut finder = BindingUsageFinder {
|
||||
cx,
|
||||
binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body),
|
||||
usage_found: false,
|
||||
};
|
||||
finder.visit_body(body);
|
||||
finder.usage_found
|
||||
}
|
||||
}
|
||||
impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if !self.usage_found {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
|
||||
if let hir::def::Res::Local(id) = path.res {
|
||||
if self.binding_ids.contains(&id) {
|
||||
self.usage_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// run-rustfix
|
||||
#![warn(clippy::option_if_let_else)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
|
||||
fn bad1(string: Option<&str>) -> (bool, &str) {
|
||||
string.map_or((false, "hello"), |x| (true, x))
|
||||
@ -36,6 +37,14 @@ fn longer_body(arg: Option<u32>) -> u32 {
|
||||
})
|
||||
}
|
||||
|
||||
fn impure_else(arg: Option<i32>) {
|
||||
let side_effect = || {
|
||||
println!("return 1");
|
||||
1
|
||||
};
|
||||
let _ = arg.map_or_else(|| side_effect(), |x| x);
|
||||
}
|
||||
|
||||
fn test_map_or_else(arg: Option<u32>) {
|
||||
let _ = arg.map_or_else(|| {
|
||||
let mut y = 1;
|
||||
@ -71,4 +80,5 @@ fn main() {
|
||||
let _ = longer_body(None);
|
||||
test_map_or_else(None);
|
||||
let _ = negative_tests(None);
|
||||
let _ = impure_else(None);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// run-rustfix
|
||||
#![warn(clippy::option_if_let_else)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
|
||||
fn bad1(string: Option<&str>) -> (bool, &str) {
|
||||
if let Some(x) = string {
|
||||
@ -52,6 +53,19 @@ fn longer_body(arg: Option<u32>) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn impure_else(arg: Option<i32>) {
|
||||
let side_effect = || {
|
||||
println!("return 1");
|
||||
1
|
||||
};
|
||||
let _ = if let Some(x) = arg {
|
||||
x
|
||||
} else {
|
||||
// map_or_else must be suggested
|
||||
side_effect()
|
||||
};
|
||||
}
|
||||
|
||||
fn test_map_or_else(arg: Option<u32>) {
|
||||
let _ = if let Some(x) = arg {
|
||||
x * x * x * x
|
||||
@ -89,4 +103,5 @@ fn main() {
|
||||
let _ = longer_body(None);
|
||||
test_map_or_else(None);
|
||||
let _ = negative_tests(None);
|
||||
let _ = impure_else(None);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:5:5
|
||||
--> $DIR/option_if_let_else.rs:6:5
|
||||
|
|
||||
LL | / if let Some(x) = string {
|
||||
LL | | (true, x)
|
||||
@ -11,7 +11,7 @@ LL | | }
|
||||
= note: `-D clippy::option-if-let-else` implied by `-D warnings`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:15:12
|
||||
--> $DIR/option_if_let_else.rs:16:12
|
||||
|
|
||||
LL | } else if let Some(x) = string {
|
||||
| ____________^
|
||||
@ -22,19 +22,19 @@ LL | | }
|
||||
| |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:23:13
|
||||
--> $DIR/option_if_let_else.rs:24:13
|
||||
|
|
||||
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:24:13
|
||||
--> $DIR/option_if_let_else.rs:25:13
|
||||
|
|
||||
LL | let _ = if let Some(s) = &num { s } else { &0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:25:13
|
||||
--> $DIR/option_if_let_else.rs:26:13
|
||||
|
|
||||
LL | let _ = if let Some(s) = &mut num {
|
||||
| _____________^
|
||||
@ -54,13 +54,13 @@ LL | });
|
||||
|
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:31:13
|
||||
--> $DIR/option_if_let_else.rs:32:13
|
||||
|
|
||||
LL | let _ = if let Some(ref s) = num { s } else { &0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:32:13
|
||||
--> $DIR/option_if_let_else.rs:33:13
|
||||
|
|
||||
LL | let _ = if let Some(mut s) = num {
|
||||
| _____________^
|
||||
@ -80,7 +80,7 @@ LL | });
|
||||
|
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:38:13
|
||||
--> $DIR/option_if_let_else.rs:39:13
|
||||
|
|
||||
LL | let _ = if let Some(ref mut s) = num {
|
||||
| _____________^
|
||||
@ -100,7 +100,7 @@ LL | });
|
||||
|
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:47:5
|
||||
--> $DIR/option_if_let_else.rs:48:5
|
||||
|
|
||||
LL | / if let Some(x) = arg {
|
||||
LL | | let y = x * x;
|
||||
@ -119,7 +119,19 @@ LL | })
|
||||
|
|
||||
|
||||
error: use Option::map_or_else instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:56:13
|
||||
--> $DIR/option_if_let_else.rs:61:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = arg {
|
||||
| _____________^
|
||||
LL | | x
|
||||
LL | | } else {
|
||||
LL | | // map_or_else must be suggested
|
||||
LL | | side_effect()
|
||||
LL | | };
|
||||
| |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
|
||||
|
||||
error: use Option::map_or_else instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:70:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = arg {
|
||||
| _____________^
|
||||
@ -142,10 +154,10 @@ LL | }, |x| x * x * x * x);
|
||||
|
|
||||
|
||||
error: use Option::map_or instead of an if let/else
|
||||
--> $DIR/option_if_let_else.rs:85:13
|
||||
--> $DIR/option_if_let_else.rs:99:13
|
||||
|
|
||||
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#![warn(clippy::unnecessary_lazy_evaluations)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
#![allow(clippy::bind_instead_of_map)]
|
||||
#![allow(clippy::map_identity)]
|
||||
|
||||
struct Deep(Option<usize>);
|
||||
|
||||
@ -34,13 +35,13 @@ fn main() {
|
||||
let _ = opt.unwrap_or(2);
|
||||
let _ = opt.unwrap_or(astronomers_pi);
|
||||
let _ = opt.unwrap_or(ext_str.some_field);
|
||||
let _ = opt.unwrap_or(ext_arr[0]);
|
||||
let _ = opt.unwrap_or_else(|| ext_arr[0]);
|
||||
let _ = opt.and(ext_opt);
|
||||
let _ = opt.or(ext_opt);
|
||||
let _ = opt.or(None);
|
||||
let _ = opt.get_or_insert(2);
|
||||
let _ = opt.ok_or(2);
|
||||
let _ = opt.ok_or(ext_arr[0]);
|
||||
let _ = nested_tuple_opt.unwrap_or(Some((1, 2)));
|
||||
|
||||
// Cases when unwrap is not called on a simple variable
|
||||
let _ = Some(10).unwrap_or(2);
|
||||
@ -60,7 +61,6 @@ fn main() {
|
||||
// Should not lint - Option
|
||||
let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
|
||||
let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
|
||||
let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
|
||||
let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
|
||||
let _ = opt.or_else(some_call);
|
||||
let _ = opt.or_else(|| some_call());
|
||||
@ -69,13 +69,16 @@ fn main() {
|
||||
let _ = deep.0.get_or_insert_with(|| some_call());
|
||||
let _ = deep.0.or_else(some_call);
|
||||
let _ = deep.0.or_else(|| some_call());
|
||||
let _ = opt.ok_or_else(|| ext_arr[0]);
|
||||
|
||||
// These are handled by bind_instead_of_map
|
||||
// should not lint, bind_instead_of_map takes priority
|
||||
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
|
||||
let _ = Some(10).and_then(|idx| Some(idx));
|
||||
let _: Option<usize> = None.or_else(|| Some(3));
|
||||
let _ = deep.0.or_else(|| Some(3));
|
||||
let _ = opt.or_else(|| Some(3));
|
||||
|
||||
// should lint, bind_instead_of_map doesn't apply
|
||||
let _: Option<usize> = None.or(Some(3));
|
||||
let _ = deep.0.or(Some(3));
|
||||
let _ = opt.or(Some(3));
|
||||
|
||||
// Should lint - Result
|
||||
let res: Result<usize, usize> = Err(5);
|
||||
@ -92,26 +95,28 @@ fn main() {
|
||||
let _ = res2.unwrap_or_else(|err| err.return_some_field());
|
||||
let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
|
||||
|
||||
// should not lint, bind_instead_of_map takes priority
|
||||
let _: Result<usize, usize> = res.and_then(|x| Ok(x));
|
||||
let _: Result<usize, usize> = res.and_then(|x| Err(x));
|
||||
|
||||
let _: Result<usize, usize> = res.or_else(|err| Ok(err));
|
||||
let _: Result<usize, usize> = res.or_else(|err| Err(err));
|
||||
|
||||
// These are handled by bind_instead_of_map
|
||||
let _: Result<usize, usize> = res.and_then(|_| Ok(2));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
|
||||
|
||||
let _: Result<usize, usize> = res.and_then(|_| Err(2));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
|
||||
|
||||
let _: Result<usize, usize> = res.or_else(|_| Ok(2));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
|
||||
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(2));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
|
||||
|
||||
// should lint, bind_instead_of_map doesn't apply
|
||||
let _: Result<usize, usize> = res.and(Err(2));
|
||||
let _: Result<usize, usize> = res.and(Err(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.and(Err(ext_str.some_field));
|
||||
|
||||
let _: Result<usize, usize> = res.or(Ok(2));
|
||||
let _: Result<usize, usize> = res.or(Ok(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.or(Ok(ext_str.some_field));
|
||||
|
||||
// neither bind_instead_of_map nor unnecessary_lazy_eval applies here
|
||||
let _: Result<usize, usize> = res.and_then(|x| Err(x));
|
||||
let _: Result<usize, usize> = res.or_else(|err| Ok(err));
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#![warn(clippy::unnecessary_lazy_evaluations)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
#![allow(clippy::bind_instead_of_map)]
|
||||
#![allow(clippy::map_identity)]
|
||||
|
||||
struct Deep(Option<usize>);
|
||||
|
||||
@ -40,7 +41,7 @@ fn main() {
|
||||
let _ = opt.or_else(|| None);
|
||||
let _ = opt.get_or_insert_with(|| 2);
|
||||
let _ = opt.ok_or_else(|| 2);
|
||||
let _ = opt.ok_or_else(|| ext_arr[0]);
|
||||
let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
|
||||
|
||||
// Cases when unwrap is not called on a simple variable
|
||||
let _ = Some(10).unwrap_or_else(|| 2);
|
||||
@ -60,7 +61,6 @@ fn main() {
|
||||
// Should not lint - Option
|
||||
let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
|
||||
let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
|
||||
let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
|
||||
let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
|
||||
let _ = opt.or_else(some_call);
|
||||
let _ = opt.or_else(|| some_call());
|
||||
@ -69,10 +69,13 @@ fn main() {
|
||||
let _ = deep.0.get_or_insert_with(|| some_call());
|
||||
let _ = deep.0.or_else(some_call);
|
||||
let _ = deep.0.or_else(|| some_call());
|
||||
let _ = opt.ok_or_else(|| ext_arr[0]);
|
||||
|
||||
// These are handled by bind_instead_of_map
|
||||
// should not lint, bind_instead_of_map takes priority
|
||||
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
|
||||
let _ = Some(10).and_then(|idx| Some(idx));
|
||||
|
||||
// should lint, bind_instead_of_map doesn't apply
|
||||
let _: Option<usize> = None.or_else(|| Some(3));
|
||||
let _ = deep.0.or_else(|| Some(3));
|
||||
let _ = opt.or_else(|| Some(3));
|
||||
@ -92,17 +95,19 @@ fn main() {
|
||||
let _ = res2.unwrap_or_else(|err| err.return_some_field());
|
||||
let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
|
||||
|
||||
// should not lint, bind_instead_of_map takes priority
|
||||
let _: Result<usize, usize> = res.and_then(|x| Ok(x));
|
||||
let _: Result<usize, usize> = res.and_then(|x| Err(x));
|
||||
|
||||
let _: Result<usize, usize> = res.or_else(|err| Ok(err));
|
||||
let _: Result<usize, usize> = res.or_else(|err| Err(err));
|
||||
|
||||
// These are handled by bind_instead_of_map
|
||||
let _: Result<usize, usize> = res.and_then(|_| Ok(2));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
|
||||
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(2));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
|
||||
|
||||
// should lint, bind_instead_of_map doesn't apply
|
||||
let _: Result<usize, usize> = res.and_then(|_| Err(2));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
|
||||
@ -111,7 +116,7 @@ fn main() {
|
||||
let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
|
||||
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(2));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
|
||||
let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
|
||||
// neither bind_instead_of_map nor unnecessary_lazy_eval applies here
|
||||
let _: Result<usize, usize> = res.and_then(|x| Err(x));
|
||||
let _: Result<usize, usize> = res.or_else(|err| Ok(err));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:34:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:35:13
|
||||
|
|
||||
LL | let _ = opt.unwrap_or_else(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(2)`
|
||||
@ -7,142 +7,190 @@ LL | let _ = opt.unwrap_or_else(|| 2);
|
||||
= note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:35:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:36:13
|
||||
|
|
||||
LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(astronomers_pi)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:36:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:37:13
|
||||
|
|
||||
LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_str.some_field)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:37:13
|
||||
|
|
||||
LL | let _ = opt.unwrap_or_else(|| ext_arr[0]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `opt.unwrap_or(ext_arr[0])`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:38:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:39:13
|
||||
|
|
||||
LL | let _ = opt.and_then(|_| ext_opt);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `opt.and(ext_opt)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:39:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:40:13
|
||||
|
|
||||
LL | let _ = opt.or_else(|| ext_opt);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(ext_opt)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:40:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:41:13
|
||||
|
|
||||
LL | let _ = opt.or_else(|| None);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(None)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:41:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:42:13
|
||||
|
|
||||
LL | let _ = opt.get_or_insert_with(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `opt.get_or_insert(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:42:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:43:13
|
||||
|
|
||||
LL | let _ = opt.ok_or_else(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:43:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:44:13
|
||||
|
|
||||
LL | let _ = opt.ok_or_else(|| ext_arr[0]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `opt.ok_or(ext_arr[0])`
|
||||
LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `nested_tuple_opt.unwrap_or(Some((1, 2)))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:46:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:47:13
|
||||
|
|
||||
LL | let _ = Some(10).unwrap_or_else(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Some(10).unwrap_or(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:47:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:48:13
|
||||
|
|
||||
LL | let _ = Some(10).and_then(|_| ext_opt);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `Some(10).and(ext_opt)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:48:28
|
||||
--> $DIR/unnecessary_lazy_eval.rs:49:28
|
||||
|
|
||||
LL | let _: Option<usize> = None.or_else(|| ext_opt);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(ext_opt)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:49:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:50:13
|
||||
|
|
||||
LL | let _ = None.get_or_insert_with(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `None.get_or_insert(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:50:35
|
||||
--> $DIR/unnecessary_lazy_eval.rs:51:35
|
||||
|
|
||||
LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `None.ok_or(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:51:28
|
||||
--> $DIR/unnecessary_lazy_eval.rs:52:28
|
||||
|
|
||||
LL | let _: Option<usize> = None.or_else(|| None);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(None)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:54:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:55:13
|
||||
|
|
||||
LL | let _ = deep.0.unwrap_or_else(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `deep.0.unwrap_or(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:55:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:56:13
|
||||
|
|
||||
LL | let _ = deep.0.and_then(|_| ext_opt);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `deep.0.and(ext_opt)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:56:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:57:13
|
||||
|
|
||||
LL | let _ = deep.0.or_else(|| None);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(None)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:57:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:58:13
|
||||
|
|
||||
LL | let _ = deep.0.get_or_insert_with(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `get_or_insert` instead: `deep.0.get_or_insert(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:58:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:59:13
|
||||
|
|
||||
LL | let _ = deep.0.ok_or_else(|| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `ok_or` instead: `deep.0.ok_or(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:79:28
|
||||
|
|
||||
LL | let _: Option<usize> = None.or_else(|| Some(3));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `None.or(Some(3))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:80:13
|
||||
|
|
||||
LL | let _ = deep.0.or_else(|| Some(3));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `deep.0.or(Some(3))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Option::None`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:81:13
|
||||
|
|
||||
LL | let _ = opt.or_else(|| Some(3));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `opt.or(Some(3))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:84:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:87:13
|
||||
|
|
||||
LL | let _ = res2.unwrap_or_else(|_| 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(2)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:85:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:88:13
|
||||
|
|
||||
LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(astronomers_pi)`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:86:13
|
||||
--> $DIR/unnecessary_lazy_eval.rs:89:13
|
||||
|
|
||||
LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `res2.unwrap_or(ext_str.some_field)`
|
||||
|
||||
error: aborting due to 24 previous errors
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:111:35
|
||||
|
|
||||
LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(2))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:112:35
|
||||
|
|
||||
LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(astronomers_pi))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:113:35
|
||||
|
|
||||
LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `and` instead: `res.and(Err(ext_str.some_field))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:115:35
|
||||
|
|
||||
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(2))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:116:35
|
||||
|
|
||||
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(astronomers_pi))`
|
||||
|
||||
error: unnecessary closure used to substitute value for `Result::Err`
|
||||
--> $DIR/unnecessary_lazy_eval.rs:117:35
|
||||
|
|
||||
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `or` instead: `res.or(Ok(ext_str.some_field))`
|
||||
|
||||
error: aborting due to 32 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user