2 use rustc_lint::{LateContext, LintContext};
3 use rustc_middle::lint::in_external_macro;
5 use rustc_span::{sym, Span};
6 use rustc_typeck::hir_ty_to_ty;
8 use if_chain::if_chain;
10 use clippy_utils::diagnostics::span_lint_and_help;
11 use clippy_utils::trait_ref_of_method;
12 use clippy_utils::ty::is_type_diagnostic_item;
14 use super::RESULT_UNIT_ERR;
16 pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
17 if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind {
18 let is_public = cx.access_levels.is_exported(item.def_id);
19 let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
21 check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
26 pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
27 if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
28 let is_public = cx.access_levels.is_exported(item.def_id);
29 let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
30 if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() {
31 check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
36 pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) {
37 if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
38 let is_public = cx.access_levels.is_exported(item.def_id);
39 let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
41 check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
46 fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) {
48 if !in_external_macro(cx.sess(), item_span);
49 if let hir::FnRetTy::Return(ty) = decl.output;
50 let ty = hir_ty_to_ty(cx.tcx, ty);
51 if is_type_diagnostic_item(cx, ty, sym::Result);
52 if let ty::Adt(_, substs) = ty.kind();
53 let err_ty = substs.type_at(1);
60 "this returns a `Result<_, ()>`",
62 "use a custom `Error` type instead",