Back to Foundry

Empty block

crates/lint/docs/empty-block.md

1.8.11.8 KB
Original Source

Empty block

Severity: Low ID: empty-block

Flags regular functions whose body is empty, which is dead or unfinished code.

What it does

Reports a function whose body is {} (a comment does not make a body non-empty). This mirrors Aderyn's empty-block detector, restricted to function bodies.

Bodies whose emptiness is the behavior are exempt:

  • constructors: an empty body is how a contract calls base constructors (constructor() Base(1) {}) or is simply made deployable;
  • receive and fallback: the empty body is what accepts plain ether transfers or unknown calls;
  • virtual functions: an empty body is the intentional default of an extension hook meant to be overridden;
  • functions with modifiers: the modifier carries the behavior, as in initialize() external initializer {} or _authorizeUpgrade(address) internal override onlyOwner {};
  • payable functions without return values: an empty body is an intentional ether sink (function deposit() external payable {}). With a return value the body silently returns the default, which reads as an unfinished stub and is reported.

Functions without a body (interface members, abstract declarations) never fire, and an empty modifier body is a solc compile error (2883), so it never reaches the linter. Empty blocks nested inside a non-empty body (if (x) {}) are out of scope.

Why is this bad?

An empty body on a regular function does nothing: either the implementation was forgotten, or the function is dead code that bloats the contract surface and misleads readers and integrators. An empty override can also silently disable behavior a parent contract intended to provide.

Example

Bad

solidity
function withdraw() external {}

Good

solidity
function withdraw() external {
    payable(msg.sender).transfer(address(this).balance);
}