]> 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 00592a4035c4f43a21f1c668ec5a6726e1783114..133a20b669a17720faab96f0cb22031939e01f2a 100644 (file)
@@ -1,14 +1,15 @@
-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::hir;
-use rustc::impl_lint_pass;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::lint::in_external_macro;
+use rustc::ty::TyKind;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_session::declare_tool_lint;
+use rustc_hir as hir;
+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;
 use syntax::ast::{AttrKind, Attribute};
-use syntax::source_map::{BytePos, MultiSpan, Span};
-use syntax_pos::Pos;
 use url::Url;
 
 declare_clippy_lint! {
@@ -153,9 +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, ..) => {
-                lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
+                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();
             },
             _ => {},
@@ -163,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;
         }
     }
@@ -171,13 +179,15 @@ fn check_item_post(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item
     fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem<'_>) {
         let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
         if let hir::TraitItemKind::Method(ref sig, ..) = item.kind {
-            lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
+            if !in_external_macro(cx.tcx.sess, item.span) {
+                lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
+            }
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem<'_>) {
         let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
-        if self.in_trait_impl {
+        if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
             return;
         }
         if let hir::ImplItemKind::Method(ref sig, ..) = item.kind {
@@ -190,7 +200,7 @@ fn lint_for_missing_headers<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     hir_id: hir::HirId,
     span: impl Into<MultiSpan> + Copy,
-    sig: &hir::FnSig,
+    sig: &hir::FnSig<'_>,
     headers: DocHeaders,
 ) {
     if !cx.access_levels.is_exported(hir_id) {
@@ -204,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",
+                                    );
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
 }