]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/passes/doc_test_lints.rs
Fix font color for help button in ayu and dark themes
[rust.git] / src / librustdoc / passes / doc_test_lints.rs
1 //! This pass is overloaded and runs two different lints.
2 //!
3 //! - MISSING_DOC_CODE_EXAMPLES: this looks for public items missing doc-tests
4 //! - PRIVATE_DOC_TESTS: this looks for private items with doc-tests.
5
6 use super::{span_of_attrs, Pass};
7 use crate::clean::*;
8 use crate::core::DocContext;
9 use crate::fold::DocFolder;
10 use crate::html::markdown::{find_testable_code, ErrorCodes, LangString};
11 use rustc_session::lint;
12
13 pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
14     name: "check-private-items-doc-tests",
15     run: check_private_items_doc_tests,
16     description: "check private items doc tests",
17 };
18
19 struct PrivateItemDocTestLinter<'a, 'tcx> {
20     cx: &'a DocContext<'tcx>,
21 }
22
23 impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> {
24     fn new(cx: &'a DocContext<'tcx>) -> Self {
25         PrivateItemDocTestLinter { cx }
26     }
27 }
28
29 pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate {
30     let mut coll = PrivateItemDocTestLinter::new(cx);
31
32     coll.fold_crate(krate)
33 }
34
35 impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
36     fn fold_item(&mut self, item: Item) -> Option<Item> {
37         let cx = self.cx;
38         let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
39
40         look_for_tests(&cx, &dox, &item);
41
42         self.fold_item_recur(item)
43     }
44 }
45
46 pub(crate) struct Tests {
47     pub(crate) found_tests: usize,
48 }
49
50 impl Tests {
51     pub(crate) fn new() -> Tests {
52         Tests { found_tests: 0 }
53     }
54 }
55
56 impl crate::test::Tester for Tests {
57     fn add_test(&mut self, _: String, _: LangString, _: usize) {
58         self.found_tests += 1;
59     }
60 }
61
62 pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
63     let hir_id = match cx.as_local_hir_id(item.def_id) {
64         Some(hir_id) => hir_id,
65         None => {
66             // If non-local, no need to check anything.
67             return;
68         }
69     };
70
71     let mut tests = Tests::new();
72
73     find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
74
75     if tests.found_tests == 0 {
76         use ItemEnum::*;
77
78         let should_report = match item.inner {
79             ExternCrateItem(_, _) | ImportItem(_) | PrimitiveItem(_) | KeywordItem(_) => false,
80             _ => true,
81         };
82         if should_report {
83             debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
84             let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
85             cx.tcx.struct_span_lint_hir(
86                 lint::builtin::MISSING_DOC_CODE_EXAMPLES,
87                 hir_id,
88                 sp,
89                 |lint| lint.build("missing code example in this documentation").emit(),
90             );
91         }
92     } else if rustc_feature::UnstableFeatures::from_environment().is_nightly_build()
93         && tests.found_tests > 0
94         && !cx.renderinfo.borrow().access_levels.is_public(item.def_id)
95     {
96         cx.tcx.struct_span_lint_hir(
97             lint::builtin::PRIVATE_DOC_TESTS,
98             hir_id,
99             span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
100             |lint| lint.build("documentation test in private item").emit(),
101         );
102     }
103 }