Crates.io | dylint_linting |
lib.rs | dylint_linting |
version | 3.1.2 |
source | src |
created_at | 2021-03-25 12:20:18.654917 |
updated_at | 2024-05-15 16:41:09.543235 |
description | Utilities for writing Dylint libraries |
homepage | |
repository | https://github.com/trailofbits/dylint |
max_upload_size | |
id | 373363 |
size | 36,198 |
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_lints
Such 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.