repo_description: Empowering everyone to build reliable and efficient software.
repo_topics: compiler language rust
code: 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");
  }
  