]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use crate::utils::{implements_trait, is_type_diagnostic_item, span_lint_and_help}; |
2 | use if_chain::if_chain; | |
3 | use rustc_hir as hir; | |
4 | use rustc_lint::LateContext; | |
5 | use rustc_middle::ty::{self, Ty}; | |
6 | use rustc_span::sym; | |
7 | ||
8 | use super::OK_EXPECT; | |
9 | ||
10 | /// lint use of `ok().expect()` for `Result`s | |
11 | pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) { | |
12 | if_chain! { | |
13 | // lint if the caller of `ok()` is a `Result` | |
14 | if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type); | |
15 | let result_type = cx.typeck_results().expr_ty(&ok_args[0]); | |
16 | if let Some(error_type) = get_error_type(cx, result_type); | |
17 | if has_debug_impl(error_type, cx); | |
18 | ||
19 | then { | |
20 | span_lint_and_help( | |
21 | cx, | |
22 | OK_EXPECT, | |
23 | expr.span, | |
24 | "called `ok().expect()` on a `Result` value", | |
25 | None, | |
26 | "you can call `expect()` directly on the `Result`", | |
27 | ); | |
28 | } | |
29 | } | |
30 | } | |
31 | ||
32 | /// Given a `Result<T, E>` type, return its error type (`E`). | |
33 | fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> { | |
34 | match ty.kind() { | |
35 | ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1), | |
36 | _ => None, | |
37 | } | |
38 | } | |
39 | ||
40 | /// This checks whether a given type is known to implement Debug. | |
41 | fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { | |
42 | cx.tcx | |
43 | .get_diagnostic_item(sym::debug_trait) | |
44 | .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) | |
45 | } |