Skip to main content

forge_lint/sol/info/
multi_contract_file.rs

1use crate::{
2    linter::{EarlyLintPass, Lint, LintContext},
3    sol::{Severity, SolLint, info::MultiContractFile},
4};
5
6use solar::ast::{self as ast};
7
8declare_forge_lint!(
9    MULTI_CONTRACT_FILE,
10    Severity::Info,
11    "multi-contract-file",
12    "prefer having only one contract, interface or library per file"
13);
14
15impl<'ast> EarlyLintPass<'ast> for MultiContractFile {
16    fn check_full_source_unit(
17        &mut self,
18        ctx: &LintContext<'ast, '_>,
19        unit: &'ast ast::SourceUnit<'ast>,
20    ) {
21        if !ctx.is_lint_enabled(MULTI_CONTRACT_FILE.id()) {
22            return;
23        }
24
25        // Collect spans of all contract-like items, skipping those that are exempted
26        let relevant_spans: Vec<_> = unit
27            .items
28            .iter()
29            .filter_map(|item| match &item.kind {
30                ast::ItemKind::Contract(c) => {
31                    (!ctx.config.lint_specific.is_exempted(&c.kind)).then_some(c.name.span)
32                }
33                _ => None,
34            })
35            .collect();
36
37        // Flag all if there's more than one
38        if relevant_spans.len() > 1 {
39            relevant_spans.into_iter().for_each(|span| ctx.emit(&MULTI_CONTRACT_FILE, span));
40        }
41    }
42}