From 068e41d96e521e1891e24de5258300a0b0ecd3a2 Mon Sep 17 00:00:00 2001 From: Jorge Lee Date: Wed, 8 Feb 2023 23:56:33 -0800 Subject: [PATCH] Handle branches in anonymous function pattern matching (#534) * Handle branches in anonymous function pattern matching * Handle canbuildfrom --- .gitignore | 3 ++ .../scala/scoverage/ScoveragePlugin.scala | 15 +++++++- .../scala/scoverage/PluginCoverageTest.scala | 38 ++++++++++++++++--- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 19961ed1..ad137db7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ *.log +# Build Server Protocol +.bsp/ + # SBT specific target/ project/boot/ diff --git a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala index 3acc83a7..d772e07b 100644 --- a/plugin/src/main/scala/scoverage/ScoveragePlugin.scala +++ b/plugin/src/main/scala/scoverage/ScoveragePlugin.scala @@ -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 diff --git a/plugin/src/test/scala/scoverage/PluginCoverageTest.scala b/plugin/src/test/scala/scoverage/PluginCoverageTest.scala index 609142b0..74ebde3f 100644 --- a/plugin/src/test/scala/scoverage/PluginCoverageTest.scala +++ b/plugin/src/test/scala/scoverage/PluginCoverageTest.scala @@ -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" @@ -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") {