]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/doc.rs
Add tests and improve checks.
[rust.git] / clippy_lints / src / doc.rs
index d7c232eec1a231c1534cbf4792a52b0c7e0cc30f..133a20b669a17720faab96f0cb22031939e01f2a 100644 (file)
@@ -1,10 +1,11 @@
-use crate::utils::{match_type, paths, return_ty, span_lint};
+use crate::utils::{get_trait_def_id, implements_trait, is_entrypoint_fn, match_type, paths, return_ty, span_lint};
 use itertools::Itertools;
-use rustc::impl_lint_pass;
-use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintPass};
+use rustc::lint::in_external_macro;
+use rustc::ty::TyKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_session::declare_tool_lint;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{BytePos, MultiSpan, Span};
 use rustc_span::Pos;
 use std::ops::Range;
@@ -153,11 +154,16 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>)
         let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
         match item.kind {
             hir::ItemKind::Fn(ref sig, ..) => {
-                if !in_external_macro(cx.tcx.sess, item.span) {
+                if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id))
+                    || in_external_macro(cx.tcx.sess, item.span))
+                {
                     lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
                 }
             },
-            hir::ItemKind::Impl(_, _, _, _, ref trait_ref, ..) => {
+            hir::ItemKind::Impl {
+                of_trait: ref trait_ref,
+                ..
+            } => {
                 self.in_trait_impl = trait_ref.is_some();
             },
             _ => {},
@@ -165,7 +171,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>)
     }
 
     fn check_item_post(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
-        if let hir::ItemKind::Impl(..) = item.kind {
+        if let hir::ItemKind::Impl { .. } = item.kind {
             self.in_trait_impl = false;
         }
     }
@@ -208,13 +214,38 @@ fn lint_for_missing_headers<'a, 'tcx>(
             "unsafe function's docs miss `# Safety` section",
         );
     }
-    if !headers.errors && match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
-        span_lint(
-            cx,
-            MISSING_ERRORS_DOC,
-            span,
-            "docs for function returning `Result` missing `# Errors` section",
-        );
+    if !headers.errors {
+        if match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
+            span_lint(
+                cx,
+                MISSING_ERRORS_DOC,
+                span,
+                "docs for function returning `Result` missing `# Errors` section",
+            );
+        } else {
+            let def_id = cx.tcx.hir().local_def_id(hir_id);
+            let mir = cx.tcx.optimized_mir(def_id);
+            if let Some(future) = get_trait_def_id(cx, &paths::FUTURE) {
+                if implements_trait(cx, mir.return_ty(), future, &[]) {
+                    use TyKind::*;
+
+                    if let Opaque(_, subs) = mir.return_ty().kind {
+                        if let Some(ty) = subs.types().next() {
+                            if let Generator(_, subs, _) = ty.kind {
+                                if match_type(cx, subs.as_generator().return_ty(def_id, cx.tcx), &paths::RESULT) {
+                                    span_lint(
+                                        cx,
+                                        MISSING_ERRORS_DOC,
+                                        span,
+                                        "docs for function returning `Result` missing `# Errors` section",
+                                    );
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
 }