Skip to content

Commit 040be03

Browse files
authored
fix(coverage): exclude only virtual fns without impl (#12216)
1 parent 1cdc7e0 commit 040be03

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

crates/evm/coverage/src/analysis.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,15 @@ impl<'ast> ast::Visit<'ast> for SourceVisitor<'_> {
218218
}
219219
});
220220

221-
self.push_item_kind(CoverageItemKind::Function { name: name.into() }, item.span);
221+
// Exclude function from coverage report if it is virtual without implementation.
222+
let exclude_func = func.header.virtual_() && !func.is_implemented();
223+
if !exclude_func {
224+
self.push_item_kind(
225+
CoverageItemKind::Function { name: name.into() },
226+
item.span,
227+
);
228+
}
229+
222230
self.walk_item(item)?;
223231
}
224232
_ => {}
@@ -456,7 +464,7 @@ impl SourceAnalysis {
456464
/// Analyzes contracts in the sources held by the source analyzer.
457465
///
458466
/// Coverage items are found by:
459-
/// - Walking the AST of each contract (except interfaces and abstract contracts)
467+
/// - Walking the AST of each contract (except interfaces)
460468
/// - Recording the items of each contract
461469
///
462470
/// Each coverage item contains relevant information to find opcodes corresponding to them: the
@@ -483,9 +491,8 @@ impl SourceAnalysis {
483491
// Visit only top-level contracts.
484492
let ItemKind::Contract(contract) = &item.kind else { continue };
485493

486-
// Skip interfaces and abstract contracts which have no function
487-
// implementations.
488-
if contract.kind.is_interface() || contract.kind.is_abstract_contract() {
494+
// Skip interfaces which have no function implementations.
495+
if contract.kind.is_interface() {
489496
continue;
490497
}
491498

crates/forge/tests/cli/coverage.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,6 +2147,10 @@ interface ContractIf {
21472147
21482148
abstract contract AbstractCounter {
21492149
function _setNumber(uint256 newNumber) internal virtual;
2150+
2151+
function _incrementNumber(uint256 newNumber) internal virtual returns (uint256 inc) {
2152+
inc = newNumber + 1;
2153+
}
21502154
}
21512155
21522156
contract Counter is AbstractCounter, ContractIf {
@@ -2157,7 +2161,11 @@ contract Counter is AbstractCounter, ContractIf {
21572161
}
21582162
21592163
function _setNumber(uint256 newNumber) internal override {
2160-
number = newNumber;
2164+
number = _incrementNumber(newNumber);
2165+
}
2166+
2167+
function _incrementNumber(uint256 newNumber) internal override returns (uint256 inc) {
2168+
inc = super._incrementNumber(newNumber);
21612169
}
21622170
}
21632171
"#,
@@ -2177,14 +2185,18 @@ contract CounterTest is DSTest {
21772185
"#,
21782186
);
21792187

2188+
// Test there are 4 functions reported:
2189+
// - `setNumber`, `_setNumber` and `_incrementNumber` from `Counter` contract
2190+
// - `_incrementNumber` from `AbstractCounter` (virtual with implementation). `_setNumber` is
2191+
// excluded as it is not implemented.
21802192
cmd.arg("coverage").assert_success().stdout_eq(str![[r#"
21812193
...
21822194
╭-----------------+---------------+---------------+---------------+---------------╮
21832195
| File | % Lines | % Statements | % Branches | % Funcs |
21842196
+=================================================================================+
2185-
| src/Counter.sol | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |
2197+
| src/Counter.sol | 100.00% (8/8) | 100.00% (4/4) | 100.00% (0/0) | 100.00% (4/4) |
21862198
|-----------------+---------------+---------------+---------------+---------------|
2187-
| Total | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |
2199+
| Total | 100.00% (8/8) | 100.00% (4/4) | 100.00% (0/0) | 100.00% (4/4) |
21882200
╰-----------------+---------------+---------------+---------------+---------------╯
21892201
...
21902202
"#]]);

0 commit comments

Comments
 (0)