1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
//! Helper crate for creating nag lints.
//!
//! Usage looks like following:
//! ```rust,no_run
//! // Needed to link into rustc
//! #![feature(rustc_private)]
//!
//! extern crate rustc_lint;
//! extern crate rustc_middle;
//! // Not used directly in this example, but needed for `declare_lints!()` to work.
//! extern crate rustc_session;
//!
//! mod my_cool_lint {
//! // This is a lint pass. It holds all the lint logic.
//! pub(super) struct MyCoolLintPass;
//!
//! // This needed for `nag_toolkit` to know how to create your lint pass.
//! impl nag_toolkit::NagLint for MyCoolLintPass {
//! // There's no need to save `tcx`, you'll have access to it later
//! fn new(_tcx: rustc_middle::ty::TyCtxt) -> Self {
//! Self
//! }
//! }
//!
//! // You can choose to implement `EarlyLintPass` instead if you want to.
//! impl<'tcx> rustc_lint::LateLintPass<'tcx> for MyCoolLintPass {
//! // Implement various `check_` methods here.
//! }
//! }
//!
//! nag_toolkit::declare_lints!(
//! // `my_cool_lint` is a name that will be used for `#[allow()]`/`#[deny()]`/etc.
//! (lint: my_cool_lint(Warn, "An example lint."));
//! // specify `early` instead of `late`, if you implemented `EarlyLintPass`
//! (pass: late my_cool_lint::MyCoolLintPass);
//! );
//!
//! # fn main() {
//! // As a result you have a function `register`, which you can pass to `nag_driver`:
//! let _: fn(&rustc_session::Session, &mut rustc_lint::LintStore) = register;
//! // And a `MY_COOL_LINT: Lint` static that can be used inside of lint passes:
//! let _: &rustc_lint::Lint = &MY_COOL_LINT;
//! // It's private by default, but you can put custom visibility before lint name.
//! # }
//! ```
#![feature(rustc_private)]
extern crate rustc_middle;
use rustc_middle::ty::TyCtxt;
#[doc(hidden)]
pub use paste;
/// A lint that can be used with [`declare_lints!()`].
pub trait NagLint {
fn new(tcx: TyCtxt) -> Self;
}
/// Declare lints and lint passes.
///
/// See crate-level documentation for details.
#[macro_export]
macro_rules! declare_lints {
($(($($t:tt)*));*$(;)?) => {
$($crate::declare_lints!(@declare $($t)*);)*
pub fn register(_sess: &::rustc_session::Session, store: &mut ::rustc_lint::LintStore) {
$($crate::declare_lints!(@register store $($t)*);)*
}
};
(@declare lint: $v:vis $name:ident($level:ident, $description:literal)) => {
$crate::paste::paste! {
$v static [< $name:upper >]: ::rustc_lint::Lint = ::rustc_lint::Lint {
name: stringify!($name),
default_level: ::rustc_lint::Level::$level,
desc: $description,
edition_lint_opts: None,
report_in_external_macro: false,
future_incompatible: None,
is_plugin: false,
feature_gate: None,
crate_level_only: false,
};
}
};
(@declare pass: $kind:ident $name:path) => {
impl ::rustc_lint::LintPass for $name {
fn name(&self) -> &'static str {
stringify!($name)
}
}
};
(@register $store:ident lint: $v:vis $name:ident($_level:ident, $_description:literal)) => {
$crate::paste::paste! {
$store.register_lints(&[&[< $name:upper >]]);
}
};
(@register $store:ident pass: $kind:ident $name:path) => {
$crate::paste::paste! {
$store.[< register_ $kind _pass >](
|tcx| Box::new(<$name as $crate::NagLint>::new(tcx))
);
}
};
}