Skip to main content

forge_lint/sol/low/
empty_block.rs

1use super::EmptyBlock;
2use crate::{
3    linter::{EarlyLintPass, LintContext},
4    sol::{Severity, SolLint},
5};
6use solar::ast::{FunctionKind, ItemFunction, StateMutability};
7
8declare_forge_lint!(EMPTY_BLOCK, Severity::Low, "empty-block", "empty function body");
9
10impl<'ast> EarlyLintPass<'ast> for EmptyBlock {
11    fn check_item_function(&mut self, ctx: &LintContext, func: &'ast ItemFunction<'ast>) {
12        // An empty body on a regular function is dead or unfinished code. Bodies whose emptiness
13        // is the behavior are exempt: constructors, receive/fallback (the empty body accepts
14        // calls or ether), `virtual` functions (an empty default meant to be overridden),
15        // functions with modifiers (`initialize() external initializer {}`,
16        // `_authorizeUpgrade(address) internal override onlyOwner {}`: the modifier carries the
17        // behavior) and `payable` functions without return values (an empty ether sink; with a
18        // return value the body silently returns the default, an unfinished stub). Functions
19        // without a body (interfaces, abstract declarations) have nothing to flag, and an empty
20        // modifier body is a solc compile error (2883), so it never reaches the linter.
21        if let Some(body) = &func.body
22            && body.is_empty()
23            && matches!(func.kind, FunctionKind::Function)
24            && func.header.virtual_.is_none()
25            && func.header.modifiers.is_empty()
26            && (func.header.state_mutability() != StateMutability::Payable
27                || func.header.returns.is_some())
28        {
29            ctx.emit(&EMPTY_BLOCK, body.span);
30        }
31    }
32}