1 //! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
3 use super::UNWRAP_OR_ELSE_DEFAULT;
5 diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
6 ty::is_type_diagnostic_item,
8 use rustc_ast::ast::LitKind;
9 use rustc_errors::Applicability;
11 use rustc_lint::LateContext;
12 use rustc_span::{sym, symbol};
14 pub(super) fn check<'tcx>(
15 cx: &LateContext<'tcx>,
16 expr: &'tcx hir::Expr<'_>,
17 recv: &'tcx hir::Expr<'_>,
18 u_arg: &'tcx hir::Expr<'_>,
20 // something.unwrap_or_else(Default::default)
21 // ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg
22 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
23 let recv_ty = cx.typeck_results().expr_ty(recv);
24 let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option);
25 let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result);
28 if is_option || is_result;
29 if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
31 let mut applicability = Applicability::MachineApplicable;
35 UNWRAP_OR_ELSE_DEFAULT,
37 "use of `.unwrap_or_else(..)` to construct default value",
40 "{}.unwrap_or_default()",
41 snippet_with_applicability(cx, recv.span, "..", &mut applicability)
49 fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
50 if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
51 let body = cx.tcx.hir().body(body);
53 if body.params.is_empty()
54 && let hir::Expr{ kind, .. } = &body.value
55 && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
56 && ident == &symbol::Ident::from_str("to_string")
57 && let hir::Expr{ kind, .. } = self_arg
58 && let hir::ExprKind::Lit(lit) = kind
59 && let LitKind::Str(symbol::kw::Empty, _) = lit.node