1 //! Contains information about "passes", used to modify crate information during the documentation
4 use rustc_middle
::ty
::TyCtxt
;
5 use rustc_span
::{InnerSpan, Span, DUMMY_SP}
;
8 use self::Condition
::*;
9 use crate::clean
::{self, DocFragmentKind}
;
10 use crate::core
::DocContext
;
13 pub(crate) use stripper
::*;
16 pub(crate) use self::bare_urls
::CHECK_BARE_URLS
;
19 pub(crate) use self::strip_hidden
::STRIP_HIDDEN
;
22 pub(crate) use self::strip_private
::STRIP_PRIVATE
;
24 mod strip_priv_imports
;
25 pub(crate) use self::strip_priv_imports
::STRIP_PRIV_IMPORTS
;
27 mod propagate_doc_cfg
;
28 pub(crate) use self::propagate_doc_cfg
::PROPAGATE_DOC_CFG
;
30 pub(crate) mod collect_intra_doc_links
;
31 pub(crate) use self::collect_intra_doc_links
::COLLECT_INTRA_DOC_LINKS
;
33 mod check_doc_test_visibility
;
34 pub(crate) use self::check_doc_test_visibility
::CHECK_DOC_TEST_VISIBILITY
;
36 mod collect_trait_impls
;
37 pub(crate) use self::collect_trait_impls
::COLLECT_TRAIT_IMPLS
;
39 mod check_code_block_syntax
;
40 pub(crate) use self::check_code_block_syntax
::CHECK_CODE_BLOCK_SYNTAX
;
42 mod calculate_doc_coverage
;
43 pub(crate) use self::calculate_doc_coverage
::CALCULATE_DOC_COVERAGE
;
46 pub(crate) use self::html_tags
::CHECK_INVALID_HTML_TAGS
;
48 /// A single pass over the cleaned documentation.
50 /// Runs in the compiler context, so it has access to types and traits and the like.
51 #[derive(Copy, Clone)]
52 pub(crate) struct Pass
{
53 pub(crate) name
: &'
static str,
54 pub(crate) run
: fn(clean
::Crate
, &mut DocContext
<'_
>) -> clean
::Crate
,
55 pub(crate) description
: &'
static str,
58 /// In a list of passes, a pass that may or may not need to be run depending on options.
59 #[derive(Copy, Clone)]
60 pub(crate) struct ConditionalPass
{
61 pub(crate) pass
: Pass
,
62 pub(crate) condition
: Condition
,
65 /// How to decide whether to run a conditional pass.
66 #[derive(Copy, Clone)]
67 pub(crate) enum Condition
{
69 /// When `--document-private-items` is passed.
71 /// When `--document-private-items` is not passed.
72 WhenNotDocumentPrivate
,
73 /// When `--document-hidden-items` is not passed.
74 WhenNotDocumentHidden
,
77 /// The full list of passes.
78 pub(crate) const PASSES
: &[Pass
] = &[
79 CHECK_DOC_TEST_VISIBILITY
,
84 COLLECT_INTRA_DOC_LINKS
,
85 CHECK_CODE_BLOCK_SYNTAX
,
87 CALCULATE_DOC_COVERAGE
,
88 CHECK_INVALID_HTML_TAGS
,
92 /// The list of passes run by default.
93 pub(crate) const DEFAULT_PASSES
: &[ConditionalPass
] = &[
94 ConditionalPass
::always(COLLECT_TRAIT_IMPLS
),
95 ConditionalPass
::always(CHECK_DOC_TEST_VISIBILITY
),
96 ConditionalPass
::new(STRIP_HIDDEN
, WhenNotDocumentHidden
),
97 ConditionalPass
::new(STRIP_PRIVATE
, WhenNotDocumentPrivate
),
98 ConditionalPass
::new(STRIP_PRIV_IMPORTS
, WhenDocumentPrivate
),
99 ConditionalPass
::always(COLLECT_INTRA_DOC_LINKS
),
100 ConditionalPass
::always(CHECK_CODE_BLOCK_SYNTAX
),
101 ConditionalPass
::always(CHECK_INVALID_HTML_TAGS
),
102 ConditionalPass
::always(PROPAGATE_DOC_CFG
),
103 ConditionalPass
::always(CHECK_BARE_URLS
),
106 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.
107 pub(crate) const COVERAGE_PASSES
: &[ConditionalPass
] = &[
108 ConditionalPass
::new(STRIP_HIDDEN
, WhenNotDocumentHidden
),
109 ConditionalPass
::new(STRIP_PRIVATE
, WhenNotDocumentPrivate
),
110 ConditionalPass
::always(CALCULATE_DOC_COVERAGE
),
113 impl ConditionalPass
{
114 pub(crate) const fn always(pass
: Pass
) -> Self {
115 Self::new(pass
, Always
)
118 pub(crate) const fn new(pass
: Pass
, condition
: Condition
) -> Self {
119 ConditionalPass { pass, condition }
123 /// Returns the given default set of passes.
124 pub(crate) fn defaults(show_coverage
: bool
) -> &'
static [ConditionalPass
] {
125 if show_coverage { COVERAGE_PASSES }
else { DEFAULT_PASSES }
128 /// Returns a span encompassing all the given attributes.
129 pub(crate) fn span_of_attrs(attrs
: &clean
::Attributes
) -> Option
<Span
> {
130 if attrs
.doc_strings
.is_empty() {
133 let start
= attrs
.doc_strings
[0].span
;
134 if start
== DUMMY_SP
{
137 let end
= attrs
.doc_strings
.last().expect("no doc strings provided").span
;
141 /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
143 /// This method will return `None` if we cannot construct a span from the source map or if the
144 /// attributes are not all sugared doc comments. It's difficult to calculate the correct span in
145 /// that case due to escaping and other source features.
146 pub(crate) fn source_span_for_markdown_range(
149 md_range
: &Range
<usize>,
150 attrs
: &clean
::Attributes
,
152 let is_all_sugared_doc
=
153 attrs
.doc_strings
.iter().all(|frag
| frag
.kind
== DocFragmentKind
::SugaredDoc
);
155 if !is_all_sugared_doc
{
159 let snippet
= tcx
.sess
.source_map().span_to_snippet(span_of_attrs(attrs
)?
).ok()?
;
161 let starting_line
= markdown
[..md_range
.start
].matches('
\n'
).count();
162 let ending_line
= starting_line
+ markdown
[md_range
.start
..md_range
.end
].matches('
\n'
).count();
164 // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat
165 // CRLF and LF line endings the same way.
166 let mut src_lines
= snippet
.split_terminator('
\n'
);
167 let md_lines
= markdown
.split_terminator('
\n'
);
169 // The number of bytes from the source span to the markdown span that are not part
170 // of the markdown, like comment markers.
171 let mut start_bytes
= 0;
172 let mut end_bytes
= 0;
174 'outer
: for (line_no
, md_line
) in md_lines
.enumerate() {
176 let source_line
= src_lines
.next()?
;
177 match source_line
.find(md_line
) {
179 if line_no
== starting_line
{
180 start_bytes
+= offset
;
182 if starting_line
== ending_line
{
185 } else if line_no
== ending_line
{
188 } else if line_no
< starting_line
{
189 start_bytes
+= source_line
.len() - md_line
.len();
191 end_bytes
+= source_line
.len() - md_line
.len();
196 // Since this is a source line that doesn't include a markdown line,
197 // we have to count the newline that we split from earlier.
198 if line_no
<= starting_line
{
199 start_bytes
+= source_line
.len() + 1;
201 end_bytes
+= source_line
.len() + 1;
208 Some(span_of_attrs(attrs
)?
.from_inner(InnerSpan
::new(
209 md_range
.start
+ start_bytes
,
210 md_range
.end
+ start_bytes
+ end_bytes
,