1 //! Looks for items missing (or incorrectly having) doctests.
3 //! This pass is overloaded and runs two different lints.
5 //! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doctests.
6 //! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests.
11 use crate::core
::DocContext
;
12 use crate::html
::markdown
::{find_testable_code, ErrorCodes, Ignore, LangString}
;
13 use crate::visit
::DocVisitor
;
14 use crate::visit_ast
::inherits_doc_hidden
;
16 use rustc_middle
::lint
::LintLevelSource
;
17 use rustc_middle
::ty
::DefIdTree
;
18 use rustc_session
::lint
;
20 pub(crate) const CHECK_DOC_TEST_VISIBILITY
: Pass
= Pass
{
21 name
: "check_doc_test_visibility",
22 run
: check_doc_test_visibility
,
23 description
: "run various visibility-related lints on doctests",
26 struct DocTestVisibilityLinter
<'a
, 'tcx
> {
27 cx
: &'a
mut DocContext
<'tcx
>,
30 pub(crate) fn check_doc_test_visibility(krate
: Crate
, cx
: &mut DocContext
<'_
>) -> Crate
{
31 let mut coll
= DocTestVisibilityLinter { cx }
;
32 coll
.visit_crate(&krate
);
36 impl<'a
, 'tcx
> DocVisitor
for DocTestVisibilityLinter
<'a
, 'tcx
> {
37 fn visit_item(&mut self, item
: &Item
) {
38 let dox
= item
.attrs
.collapsed_doc_value().unwrap_or_default();
40 look_for_tests(self.cx
, &dox
, item
);
42 self.visit_item_recur(item
)
46 pub(crate) struct Tests
{
47 pub(crate) found_tests
: usize,
50 impl crate::doctest
::Tester
for Tests
{
51 fn add_test(&mut self, _
: String
, config
: LangString
, _
: usize) {
52 if config
.rust
&& config
.ignore
== Ignore
::None
{
53 self.found_tests
+= 1;
58 pub(crate) fn should_have_doc_example(cx
: &DocContext
<'_
>, item
: &clean
::Item
) -> bool
{
59 if !cx
.cache
.effective_visibilities
.is_directly_public(cx
.tcx
, item
.item_id
.expect_def_id())
62 clean
::StructFieldItem(_
)
63 | clean
::VariantItem(_
)
64 | clean
::AssocConstItem(..)
65 | clean
::AssocTypeItem(..)
66 | clean
::TypedefItem(_
)
67 | clean
::StaticItem(_
)
68 | clean
::ConstantItem(_
)
69 | clean
::ExternCrateItem { .. }
70 | clean
::ImportItem(_
)
71 | clean
::PrimitiveItem(_
)
73 // check for trait impl
74 | clean
::ImplItem(box clean
::Impl { trait_: Some(_), .. }
)
80 // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
81 // would presumably panic if a fake `DefIndex` were passed.
82 let def_id
= item
.item_id
.expect_def_id().expect_local();
84 // check if parent is trait impl
85 if let Some(parent_def_id
) = cx
.tcx
.opt_local_parent(def_id
) &&
86 let Some(parent_node
) = cx
.tcx
.hir().find_by_def_id(parent_def_id
) &&
89 hir
::Node
::Item(hir
::Item
{
90 kind
: hir
::ItemKind
::Impl(hir
::Impl { of_trait: Some(_), .. }
),
98 if cx
.tcx
.is_doc_hidden(def_id
.to_def_id())
99 || inherits_doc_hidden(cx
.tcx
, def_id
)
100 || cx
.tcx
.def_span(def_id
.to_def_id()).in_derive_expansion()
104 let (level
, source
) = cx
.tcx
.lint_level_at_node(
105 crate::lint
::MISSING_DOC_CODE_EXAMPLES
,
106 cx
.tcx
.hir().local_def_id_to_hir_id(def_id
),
108 level
!= lint
::Level
::Allow
|| matches
!(source
, LintLevelSource
::Default
)
111 pub(crate) fn look_for_tests
<'tcx
>(cx
: &DocContext
<'tcx
>, dox
: &str, item
: &Item
) {
112 let Some(hir_id
) = DocContext
::as_local_hir_id(cx
.tcx
, item
.item_id
)
114 // If non-local, no need to check anything.
118 let mut tests
= Tests { found_tests: 0 }
;
120 find_testable_code(dox
, &mut tests
, ErrorCodes
::No
, false, None
);
122 if tests
.found_tests
== 0 && cx
.tcx
.features().rustdoc_missing_doc_code_examples
{
123 if should_have_doc_example(cx
, item
) {
124 debug
!("reporting error for {:?} (hir_id={:?})", item
, hir_id
);
125 let sp
= item
.attr_span(cx
.tcx
);
126 cx
.tcx
.struct_span_lint_hir(
127 crate::lint
::MISSING_DOC_CODE_EXAMPLES
,
130 "missing code example in this documentation",
134 } else if tests
.found_tests
> 0
135 && !cx
.cache
.effective_visibilities
.is_exported(cx
.tcx
, item
.item_id
.expect_def_id())
137 cx
.tcx
.struct_span_lint_hir(
138 crate::lint
::PRIVATE_DOC_TESTS
,
140 item
.attr_span(cx
.tcx
),
141 "documentation test in private item",