2022-03-18 22:18:36 +00:00
|
|
|
use clippy_utils::source::snippet_with_applicability;
|
2022-03-18 20:11:54 +00:00
|
|
|
use clippy_utils::ty::is_type_diagnostic_item;
|
2022-06-29 02:34:02 +00:00
|
|
|
use clippy_utils::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res};
|
2022-03-18 21:44:56 +00:00
|
|
|
use rustc_errors::Applicability;
|
2022-03-20 22:54:04 +00:00
|
|
|
use rustc_hir::{lang_items::LangItem, Expr, ExprKind};
|
2022-03-18 20:11:54 +00:00
|
|
|
use rustc_lint::LateContext;
|
|
|
|
use rustc_span::{sym, Span};
|
|
|
|
|
|
|
|
use super::OR_THEN_UNWRAP;
|
|
|
|
|
|
|
|
pub(super) fn check<'tcx>(
|
|
|
|
cx: &LateContext<'tcx>,
|
|
|
|
unwrap_expr: &Expr<'_>,
|
|
|
|
recv: &'tcx Expr<'tcx>,
|
|
|
|
or_arg: &'tcx Expr<'_>,
|
|
|
|
or_span: Span,
|
|
|
|
) {
|
|
|
|
let ty = cx.typeck_results().expr_ty(recv); // get type of x (we later check if it's Option or Result)
|
|
|
|
let title;
|
2022-03-18 22:18:36 +00:00
|
|
|
let or_arg_content: Span;
|
2022-03-18 20:11:54 +00:00
|
|
|
|
|
|
|
if is_type_diagnostic_item(cx, ty, sym::Option) {
|
2022-03-20 22:43:17 +00:00
|
|
|
title = "found `.or(Some(…)).unwrap()`";
|
2022-03-20 22:54:04 +00:00
|
|
|
if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) {
|
2022-03-18 22:18:36 +00:00
|
|
|
or_arg_content = content;
|
|
|
|
} else {
|
2022-03-18 20:11:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if is_type_diagnostic_item(cx, ty, sym::Result) {
|
2022-03-20 22:43:17 +00:00
|
|
|
title = "found `.or(Ok(…)).unwrap()`";
|
2022-03-20 22:54:04 +00:00
|
|
|
if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) {
|
2022-03-18 22:18:36 +00:00
|
|
|
or_arg_content = content;
|
|
|
|
} else {
|
2022-03-18 20:11:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Someone has implemented a struct with .or(...).unwrap() chaining,
|
|
|
|
// but it's not an Option or a Result, so bail
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-18 22:18:36 +00:00
|
|
|
let mut applicability = Applicability::MachineApplicable;
|
|
|
|
let suggestion = format!(
|
|
|
|
"unwrap_or({})",
|
|
|
|
snippet_with_applicability(cx, or_arg_content, "..", &mut applicability)
|
|
|
|
);
|
|
|
|
|
2022-03-18 21:44:56 +00:00
|
|
|
span_lint_and_sugg(
|
2022-03-18 20:11:54 +00:00
|
|
|
cx,
|
|
|
|
OR_THEN_UNWRAP,
|
2022-03-20 23:04:37 +00:00
|
|
|
unwrap_expr.span.with_lo(or_span.lo()),
|
2022-03-18 20:11:54 +00:00
|
|
|
title,
|
2022-03-18 21:44:56 +00:00
|
|
|
"try this",
|
2022-03-18 22:18:36 +00:00
|
|
|
suggestion,
|
|
|
|
applicability,
|
2022-03-18 20:11:54 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-03-20 22:54:04 +00:00
|
|
|
fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option<Span> {
|
|
|
|
if let ExprKind::Call(some_expr, [arg]) = expr.kind
|
2022-06-29 02:34:02 +00:00
|
|
|
&& is_res_lang_ctor(cx, path_res(cx, some_expr), item)
|
2022-03-20 22:54:04 +00:00
|
|
|
{
|
|
|
|
Some(arg.span)
|
|
|
|
} else {
|
|
|
|
None
|
2022-03-18 20:11:54 +00:00
|
|
|
}
|
|
|
|
}
|