rustdoc/passes/
lint.rs

1//! Runs several rustdoc lints, consolidating them into a single pass for
2//! efficiency and simplicity.
3
4mod bare_urls;
5mod check_code_block_syntax;
6mod html_tags;
7mod redundant_explicit_links;
8mod unescaped_backticks;
9
10use super::Pass;
11use crate::clean::*;
12use crate::core::DocContext;
13use crate::visit::DocVisitor;
14
15pub(crate) const RUN_LINTS: Pass =
16    Pass { name: "run-lints", run: Some(run_lints), description: "runs some of rustdoc's lints" };
17
18struct Linter<'a, 'tcx> {
19    cx: &'a mut DocContext<'tcx>,
20}
21
22pub(crate) fn run_lints(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
23    Linter { cx }.visit_crate(&krate);
24    krate
25}
26
27impl DocVisitor<'_> for Linter<'_, '_> {
28    fn visit_item(&mut self, item: &Item) {
29        let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.item_id) else {
30            // If non-local, no need to check anything.
31            return;
32        };
33        let dox = item.doc_value();
34        if !dox.is_empty() {
35            let may_have_link = dox.contains(&[':', '['][..]);
36            let may_have_block_comment_or_html = dox.contains(['<', '>']);
37            // ~~~rust
38            // // This is a real, supported commonmark syntax for block code
39            // ~~~
40            let may_have_code = dox.contains(&['~', '`', '\t'][..]) || dox.contains("    ");
41            if may_have_link {
42                bare_urls::visit_item(self.cx, item, hir_id, &dox);
43                redundant_explicit_links::visit_item(self.cx, item, hir_id);
44            }
45            if may_have_code {
46                check_code_block_syntax::visit_item(self.cx, item, &dox);
47                unescaped_backticks::visit_item(self.cx, item, hir_id, &dox);
48            }
49            if may_have_block_comment_or_html {
50                html_tags::visit_item(self.cx, item, hir_id, &dox);
51            }
52        }
53
54        self.visit_item_recur(item)
55    }
56}