Skip to content

Commit 168b239

Browse files
authored
fix(coverage): special functions have no name (#9441)
* fix(coverage): special functions have no name * test: don't to_string * test: rm --summary which is not --report=summary * test: add regression test for #9437 * fmt * docs
1 parent ac81a53 commit 168b239

File tree

7 files changed

+202
-124
lines changed

7 files changed

+202
-124
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/evm/coverage/src/analysis.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,20 @@ impl<'a> ContractVisitor<'a> {
5252
fn visit_function_definition(&mut self, node: &Node) -> eyre::Result<()> {
5353
let Some(body) = &node.body else { return Ok(()) };
5454

55-
let kind: String =
56-
node.attribute("kind").ok_or_else(|| eyre::eyre!("Function has no kind"))?;
57-
5855
let name: String =
5956
node.attribute("name").ok_or_else(|| eyre::eyre!("Function has no name"))?;
57+
let kind: String =
58+
node.attribute("kind").ok_or_else(|| eyre::eyre!("Function has no kind"))?;
6059

6160
// Do not add coverage item for constructors without statements.
6261
if kind == "constructor" && !has_statements(body) {
6362
return Ok(())
6463
}
64+
65+
// `fallback`, `receive`, and `constructor` functions have an empty `name`.
66+
// Use the `kind` itself as the name.
67+
let name = if name.is_empty() { kind } else { name };
68+
6569
self.push_item_kind(CoverageItemKind::Function { name }, &node.src);
6670
self.visit_block(body)
6771
}
@@ -498,10 +502,7 @@ fn has_statements(node: &Node) -> bool {
498502
NodeType::TryStatement |
499503
NodeType::VariableDeclarationStatement |
500504
NodeType::WhileStatement => true,
501-
_ => {
502-
let statements: Vec<Node> = node.attribute("statements").unwrap_or_default();
503-
!statements.is_empty()
504-
}
505+
_ => node.attribute::<Vec<Node>>("statements").is_some_and(|s| !s.is_empty()),
505506
}
506507
}
507508

crates/forge/bin/cmd/coverage.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,10 @@ impl CoverageArgs {
310310
}
311311
}
312312

313-
// TODO: HTML
314-
#[derive(Clone, Debug, ValueEnum)]
313+
/// Coverage reports to generate.
314+
#[derive(Clone, Debug, Default, ValueEnum)]
315315
pub enum CoverageReportKind {
316+
#[default]
316317
Summary,
317318
Lcov,
318319
Debug,

crates/forge/src/coverage.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,13 @@ impl CoverageReporter for LcovReporter<'_> {
102102

103103
for item in items {
104104
let line = item.loc.lines.start;
105-
let line_end = item.loc.lines.end - 1;
105+
// `lines` is half-open, so we need to subtract 1 to get the last included line.
106+
let end_line = item.loc.lines.end - 1;
106107
let hits = item.hits;
107108
match item.kind {
108109
CoverageItemKind::Function { ref name } => {
109110
let name = format!("{}.{name}", item.loc.contract_name);
110-
writeln!(self.out, "FN:{line},{line_end},{name}")?;
111+
writeln!(self.out, "FN:{line},{end_line},{name}")?;
111112
writeln!(self.out, "FNDA:{hits},{name}")?;
112113
}
113114
CoverageItemKind::Line => {

0 commit comments

Comments
 (0)