Skip to main content

forge_lint/sol/info/
multi_contract_file.rs

1use crate::{
2    linter::{EarlyLintPass, Lint, LintContext},
3    sol::{Severity, SolLint},
4};
5use foundry_config::lint::LintSpecificConfig;
6use solar::ast;
7use std::sync::Arc;
8
9declare_forge_lint!(
10    MULTI_CONTRACT_FILE,
11    Severity::Info,
12    "multi-contract-file",
13    "file contains multiple contracts, interfaces or libraries"
14);
15
16#[derive(Debug)]
17pub(super) struct MultiContractFilePass {
18    config: Arc<LintSpecificConfig>,
19}
20
21impl MultiContractFilePass {
22    pub(super) const fn new(config: Arc<LintSpecificConfig>) -> Self {
23        Self { config }
24    }
25}
26
27impl<'ast> EarlyLintPass<'ast> for MultiContractFilePass {
28    fn check_full_source_unit(
29        &mut self,
30        ctx: &LintContext<'ast, '_>,
31        unit: &'ast ast::SourceUnit<'ast>,
32    ) {
33        if !ctx.is_lint_enabled(MULTI_CONTRACT_FILE.id()) {
34            return;
35        }
36        // Every non-exempted contract-like item is flagged when there is more than one.
37        let spans: Vec<_> = unit
38            .items
39            .iter()
40            .filter_map(|item| match &item.kind {
41                ast::ItemKind::Contract(c) if !self.config.is_exempted(&c.kind) => {
42                    Some(c.name.span)
43                }
44                _ => None,
45            })
46            .collect();
47        if spans.len() > 1 {
48            for span in spans {
49                ctx.emit(&MULTI_CONTRACT_FILE, span);
50            }
51        }
52    }
53}