• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use rustc_data_structures::fx::FxHashMap;
2 use rustc_lint::LintStore;
3 use rustc_lint_defs::{declare_tool_lint, Lint, LintId};
4 use rustc_session::{lint, Session};
5 
6 use std::sync::LazyLock as Lazy;
7 
8 /// This function is used to setup the lint initialization. By default, in rustdoc, everything
9 /// is "allowed". Depending if we run in test mode or not, we want some of them to be at their
10 /// default level. For example, the "INVALID_CODEBLOCK_ATTRIBUTES" lint is activated in both
11 /// modes.
12 ///
13 /// A little detail easy to forget is that there is a way to set the lint level for all lints
14 /// through the "WARNINGS" lint. To prevent this to happen, we set it back to its "normal" level
15 /// inside this function.
16 ///
17 /// It returns a tuple containing:
18 ///  * Vector of tuples of lints' name and their associated "max" level
19 ///  * HashMap of lint id with their associated "max" level
init_lints<F>( mut allowed_lints: Vec<String>, lint_opts: Vec<(String, lint::Level)>, filter_call: F, ) -> (Vec<(String, lint::Level)>, FxHashMap<lint::LintId, lint::Level>) where F: Fn(&lint::Lint) -> Option<(String, lint::Level)>,20 pub(crate) fn init_lints<F>(
21     mut allowed_lints: Vec<String>,
22     lint_opts: Vec<(String, lint::Level)>,
23     filter_call: F,
24 ) -> (Vec<(String, lint::Level)>, FxHashMap<lint::LintId, lint::Level>)
25 where
26     F: Fn(&lint::Lint) -> Option<(String, lint::Level)>,
27 {
28     let warnings_lint_name = lint::builtin::WARNINGS.name;
29 
30     allowed_lints.push(warnings_lint_name.to_owned());
31     allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
32 
33     let lints = || {
34         lint::builtin::HardwiredLints::get_lints()
35             .into_iter()
36             .chain(rustc_lint::SoftLints::get_lints().into_iter())
37     };
38 
39     let lint_opts = lints()
40         .filter_map(|lint| {
41             // Permit feature-gated lints to avoid feature errors when trying to
42             // allow all lints.
43             if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) {
44                 None
45             } else {
46                 filter_call(lint)
47             }
48         })
49         .chain(lint_opts.into_iter())
50         .collect::<Vec<_>>();
51 
52     let lint_caps = lints()
53         .filter_map(|lint| {
54             // We don't want to allow *all* lints so let's ignore
55             // those ones.
56             if allowed_lints.iter().any(|l| lint.name == l) {
57                 None
58             } else {
59                 Some((lint::LintId::of(lint), lint::Allow))
60             }
61         })
62         .collect();
63     (lint_opts, lint_caps)
64 }
65 
66 macro_rules! declare_rustdoc_lint {
67     (
68         $(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?
69         $(@feature_gate = $gate:expr;)?
70     ) => {
71         declare_tool_lint! {
72             $(#[$attr])* pub rustdoc::$name, $level, $descr
73             $(, @feature_gate = $gate;)?
74         }
75     }
76 }
77 
78 declare_rustdoc_lint! {
79     /// The `broken_intra_doc_links` lint detects failures in resolving
80     /// intra-doc link targets. This is a `rustdoc` only lint, see the
81     /// documentation in the [rustdoc book].
82     ///
83     /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links
84     BROKEN_INTRA_DOC_LINKS,
85     Warn,
86     "failures in resolving intra-doc link targets"
87 }
88 
89 declare_rustdoc_lint! {
90     /// This is a subset of `broken_intra_doc_links` that warns when linking from
91     /// a public item to a private one. This is a `rustdoc` only lint, see the
92     /// documentation in the [rustdoc book].
93     ///
94     /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links
95     PRIVATE_INTRA_DOC_LINKS,
96     Warn,
97     "linking from a public item to a private one"
98 }
99 
100 declare_rustdoc_lint! {
101     /// The `invalid_codeblock_attributes` lint detects code block attributes
102     /// in documentation examples that have potentially mis-typed values. This
103     /// is a `rustdoc` only lint, see the documentation in the [rustdoc book].
104     ///
105     /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes
106     INVALID_CODEBLOCK_ATTRIBUTES,
107     Warn,
108     "codeblock attribute looks a lot like a known one"
109 }
110 
111 declare_rustdoc_lint! {
112     /// The `missing_crate_level_docs` lint detects if documentation is
113     /// missing at the crate root. This is a `rustdoc` only lint, see the
114     /// documentation in the [rustdoc book].
115     ///
116     /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs
117     MISSING_CRATE_LEVEL_DOCS,
118     Allow,
119     "detects crates with no crate-level documentation"
120 }
121 
122 declare_rustdoc_lint! {
123     /// The `missing_doc_code_examples` lint detects publicly-exported items
124     /// without code samples in their documentation. This is a `rustdoc` only
125     /// lint, see the documentation in the [rustdoc book].
126     ///
127     /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples
128     MISSING_DOC_CODE_EXAMPLES,
129     Allow,
130     "detects publicly-exported items without code samples in their documentation",
131     @feature_gate = rustc_span::symbol::sym::rustdoc_missing_doc_code_examples;
132 }
133 
134 declare_rustdoc_lint! {
135     /// The `private_doc_tests` lint detects code samples in docs of private
136     /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see
137     /// the documentation in the [rustdoc book].
138     ///
139     /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests
140     PRIVATE_DOC_TESTS,
141     Allow,
142     "detects code samples in docs of private items not documented by rustdoc"
143 }
144 
145 declare_rustdoc_lint! {
146     /// The `invalid_html_tags` lint detects invalid HTML tags. This is a
147     /// `rustdoc` only lint, see the documentation in the [rustdoc book].
148     ///
149     /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags
150     INVALID_HTML_TAGS,
151     Warn,
152     "detects invalid HTML tags in doc comments"
153 }
154 
155 declare_rustdoc_lint! {
156     /// The `bare_urls` lint detects when a URL is not a hyperlink.
157     /// This is a `rustdoc` only lint, see the documentation in the [rustdoc book].
158     ///
159     /// [rustdoc book]: ../../../rustdoc/lints.html#bare_urls
160     BARE_URLS,
161     Warn,
162     "detects URLs that are not hyperlinks"
163 }
164 
165 declare_rustdoc_lint! {
166    /// The `invalid_rust_codeblocks` lint detects Rust code blocks in
167    /// documentation examples that are invalid (e.g. empty, not parsable as
168    /// Rust code). This is a `rustdoc` only lint, see the documentation in the
169    /// [rustdoc book].
170    ///
171    /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_rust_codeblocks
172    INVALID_RUST_CODEBLOCKS,
173    Warn,
174    "codeblock could not be parsed as valid Rust or is empty"
175 }
176 
177 declare_rustdoc_lint! {
178    /// The `unescaped_backticks` lint detects unescaped backticks (\`), which usually
179    /// mean broken inline code. This is a `rustdoc` only lint, see the documentation
180    /// in the [rustdoc book].
181    ///
182    /// [rustdoc book]: ../../../rustdoc/lints.html#unescaped_backticks
183    UNESCAPED_BACKTICKS,
184    Allow,
185    "detects unescaped backticks in doc comments"
186 }
187 
188 pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
189     vec![
190         BROKEN_INTRA_DOC_LINKS,
191         PRIVATE_INTRA_DOC_LINKS,
192         MISSING_DOC_CODE_EXAMPLES,
193         PRIVATE_DOC_TESTS,
194         INVALID_CODEBLOCK_ATTRIBUTES,
195         INVALID_RUST_CODEBLOCKS,
196         INVALID_HTML_TAGS,
197         BARE_URLS,
198         MISSING_CRATE_LEVEL_DOCS,
199         UNESCAPED_BACKTICKS,
200     ]
201 });
202 
register_lints(_sess: &Session, lint_store: &mut LintStore)203 pub(crate) fn register_lints(_sess: &Session, lint_store: &mut LintStore) {
204     lint_store.register_lints(&**RUSTDOC_LINTS);
205     lint_store.register_group(
206         true,
207         "rustdoc::all",
208         Some("rustdoc"),
209         RUSTDOC_LINTS
210             .iter()
211             .filter(|lint| lint.feature_gate.is_none()) // only include stable lints
212             .map(|&lint| LintId::of(lint))
213             .collect(),
214     );
215     for lint in &*RUSTDOC_LINTS {
216         let name = lint.name_lower();
217         lint_store.register_renamed(&name.replace("rustdoc::", ""), &name);
218     }
219     lint_store
220         .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links");
221     lint_store.register_renamed("non_autolinks", "rustdoc::bare_urls");
222     lint_store.register_renamed("rustdoc::non_autolinks", "rustdoc::bare_urls");
223 }
224