forge_lint/sol/macros.rs
1/// Macro for defining lints and relevant metadata for the Solidity linter.
2///
3/// # Parameters
4///
5/// Each lint requires the following input fields:
6/// - `$id`: Identitifier of the generated `SolLint` constant.
7/// - `$severity`: The `Severity` of the lint (e.g. `High`, `Med`, `Low`, `Info`, `Gas`).
8/// - `$str_id`: A unique identifier used to reference a specific lint during configuration.
9/// - `$desc`: A short description of the lint.
10///
11/// # Note
12/// Each lint must have a `help` section in the foundry book. This help field is auto-generated by
13/// the macro. Because of that, to ensure that new lint rules have their corresponding docs in the
14/// book, the existence of the lint rule's help section is validated with a unit test.
15#[macro_export]
16macro_rules! declare_forge_lint {
17 ($id:ident, $severity:expr, $str_id:expr, $desc:expr) => {
18 // Declare the static `Lint` metadata
19 pub static $id: SolLint = SolLint {
20 id: $str_id,
21 severity: $severity,
22 description: $desc,
23 help: concat!("https://book.getfoundry.sh/reference/forge/forge-lint#", $str_id),
24 };
25 };
26
27 ($id:ident, $severity:expr, $str_id:expr, $desc:expr) => {
28 $crate::declare_forge_lint!($id, $severity, $str_id, $desc, "");
29 };
30}
31
32/// Registers Solidity linter passes with their corresponding `SolLint`.
33///
34/// # Parameters
35///
36/// - `$pass_id`: Identitifier of the generated struct that will implement the pass trait.
37/// - (`$lint`): tuple with `SolLint` constants that should be evaluated on every input that pass.
38///
39/// # Outputs
40///
41/// - Structs for each linting pass (which should manually implement `EarlyLintPass`)
42/// - `const REGISTERED_LINTS` containing all registered lint objects
43/// - `const LINT_PASSES` mapping each lint to its corresponding pass
44#[macro_export]
45macro_rules! register_lints {
46 ( $( ($pass_id:ident, ($($lint:expr),+ $(,)?)) ),* $(,)? ) => {
47 // Declare the structs that will implement the pass trait
48 $(
49 #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
50 pub struct $pass_id;
51
52 impl $pass_id {
53 pub fn as_lint_pass<'a>() -> Box<dyn EarlyLintPass<'a>> {
54 Box::new(Self::default())
55 }
56 }
57 )*
58
59 // Expose array constants
60 pub const REGISTERED_LINTS: &[SolLint] = &[$( $($lint,) + )*];
61 pub const LINT_PASSES: &[(SolLint, fn() -> Box<dyn EarlyLintPass<'static>>)] = &[
62 $( $( ($lint, || Box::new($pass_id::default())), )+ )*
63 ];
64
65 // Helper function to create lint passes with the required lifetime
66 pub fn create_lint_passes<'a>() -> Vec<(Box<dyn EarlyLintPass<'a>>, SolLint)>
67 {
68 vec![ $( $(($pass_id::as_lint_pass(), $lint), )+ )* ]
69 }
70 };
71}