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}