| use std::sync::LazyLock as Lazy; | |
| use rustc_data_structures::fx::FxHashMap; | |
| use rustc_lint::LintStore; | |
| use rustc_lint_defs::{Lint, LintId, declare_tool_lint}; | |
| use rustc_session::{Session, lint}; | |
| /// This function is used to setup the lint initialization. By default, in rustdoc, everything | |
| /// is "allowed". Depending if we run in test mode or not, we want some of them to be at their | |
| /// default level. For example, the "INVALID_CODEBLOCK_ATTRIBUTES" lint is activated in both | |
| /// modes. | |
| /// | |
| /// A little detail easy to forget is that there is a way to set the lint level for all lints | |
| /// through the "WARNINGS" lint. To prevent this to happen, we set it back to its "normal" level | |
| /// inside this function. | |
| /// | |
| /// It returns a tuple containing: | |
| /// * Vector of tuples of lints' name and their associated "max" level | |
| /// * HashMap of lint id with their associated "max" level | |
| pub(crate) fn 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)>, | |
| { | |
| let warnings_lint_name = lint::builtin::WARNINGS.name; | |
| allowed_lints.push(warnings_lint_name.to_owned()); | |
| allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); | |
| let lints = || { | |
| lint::builtin::HardwiredLints::lint_vec() | |
| .into_iter() | |
| .chain(rustc_lint::SoftLints::lint_vec()) | |
| }; | |
| let lint_opts = lints() | |
| .filter_map(|lint| { | |
| // Permit feature-gated lints to avoid feature errors when trying to | |
| // allow all lints. | |
| if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) { | |
| None | |
| } else { | |
| filter_call(lint) | |
| } | |
| }) | |
| .chain(lint_opts) | |
| .collect::<Vec<_>>(); | |
| let lint_caps = lints() | |
| .filter_map(|lint| { | |
| // We don't want to allow *all* lints so let's ignore | |
| // those ones. | |
| if allowed_lints.iter().any(|l| lint.name == l) { | |
| None | |
| } else { | |
| Some((lint::LintId::of(lint), lint::Allow)) | |
| } | |
| }) | |
| .collect(); | |
| (lint_opts, lint_caps) | |
| } | |
| macro_rules! declare_rustdoc_lint { | |
| ( | |
| $(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)? | |
| $(@feature_gate = $gate:ident;)? | |
| ) => { | |
| declare_tool_lint! { | |
| $(#[$attr])* pub rustdoc::$name, $level, $descr | |
| $(, @feature_gate = $gate;)? | |
| } | |
| } | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `broken_intra_doc_links` lint detects failures in resolving | |
| /// intra-doc link targets. This is a `rustdoc` only lint, see the | |
| /// documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links | |
| BROKEN_INTRA_DOC_LINKS, | |
| Warn, | |
| "failures in resolving intra-doc link targets" | |
| } | |
| declare_rustdoc_lint! { | |
| /// This is a subset of `broken_intra_doc_links` that warns when linking from | |
| /// a public item to a private one. This is a `rustdoc` only lint, see the | |
| /// documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links | |
| PRIVATE_INTRA_DOC_LINKS, | |
| Warn, | |
| "linking from a public item to a private one" | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `invalid_codeblock_attributes` lint detects code block attributes | |
| /// in documentation examples that have potentially mis-typed values. This | |
| /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes | |
| INVALID_CODEBLOCK_ATTRIBUTES, | |
| Warn, | |
| "codeblock attribute looks a lot like a known one" | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `missing_crate_level_docs` lint detects if documentation is | |
| /// missing at the crate root. This is a `rustdoc` only lint, see the | |
| /// documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs | |
| MISSING_CRATE_LEVEL_DOCS, | |
| Allow, | |
| "detects crates with no crate-level documentation" | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `missing_doc_code_examples` lint detects publicly-exported items | |
| /// without code samples in their documentation. This is a `rustdoc` only | |
| /// lint, see the documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples | |
| MISSING_DOC_CODE_EXAMPLES, | |
| Allow, | |
| "detects publicly-exported items without code samples in their documentation", | |
| @feature_gate = rustdoc_missing_doc_code_examples; | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `private_doc_tests` lint detects code samples in docs of private | |
| /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see | |
| /// the documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests | |
| PRIVATE_DOC_TESTS, | |
| Allow, | |
| "detects code samples in docs of private items not documented by rustdoc" | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `invalid_html_tags` lint detects invalid HTML tags. This is a | |
| /// `rustdoc` only lint, see the documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags | |
| INVALID_HTML_TAGS, | |
| Warn, | |
| "detects invalid HTML tags in doc comments" | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `bare_urls` lint detects when a URL is not a hyperlink. | |
| /// This is a `rustdoc` only lint, see the documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#bare_urls | |
| BARE_URLS, | |
| Warn, | |
| "detects URLs that are not hyperlinks" | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `invalid_rust_codeblocks` lint detects Rust code blocks in | |
| /// documentation examples that are invalid (e.g. empty, not parsable as | |
| /// Rust code). This is a `rustdoc` only lint, see the documentation in the | |
| /// [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_rust_codeblocks | |
| INVALID_RUST_CODEBLOCKS, | |
| Warn, | |
| "codeblock could not be parsed as valid Rust or is empty" | |
| } | |
| declare_rustdoc_lint! { | |
| /// The `unescaped_backticks` lint detects unescaped backticks (\`), which usually | |
| /// mean broken inline code. This is a `rustdoc` only lint, see the documentation | |
| /// in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#unescaped_backticks | |
| UNESCAPED_BACKTICKS, | |
| Allow, | |
| "detects unescaped backticks in doc comments" | |
| } | |
| declare_rustdoc_lint! { | |
| /// This lint is **warn-by-default**. It detects explicit links that are the same | |
| /// as computed automatic links. This usually means the explicit links are removable. | |
| /// This is a `rustdoc` only lint, see the documentation in the [rustdoc book]. | |
| /// | |
| /// [rustdoc book]: ../../../rustdoc/lints.html#redundant_explicit_links | |
| REDUNDANT_EXPLICIT_LINKS, | |
| Warn, | |
| "detects redundant explicit links in doc comments" | |
| } | |
| pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| { | |
| vec![ | |
| BROKEN_INTRA_DOC_LINKS, | |
| PRIVATE_INTRA_DOC_LINKS, | |
| MISSING_DOC_CODE_EXAMPLES, | |
| PRIVATE_DOC_TESTS, | |
| INVALID_CODEBLOCK_ATTRIBUTES, | |
| INVALID_RUST_CODEBLOCKS, | |
| INVALID_HTML_TAGS, | |
| BARE_URLS, | |
| MISSING_CRATE_LEVEL_DOCS, | |
| UNESCAPED_BACKTICKS, | |
| REDUNDANT_EXPLICIT_LINKS, | |
| ] | |
| }); | |
| pub(crate) fn register_lints(_sess: &Session, lint_store: &mut LintStore) { | |
| lint_store.register_lints(&RUSTDOC_LINTS); | |
| lint_store.register_group( | |
| true, | |
| "rustdoc::all", | |
| Some("rustdoc"), | |
| RUSTDOC_LINTS | |
| .iter() | |
| .filter(|lint| lint.feature_gate.is_none()) // only include stable lints | |
| .map(|&lint| LintId::of(lint)) | |
| .collect(), | |
| ); | |
| for lint in &*RUSTDOC_LINTS { | |
| let name = lint.name_lower(); | |
| lint_store.register_renamed(&name.replace("rustdoc::", ""), &name); | |
| } | |
| lint_store | |
| .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links"); | |
| lint_store.register_renamed("non_autolinks", "rustdoc::bare_urls"); | |
| lint_store.register_renamed("rustdoc::non_autolinks", "rustdoc::bare_urls"); | |
| lint_store.register_removed("rustdoc::unportable_markdown", "old parser removed"); | |
| } |