| use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; |
| use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; |
| use clippy_utils::{is_doc_hidden, return_ty}; |
| use rustc_hir::{BodyId, FnSig, OwnerId, Unsafety}; |
| use rustc_lint::LateContext; |
| use rustc_middle::ty; |
| use rustc_span::{sym, Span}; |
| |
| use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; |
| |
| pub fn check( |
| cx: &LateContext<'_>, |
| owner_id: OwnerId, |
| sig: &FnSig<'_>, |
| headers: DocHeaders, |
| body_id: Option<BodyId>, |
| panic_span: Option<Span>, |
| check_private_items: bool, |
| ) { |
| if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) { |
| return; // Private functions do not require doc comments |
| } |
| |
| // do not lint if any parent has `#[doc(hidden)]` attribute (#7347) |
| if !check_private_items |
| && cx |
| .tcx |
| .hir() |
| .parent_iter(owner_id.into()) |
| .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) |
| { |
| return; |
| } |
| |
| let span = cx.tcx.def_span(owner_id); |
| match (headers.safety, sig.header.unsafety) { |
| (false, Unsafety::Unsafe) => span_lint( |
| cx, |
| MISSING_SAFETY_DOC, |
| span, |
| "unsafe function's docs miss `# Safety` section", |
| ), |
| (true, Unsafety::Normal) => span_lint( |
| cx, |
| UNNECESSARY_SAFETY_DOC, |
| span, |
| "safe function's docs have unnecessary `# Safety` section", |
| ), |
| _ => (), |
| } |
| if !headers.panics && panic_span.is_some() { |
| span_lint_and_note( |
| cx, |
| MISSING_PANICS_DOC, |
| span, |
| "docs for function which may panic missing `# Panics` section", |
| panic_span, |
| "first possible panic found here", |
| ); |
| } |
| if !headers.errors { |
| if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) { |
| span_lint( |
| cx, |
| MISSING_ERRORS_DOC, |
| span, |
| "docs for function returning `Result` missing `# Errors` section", |
| ); |
| } else if let Some(body_id) = body_id |
| && let Some(future) = cx.tcx.lang_items().future_trait() |
| && let typeck = cx.tcx.typeck_body(body_id) |
| && let body = cx.tcx.hir().body(body_id) |
| && let ret_ty = typeck.expr_ty(body.value) |
| && implements_trait(cx, ret_ty, future, &[]) |
| && let ty::Coroutine(_, subs) = ret_ty.kind() |
| && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) |
| { |
| span_lint( |
| cx, |
| MISSING_ERRORS_DOC, |
| span, |
| "docs for function returning `Result` missing `# Errors` section", |
| ); |
| } |
| } |
| } |