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

Backport "Fix the issue with coverage inside of a TypeApply" to LTS #19233

Merged
merged 1 commit into from
Dec 13, 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
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
val InstrumentedParts(pre, coverageCall, expr) = tryInstrument(fun)

if coverageCall.isEmpty then
// `fun` cannot be instrumented, and `args` is a type so we keep this tree as it is
tree
// `fun` cannot be instrumented and `args` is a type, but `expr` may have been transformed
cpy.TypeApply(tree)(expr, args)
else
// expr[T] shouldn't be transformed to:
// {invoked(...), expr}[T]
Expand Down
30 changes: 30 additions & 0 deletions compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import scala.language.unsafeNulls
import scala.collection.mutable.Buffer
import dotty.tools.dotc.util.DiffUtil

import java.util.stream.Collectors

@Category(Array(classOf[BootstrappedOnlyTests]))
class CoverageTests:
import CoverageTests.{*, given}
Expand Down Expand Up @@ -61,6 +63,26 @@ class CoverageTests:
val instructions = FileDiff.diffMessage(expectFile.toString, targetFile.toString)
fail(s"Coverage report differs from expected data.\n$instructions")

// measurement files only exist in the "run" category
// as these are generated at runtime by the scala.runtime.coverage.Invoker
val expectMeasurementFile = path.resolveSibling(s"$fileName.measurement.check")
if run && Files.exists(expectMeasurementFile) then

// Note that this assumes that the test invoked was single threaded,
// if that is not the case then this will have to be adjusted
val targetMeasurementFile = findMeasurementFile(targetDir)

if updateCheckFiles then
Files.copy(targetMeasurementFile, expectMeasurementFile, StandardCopyOption.REPLACE_EXISTING)

else
val targetMeasurementFile = findMeasurementFile(targetDir)
val expectedMeasurements = fixWindowsPaths(Files.readAllLines(expectMeasurementFile).asScala)
val obtainedMeasurements = fixWindowsPaths(Files.readAllLines(targetMeasurementFile).asScala)
if expectedMeasurements != obtainedMeasurements then
val instructions = FileDiff.diffMessage(expectMeasurementFile.toString, targetMeasurementFile.toString)
fail(s"Measurement report differs from expected data.\n$instructions")
()
})

/** Generates the coverage report for the given input file, in a temporary directory. */
Expand All @@ -75,6 +97,14 @@ class CoverageTests:
test.checkCompile()
target

private def findMeasurementFile(targetDir: Path): Path = {
val allFilesInTarget = Files.list(targetDir).collect(Collectors.toList).asScala
allFilesInTarget.filter(_.getFileName.toString.startsWith("scoverage.measurements.")).headOption.getOrElse(
throw new AssertionError(s"Expected to find measurement file in targetDir [${targetDir}] but none were found.")
)
}


object CoverageTests extends ParallelTesting:
import scala.concurrent.duration.*

Expand Down
1 change: 1 addition & 0 deletions tests/coverage/run/type-apply/test.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
List(List(1), List(2), List(3))
7 changes: 7 additions & 0 deletions tests/coverage/run/type-apply/test.measurement.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
6
1
3
2
5
4
0
5 changes: 5 additions & 0 deletions tests/coverage/run/type-apply/test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@main
def Test: Unit =
// verifies a problematic case where the TypeApply instrumentation was added to the coverage file,
// but was never marked as invoked
println(List(1,2,3).map(a => List(a)))
139 changes: 139 additions & 0 deletions tests/coverage/run/type-apply/test.scoverage.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Coverage data, format version: 3.0
# Statement data:
# - id
# - source path
# - package name
# - class name
# - class type (Class, Object or Trait)
# - full class name
# - method name
# - start offset
# - end offset
# - line number
# - symbol name
# - tree name
# - is branch
# - invocations count
# - is ignored
# - description (can be multi-line)
# ' ' sign
# ------------------------------------------
0
type-apply/test.scala
<empty>
test$package$
Object
<empty>.test$package$
Test
163
201
4
println
Apply
false
0
false
println(List(1,2,3).map(a => List(a)))

1
type-apply/test.scala
<empty>
test$package$
Object
<empty>.test$package$
Test
171
200
4
map
Apply
false
0
false
List(1,2,3).map(a => List(a))

2
type-apply/test.scala
<empty>
test$package$
Object
<empty>.test$package$
Test
171
182
4
apply
Apply
false
0
false
List(1,2,3)

3
type-apply/test.scala
<empty>
test$package$
Object
<empty>.test$package$
Test
171
175
4
List
Ident
false
0
false
List

4
type-apply/test.scala
<empty>
test$package$
Object
<empty>.test$package$
$anonfun
192
199
4
apply
Apply
false
0
false
List(a)

5
type-apply/test.scala
<empty>
test$package$
Object
<empty>.test$package$
$anonfun
192
196
4
List
Ident
false
0
false
List

6
type-apply/test.scala
<empty>
test$package$
Object
<empty>.test$package$
Test
0
14
1
Test
DefDef
false
0
false
@main\ndef Test