]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
Auto merge of #103828 - cassaundra:fix-format-args-span2, r=cjgillot
[rust.git] / src / tools / clippy / clippy_lints / src / methods / or_then_unwrap.rs
1 use clippy_utils::source::snippet_with_applicability;
2 use clippy_utils::ty::is_type_diagnostic_item;
3 use clippy_utils::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res};
4 use rustc_errors::Applicability;
5 use rustc_hir::{lang_items::LangItem, Expr, ExprKind};
6 use rustc_lint::LateContext;
7 use rustc_span::{sym, Span};
8
9 use super::OR_THEN_UNWRAP;
10
11 pub(super) fn check<'tcx>(
12     cx: &LateContext<'tcx>,
13     unwrap_expr: &Expr<'_>,
14     recv: &'tcx Expr<'tcx>,
15     or_arg: &'tcx Expr<'_>,
16     or_span: Span,
17 ) {
18     let ty = cx.typeck_results().expr_ty(recv); // get type of x (we later check if it's Option or Result)
19     let title;
20     let or_arg_content: Span;
21
22     if is_type_diagnostic_item(cx, ty, sym::Option) {
23         title = "found `.or(Some(…)).unwrap()`";
24         if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) {
25             or_arg_content = content;
26         } else {
27             return;
28         }
29     } else if is_type_diagnostic_item(cx, ty, sym::Result) {
30         title = "found `.or(Ok(…)).unwrap()`";
31         if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) {
32             or_arg_content = content;
33         } else {
34             return;
35         }
36     } else {
37         // Someone has implemented a struct with .or(...).unwrap() chaining,
38         // but it's not an Option or a Result, so bail
39         return;
40     }
41
42     let mut applicability = Applicability::MachineApplicable;
43     let suggestion = format!(
44         "unwrap_or({})",
45         snippet_with_applicability(cx, or_arg_content, "..", &mut applicability)
46     );
47
48     span_lint_and_sugg(
49         cx,
50         OR_THEN_UNWRAP,
51         unwrap_expr.span.with_lo(or_span.lo()),
52         title,
53         "try this",
54         suggestion,
55         applicability,
56     );
57 }
58
59 fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option<Span> {
60     if let ExprKind::Call(some_expr, [arg]) = expr.kind
61         && is_res_lang_ctor(cx, path_res(cx, some_expr), item)
62     {
63         Some(arg.span)
64     } else {
65         None
66     }
67 }