]>
Commit | Line | Data |
---|---|---|
b7449926 XL |
1 | //! Contains information about "passes", used to modify crate information during the documentation |
2 | //! process. | |
3 | ||
6a06907d | 4 | use rustc_middle::ty::TyCtxt; |
dfeec247 | 5 | use rustc_span::{InnerSpan, Span, DUMMY_SP}; |
9fa01778 | 6 | use std::ops::Range; |
9e0c209e | 7 | |
60c5eb7d | 8 | use self::Condition::*; |
29967ef6 | 9 | use crate::clean::{self, DocFragmentKind}; |
416331ca | 10 | use crate::core::DocContext; |
29967ef6 XL |
11 | |
12 | mod stripper; | |
fc512014 | 13 | crate use stripper::*; |
29967ef6 | 14 | |
cdc7bbd5 XL |
15 | mod bare_urls; |
16 | crate use self::bare_urls::CHECK_BARE_URLS; | |
a1dfa0c6 | 17 | |
9e0c209e | 18 | mod strip_hidden; |
fc512014 | 19 | crate use self::strip_hidden::STRIP_HIDDEN; |
9e0c209e SL |
20 | |
21 | mod strip_private; | |
fc512014 | 22 | crate use self::strip_private::STRIP_PRIVATE; |
9e0c209e SL |
23 | |
24 | mod strip_priv_imports; | |
fc512014 | 25 | crate use self::strip_priv_imports::STRIP_PRIV_IMPORTS; |
9e0c209e SL |
26 | |
27 | mod unindent_comments; | |
fc512014 | 28 | crate use self::unindent_comments::UNINDENT_COMMENTS; |
9e0c209e | 29 | |
3b2f2976 | 30 | mod propagate_doc_cfg; |
fc512014 | 31 | crate use self::propagate_doc_cfg::PROPAGATE_DOC_CFG; |
b7449926 | 32 | |
94222f64 | 33 | crate mod collect_intra_doc_links; |
fc512014 | 34 | crate use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; |
b7449926 | 35 | |
c295e0f8 XL |
36 | mod check_doc_test_visibility; |
37 | crate use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; | |
a1dfa0c6 | 38 | |
0bf4aa26 | 39 | mod collect_trait_impls; |
fc512014 | 40 | crate use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; |
0bf4aa26 | 41 | |
9fa01778 | 42 | mod check_code_block_syntax; |
fc512014 | 43 | crate use self::check_code_block_syntax::CHECK_CODE_BLOCK_SYNTAX; |
9fa01778 | 44 | |
532ac7d7 | 45 | mod calculate_doc_coverage; |
fc512014 | 46 | crate use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; |
b7449926 | 47 | |
29967ef6 | 48 | mod html_tags; |
fc512014 | 49 | crate use self::html_tags::CHECK_INVALID_HTML_TAGS; |
29967ef6 | 50 | |
532ac7d7 XL |
51 | /// A single pass over the cleaned documentation. |
52 | /// | |
53 | /// Runs in the compiler context, so it has access to types and traits and the like. | |
54 | #[derive(Copy, Clone)] | |
fc512014 XL |
55 | crate struct Pass { |
56 | crate name: &'static str, | |
6a06907d | 57 | crate run: fn(clean::Crate, &mut DocContext<'_>) -> clean::Crate, |
fc512014 | 58 | crate description: &'static str, |
b7449926 XL |
59 | } |
60 | ||
60c5eb7d XL |
61 | /// In a list of passes, a pass that may or may not need to be run depending on options. |
62 | #[derive(Copy, Clone)] | |
fc512014 XL |
63 | crate struct ConditionalPass { |
64 | crate pass: Pass, | |
65 | crate condition: Condition, | |
60c5eb7d XL |
66 | } |
67 | ||
68 | /// How to decide whether to run a conditional pass. | |
69 | #[derive(Copy, Clone)] | |
fc512014 | 70 | crate enum Condition { |
60c5eb7d XL |
71 | Always, |
72 | /// When `--document-private-items` is passed. | |
73 | WhenDocumentPrivate, | |
74 | /// When `--document-private-items` is not passed. | |
75 | WhenNotDocumentPrivate, | |
76 | /// When `--document-hidden-items` is not passed. | |
77 | WhenNotDocumentHidden, | |
78 | } | |
416331ca | 79 | |
b7449926 | 80 | /// The full list of passes. |
fc512014 | 81 | crate const PASSES: &[Pass] = &[ |
c295e0f8 | 82 | CHECK_DOC_TEST_VISIBILITY, |
b7449926 XL |
83 | STRIP_HIDDEN, |
84 | UNINDENT_COMMENTS, | |
b7449926 XL |
85 | STRIP_PRIVATE, |
86 | STRIP_PRIV_IMPORTS, | |
87 | PROPAGATE_DOC_CFG, | |
88 | COLLECT_INTRA_DOC_LINKS, | |
9fa01778 | 89 | CHECK_CODE_BLOCK_SYNTAX, |
0bf4aa26 | 90 | COLLECT_TRAIT_IMPLS, |
532ac7d7 | 91 | CALCULATE_DOC_COVERAGE, |
29967ef6 | 92 | CHECK_INVALID_HTML_TAGS, |
cdc7bbd5 | 93 | CHECK_BARE_URLS, |
9e0c209e SL |
94 | ]; |
95 | ||
b7449926 | 96 | /// The list of passes run by default. |
fc512014 | 97 | crate const DEFAULT_PASSES: &[ConditionalPass] = &[ |
60c5eb7d | 98 | ConditionalPass::always(COLLECT_TRAIT_IMPLS), |
60c5eb7d | 99 | ConditionalPass::always(UNINDENT_COMMENTS), |
c295e0f8 | 100 | ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), |
60c5eb7d XL |
101 | ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), |
102 | ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), | |
103 | ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), | |
104 | ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), | |
105 | ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX), | |
29967ef6 | 106 | ConditionalPass::always(CHECK_INVALID_HTML_TAGS), |
60c5eb7d | 107 | ConditionalPass::always(PROPAGATE_DOC_CFG), |
cdc7bbd5 | 108 | ConditionalPass::always(CHECK_BARE_URLS), |
8faf50e0 XL |
109 | ]; |
110 | ||
532ac7d7 | 111 | /// The list of default passes run when `--doc-coverage` is passed to rustdoc. |
fc512014 | 112 | crate const COVERAGE_PASSES: &[ConditionalPass] = &[ |
60c5eb7d XL |
113 | ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), |
114 | ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), | |
115 | ConditionalPass::always(CALCULATE_DOC_COVERAGE), | |
532ac7d7 XL |
116 | ]; |
117 | ||
60c5eb7d | 118 | impl ConditionalPass { |
fc512014 | 119 | crate const fn always(pass: Pass) -> Self { |
60c5eb7d XL |
120 | Self::new(pass, Always) |
121 | } | |
122 | ||
fc512014 | 123 | crate const fn new(pass: Pass, condition: Condition) -> Self { |
60c5eb7d XL |
124 | ConditionalPass { pass, condition } |
125 | } | |
126 | } | |
532ac7d7 | 127 | |
b7449926 | 128 | /// A shorthand way to refer to which set of passes to use, based on the presence of |
60c5eb7d | 129 | /// `--no-defaults` and `--show-coverage`. |
8faf50e0 | 130 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
fc512014 | 131 | crate enum DefaultPassOption { |
8faf50e0 | 132 | Default, |
532ac7d7 | 133 | Coverage, |
8faf50e0 XL |
134 | None, |
135 | } | |
136 | ||
b7449926 | 137 | /// Returns the given default set of passes. |
fc512014 | 138 | crate fn defaults(default_set: DefaultPassOption) -> &'static [ConditionalPass] { |
8faf50e0 XL |
139 | match default_set { |
140 | DefaultPassOption::Default => DEFAULT_PASSES, | |
60c5eb7d | 141 | DefaultPassOption::Coverage => COVERAGE_PASSES, |
8faf50e0 XL |
142 | DefaultPassOption::None => &[], |
143 | } | |
144 | } | |
9e0c209e | 145 | |
b7449926 | 146 | /// If the given name matches a known pass, returns its information. |
fc512014 | 147 | crate fn find_pass(pass_name: &str) -> Option<Pass> { |
60c5eb7d | 148 | PASSES.iter().find(|p| p.name == pass_name).copied() |
b7449926 XL |
149 | } |
150 | ||
9fa01778 | 151 | /// Returns a span encompassing all the given attributes. |
416331ca | 152 | crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> { |
9fa01778 | 153 | if attrs.doc_strings.is_empty() { |
416331ca | 154 | return None; |
9fa01778 | 155 | } |
29967ef6 | 156 | let start = attrs.doc_strings[0].span; |
416331ca XL |
157 | if start == DUMMY_SP { |
158 | return None; | |
159 | } | |
29967ef6 | 160 | let end = attrs.doc_strings.last().expect("no doc strings provided").span; |
416331ca | 161 | Some(start.to(end)) |
9fa01778 XL |
162 | } |
163 | ||
164 | /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. | |
165 | /// | |
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( | |
6a06907d | 170 | tcx: TyCtxt<'_>, |
9fa01778 XL |
171 | markdown: &str, |
172 | md_range: &Range<usize>, | |
173 | attrs: &clean::Attributes, | |
174 | ) -> Option<Span> { | |
29967ef6 XL |
175 | let is_all_sugared_doc = |
176 | attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc); | |
9fa01778 XL |
177 | |
178 | if !is_all_sugared_doc { | |
179 | return None; | |
180 | } | |
181 | ||
6a06907d | 182 | let snippet = tcx.sess.source_map().span_to_snippet(span_of_attrs(attrs)?).ok()?; |
9fa01778 | 183 | |
532ac7d7 XL |
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(); | |
9fa01778 | 186 | |
532ac7d7 XL |
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. | |
9fa01778 XL |
189 | let mut src_lines = snippet.split_terminator('\n'); |
190 | let md_lines = markdown.split_terminator('\n'); | |
191 | ||
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; | |
196 | ||
197 | 'outer: for (line_no, md_line) in md_lines.enumerate() { | |
198 | loop { | |
199 | let source_line = src_lines.next().expect("could not find markdown in source"); | |
200 | match source_line.find(md_line) { | |
201 | Some(offset) => { | |
202 | if line_no == starting_line { | |
203 | start_bytes += offset; | |
204 | ||
205 | if starting_line == ending_line { | |
206 | break 'outer; | |
207 | } | |
208 | } else if line_no == ending_line { | |
209 | end_bytes += offset; | |
210 | break 'outer; | |
211 | } else if line_no < starting_line { | |
212 | start_bytes += source_line.len() - md_line.len(); | |
213 | } else { | |
214 | end_bytes += source_line.len() - md_line.len(); | |
215 | } | |
216 | break; | |
217 | } | |
218 | None => { | |
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; | |
223 | } else { | |
224 | end_bytes += source_line.len() + 1; | |
225 | } | |
226 | } | |
227 | } | |
228 | } | |
229 | } | |
230 | ||
416331ca | 231 | Some(span_of_attrs(attrs)?.from_inner(InnerSpan::new( |
9fa01778 XL |
232 | md_range.start + start_bytes, |
233 | md_range.end + start_bytes + end_bytes, | |
416331ca | 234 | ))) |
9fa01778 | 235 | } |