From 8466c09c2402030f6d7e73d8490d3987bec847c6 Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Tue, 16 Apr 2024 22:01:27 +0400 Subject: [PATCH] feat: coverage for modifiers (#7669) --- crates/evm/coverage/src/analysis.rs | 34 +++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/crates/evm/coverage/src/analysis.rs b/crates/evm/coverage/src/analysis.rs index fad5b65768d2..040da5a0f4fa 100644 --- a/crates/evm/coverage/src/analysis.rs +++ b/crates/evm/coverage/src/analysis.rs @@ -33,8 +33,14 @@ impl<'a> ContractVisitor<'a> { pub fn visit(mut self, contract_ast: Node) -> eyre::Result { // Find all functions and walk their AST for node in contract_ast.nodes { - if node.node_type == NodeType::FunctionDefinition { - self.visit_function_definition(node.clone())?; + match &node.node_type { + NodeType::FunctionDefinition => { + self.visit_function_definition(node)?; + } + NodeType::ModifierDefinition => { + self.visit_modifier_definition(node)?; + } + _ => {} } } @@ -65,6 +71,23 @@ impl<'a> ContractVisitor<'a> { } } + fn visit_modifier_definition(&mut self, mut node: Node) -> eyre::Result<()> { + let name: String = + node.attribute("name").ok_or_else(|| eyre::eyre!("Modifier has no name"))?; + + match node.body.take() { + Some(body) => { + self.push_item(CoverageItem { + kind: CoverageItemKind::Function { name }, + loc: self.source_location_for(&node.src), + hits: 0, + }); + self.visit_block(*body) + } + _ => Ok(()), + } + } + fn visit_block(&mut self, node: Node) -> eyre::Result<()> { let statements: Vec = node.attribute("statements").unwrap_or_default(); @@ -90,7 +113,6 @@ impl<'a> ContractVisitor<'a> { NodeType::Break | NodeType::Continue | NodeType::EmitStatement | - NodeType::PlaceholderStatement | NodeType::RevertStatement | NodeType::YulAssignment | NodeType::YulBreak | @@ -104,6 +126,9 @@ impl<'a> ContractVisitor<'a> { Ok(()) } + // Skip placeholder statements as they are never referenced in source maps. + NodeType::PlaceholderStatement => Ok(()), + // Return with eventual subcall NodeType::Return => { self.push_item(CoverageItem { @@ -338,12 +363,13 @@ impl<'a> ContractVisitor<'a> { NodeType::ForStatement | NodeType::IfStatement | NodeType::InlineAssembly | - NodeType::PlaceholderStatement | NodeType::Return | NodeType::RevertStatement | NodeType::TryStatement | NodeType::VariableDeclarationStatement | NodeType::WhileStatement => self.visit_statement(node), + // Skip placeholder statements as they are never referenced in source maps. + NodeType::PlaceholderStatement => Ok(()), _ => { warn!("unexpected node type, expected block or statement: {:?}", node.node_type); Ok(())