Skip to content

Commit 0d84f00

Browse files
committed
Auto merge of rust-lang#12635 - Alexendoo:doc-check-attributes, r=Jarcho
Use `check_attributes` in doc lints Ensures we catch all the places that doc comments could occur, found one that we were currently missing - docs on `extern` items changelog: none
2 parents 6b1c828 + d4a8f61 commit 0d84f00

File tree

5 files changed

+84
-90
lines changed

5 files changed

+84
-90
lines changed

clippy_lints/src/doc/missing_headers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_D
1111
pub fn check(
1212
cx: &LateContext<'_>,
1313
owner_id: OwnerId,
14-
sig: &FnSig<'_>,
14+
sig: FnSig<'_>,
1515
headers: DocHeaders,
1616
body_id: Option<BodyId>,
1717
panic_span: Option<Span>,

clippy_lints/src/doc/mod.rs

Lines changed: 61 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
33
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
44
use clippy_utils::ty::is_type_diagnostic_item;
55
use clippy_utils::visitors::Visitable;
6-
use clippy_utils::{is_entrypoint_fn, method_chain_args};
6+
use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args};
77
use pulldown_cmark::Event::{
88
Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
99
};
1010
use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph};
1111
use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
1212
use rustc_ast::ast::Attribute;
1313
use rustc_data_structures::fx::FxHashSet;
14-
use rustc_hir as hir;
1514
use rustc_hir::intravisit::{self, Visitor};
16-
use rustc_hir::{AnonConst, Expr};
15+
use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, TraitItemKind, Unsafety};
1716
use rustc_lint::{LateContext, LateLintPass, LintContext};
1817
use rustc_middle::hir::nested_filter;
1918
use rustc_middle::lint::in_external_macro;
@@ -366,15 +365,13 @@ declare_clippy_lint! {
366365
#[derive(Clone)]
367366
pub struct Documentation {
368367
valid_idents: FxHashSet<String>,
369-
in_trait_impl: bool,
370368
check_private_items: bool,
371369
}
372370

373371
impl Documentation {
374372
pub fn new(valid_idents: &[String], check_private_items: bool) -> Self {
375373
Self {
376374
valid_idents: valid_idents.iter().cloned().collect(),
377-
in_trait_impl: false,
378375
check_private_items,
379376
}
380377
}
@@ -394,36 +391,72 @@ impl_lint_pass!(Documentation => [
394391
]);
395392

396393
impl<'tcx> LateLintPass<'tcx> for Documentation {
397-
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
398-
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
399-
check_attrs(cx, &self.valid_idents, attrs);
400-
}
401-
402-
fn check_variant(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::Variant<'tcx>) {
403-
let attrs = cx.tcx.hir().attrs(variant.hir_id);
404-
check_attrs(cx, &self.valid_idents, attrs);
405-
}
406-
407-
fn check_field_def(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::FieldDef<'tcx>) {
408-
let attrs = cx.tcx.hir().attrs(variant.hir_id);
409-
check_attrs(cx, &self.valid_idents, attrs);
410-
}
411-
412-
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
413-
let attrs = cx.tcx.hir().attrs(item.hir_id());
394+
fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
414395
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
415396
return;
416397
};
417398

418-
match item.kind {
419-
hir::ItemKind::Fn(ref sig, _, body_id) => {
420-
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
399+
match cx.tcx.hir_node(cx.last_node_with_lint_attrs) {
400+
Node::Item(item) => match item.kind {
401+
ItemKind::Fn(sig, _, body_id) => {
402+
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
403+
let body = cx.tcx.hir().body(body_id);
404+
405+
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
406+
missing_headers::check(
407+
cx,
408+
item.owner_id,
409+
sig,
410+
headers,
411+
Some(body_id),
412+
panic_span,
413+
self.check_private_items,
414+
);
415+
}
416+
},
417+
ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
418+
(false, Unsafety::Unsafe) => span_lint(
419+
cx,
420+
MISSING_SAFETY_DOC,
421+
cx.tcx.def_span(item.owner_id),
422+
"docs for unsafe trait missing `# Safety` section",
423+
),
424+
(true, Unsafety::Normal) => span_lint(
425+
cx,
426+
UNNECESSARY_SAFETY_DOC,
427+
cx.tcx.def_span(item.owner_id),
428+
"docs for safe trait have unnecessary `# Safety` section",
429+
),
430+
_ => (),
431+
},
432+
_ => (),
433+
},
434+
Node::TraitItem(trait_item) => {
435+
if let TraitItemKind::Fn(sig, ..) = trait_item.kind
436+
&& !in_external_macro(cx.tcx.sess, trait_item.span)
437+
{
438+
missing_headers::check(
439+
cx,
440+
trait_item.owner_id,
441+
sig,
442+
headers,
443+
None,
444+
None,
445+
self.check_private_items,
446+
);
447+
}
448+
},
449+
Node::ImplItem(impl_item) => {
450+
if let ImplItemKind::Fn(sig, body_id) = impl_item.kind
451+
&& !in_external_macro(cx.tcx.sess, impl_item.span)
452+
&& !is_trait_impl_item(cx, impl_item.hir_id())
453+
{
421454
let body = cx.tcx.hir().body(body_id);
422455

423-
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
456+
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value);
424457
missing_headers::check(
425458
cx,
426-
item.owner_id,
459+
impl_item.owner_id,
427460
sig,
428461
headers,
429462
Some(body_id),
@@ -432,67 +465,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
432465
);
433466
}
434467
},
435-
hir::ItemKind::Impl(impl_) => {
436-
self.in_trait_impl = impl_.of_trait.is_some();
437-
},
438-
hir::ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
439-
(false, hir::Unsafety::Unsafe) => span_lint(
440-
cx,
441-
MISSING_SAFETY_DOC,
442-
cx.tcx.def_span(item.owner_id),
443-
"docs for unsafe trait missing `# Safety` section",
444-
),
445-
(true, hir::Unsafety::Normal) => span_lint(
446-
cx,
447-
UNNECESSARY_SAFETY_DOC,
448-
cx.tcx.def_span(item.owner_id),
449-
"docs for safe trait have unnecessary `# Safety` section",
450-
),
451-
_ => (),
452-
},
453-
_ => (),
454-
}
455-
}
456-
457-
fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
458-
if let hir::ItemKind::Impl { .. } = item.kind {
459-
self.in_trait_impl = false;
460-
}
461-
}
462-
463-
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
464-
let attrs = cx.tcx.hir().attrs(item.hir_id());
465-
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
466-
return;
467-
};
468-
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
469-
if !in_external_macro(cx.tcx.sess, item.span) {
470-
missing_headers::check(cx, item.owner_id, sig, headers, None, None, self.check_private_items);
471-
}
472-
}
473-
}
474-
475-
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
476-
let attrs = cx.tcx.hir().attrs(item.hir_id());
477-
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
478-
return;
479-
};
480-
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
481-
return;
482-
}
483-
if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind {
484-
let body = cx.tcx.hir().body(body_id);
485-
486-
let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
487-
missing_headers::check(
488-
cx,
489-
item.owner_id,
490-
sig,
491-
headers,
492-
Some(body_id),
493-
panic_span,
494-
self.check_private_items,
495-
);
468+
_ => {},
496469
}
497470
}
498471
}

tests/ui/doc/doc-fixable.fixed

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,8 @@ fn parenthesized_word() {}
235235
/// OSes
236236
/// UXes
237237
fn plural_acronym_test() {}
238+
239+
extern {
240+
/// `foo()`
241+
fn in_extern();
242+
}

tests/ui/doc/doc-fixable.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,8 @@ fn parenthesized_word() {}
235235
/// OSes
236236
/// UXes
237237
fn plural_acronym_test() {}
238+
239+
extern {
240+
/// foo()
241+
fn in_extern();
242+
}

tests/ui/doc/doc-fixable.stderr

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,5 +352,16 @@ help: try
352352
LL | /// `ABes`
353353
| ~~~~~~
354354

355-
error: aborting due to 32 previous errors
355+
error: item in documentation is missing backticks
356+
--> tests/ui/doc/doc-fixable.rs:240:9
357+
|
358+
LL | /// foo()
359+
| ^^^^^
360+
|
361+
help: try
362+
|
363+
LL | /// `foo()`
364+
| ~~~~~~~
365+
366+
error: aborting due to 33 previous errors
356367

0 commit comments

Comments
 (0)