From e1abd8e6d2cc39ec522324bbd2954a1dcb70f8d6 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 15 Aug 2025 16:40:10 -0700 Subject: [PATCH] missing_safety_doc: guide them out of an HTML block with a header --- .../src/doc/doc_suspicious_footnotes.rs | 13 +- clippy_lints/src/doc/lazy_continuation.rs | 10 +- clippy_lints/src/doc/missing_headers.rs | 25 +- clippy_lints/src/doc/mod.rs | 201 +++++- tests/ui/doc/doc_header_html.fixed | 575 ++++++++++++++++++ tests/ui/doc/doc_header_html.rs | 559 +++++++++++++++++ tests/ui/doc/doc_header_html.stderr | 256 ++++++++ tests/ui/doc/doc_header_html_unformed.rs | 36 ++ tests/ui/doc/doc_header_html_unformed.stderr | 28 + 9 files changed, 1653 insertions(+), 50 deletions(-) create mode 100644 tests/ui/doc/doc_header_html.fixed create mode 100644 tests/ui/doc/doc_header_html.rs create mode 100644 tests/ui/doc/doc_header_html.stderr create mode 100644 tests/ui/doc/doc_header_html_unformed.rs create mode 100644 tests/ui/doc/doc_header_html_unformed.stderr diff --git a/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/clippy_lints/src/doc/doc_suspicious_footnotes.rs index 3330cc5defd3..011d3987c2d1 100644 --- a/clippy_lints/src/doc/doc_suspicious_footnotes.rs +++ b/clippy_lints/src/doc/doc_suspicious_footnotes.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::attr::AttributeExt as _; use rustc_ast::token::CommentKind; use rustc_errors::Applicability; use rustc_hir::{AttrStyle, Attribute}; @@ -8,7 +7,7 @@ use rustc_resolve::rustdoc::DocFragmentKind; use std::ops::Range; -use super::{DOC_SUSPICIOUS_FOOTNOTES, Fragments}; +use super::{DOC_SUSPICIOUS_FOOTNOTES, Fragments, find_doc_attr_by_span}; pub fn check(cx: &LateContext<'_>, doc: &str, range: Range, fragments: &Fragments<'_>, attrs: &[Attribute]) { for i in doc[range.clone()] @@ -44,14 +43,8 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range, fragments: &F "looks like a footnote ref, but has no matching footnote", |diag| { if this_fragment.kind == DocFragmentKind::SugaredDoc { - let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs - .iter() - .filter(|attr| attr.span().overlaps(this_fragment.span)) - .rev() - .find_map(|attr| { - Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?)) - }) - .unwrap(); + let (doc_attr, doc_attr_comment_kind, attr_style) = + find_doc_attr_by_span(attrs, this_fragment.span).unwrap(); let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) { (CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""), (CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""), diff --git a/clippy_lints/src/doc/lazy_continuation.rs b/clippy_lints/src/doc/lazy_continuation.rs index cb9d68224dbb..3ba9837f55c4 100644 --- a/clippy_lints/src/doc/lazy_continuation.rs +++ b/clippy_lints/src/doc/lazy_continuation.rs @@ -7,14 +7,6 @@ use std::ops::Range; use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS, Fragments}; -fn map_container_to_text(c: &super::Container) -> &'static str { - match c { - super::Container::Blockquote => "> ", - // numbered list can have up to nine digits, plus the dot, plus four spaces on either side - super::Container::List(indent) => &" "[0..*indent], - } -} - pub(super) fn check( cx: &LateContext<'_>, doc: &str, @@ -41,7 +33,7 @@ pub(super) fn check( let mut doc_start_range = &doc[cooked_range]; let mut suggested = String::new(); for c in containers { - let text = map_container_to_text(c); + let text = c.map_to_text(); if doc_start_range.starts_with(text) { doc_start_range = &doc_start_range[text.len()..]; span = span.with_lo( diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs index 3033ac0d0b0b..b80b36b7cb48 100644 --- a/clippy_lints/src/doc/missing_headers.rs +++ b/clippy_lints/src/doc/missing_headers.rs @@ -1,5 +1,5 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; -use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; +use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::ty::{get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item}; use clippy_utils::visitors::for_each_expr; @@ -14,7 +14,7 @@ pub fn check( cx: &LateContext<'_>, owner_id: OwnerId, sig: FnSig<'_>, - headers: DocHeaders, + headers: &DocHeaders, body_id: Option, check_private_items: bool, ) { @@ -33,14 +33,14 @@ pub fn check( } let span = cx.tcx.def_span(owner_id); - match (headers.safety, sig.header.safety()) { - (false, Safety::Unsafe) => span_lint( + match (headers.safety.is_missing(), sig.header.safety()) { + (true, Safety::Unsafe) => headers.safety.lint( cx, MISSING_SAFETY_DOC, span, "unsafe function's docs are missing a `# Safety` section", ), - (true, Safety::Safe) => span_lint( + (false, Safety::Safe) => span_lint( cx, UNNECESSARY_SAFETY_DOC, span, @@ -48,22 +48,23 @@ pub fn check( ), _ => (), } - if !headers.panics + if headers.panics.is_missing() && let Some(body_id) = body_id && let Some(panic_span) = find_panic(cx, body_id) { - span_lint_and_note( + headers.panics.lint_and_then( cx, MISSING_PANICS_DOC, span, "docs for function which may panic missing `# Panics` section", - Some(panic_span), - "first possible panic found here", + |diag| { + diag.span_note(panic_span, "first possible panic found here"); + }, ); } - if !headers.errors { + if headers.errors.is_missing() { if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) { - span_lint( + headers.errors.lint( cx, MISSING_ERRORS_DOC, span, @@ -85,7 +86,7 @@ pub fn check( && let ty::Coroutine(_, subs) = ret_ty.kind() && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) { - span_lint( + headers.errors.lint( cx, MISSING_ERRORS_DOC, span, diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index eca3bc390d77..709f6164cc4e 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -10,10 +10,12 @@ use pulldown_cmark::Event::{ }; use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; +use rustc_ast::attr::AttributeExt; +use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Applicability; -use rustc_hir::{Attribute, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan}; +use rustc_hir::{AttrStyle, Attribute, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Lint, LintContext}; use rustc_resolve::rustdoc::{ DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, @@ -734,20 +736,20 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { cx, item.owner_id, sig, - headers, + &headers, Some(body), self.check_private_items, ); } }, - ItemKind::Trait(_, _, unsafety, ..) => match (headers.safety, unsafety) { - (false, Safety::Unsafe) => span_lint( + ItemKind::Trait(_, _, unsafety, ..) => match (headers.safety.is_missing(), unsafety) { + (true, Safety::Unsafe) => span_lint( cx, MISSING_SAFETY_DOC, cx.tcx.def_span(item.owner_id), "docs for unsafe trait missing `# Safety` section", ), - (true, Safety::Safe) => span_lint( + (false, Safety::Safe) => headers.safety.lint( cx, UNNECESSARY_SAFETY_DOC, cx.tcx.def_span(item.owner_id), @@ -762,7 +764,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { if let TraitItemKind::Fn(sig, ..) = trait_item.kind && !trait_item.span.in_external_macro(cx.tcx.sess.source_map()) { - missing_headers::check(cx, trait_item.owner_id, sig, headers, None, self.check_private_items); + missing_headers::check(cx, trait_item.owner_id, sig, &headers, None, self.check_private_items); } }, Node::ImplItem(impl_item) => { @@ -774,7 +776,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { cx, impl_item.owner_id, sig, - headers, + &headers, Some(body_id), self.check_private_items, ); @@ -800,11 +802,100 @@ impl Fragments<'_> { } } -#[derive(Copy, Clone, Default)] +#[derive(Clone, Default)] +enum DocHeaderInfo { + #[default] + None, + Found, + SuspiciousHtml(Option, &'static str, Vec), +} + +impl DocHeaderInfo { + fn suspicious_html( + cx: &LateContext<'_>, + fragments: Fragments<'_>, + idx: usize, + attrs: &[Attribute], + containers: &[Container], + ) -> DocHeaderInfo { + use rustc_ast::token::CommentKind; + use rustc_hir::AttrStyle; + let span = fragments.span(cx, idx..idx); + let indent = span + .and_then(|span| fragments.fragments.iter().find(|fragment| fragment.span.overlaps(span))) + .map_or(0, |fragment| fragment.indent); + DocHeaderInfo::SuspiciousHtml( + span, + span.and_then(|span| find_doc_attr_by_span(attrs, span)).map_or( + "", + |(_doc_attr, doc_attr_comment_kind, attr_style)| match (doc_attr_comment_kind, attr_style) { + (CommentKind::Block, _) => &" "[..indent], + (CommentKind::Line, AttrStyle::Outer) => &"/// "[..indent + 3], + (CommentKind::Line, AttrStyle::Inner) => &"//! "[..indent + 3], + }, + ), + containers.to_vec(), + ) + } + fn is_missing(&self) -> bool { + matches!(self, DocHeaderInfo::None | DocHeaderInfo::SuspiciousHtml(..)) + } + fn lint(&self, cx: &LateContext<'_>, lint: &'static Lint, sp: impl Into, msg: impl Into) { + self.lint_and_then(cx, lint, sp, msg, |_| {}); + } + fn lint_and_then( + &self, + cx: &LateContext<'_>, + lint: &'static Lint, + sp: impl Into, + msg: impl Into, + f: impl FnOnce(&mut Diag<'_, ()>), + ) { + if let DocHeaderInfo::SuspiciousHtml(html_span, comment_prefix, containers) = self { + span_lint_and_then(cx, lint, sp, msg, |diag| { + f(diag); + diag.note("markdown syntax is not recognized within a block of raw HTML code"); + if let Some(html_span) = html_span { + diag.span_suggestion( + *html_span, + "to recognize this text as a header, add a blank line", + format!( + "\n{comment_prefix}{containers}", + containers = containers + .iter() + .map(Container::map_to_text) + .collect::>() + .join("") + ), + Applicability::Unspecified, + ); + } else { + diag.help( + "to recognize a markdown header nested within an HTML element,\ + add a blank line between the `#` and the HTML", + ); + } + }); + } else { + span_lint_and_then(cx, lint, sp, msg, f); + } + } +} + +fn find_doc_attr_by_span(attrs: &[Attribute], span: Span) -> Option<(&Attribute, CommentKind, AttrStyle)> { + let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs + .iter() + .filter(|attr| attr.span().overlaps(span)) + .rev() + .find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?)))?; + Some((doc_attr, doc_attr_comment_kind, attr_style)) +} + +#[derive(Clone, Default)] struct DocHeaders { - safety: bool, - errors: bool, - panics: bool, + safety: DocHeaderInfo, + errors: DocHeaderInfo, + panics: DocHeaderInfo, first_paragraph_len: usize, } @@ -900,11 +991,22 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"]; +#[derive(Clone)] enum Container { Blockquote, List(usize), } +impl Container { + fn map_to_text(&self) -> &'static str { + match self { + Container::Blockquote => "> ", + // numbered list can have up to nine digits, plus the dot, plus four spaces on either side + Container::List(indent) => &" "[0..*indent], + } + } +} + /// Scan the documentation for code links that are back-to-back with code spans. /// /// This is done separately from the rest of the docs, because that makes it easier to produce @@ -1011,6 +1113,51 @@ fn check_doc<'a, Events: Iterator, Range { blockquote_level += 1; @@ -1197,12 +1344,28 @@ fn check_doc<'a, Events: Iterator, Range +/// +/// # Panics +/// +/// Here's where some panic docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +/// +pub fn panicking1() { + //~^ missing_panics_doc + panic!(); +} + +/// >
+/// > +/// > # Panics +/// > +/// > Here's where some panic docs are supposed to appear, +/// > but don't, because of the div. +/// > +/// > Make sure that the generated suggestion puts a blank +/// > line between the header and the HTML. +/// > +/// >
+pub fn panicking1blockquote() { + //~^ missing_panics_doc + panic!(); +} + +#[rustfmt::skip] +/// > -
+/// > +/// > # Panics +/// > +/// > Here's where some panic docs are supposed to appear, +/// > but don't, because of the div. +// > +/// >
+/// > +/// > - Make sure that the generated suggestion puts a blank +/// > line between the header and the HTML. +pub fn panicking1blockquotelist() { + //~^ missing_panics_doc + panic!(); +} + +///
+/// +/// # Safety # +/// +/// Here's where some safety docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub unsafe fn safety1() { + //~^ missing_safety_doc +} + +///
+/// +/// # Errors ## +/// +/// Here's where some error docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub fn errors1() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +///
+/// # Panics +/// +/// # Panics +/// Here's one where the panic docs actually exist. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn panicking2() { + panic!(); +} + +///
+/// # Safety +/// +/// # Safety +/// Here's one where the safety docs actually exist. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub unsafe fn safety2() {} + +///
+/// # Errors +/// +/// # Errors +/// Here's one where the error docs actually exist. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn errors2() -> Result<(), Error> { + Ok(()) +} + +///
+/// # Panics +/// +/// Here's one where no panic docs should appear at all. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn no_panicking1() {} + +///
+/// # Safety # +/// +/// Here's one where no safety docs should appear at all. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn no_safety1() {} + +///
+/// # Errors ## +/// +/// Here's one where no error docs should appear at all. +/// Make sure there's no warning, and no suggestion. +// +///
+pub fn no_errors1() {} + +///
+/// +/// Panics +/// == +/// +/// Here's where some panic docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub fn panicking1b() { + //~^ missing_panics_doc + panic!(); +} + +///
+/// +/// Safety +/// === +/// +/// Here's where some safety docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub unsafe fn safety1b() { + //~^ missing_safety_doc +} + +///
+/// +/// Errors +/// ==== +/// +/// Here's where some error docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub fn errors1b() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +///
+/// Panics +/// == +/// +/// Panics +/// == +/// Here's one where the panic docs actually exist. +/// Make sure there's no warnings or anything. +/// +///
+pub fn panicking2b() { + panic!(); +} + +///
+/// Safety +/// == +/// +/// Safety +/// == +/// Here's one where the safety docs actually exist. +/// +///
+pub unsafe fn safety2b() {} + +///
+/// Panics +/// == +/// +/// Here's one where no panic docs should appear at all. +/// Make sure there's no warnings or suggestions. +/// +///
+pub fn no_panicking1b() {} + +///
+/// Safety +/// == +/// +/// Here's one where no safety docs should appear at all. +/// Make sure there's no warnings or suggestions. +/// +///
+pub fn no_safety1b() {} + +///
+/// # Safety +/// +/// # Safety +/// +/// Here's one where no safety docs should not appear, +/// but do. Make sure there's no spurrious suggestions +/// to add a blank line between the div and the +/// suspicious header. +/// +///
+pub fn spurrious_safety1() {} + +///
+/// Safety +/// == +/// +/// Safety +/// == +/// +/// Here's one where no safety docs should not appear, +/// but do. Make sure there's no spurrious suggestions +/// to add a blank line between the div and the +/// suspicious header. +/// +///
+pub fn spurrious_safety1b() {} + +// == block == + +/** +
+ + ## Panics + + Here's where some panic docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn panicking3() { + //~^ missing_panics_doc + panic!(); +} + +#[rustfmt::skip] +/** + -
+ + ## Panics + + Here's where some panic docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn panicking3list() { + //~^ missing_panics_doc + panic!(); +} + +#[rustfmt::skip] +/** + - >
+ > + > ## Panics + > + > Here's where some panic docs are supposed to appear, + > but don't, because of the div. + > + > Make sure that the generated suggestion puts a blank + > line between the header and the HTML. + > + >
+*/ +pub fn panicking3listblockquote() { + //~^ missing_panics_doc + panic!(); +} + +/** +
+ + ## Safety # + + Here's where some safety docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub unsafe fn safety3() { + //~^ missing_safety_doc +} + +/** +
+ + ## Errors ## + + Here's where some error docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn errors3() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +/** +
+ ## Panics + + ## Panics + Here's one where the panic docs actually exist. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn panicking4() { + panic!(); +} + +/** +
+ ## Safety + + ## Safety + Here's one where the safety docs actually exist. + Make sure there's no warning, and no suggestion. + +
+*/ +pub unsafe fn safety4() {} + +/** +
+ ## Errors + + ## Errors + Here's one where the error docs actually exist. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn errors4() -> Result<(), Error> { + Ok(()) +} + +/** +
+ ## Panics + + Here's one where no panic docs should appear at all. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn no_panicking2() {} + +/** +
+ ## Safety + + Here's one where no safety docs should appear at all. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn no_safety2() {} + +/** +
+ ## Errors + + Here's one where no error docs should appear at all. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn no_errors2() {} + +/** +
+ + Panics + -- + + Here's where some panic docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn panicking3b() { + //~^ missing_panics_doc + panic!(); +} + +/** +
+ + Safety + --- + + Here's where some safety docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub unsafe fn safety3b() { + //~^ missing_safety_doc +} + +/** +
+ + Errors + ---- + + Here's where some error docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn errors3b() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +/** +
+ Panics + -- + + Panics + -- + Here's one where the panic docs actually exist. + Make sure there's no warnings or anything. + +
+*/ +pub fn panicking4b() { + panic!(); +} + +/** +
+ Safety + -- + + Safety + -- + Here's one where the safety docs actually exist. + +
+*/ +pub unsafe fn safety4b() {} + +/** +
+ Panics + -- + + Here's one where no panic docs should appear at all. + Make sure there's no warnings or suggestions. + +
+*/ +pub fn no_panicking3b() {} + +/** +
+ Safety + -- + + Here's one where no safety docs should appear at all. + Make sure there's no warnings or suggestions. + +
+*/ +pub fn no_safety3b() {} + +/** +
+ ## Safety + + ## Safety + + Here's one where no safety docs should not appear, + but do. Make sure there's no spurrious suggestions + to add a blank line between the div and the + suspicious header. + +
+*/ +pub fn spurrious_safety3() {} + +/** +
+ Safety + -- + + Safety + -- + + Here's one where no safety docs should not appear, + but do. Make sure there's no spurrious suggestions + to add a blank line between the div and the + suspicious header. + +
+*/ +pub fn spurrious_safety3b() {} diff --git a/tests/ui/doc/doc_header_html.rs b/tests/ui/doc/doc_header_html.rs new file mode 100644 index 000000000000..1de2eb272040 --- /dev/null +++ b/tests/ui/doc/doc_header_html.rs @@ -0,0 +1,559 @@ +// https://github.com/rust-lang/rust-clippy/issues/15353 +#![warn(clippy::missing_panics_doc, clippy::missing_safety_doc, clippy::missing_errors_doc)] + +pub struct Error; + +///
+/// # Panics +/// +/// Here's where some panic docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub fn panicking1() { + //~^ missing_panics_doc + panic!(); +} + +/// >
+/// > # Panics +/// > +/// > Here's where some panic docs are supposed to appear, +/// > but don't, because of the div. +/// > +/// > Make sure that the generated suggestion puts a blank +/// > line between the header and the HTML. +/// > +/// >
+pub fn panicking1blockquote() { + //~^ missing_panics_doc + panic!(); +} + +#[rustfmt::skip] +/// > -
+/// > # Panics +/// > +/// > Here's where some panic docs are supposed to appear, +/// > but don't, because of the div. +// > +/// >
+/// > +/// > - Make sure that the generated suggestion puts a blank +/// > line between the header and the HTML. +pub fn panicking1blockquotelist() { + //~^ missing_panics_doc + panic!(); +} + +///
+/// # Safety # +/// +/// Here's where some safety docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub unsafe fn safety1() { + //~^ missing_safety_doc +} + +///
+/// # Errors ## +/// +/// Here's where some error docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub fn errors1() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +///
+/// # Panics +/// +/// # Panics +/// Here's one where the panic docs actually exist. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn panicking2() { + panic!(); +} + +///
+/// # Safety +/// +/// # Safety +/// Here's one where the safety docs actually exist. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub unsafe fn safety2() {} + +///
+/// # Errors +/// +/// # Errors +/// Here's one where the error docs actually exist. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn errors2() -> Result<(), Error> { + Ok(()) +} + +///
+/// # Panics +/// +/// Here's one where no panic docs should appear at all. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn no_panicking1() {} + +///
+/// # Safety # +/// +/// Here's one where no safety docs should appear at all. +/// Make sure there's no warning, and no suggestion. +/// +///
+pub fn no_safety1() {} + +///
+/// # Errors ## +/// +/// Here's one where no error docs should appear at all. +/// Make sure there's no warning, and no suggestion. +// +///
+pub fn no_errors1() {} + +///
+/// Panics +/// == +/// +/// Here's where some panic docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub fn panicking1b() { + //~^ missing_panics_doc + panic!(); +} + +///
+/// Safety +/// === +/// +/// Here's where some safety docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub unsafe fn safety1b() { + //~^ missing_safety_doc +} + +///
+/// Errors +/// ==== +/// +/// Here's where some error docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure that the generated suggestion puts a blank +/// line between the header and the HTML. +/// +///
+pub fn errors1b() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +///
+/// Panics +/// == +/// +/// Panics +/// == +/// Here's one where the panic docs actually exist. +/// Make sure there's no warnings or anything. +/// +///
+pub fn panicking2b() { + panic!(); +} + +///
+/// Safety +/// == +/// +/// Safety +/// == +/// Here's one where the safety docs actually exist. +/// +///
+pub unsafe fn safety2b() {} + +///
+/// Panics +/// == +/// +/// Here's one where no panic docs should appear at all. +/// Make sure there's no warnings or suggestions. +/// +///
+pub fn no_panicking1b() {} + +///
+/// Safety +/// == +/// +/// Here's one where no safety docs should appear at all. +/// Make sure there's no warnings or suggestions. +/// +///
+pub fn no_safety1b() {} + +///
+/// # Safety +/// +/// # Safety +/// +/// Here's one where no safety docs should not appear, +/// but do. Make sure there's no spurrious suggestions +/// to add a blank line between the div and the +/// suspicious header. +/// +///
+pub fn spurrious_safety1() {} + +///
+/// Safety +/// == +/// +/// Safety +/// == +/// +/// Here's one where no safety docs should not appear, +/// but do. Make sure there's no spurrious suggestions +/// to add a blank line between the div and the +/// suspicious header. +/// +///
+pub fn spurrious_safety1b() {} + +// == block == + +/** +
+ ## Panics + + Here's where some panic docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn panicking3() { + //~^ missing_panics_doc + panic!(); +} + +#[rustfmt::skip] +/** + -
+ ## Panics + + Here's where some panic docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn panicking3list() { + //~^ missing_panics_doc + panic!(); +} + +#[rustfmt::skip] +/** + - >
+ > ## Panics + > + > Here's where some panic docs are supposed to appear, + > but don't, because of the div. + > + > Make sure that the generated suggestion puts a blank + > line between the header and the HTML. + > + >
+*/ +pub fn panicking3listblockquote() { + //~^ missing_panics_doc + panic!(); +} + +/** +
+ ## Safety # + + Here's where some safety docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub unsafe fn safety3() { + //~^ missing_safety_doc +} + +/** +
+ ## Errors ## + + Here's where some error docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn errors3() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +/** +
+ ## Panics + + ## Panics + Here's one where the panic docs actually exist. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn panicking4() { + panic!(); +} + +/** +
+ ## Safety + + ## Safety + Here's one where the safety docs actually exist. + Make sure there's no warning, and no suggestion. + +
+*/ +pub unsafe fn safety4() {} + +/** +
+ ## Errors + + ## Errors + Here's one where the error docs actually exist. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn errors4() -> Result<(), Error> { + Ok(()) +} + +/** +
+ ## Panics + + Here's one where no panic docs should appear at all. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn no_panicking2() {} + +/** +
+ ## Safety + + Here's one where no safety docs should appear at all. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn no_safety2() {} + +/** +
+ ## Errors + + Here's one where no error docs should appear at all. + Make sure there's no warning, and no suggestion. + +
+*/ +pub fn no_errors2() {} + +/** +
+ Panics + -- + + Here's where some panic docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn panicking3b() { + //~^ missing_panics_doc + panic!(); +} + +/** +
+ Safety + --- + + Here's where some safety docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub unsafe fn safety3b() { + //~^ missing_safety_doc +} + +/** +
+ Errors + ---- + + Here's where some error docs are supposed to appear, + but don't, because of the div. + + Make sure that the generated suggestion puts a blank + line between the header and the HTML. + +
+*/ +pub fn errors3b() -> Result<(), Error> { + //~^ missing_errors_doc + Ok(()) +} + +/** +
+ Panics + -- + + Panics + -- + Here's one where the panic docs actually exist. + Make sure there's no warnings or anything. + +
+*/ +pub fn panicking4b() { + panic!(); +} + +/** +
+ Safety + -- + + Safety + -- + Here's one where the safety docs actually exist. + +
+*/ +pub unsafe fn safety4b() {} + +/** +
+ Panics + -- + + Here's one where no panic docs should appear at all. + Make sure there's no warnings or suggestions. + +
+*/ +pub fn no_panicking3b() {} + +/** +
+ Safety + -- + + Here's one where no safety docs should appear at all. + Make sure there's no warnings or suggestions. + +
+*/ +pub fn no_safety3b() {} + +/** +
+ ## Safety + + ## Safety + + Here's one where no safety docs should not appear, + but do. Make sure there's no spurrious suggestions + to add a blank line between the div and the + suspicious header. + +
+*/ +pub fn spurrious_safety3() {} + +/** +
+ Safety + -- + + Safety + -- + + Here's one where no safety docs should not appear, + but do. Make sure there's no spurrious suggestions + to add a blank line between the div and the + suspicious header. + +
+*/ +pub fn spurrious_safety3b() {} diff --git a/tests/ui/doc/doc_header_html.stderr b/tests/ui/doc/doc_header_html.stderr new file mode 100644 index 000000000000..7f1a044acb2b --- /dev/null +++ b/tests/ui/doc/doc_header_html.stderr @@ -0,0 +1,256 @@ +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:16:1 + | +LL | pub fn panicking1() { + | ^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:18:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code + = note: `-D clippy::missing-panics-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_panics_doc)]` +help: to recognize this text as a header, add a blank line + | +LL ~ /// +LL ~ /// # Panics + | + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:31:1 + | +LL | pub fn panicking1blockquote() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:33:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ /// > +LL ~ /// > # Panics + | + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:47:1 + | +LL | pub fn panicking1blockquotelist() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:49:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ /// > +LL ~ /// > # Panics + | + +error: unsafe function's docs are missing a `# Safety` section + --> tests/ui/doc/doc_header_html.rs:62:1 + | +LL | pub unsafe fn safety1() { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code + = note: `-D clippy::missing-safety-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_safety_doc)]` +help: to recognize this text as a header, add a blank line + | +LL ~ /// +LL ~ /// # Safety # + | + +error: docs for function returning `Result` missing `# Errors` section + --> tests/ui/doc/doc_header_html.rs:76:1 + | +LL | pub fn errors1() -> Result<(), Error> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code + = note: `-D clippy::missing-errors-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_errors_doc)]` +help: to recognize this text as a header, add a blank line + | +LL ~ /// +LL ~ /// # Errors ## + | + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:153:1 + | +LL | pub fn panicking1b() { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:155:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ /// +LL ~ /// Panics + | + +error: unsafe function's docs are missing a `# Safety` section + --> tests/ui/doc/doc_header_html.rs:169:1 + | +LL | pub unsafe fn safety1b() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ /// +LL ~ /// Safety + | + +error: docs for function returning `Result` missing `# Errors` section + --> tests/ui/doc/doc_header_html.rs:184:1 + | +LL | pub fn errors1b() -> Result<(), Error> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ /// +LL ~ /// Errors + | + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:276:1 + | +LL | pub fn panicking3() { + | ^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:278:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ +LL ~ ## Panics + | + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:294:1 + | +LL | pub fn panicking3list() { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:296:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ +LL ~ ## Panics + | + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:312:1 + | +LL | pub fn panicking3listblockquote() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:314:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ > +LL ~ > ## Panics + | + +error: unsafe function's docs are missing a `# Safety` section + --> tests/ui/doc/doc_header_html.rs:329:1 + | +LL | pub unsafe fn safety3() { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ +LL ~ ## Safety # + | + +error: docs for function returning `Result` missing `# Errors` section + --> tests/ui/doc/doc_header_html.rs:345:1 + | +LL | pub fn errors3() -> Result<(), Error> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ +LL ~ ## Errors ## + | + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html.rs:436:1 + | +LL | pub fn panicking3b() { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html.rs:438:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ +LL ~ Panics + | + +error: unsafe function's docs are missing a `# Safety` section + --> tests/ui/doc/doc_header_html.rs:454:1 + | +LL | pub unsafe fn safety3b() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ +LL ~ Safety + | + +error: docs for function returning `Result` missing `# Errors` section + --> tests/ui/doc/doc_header_html.rs:471:1 + | +LL | pub fn errors3b() -> Result<(), Error> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: markdown syntax is not recognized within a block of raw HTML code +help: to recognize this text as a header, add a blank line + | +LL ~ +LL ~ Errors + | + +error: aborting due to 16 previous errors + diff --git a/tests/ui/doc/doc_header_html_unformed.rs b/tests/ui/doc/doc_header_html_unformed.rs new file mode 100644 index 000000000000..3551236876be --- /dev/null +++ b/tests/ui/doc/doc_header_html_unformed.rs @@ -0,0 +1,36 @@ +//@ no-rustfix +// https://github.com/rust-lang/rust-clippy/issues/15353 +#![warn(clippy::missing_panics_doc, clippy::missing_safety_doc, clippy::missing_errors_doc)] + +pub struct Error; + +///
+/// # Panics # not header +/// +/// Here's where some panic docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure this thing isn't mistakened for a header, +/// since that won't work. +/// +///
+pub fn panicking1() { + //~^ missing_panics_doc + panic!(); +} + +///
+/// Panics +/// ===---- +/// +/// Here's where some panic docs are supposed to appear, +/// but don't, because of the div. +/// +/// Make sure this thing isn't mistakened for a header, +/// since that won't work. +/// +///
+pub fn panicking2() { + //~^ missing_panics_doc + panic!(); +} diff --git a/tests/ui/doc/doc_header_html_unformed.stderr b/tests/ui/doc/doc_header_html_unformed.stderr new file mode 100644 index 000000000000..bdce1e87f6d4 --- /dev/null +++ b/tests/ui/doc/doc_header_html_unformed.stderr @@ -0,0 +1,28 @@ +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html_unformed.rs:17:1 + | +LL | pub fn panicking1() { + | ^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html_unformed.rs:19:5 + | +LL | panic!(); + | ^^^^^^^^ + = note: `-D clippy::missing-panics-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_panics_doc)]` + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/doc/doc_header_html_unformed.rs:33:1 + | +LL | pub fn panicking2() { + | ^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/doc/doc_header_html_unformed.rs:35:5 + | +LL | panic!(); + | ^^^^^^^^ + +error: aborting due to 2 previous errors +