LCOV - code coverage report
Current view: top level - utils/linting/src - lib.rs (source / functions) Hit Total Coverage
Test: unnamed Lines: 0 92 0.0 %
Date: 2024-10-23 19:20:50 Functions: 0 13 0.0 %

          Line data    Source code
       1             : //! This crate provides macros for creating [Dylint] libraries, and utilities for creating
       2             : //! configurable libraries.
       3             : //!
       4             : //! **Contents**
       5             : //!
       6             : //! - [`dylint_library!`]
       7             : //! - [`declare_late_lint!`, `declare_early_lint!`, `declare_pre_expansion_lint!`]
       8             : //! - [`impl_late_lint!`, `impl_early_lint!`, `impl_pre_expansion_lint!`]
       9             : //! - [`constituent` feature]
      10             : //! - [Configurable libraries]
      11             : //!
      12             : //! # `dylint_library!`
      13             : //!
      14             : //! The `dylint_library!` macro expands to the following:
      15             : //!
      16             : //! ```rust,ignore
      17             : //! #[allow(unused_extern_crates)]
      18             : //! extern crate rustc_driver;
      19             : //!
      20             : //! #[no_mangle]
      21             : //! pub extern "C" fn dylint_version() -> *mut std::os::raw::c_char {
      22             : //!     std::ffi::CString::new($crate::DYLINT_VERSION)
      23             : //!         .unwrap()
      24             : //!         .into_raw()
      25             : //! }
      26             : //! ```
      27             : //!
      28             : //! If your library uses the `dylint_library!` macro and the [`dylint-link`] tool, then all you
      29             : //! should have to do is implement the [`register_lints`] function. See the [examples] in this
      30             : //! repository.
      31             : //!
      32             : //! # `declare_late_lint!`, etc.
      33             : //!
      34             : //! If your library contains just one lint, using `declare_late_lint!`, etc. can make your code more
      35             : //! concise. Each of these macros requires the same arguments as [`declare_lint!`], and wraps the
      36             : //! following:
      37             : //!
      38             : //! - a call to `dylint_library!`
      39             : //! - an implementation of the `register_lints` function
      40             : //! - a call to `declare_lint!`
      41             : //! - a call to [`declare_lint_pass!`]
      42             : //!
      43             : //! For example, `declare_late_lint!(vis NAME, Level, "description")` expands to the following:
      44             : //!
      45             : //! ```rust,ignore
      46             : //! dylint_linting::dylint_library!();
      47             : //!
      48             : //! extern crate rustc_lint;
      49             : //! extern crate rustc_session;
      50             : //!
      51             : //! #[no_mangle]
      52             : //! pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
      53             : //!     dylint_linting::init_config(sess);
      54             : //!     lint_store.register_lints(&[NAME]);
      55             : //!     lint_store.register_late_pass(|_| Box::new(Name));
      56             : //! }
      57             : //!
      58             : //! rustc_session::declare_lint!(vis NAME, Level, "description");
      59             : //!
      60             : //! rustc_session::declare_lint_pass!(Name => [NAME]);
      61             : //! ```
      62             : //!
      63             : //! `declare_early_lint!` and `declare_pre_expansion_lint!` are defined similarly.
      64             : //!
      65             : //! # `impl_late_lint!`, etc.
      66             : //!
      67             : //! `impl_late_lint!`, etc. are like `declare_late_lint!`, etc. except:
      68             : //!
      69             : //! - each calls [`impl_lint_pass!`] instead of `declare_lint_pass!`;
      70             : //! - each requires an additional argument to specify the value of the lint's [`LintPass`]
      71             : //!   structure.
      72             : //!
      73             : //! That is, `impl_late_lint!`'s additional argument is what goes here:
      74             : //!
      75             : //! ```rust,ignore
      76             : //!     lint_store.register_late_pass(|_| Box::new(...));
      77             : //!                                                ^^^
      78             : //! ```
      79             : //!
      80             : //! # `constituent` feature
      81             : //!
      82             : //! Enabling the package-level `constituent` feature changes the way the above macros work.
      83             : //! Specifically, it causes them to _exclude_:
      84             : //!
      85             : //! - the call to `dylint_library!`
      86             : //! - the use of `#[no_mangle]` just prior to the declaration of `register_lints`
      87             : //!
      88             : //! Such changes facilitate inclusion of a lint declared with one of the above macros into a larger
      89             : //! library. That is:
      90             : //!
      91             : //! - With the feature turned off, the lint can be built as a library by itself.
      92             : //! - With the feature turned on, the lint can be built as part of a larger library, alongside other
      93             : //!   lints.
      94             : //!
      95             : //! The [general-purpose] and [supplementary] lints in this repository employ this technique.
      96             : //! That is, each general-purpose lint can be built as a library by itself, or as part of the
      97             : //! [`general` library]. An analogous statement applies to the supplementary lints and the
      98             : //! [`supplementary` library]. The `constituent` feature is the underlying mechanism that makes this
      99             : //! work.
     100             : //!
     101             : //! # Configurable libraries
     102             : //!
     103             : //! Libraries can be configured by including a `dylint.toml` file in the target workspace's root
     104             : //! directory. This crate provides the following functions for reading and parsing `dylint.toml`
     105             : //! files:
     106             : //!
     107             : //! - [`config_or_default`]
     108             : //! - [`config`]
     109             : //! - [`config_toml`]
     110             : //! - [`init_config`]
     111             : //! - [`try_init_config`]
     112             : //!
     113             : //! A configurable library containing just one lint will typically have a `lib.rs` file of the
     114             : //! following form:
     115             : //!
     116             : //! ```rust,ignore
     117             : //! dylint_linting::impl_late_lint! {
     118             : //!     ...,
     119             : //!     LintName::new()
     120             : //! }
     121             : //!
     122             : //! // Lint configuration
     123             : //! #[derive(Default, serde::Deserialize)]
     124             : //! struct Config {
     125             : //!     boolean: bool,
     126             : //!     strings: Vec<String>,
     127             : //! }
     128             : //!
     129             : //! // Keep a copy of the configuration in the `LintPass` structure.
     130             : //! struct LintName {
     131             : //!     config: Config,
     132             : //! }
     133             : //!
     134             : //! // Read the configuration from the `dylint.toml` file, or use the default configuration if
     135             : //! // none is present.
     136             : //! impl LintName {
     137             : //!     pub fn new() -> Self {
     138             : //!         Self {
     139             : //!             config: dylint_linting::config_or_default(env!("CARGO_PKG_NAME")),
     140             : //!         }
     141             : //!     }
     142             : //! }
     143             : //! ```
     144             : //!
     145             : //! For a concrete example of a `lib.rs` file with this form, see the
     146             : //! [`non_local_effect_before_error_return`] library in this repository.
     147             : //!
     148             : //! A library containing more than one lint must implement the `register_lints` function without
     149             : //! relying on the above macros. If the library is configurable, then its `register_lints` function
     150             : //! should include a call to `dylint_linting::init_config`, as in the following example:
     151             : //!
     152             : //! ```rust,ignore
     153             : //! #[no_mangle]
     154             : //! pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
     155             : //!     // `init_config` or `try_init_config` must be called before `config_or_default`, `config`,
     156             : //!     // or `config_toml` is called.
     157             : //!     dylint_linting::init_config(sess);
     158             : //!
     159             : //!     lint_store.register_lints(&[FIRST_LINT_NAME, SECOND_LINT_NAME]);
     160             : //!
     161             : //!     lint_store.register_late_pass(|_| Box::new(LintPassName::new()));
     162             : //! }
     163             : //! ```
     164             : //!
     165             : //! Additional documentation on `config_or_default`, etc. can be found on [docs.rs].
     166             : //!
     167             : //! [Configurable libraries]: #configurable-libraries
     168             : //! [Dylint]: https://github.com/trailofbits/dylint/tree/master
     169             : //! [`LintPass`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LintPass.html
     170             : //! [`config_or_default`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.config_or_default.html
     171             : //! [`config_toml`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.config_toml.html
     172             : //! [`config`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.config.html
     173             : //! [`constituent` feature]: #constituent-feature
     174             : //! [`declare_late_lint!`, `declare_early_lint!`, `declare_pre_expansion_lint!`]: #declare_late_lint-etc
     175             : //! [`declare_lint!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_lint.html
     176             : //! [`declare_lint_pass!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.declare_lint_pass.html
     177             : //! [`dylint-link`]: https://github.com/trailofbits/dylint/tree/master/dylint-link
     178             : //! [`dylint_library!`]: #dylint_library
     179             : //! [`general` library]: https://github.com/trailofbits/dylint/tree/master/examples/general/src/lib.rs
     180             : //! [`impl_late_lint!`, `impl_early_lint!`, `impl_pre_expansion_lint!`]: #impl_late_lint-etc
     181             : //! [`impl_lint_pass!`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/macro.impl_lint_pass.html
     182             : //! [`init_config`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.init_config.html
     183             : //! [`non_local_effect_before_error_return`]: https://github.com/trailofbits/dylint/tree/master/examples/general/non_local_effect_before_error_return/src/lib.rs
     184             : //! [`register_lints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html#structfield.register_lints
     185             : //! [`supplementary` library]: https://github.com/trailofbits/dylint/tree/master/examples/supplementary/src/lib.rs
     186             : //! [`try_init_config`]: https://docs.rs/dylint_linting/latest/dylint_linting/fn.try_init_config.html
     187             : //! [docs.rs documentation]: https://docs.rs/dylint_linting/latest/dylint_linting/
     188             : //! [docs.rs]: https://docs.rs/dylint_linting/latest/dylint_linting/
     189             : //! [examples]: https://github.com/trailofbits/dylint/tree/master/examples
     190             : //! [general-purpose]: https://github.com/trailofbits/dylint/tree/master/examples/general
     191             : //! [supplementary]: https://github.com/trailofbits/dylint/tree/master/examples/supplementary
     192             : 
     193             : #![feature(rustc_private)]
     194             : #![warn(unused_extern_crates)]
     195             : 
     196             : #[allow(unused_extern_crates)]
     197             : extern crate rustc_driver;
     198             : 
     199             : extern crate rustc_session;
     200             : extern crate rustc_span;
     201             : 
     202             : use dylint_internal::{config, env};
     203             : use rustc_span::Symbol;
     204             : use std::{
     205             :     any::type_name,
     206             :     path::{Path, PathBuf},
     207             : };
     208             : 
     209             : pub use config::{Error as ConfigError, Result as ConfigResult};
     210             : 
     211             : pub const DYLINT_VERSION: &str = "0.1.0";
     212             : 
     213             : pub use paste;
     214             : 
     215             : // smoelius: Including `extern crate rustc_driver` causes the library to link against
     216             : // `librustc_driver.so`, which dylint-driver also links against. So, essentially, the library uses
     217             : // dylint-driver's copy of the Rust compiler crates.
     218             : #[macro_export]
     219             : macro_rules! dylint_library {
     220             :     () => {
     221             :         #[allow(unused_extern_crates)]
     222             :         extern crate rustc_driver;
     223             : 
     224             :         #[doc(hidden)]
     225             :         #[no_mangle]
     226             :         pub extern "C" fn dylint_version() -> *mut std::os::raw::c_char {
     227             :             std::ffi::CString::new($crate::DYLINT_VERSION)
     228             :                 .unwrap()
     229             :                 .into_raw()
     230             :         }
     231             :     };
     232             : }
     233             : 
     234             : #[cfg(not(feature = "constituent"))]
     235             : #[doc(hidden)]
     236             : #[macro_export]
     237             : macro_rules! __maybe_exclude {
     238             :     ($item:item) => {
     239             :         $item
     240             :     };
     241             : }
     242             : 
     243             : #[cfg(feature = "constituent")]
     244             : #[doc(hidden)]
     245             : #[macro_export]
     246             : macro_rules! __maybe_exclude {
     247             :     ($item:item) => {};
     248             : }
     249             : 
     250             : #[cfg(not(feature = "constituent"))]
     251             : #[doc(hidden)]
     252             : #[macro_export]
     253             : macro_rules! __maybe_mangle {
     254             :     ($item:item) => {
     255             :         #[no_mangle]
     256             :         $item
     257             :     };
     258             : }
     259             : 
     260             : #[cfg(feature = "constituent")]
     261             : #[doc(hidden)]
     262             : #[macro_export]
     263             : macro_rules! __maybe_mangle {
     264             :     ($item:item) => {
     265             :         $item
     266             :     };
     267             : }
     268             : 
     269             : #[doc(hidden)]
     270             : #[macro_export]
     271             : macro_rules! __declare_and_register_lint {
     272             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $register_pass_method:ident, $pass:expr) => {
     273             :         $crate::__maybe_exclude! {
     274             :             $crate::dylint_library!();
     275             :         }
     276             : 
     277             :         extern crate rustc_lint;
     278             :         extern crate rustc_session;
     279             : 
     280             :         $crate::__maybe_mangle! {
     281             :             #[allow(clippy::no_mangle_with_rust_abi)]
     282             :             pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
     283             :                 $crate::init_config(sess);
     284             :                 lint_store.register_lints(&[$NAME]);
     285             :                 lint_store.$register_pass_method($pass);
     286             :             }
     287             :         }
     288             : 
     289             :         rustc_session::declare_lint!($(#[$attr])* $vis $NAME, $Level, $desc);
     290             :     };
     291             : }
     292             : 
     293             : #[rustversion::before(2022-09-08)]
     294             : #[doc(hidden)]
     295             : #[macro_export]
     296             : macro_rules! __make_late_closure {
     297             :     ($pass:expr) => {
     298             :         || Box::new($pass)
     299             :     };
     300             : }
     301             : 
     302             : // smoelius: Relevant PR and merge commit:
     303             : // - https://github.com/rust-lang/rust/pull/101501
     304             : // - https://github.com/rust-lang/rust/commit/87788097b776f8e3662f76627944230684b671bd
     305             : #[rustversion::since(2022-09-08)]
     306             : #[doc(hidden)]
     307             : #[macro_export]
     308             : macro_rules! __make_late_closure {
     309             :     ($pass:expr) => {
     310             :         |_| Box::new($pass)
     311             :     };
     312             : }
     313             : 
     314             : #[macro_export]
     315             : macro_rules! impl_pre_expansion_lint {
     316             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $pass:expr) => {
     317             :         $crate::__declare_and_register_lint!(
     318             :             $(#[$attr])* $vis $NAME,
     319             :             $Level,
     320             :             $desc,
     321             :             register_pre_expansion_pass,
     322             :             || Box::new($pass)
     323             :         );
     324             :         $crate::paste::paste! {
     325             :             rustc_session::impl_lint_pass!([< $NAME:camel >] => [$NAME]);
     326             :         }
     327             :     };
     328             : }
     329             : 
     330             : #[macro_export]
     331             : macro_rules! impl_early_lint {
     332             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $pass:expr) => {
     333             :         $crate::__declare_and_register_lint!(
     334             :             $(#[$attr])* $vis $NAME,
     335             :             $Level,
     336             :             $desc,
     337             :             register_early_pass,
     338             :             || Box::new($pass)
     339             :         );
     340             :         $crate::paste::paste! {
     341             :             rustc_session::impl_lint_pass!([< $NAME:camel >] => [$NAME]);
     342             :         }
     343             :     };
     344             : }
     345             : 
     346             : #[macro_export]
     347             : macro_rules! impl_late_lint {
     348             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr, $pass:expr) => {
     349             :         $crate::__declare_and_register_lint!(
     350             :             $(#[$attr])* $vis $NAME,
     351             :             $Level,
     352             :             $desc,
     353             :             register_late_pass,
     354             :             $crate::__make_late_closure!($pass)
     355             :         );
     356             :         $crate::paste::paste! {
     357             :             rustc_session::impl_lint_pass!([< $NAME:camel >] => [$NAME]);
     358             :         }
     359             :     };
     360             : }
     361             : 
     362             : #[macro_export]
     363             : macro_rules! declare_pre_expansion_lint {
     364             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr) => {
     365             :         $crate::paste::paste! {
     366             :             $crate::__declare_and_register_lint!(
     367             :                 $(#[$attr])* $vis $NAME,
     368             :                 $Level,
     369             :                 $desc,
     370             :                 register_pre_expansion_pass,
     371             :                 || Box::new([< $NAME:camel >])
     372             :             );
     373             :             rustc_session::declare_lint_pass!([< $NAME:camel >] => [$NAME]);
     374             :         }
     375             :     };
     376             : }
     377             : 
     378             : #[macro_export]
     379             : macro_rules! declare_early_lint {
     380             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr) => {
     381             :         $crate::paste::paste! {
     382             :             $crate::__declare_and_register_lint!(
     383             :                 $(#[$attr])* $vis $NAME,
     384             :                 $Level,
     385             :                 $desc,
     386             :                 register_early_pass,
     387             :                 || Box::new([< $NAME:camel >])
     388             :             );
     389             :             rustc_session::declare_lint_pass!([< $NAME:camel >] => [$NAME]);
     390             :         }
     391             :     };
     392             : }
     393             : 
     394             : #[macro_export]
     395             : macro_rules! declare_late_lint {
     396             :     ($(#[$attr:meta])* $vis:vis $NAME:ident, $Level:ident, $desc:expr) => {
     397             :         $crate::paste::paste! {
     398             :             $crate::__declare_and_register_lint!(
     399             :                 $(#[$attr])* $vis $NAME,
     400             :                 $Level,
     401             :                 $desc,
     402             :                 register_late_pass,
     403             :                 $crate::__make_late_closure!([< $NAME:camel >])
     404             :             );
     405             :             rustc_session::declare_lint_pass!([< $NAME:camel >] => [$NAME]);
     406             :         }
     407             :     };
     408             : }
     409             : 
     410             : /// Reads and deserializes an entry from the workspace's `dylint.toml` file, and returns the default
     411             : /// value if the entry is not present.
     412             : ///
     413             : /// - If the target workspace's `dylint.toml` file contains key `name` and its value can be
     414             : ///   deserializes as `T`, `config_or_default` returns the deserialized value.
     415             : /// - If the target workspace's `dylint.toml` file does not exist or does not contain key `name`,
     416             : ///   `config_or_default` returns `T::default()`.
     417             : /// - If an error occurs (e.g., the value cannot be deserialized as `T`), `config_or_default`
     418             : ///   panics.
     419             : ///
     420             : /// Note: `init_config` or `try_init_config` must be called before `config_or_default` is called.
     421             : /// However, the `register_lints` function generated by `impl_late_lint`, etc. includes a call to
     422             : /// `init_config`.
     423           0 : pub fn config_or_default<T: Default + serde::de::DeserializeOwned>(name: &str) -> T {
     424           0 :     config::<T>(name).map_or_else(
     425           0 :         |error| {
     426           0 :             panic!(
     427           0 :                 "Could not parse config as `{}`: {}",
     428           0 :                 type_name::<T>(),
     429           0 :                 error
     430           0 :             )
     431           0 :         },
     432           0 :         Option::unwrap_or_default,
     433           0 :     )
     434           0 : }
     435             : 
     436             : /// Reads and deserializes an entry from the workspace's `dylint.toml` file.
     437             : ///
     438             : /// Returns:
     439             : /// - `Ok(Some(...))` if the target workspace's `dylint.toml` file contains key `name` and its value
     440             : ///   can be deserialized as `T`
     441             : /// - `Ok(None)` if the target workspace's `dylint.toml` file does not exist or does not contain key
     442             : ///   `name`
     443             : /// - `Err(...)` if an error occurs (e.g., the value cannot be deserialized as `T`)
     444             : ///
     445             : /// Note: `init_config` or `try_init_config` must be called before `config` is called. However, the
     446             : /// `register_lints` function generated by `impl_late_lint`, etc. includes a call to `init_config`.
     447           0 : pub fn config<T: serde::de::DeserializeOwned>(name: &str) -> ConfigResult<Option<T>> {
     448           0 :     let toml = config_toml(name)?;
     449           0 :     toml.map(toml::Value::try_into::<T>)
     450           0 :         .transpose()
     451           0 :         .map_err(Into::into)
     452           0 : }
     453             : 
     454             : /// Reads an entry from the workspace's `dylint.toml` file as a raw `toml::Value`.
     455             : ///
     456             : /// Returns:
     457             : /// - `Ok(Some(...))` if the target workspace's `dylint.toml` file contains key `name`
     458             : /// - `Ok(None)` if the target workspace's `dylint.toml` file does not exist or does not contain key
     459             : ///   `name`
     460             : /// - `Err(...)` if an error occurs (e.g., `init_config` was not called)
     461             : ///
     462             : /// Note: `init_config` or `try_init_config` must be called before `config_toml` is called. However,
     463             : /// the `register_lints` function generated by `impl_late_lint`, etc. includes a call to
     464             : /// `init_config`.
     465           0 : pub fn config_toml(name: &str) -> ConfigResult<Option<toml::Value>> {
     466           0 :     let Some(config_table) = config::get() else {
     467           0 :         return Err(ConfigError::other(
     468           0 :             "Config is not initialized; `init_config` should have been called from \
     469           0 :              `register_lints`"
     470           0 :                 .into(),
     471           0 :         ));
     472             :     };
     473           0 :     Ok(config_table.get(name).cloned())
     474           0 : }
     475             : 
     476             : /// A wrapper around `try_init_config`. Calls `rustc_session::early_error` if `try_init_config`
     477             : /// returns an error.
     478             : ///
     479             : /// Note: `init_config` or `try_init_config` must be called before `config_or_default`, `config`, or
     480             : /// `config_toml` is called. However, the `register_lints` function generated by `impl_late_lint`,
     481             : /// etc. includes a call to `init_config`.
     482           0 : pub fn init_config(sess: &rustc_session::Session) {
     483           0 :     try_init_config(sess).unwrap_or_else(|err| {
     484           0 :         let msg = format!("could not read configuration file: {err}");
     485           0 :         early_error(msg);
     486           0 :     });
     487           0 : }
     488             : 
     489             : trait ParseSess {
     490             :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess;
     491             : }
     492             : 
     493             : impl ParseSess for rustc_session::Session {
     494             :     #[rustversion::before(2024-03-05)]
     495             :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess {
     496             :         &self.parse_sess
     497             :     }
     498             : 
     499             :     #[rustversion::since(2024-03-05)]
     500           0 :     fn parse_sess(&self) -> &rustc_session::parse::ParseSess {
     501           0 :         &self.psess
     502           0 :     }
     503             : }
     504             : 
     505             : /// Reads the target workspace's `dylint.toml` file and parses it as a `toml::value::Table`.
     506             : ///
     507             : /// Note: `init_config` or `try_init_config` must be called before `config_or_default`, `config`, or
     508             : /// `config_toml` is called. However, the `register_lints` function generated by `impl_late_lint`,
     509             : /// etc. includes a call to `init_config`.
     510           0 : pub fn try_init_config(sess: &rustc_session::Session) -> ConfigResult<()> {
     511           0 :     let result = try_init_config_guarded(sess);
     512           0 : 
     513           0 :     // smoelius: If we're returning `Ok(())`, ensure that `config::get()` will later return
     514           0 :     // `Some(..)`.
     515           0 :     if result.is_ok() && config::get().is_none() {
     516           0 :         config::init_from_string("").unwrap();
     517           0 :     }
     518             : 
     519           0 :     result
     520           0 : }
     521             : 
     522             : #[allow(clippy::empty_line_after_outer_attr)]
     523             : #[cfg_attr(dylint_lib = "supplementary", allow(commented_code))]
     524           0 : fn try_init_config_guarded(sess: &rustc_session::Session) -> ConfigResult<()> {
     525           0 :     if config::get().is_some() {
     526           0 :         return Ok(());
     527           0 :     }
     528             : 
     529           0 :     if let Ok(value) = std::env::var(env::DYLINT_TOML) {
     530           0 :         config::init_from_string(&value)?;
     531           0 :         sess.parse_sess().env_depinfo.lock().insert((
     532           0 :             Symbol::intern(env::DYLINT_TOML),
     533           0 :             Some(Symbol::intern(&value)),
     534           0 :         ));
     535           0 :         return Ok(());
     536           0 :     }
     537             : 
     538           0 :     let Some(local_crate_source_file) =
     539           0 :         local_crate_source_file(sess).filter(|path| *path != PathBuf::new())
     540             :     else {
     541           0 :         return Ok(());
     542             :     };
     543             : 
     544             :     #[rustfmt::skip]
     545             :     // smoelius: Canonicalizing `local_crate_source_file` causes errors like the following on
     546             :     // Windows:
     547             :     //
     548             :     //   error: could not read configuration file: cargo metadata error: `cargo metadata` exited with an error: error: failed to load manifest for dependency `await_holding_span_guard`
     549             :     //
     550             :     //          Caused by:
     551             :     //            failed to parse manifest at `D:\a\dylint\dylint\examples\general\await_holding_span_guard\Cargo.toml`
     552             :     //
     553             :     //          Caused by:
     554             :     //            error inheriting `clippy_utils` from workspace root manifest's `workspace.dependencies.clippy_utils`
     555             :     //
     556             :     //          Caused by:
     557             :     //            `workspace.dependencies` was not defined
     558             :     //
     559             :     // The issue is that `canonicalize` prepends `\\?\` to the path, and such "verbatim" paths
     560             :     // cause problems for Cargo. See the following GitHub issue for more information:
     561             :     // https://github.com/rust-lang/cargo/issues/9770#issuecomment-993069234
     562             :     //
     563             :     // For reasons that I don't understand, fixing this problem in Cargo would be difficult.
     564             : 
     565             :     /* let local_crate_source_file = local_crate_source_file.canonicalize().map_err(|error| {
     566             :         ConfigErrorInner::Io(
     567             :             format!("Could not canonicalize {local_crate_source_file:?}"),
     568             :             error,
     569             :         )
     570             :     })?; */
     571             : 
     572           0 :     let mut parent = local_crate_source_file
     573           0 :         .parent()
     574           0 :         .ok_or_else(|| ConfigError::other("Could not get parent directory".into()))?;
     575             : 
     576             :     // smoelius: https://users.rust-lang.org/t/pathbuf-equivalent-to-string-is-empty/24823
     577           0 :     if parent.as_os_str().is_empty() {
     578           0 :         parent = Path::new(".");
     579           0 :     };
     580             : 
     581           0 :     let result = cargo_metadata::MetadataCommand::new()
     582           0 :         .current_dir(parent)
     583           0 :         .no_deps()
     584           0 :         .exec();
     585             : 
     586           0 :     match result {
     587           0 :         Err(cargo_metadata::Error::CargoMetadata { stderr })
     588           0 :             if stderr.contains("could not find `Cargo.toml`") => {}
     589             :         _ => {
     590           0 :             let metadata = result?;
     591             : 
     592           0 :             let value = config::try_init_with_metadata(&metadata)?;
     593             : 
     594           0 :             if let Some(s) = &value {
     595           0 :                 sess.parse_sess()
     596           0 :                     .file_depinfo
     597           0 :                     .lock()
     598           0 :                     .insert(Symbol::intern(s));
     599           0 :             }
     600             :         }
     601             :     }
     602             : 
     603           0 :     Ok(())
     604           0 : }
     605             : 
     606             : #[rustversion::before(2023-01-19)]
     607             : fn local_crate_source_file(sess: &rustc_session::Session) -> Option<PathBuf> {
     608             :     sess.local_crate_source_file.clone()
     609             : }
     610             : 
     611             : // smoelius: Relevant PR and merge commit:
     612             : // - https://github.com/rust-lang/rust/pull/106810
     613             : // - https://github.com/rust-lang/rust/commit/65d2f2a5f9c323c88d1068e8e90d0b47a20d491c
     614             : #[rustversion::all(since(2023-01-19), before(2024-03-29))]
     615             : fn local_crate_source_file(sess: &rustc_session::Session) -> Option<PathBuf> {
     616             :     sess.local_crate_source_file()
     617             : }
     618             : 
     619             : // smoelius: Relevant PR and merge commit:
     620             : // - https://github.com/rust-lang/rust/pull/122450
     621             : // - https://github.com/rust-lang/rust/commit/685927aae69657b46323cffbeb0062835bd7fa2b
     622             : #[rustversion::since(2024-03-29)]
     623           0 : fn local_crate_source_file(sess: &rustc_session::Session) -> Option<PathBuf> {
     624             :     use rustc_span::RealFileName;
     625           0 :     sess.local_crate_source_file()
     626           0 :         .and_then(RealFileName::into_local_path)
     627           0 : }
     628             : 
     629             : #[rustversion::before(2023-06-28)]
     630             : fn early_error(msg: String) -> ! {
     631             :     rustc_session::early_error(
     632             :         rustc_session::config::ErrorOutputType::default(),
     633             :         Box::leak(msg.into_boxed_str()) as &str,
     634             :     )
     635             : }
     636             : 
     637             : #[rustversion::since(2023-06-28)]
     638             : extern crate rustc_errors;
     639             : 
     640             : #[rustversion::all(since(2023-06-28), before(2023-12-18))]
     641             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
     642             :     let handler =
     643             :         rustc_session::EarlyErrorHandler::new(rustc_session::config::ErrorOutputType::default());
     644             :     handler.early_error(msg)
     645             : }
     646             : 
     647             : #[rustversion::all(since(2023-12-18), before(2023-12-23))]
     648             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
     649             :     let handler =
     650             :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
     651             :     handler.early_error(msg)
     652             : }
     653             : 
     654             : #[rustversion::all(since(2023-12-23), before(2024-03-05))]
     655             : fn early_error(msg: impl Into<rustc_errors::DiagnosticMessage>) -> ! {
     656             :     let handler =
     657             :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
     658             :     handler.early_fatal(msg)
     659             : }
     660             : 
     661             : #[rustversion::since(2024-03-05)]
     662           0 : fn early_error(msg: impl Into<rustc_errors::DiagMessage>) -> ! {
     663           0 :     let handler =
     664           0 :         rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
     665           0 :     handler.early_fatal(msg)
     666             : }

Generated by: LCOV version 1.14