Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle branches in anonymous function pattern matching #534

Merged
merged 2 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
*.log

# Build Server Protocol
.bsp/

# SBT specific
target/
project/boot/
Expand Down
15 changes: 14 additions & 1 deletion plugin/src/main/scala/scoverage/ScoveragePlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,20 @@ class ScoverageInstrumentationComponent(

// handle function bodies. This AST node corresponds to the following Scala code: vparams => body
case f: Function =>
treeCopy.Function(tree, f.vparams, process(f.body))
f.body match {
case b: Match =>
// anonymous function bodies with pattern matching needs to account for branches
treeCopy.Function(
tree,
f.vparams,
treeCopy.Match(
b,
b.selector,
transformCases(b.cases, branch = true)
)
)
case _ => treeCopy.Function(tree, f.vparams, process(f.body))
}

case _: Ident => tree

Expand Down
38 changes: 32 additions & 6 deletions plugin/src/test/scala/scoverage/PluginCoverageTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,41 @@ class PluginCoverageTest extends FunSuite with MacroSupport {
assert(!compiler.reporter.hasErrors)
// should instrument:
// the if clause,
// thenp block,
// thenp literal "1",
// elsep block,
// elsep literal "2",
// then block,
// then literal "1",
// else block,
// else literal "2",
// case block "yes" literal
// skip case block "yes" literal
compiler.assertNMeasuredStatements(7)
}

test(
"scoverage should instrument anonymous function with pattern matching body"
) {
val compiler = ScoverageCompiler.default
compiler.compileCodeSnippet(
""" object A {
| def foo(a: List[Option[Int]]) = a.map {
| case Some(value) => value + 1
| case None => 0
| }
|} """.stripMargin
)
assert(!compiler.reporter.hasErrors)
// should instrument:
// the def method entry,
// case Some,
// case block expression
// case none,
// case block literal "0"

// account for canbuildfrom statement
val expectedStatementsCount =
if (ScoverageCompiler.ShortScalaVersion < "2.13") 6 else 5
compiler.assertNMeasuredStatements(expectedStatementsCount)
}

// https://github.com/scoverage/sbt-scoverage/issues/16
test(
"scoverage should instrument for-loops but not the generated scaffolding"
Expand Down Expand Up @@ -246,9 +272,9 @@ class PluginCoverageTest extends FunSuite with MacroSupport {

assert(!compiler.reporter.hasErrors)
assert(!compiler.reporter.hasWarnings)
// should have 4 profiled statements: the outer apply, the true, the a < b, the false
// should have 7 profiled statements: the outer apply, and three pairs of case patterns & blocks
// we are testing that we don't instrument the tuple2 call used here
compiler.assertNMeasuredStatements(4)
compiler.assertNMeasuredStatements(7)
}

test("scoverage should instrument all case statements in an explicit match") {
Expand Down