]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / src / tools / clippy / clippy_lints / src / methods / option_map_or_none.rs
CommitLineData
f20569fa
XL
1use crate::utils::{is_type_diagnostic_item, match_qpath, paths, snippet, span_lint_and_sugg};
2use rustc_errors::Applicability;
3use rustc_hir as hir;
4use rustc_lint::LateContext;
5use rustc_span::symbol::sym;
6
7use super::OPTION_MAP_OR_NONE;
8use super::RESULT_MAP_OR_INTO_OPTION;
9
10/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
11pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
12 let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type);
13 let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type);
14
15 // There are two variants of this `map_or` lint:
16 // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
17 // (2) using `map_or` as a combinator instead of `and_then`
18 //
19 // (For this lint) we don't care if any other type calls `map_or`
20 if !is_option && !is_result {
21 return;
22 }
23
24 let (lint_name, msg, instead, hint) = {
25 let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
26 match_qpath(qpath, &paths::OPTION_NONE)
27 } else {
28 return;
29 };
30
31 if !default_arg_is_none {
32 // nothing to lint!
33 return;
34 }
35
36 let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind {
37 match_qpath(qpath, &paths::OPTION_SOME)
38 } else {
39 false
40 };
41
42 if is_option {
43 let self_snippet = snippet(cx, map_or_args[0].span, "..");
44 let func_snippet = snippet(cx, map_or_args[2].span, "..");
45 let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
46 `and_then(..)` instead";
47 (
48 OPTION_MAP_OR_NONE,
49 msg,
50 "try using `and_then` instead",
51 format!("{0}.and_then({1})", self_snippet, func_snippet),
52 )
53 } else if f_arg_is_some {
54 let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
55 `ok()` instead";
56 let self_snippet = snippet(cx, map_or_args[0].span, "..");
57 (
58 RESULT_MAP_OR_INTO_OPTION,
59 msg,
60 "try using `ok` instead",
61 format!("{0}.ok()", self_snippet),
62 )
63 } else {
64 // nothing to lint!
65 return;
66 }
67 };
68
69 span_lint_and_sugg(
70 cx,
71 lint_name,
72 expr.span,
73 msg,
74 instead,
75 hint,
76 Applicability::MachineApplicable,
77 );
78}