This crate provides macros for creating Dylint libraries, and utilities for creating configurable libraries.
Contents
dylint_library!declare_late_lint!, declare_early_lint!, declare_pre_expansion_lint!impl_late_lint!, impl_early_lint!, impl_pre_expansion_lint!constituent featuredylint_library!The dylint_library! macro expands to the following:
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[no_mangle]
pub extern "C" fn dylint_version() -> *mut std::os::raw::c_char {
    std::ffi::CString::new($crate::DYLINT_VERSION)
        .unwrap()
        .into_raw()
}
If your library uses the dylint_library! macro and the dylint-link tool, then all you
should have to do is implement the register_lints function. See the examples in this
repository.
declare_late_lint!, etc.If your library contains just one lint, using declare_late_lint!, etc. can make your code more
concise. Each of these macros requires the same arguments as declare_lint!, and wraps the
following:
dylint_library!register_lints functiondeclare_lint!declare_lint_pass!For example, declare_late_lint!(vis NAME, Level, "description") expands to the following:
dylint_linting::dylint_library!();
extern crate rustc_lint;
extern crate rustc_session;
#[no_mangle]
pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
    dylint_linting::init_config(sess);
    lint_store.register_lints(&[NAME]);
    lint_store.register_late_pass(|_| Box::new(Name));
}
rustc_session::declare_lint!(vis NAME, Level, "description");
rustc_session::declare_lint_pass!(Name => [NAME]);
declare_early_lint! and declare_pre_expansion_lint! are defined similarly.
impl_late_lint!, etc.impl_late_lint!, etc. are like declare_late_lint!, etc. except:
impl_lint_pass! instead of declare_lint_pass!;LintPass
structure.That is, impl_late_lint!’s additional argument is what goes here:
    lint_store.register_late_pass(|_| Box::new(...));
                                               ^^^
constituent featureEnabling the package-level constituent feature changes the way the above macros work.
Specifically, it causes them to exclude:
dylint_library!#[no_mangle] just prior to the declaration of register_lintsSuch changes facilitate inclusion of a lint declared with one of the above macros into a larger library. That is:
The general-purpose and supplementary lints in this repository employ this technique.
That is, each general-purpose lint can be built as a library by itself, or as part of the
general library. An analogous statement applies to the supplementary lints and the
supplementary library. The constituent feature is the underlying mechanism that makes this
work.
Libraries can be configured by including a dylint.toml file in the target workspace’s root
directory. This crate provides the following functions for reading and parsing dylint.toml
files:
A configurable library containing just one lint will typically have a lib.rs file of the
following form:
dylint_linting::impl_late_lint! {
    ...,
    LintName::new()
}
// Lint configuration
#[derive(Default, serde::Deserialize)]
struct Config {
    boolean: bool,
    strings: Vec<String>,
}
// Keep a copy of the configuration in the `LintPass` structure.
struct LintName {
    config: Config,
}
// Read the configuration from the `dylint.toml` file, or use the default configuration if
// none is present.
impl LintName {
    pub fn new() -> Self {
        Self {
            config: dylint_linting::config_or_default(env!("CARGO_PKG_NAME")),
        }
    }
}
For a concrete example of a lib.rs file with this form, see the
non_local_effect_before_error_return library in this repository.
A library containing more than one lint must implement the register_lints function without
relying on the above macros. If the library is configurable, then its register_lints function
should include a call to dylint_linting::init_config, as in the following example:
#[no_mangle]
pub fn register_lints(sess: &rustc_session::Session, lint_store: &mut rustc_lint::LintStore) {
    // `init_config` or `try_init_config` must be called before `config_or_default`, `config`,
    // or `config_toml` is called.
    dylint_linting::init_config(sess);
    lint_store.register_lints(&[FIRST_LINT_NAME, SECOND_LINT_NAME]);
    lint_store.register_late_pass(|_| Box::new(LintPassName::new()));
}
Additional documentation on config_or_default, etc. can be found on docs.rs.