Skip to main content

forge_lint/sol/
macros.rs

1/// Declares the static metadata of a lint.
2///
3/// - `$id`: identifier of the generated `SolLint` constant.
4/// - `$severity`: the `Severity` of the lint.
5/// - `$str_id`: the user-facing lint id used in configuration and diagnostics.
6/// - `$desc`: a short description.
7///
8/// Each lint must have a markdown page at `crates/lint/docs/<str_id>.md`; the `help` URL is
9/// derived from `$str_id` and validated by a unit test in `crates/lint/src/sol/mod.rs`.
10#[macro_export]
11macro_rules! declare_forge_lint {
12    ($id:ident, $severity:expr, $str_id:expr, $desc:expr) => {
13        pub static $id: SolLint = SolLint {
14            id: $str_id,
15            severity: $severity,
16            description: $desc,
17            help: concat!("https://getfoundry.sh/forge/linting/", $str_id),
18        };
19    };
20}
21
22/// Declares the lint modules of a severity group and registers their passes.
23///
24/// Each entry is `module: (PassStruct, early|late|project, (LINT, ...) [, constructor]), ...;`.
25/// The macro glob-imports each module (which the caller declares with `mod`, so that rustfmt
26/// still discovers the files), generates the `PassStruct` marker types,
27/// the `REGISTERED_LINTS` slice and a `register_lints` function that adds every pass to Solar's
28/// registry. A constructor, when given, receives the lint-specific configuration.
29#[macro_export]
30macro_rules! register_lints {
31    (@register $registry:ident, $config:ident, $pass:ident, early $(, $ctor:expr)?) => {
32        register_lints!(@call $registry, $config, $pass, register_early_pass $(, $ctor)?);
33    };
34    (@register $registry:ident, $config:ident, $pass:ident, late $(, $ctor:expr)?) => {
35        register_lints!(@call $registry, $config, $pass, register_late_pass $(, $ctor)?);
36    };
37    (@register $registry:ident, $config:ident, $pass:ident, project $(, $ctor:expr)?) => {
38        register_lints!(@call $registry, $config, $pass, register_project_pass $(, $ctor)?);
39    };
40
41    (@call $registry:ident, $config:ident, $pass:ident, $method:ident, $ctor:expr) => {{
42        let config = std::sync::Arc::clone($config);
43        $registry.$method($pass::LINT_IDS, move || ($ctor)(std::sync::Arc::clone(&config)));
44    }};
45    (@call $registry:ident, $config:ident, $pass:ident, $method:ident) => {
46        $registry.$method($pass::LINT_IDS, $pass::default);
47    };
48
49    ( $( $module:ident: $( ($pass:ident, $kind:ident, ($($lint:ident),* $(,)?) $(, $ctor:expr)?) ),+ $(,)? ; )* ) => {
50        $(
51            use $module::*;
52
53            $(
54                #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
55                pub struct $pass;
56
57                impl $pass {
58                    const LINT_IDS: &'static [&'static str] = &[$($lint.id),*];
59                }
60            )+
61        )*
62
63        pub const REGISTERED_LINTS: &[SolLint] = &[$($($($lint,)*)+)*];
64
65        pub fn register_lints(
66            registry: &mut solar_lint::LintRegistry,
67            config: &std::sync::Arc<foundry_config::lint::LintSpecificConfig>,
68        ) {
69            let _ = config;
70            $($( register_lints!(@register registry, config, $pass, $kind $(, $ctor)?); )+)*
71        }
72    };
73}