1 //! Contains information about "passes", used to modify crate information during the documentation
4 use rustc_span
::{InnerSpan, Span, DUMMY_SP}
;
7 use self::Condition
::*;
8 use crate::clean
::{self, DocFragmentKind}
;
9 use crate::core
::DocContext
;
12 crate use stripper
::*;
15 crate use self::non_autolinks
::CHECK_NON_AUTOLINKS
;
18 crate use self::strip_hidden
::STRIP_HIDDEN
;
21 crate use self::strip_private
::STRIP_PRIVATE
;
23 mod strip_priv_imports
;
24 crate use self::strip_priv_imports
::STRIP_PRIV_IMPORTS
;
26 mod unindent_comments
;
27 crate use self::unindent_comments
::UNINDENT_COMMENTS
;
29 mod propagate_doc_cfg
;
30 crate use self::propagate_doc_cfg
::PROPAGATE_DOC_CFG
;
32 mod collect_intra_doc_links
;
33 crate use self::collect_intra_doc_links
::COLLECT_INTRA_DOC_LINKS
;
36 crate use self::doc_test_lints
::CHECK_PRIVATE_ITEMS_DOC_TESTS
;
38 mod collect_trait_impls
;
39 crate use self::collect_trait_impls
::COLLECT_TRAIT_IMPLS
;
41 mod check_code_block_syntax
;
42 crate use self::check_code_block_syntax
::CHECK_CODE_BLOCK_SYNTAX
;
44 mod calculate_doc_coverage
;
45 crate use self::calculate_doc_coverage
::CALCULATE_DOC_COVERAGE
;
48 crate use self::html_tags
::CHECK_INVALID_HTML_TAGS
;
50 /// A single pass over the cleaned documentation.
52 /// Runs in the compiler context, so it has access to types and traits and the like.
53 #[derive(Copy, Clone)]
55 crate name
: &'
static str,
56 crate run
: fn(clean
::Crate
, &DocContext
<'_
>) -> clean
::Crate
,
57 crate description
: &'
static str,
60 /// In a list of passes, a pass that may or may not need to be run depending on options.
61 #[derive(Copy, Clone)]
62 crate struct ConditionalPass
{
64 crate condition
: Condition
,
67 /// How to decide whether to run a conditional pass.
68 #[derive(Copy, Clone)]
69 crate enum Condition
{
71 /// When `--document-private-items` is passed.
73 /// When `--document-private-items` is not passed.
74 WhenNotDocumentPrivate
,
75 /// When `--document-hidden-items` is not passed.
76 WhenNotDocumentHidden
,
79 /// The full list of passes.
80 crate const PASSES
: &[Pass
] = &[
81 CHECK_PRIVATE_ITEMS_DOC_TESTS
,
87 COLLECT_INTRA_DOC_LINKS
,
88 CHECK_CODE_BLOCK_SYNTAX
,
90 CALCULATE_DOC_COVERAGE
,
91 CHECK_INVALID_HTML_TAGS
,
95 /// The list of passes run by default.
96 crate const DEFAULT_PASSES
: &[ConditionalPass
] = &[
97 ConditionalPass
::always(COLLECT_TRAIT_IMPLS
),
98 ConditionalPass
::always(UNINDENT_COMMENTS
),
99 ConditionalPass
::always(CHECK_PRIVATE_ITEMS_DOC_TESTS
),
100 ConditionalPass
::new(STRIP_HIDDEN
, WhenNotDocumentHidden
),
101 ConditionalPass
::new(STRIP_PRIVATE
, WhenNotDocumentPrivate
),
102 ConditionalPass
::new(STRIP_PRIV_IMPORTS
, WhenDocumentPrivate
),
103 ConditionalPass
::always(COLLECT_INTRA_DOC_LINKS
),
104 ConditionalPass
::always(CHECK_CODE_BLOCK_SYNTAX
),
105 ConditionalPass
::always(CHECK_INVALID_HTML_TAGS
),
106 ConditionalPass
::always(PROPAGATE_DOC_CFG
),
107 ConditionalPass
::always(CHECK_NON_AUTOLINKS
),
110 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.
111 crate const COVERAGE_PASSES
: &[ConditionalPass
] = &[
112 ConditionalPass
::always(COLLECT_TRAIT_IMPLS
),
113 ConditionalPass
::new(STRIP_HIDDEN
, WhenNotDocumentHidden
),
114 ConditionalPass
::new(STRIP_PRIVATE
, WhenNotDocumentPrivate
),
115 ConditionalPass
::always(CALCULATE_DOC_COVERAGE
),
118 impl ConditionalPass
{
119 crate const fn always(pass
: Pass
) -> Self {
120 Self::new(pass
, Always
)
123 crate const fn new(pass
: Pass
, condition
: Condition
) -> Self {
124 ConditionalPass { pass, condition }
128 /// A shorthand way to refer to which set of passes to use, based on the presence of
129 /// `--no-defaults` and `--show-coverage`.
130 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
131 crate enum DefaultPassOption
{
137 /// Returns the given default set of passes.
138 crate fn defaults(default_set
: DefaultPassOption
) -> &'
static [ConditionalPass
] {
140 DefaultPassOption
::Default
=> DEFAULT_PASSES
,
141 DefaultPassOption
::Coverage
=> COVERAGE_PASSES
,
142 DefaultPassOption
::None
=> &[],
146 /// If the given name matches a known pass, returns its information.
147 crate fn find_pass(pass_name
: &str) -> Option
<Pass
> {
148 PASSES
.iter().find(|p
| p
.name
== pass_name
).copied()
151 /// Returns a span encompassing all the given attributes.
152 crate fn span_of_attrs(attrs
: &clean
::Attributes
) -> Option
<Span
> {
153 if attrs
.doc_strings
.is_empty() {
156 let start
= attrs
.doc_strings
[0].span
;
157 if start
== DUMMY_SP
{
160 let end
= attrs
.doc_strings
.last().expect("no doc strings provided").span
;
164 /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
166 /// This method will return `None` if we cannot construct a span from the source map or if the
167 /// attributes are not all sugared doc comments. It's difficult to calculate the correct span in
168 /// that case due to escaping and other source features.
169 crate fn source_span_for_markdown_range(
172 md_range
: &Range
<usize>,
173 attrs
: &clean
::Attributes
,
175 let is_all_sugared_doc
=
176 attrs
.doc_strings
.iter().all(|frag
| frag
.kind
== DocFragmentKind
::SugaredDoc
);
178 if !is_all_sugared_doc
{
182 let snippet
= cx
.sess().source_map().span_to_snippet(span_of_attrs(attrs
)?
).ok()?
;
184 let starting_line
= markdown
[..md_range
.start
].matches('
\n'
).count();
185 let ending_line
= starting_line
+ markdown
[md_range
.start
..md_range
.end
].matches('
\n'
).count();
187 // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat
188 // CRLF and LF line endings the same way.
189 let mut src_lines
= snippet
.split_terminator('
\n'
);
190 let md_lines
= markdown
.split_terminator('
\n'
);
192 // The number of bytes from the source span to the markdown span that are not part
193 // of the markdown, like comment markers.
194 let mut start_bytes
= 0;
195 let mut end_bytes
= 0;
197 'outer
: for (line_no
, md_line
) in md_lines
.enumerate() {
199 let source_line
= src_lines
.next().expect("could not find markdown in source");
200 match source_line
.find(md_line
) {
202 if line_no
== starting_line
{
203 start_bytes
+= offset
;
205 if starting_line
== ending_line
{
208 } else if line_no
== ending_line
{
211 } else if line_no
< starting_line
{
212 start_bytes
+= source_line
.len() - md_line
.len();
214 end_bytes
+= source_line
.len() - md_line
.len();
219 // Since this is a source line that doesn't include a markdown line,
220 // we have to count the newline that we split from earlier.
221 if line_no
<= starting_line
{
222 start_bytes
+= source_line
.len() + 1;
224 end_bytes
+= source_line
.len() + 1;
231 Some(span_of_attrs(attrs
)?
.from_inner(InnerSpan
::new(
232 md_range
.start
+ start_bytes
,
233 md_range
.end
+ start_bytes
+ end_bytes
,