]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
bump version to 1.79.0+dfsg1-1~bpo12+pve2
[rustc.git] / src / tools / clippy / clippy_lints / src / unwrap_in_result.rs
CommitLineData
cdc7bbd5
XL
1use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::ty::is_type_diagnostic_item;
2b03887a 3use clippy_utils::visitors::for_each_expr;
cdc7bbd5 4use clippy_utils::{method_chain_args, return_ty};
2b03887a 5use core::ops::ControlFlow;
f20569fa 6use rustc_hir as hir;
2b03887a 7use rustc_hir::ImplItemKind;
f20569fa 8use rustc_lint::{LateContext, LateLintPass};
4b012472 9use rustc_session::declare_lint_pass;
f20569fa
XL
10use rustc_span::{sym, Span};
11
12declare_clippy_lint! {
94222f64 13 /// ### What it does
3c0e092e 14 /// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
f20569fa 15 ///
94222f64
XL
16 /// ### Why is this bad?
17 /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
f20569fa 18 ///
94222f64
XL
19 /// ### Known problems
20 /// This can cause false positives in functions that handle both recoverable and non recoverable errors.
f20569fa 21 ///
94222f64 22 /// ### Example
f20569fa 23 /// Before:
ed00b5ec 24 /// ```no_run
f20569fa
XL
25 /// fn divisible_by_3(i_str: String) -> Result<(), String> {
26 /// let i = i_str
27 /// .parse::<i32>()
28 /// .expect("cannot divide the input by three");
29 ///
30 /// if i % 3 != 0 {
31 /// Err("Number is not divisible by 3")?
32 /// }
33 ///
34 /// Ok(())
35 /// }
36 /// ```
37 ///
38 /// After:
ed00b5ec 39 /// ```no_run
f20569fa
XL
40 /// fn divisible_by_3(i_str: String) -> Result<(), String> {
41 /// let i = i_str
42 /// .parse::<i32>()
43 /// .map_err(|e| format!("cannot divide the input by three: {}", e))?;
44 ///
45 /// if i % 3 != 0 {
46 /// Err("Number is not divisible by 3")?
47 /// }
48 ///
49 /// Ok(())
50 /// }
51 /// ```
a2a8927a 52 #[clippy::version = "1.48.0"]
f20569fa
XL
53 pub UNWRAP_IN_RESULT,
54 restriction,
55 "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`"
56}
57
58declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]);
59
60impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
61 fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
e8be2606 62 if let ImplItemKind::Fn(ref _signature, _) = impl_item.kind
f20569fa 63 // first check if it's a method or function
f20569fa 64 // checking if its return type is `result` or `option`
4b012472
FG
65 && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
66 || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option))
67 {
68 lint_impl_body(cx, impl_item.span, impl_item);
f20569fa
XL
69 }
70 }
71}
72
2b03887a
FG
73fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
74 if let ImplItemKind::Fn(_, body_id) = impl_item.kind {
75 let body = cx.tcx.hir().body(body_id);
76 let typeck = cx.tcx.typeck(impl_item.owner_id.def_id);
77 let mut result = Vec::new();
78 let _: Option<!> = for_each_expr(body.value, |e| {
79 // check for `expect`
80 if let Some(arglists) = method_chain_args(e, &["expect"]) {
81 let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
82 if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
83 || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
84 {
85 result.push(e.span);
86 }
f20569fa 87 }
f20569fa 88
2b03887a
FG
89 // check for `unwrap`
90 if let Some(arglists) = method_chain_args(e, &["unwrap"]) {
91 let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
92 if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
93 || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
94 {
95 result.push(e.span);
96 }
f20569fa 97 }
f20569fa 98
2b03887a
FG
99 ControlFlow::Continue(())
100 });
f20569fa 101
cdc7bbd5 102 // if we've found one, lint
2b03887a 103 if !result.is_empty() {
cdc7bbd5
XL
104 span_lint_and_then(
105 cx,
106 UNWRAP_IN_RESULT,
107 impl_span,
108 "used unwrap or expect in a function that returns result or option",
109 move |diag| {
110 diag.help("unwrap and expect should not be used in a function that returns result or option");
2b03887a 111 diag.span_note(result, "potential non-recoverable error(s)");
cdc7bbd5
XL
112 },
113 );
f20569fa
XL
114 }
115 }
116}