From 28bc87eedf02f1353fbb0688880c6edbae661fc1 Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Fri, 4 Mar 2022 15:08:39 +0100 Subject: [PATCH 01/15] Add in initial support for code coverage. Co-Authored-By: Quentin Jaquier --- compiler/src/dotty/tools/dotc/Compiler.scala | 1 + .../tools/dotc/config/ScalaSettings.scala | 3 + .../dotty/tools/dotc/core/Definitions.scala | 3 + .../dotty/tools/dotc/coverage/Coverage.scala | 30 + .../dotty/tools/dotc/coverage/Location.scala | 38 + .../tools/dotc/coverage/Serializer.scala | 83 + .../transform/CoverageTransformMacro.scala | 204 ++ .../dotty/tools/dotc/typer/EtaExpansion.scala | 24 + .../tools/dotc/coverage/CoverageTests.scala | 75 + library/src/scala/runtime/Invoker.scala | 74 + project/Build.scala | 6 +- tests/coverage/expect/ContextFunctions.scala | 30 + tests/coverage/expect/Enum.scala | 42 + .../coverage/expect/MultiversalEquality.scala | 31 + .../coverage/expect/ParameterUntupling.scala | 19 + tests/coverage/expect/PatternMatching.scala | 87 + tests/coverage/expect/StructuralTypes.scala | 29 + tests/coverage/expect/TraitParams.scala | 22 + tests/coverage/expect/TypeLambdas.scala | 19 + tests/coverage/expect/UnionTypes.scala | 44 + tests/coverage/scoverage.coverage.expect | 3030 +++++++++++++++++ 21 files changed, 3892 insertions(+), 2 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/coverage/Coverage.scala create mode 100644 compiler/src/dotty/tools/dotc/coverage/Location.scala create mode 100644 compiler/src/dotty/tools/dotc/coverage/Serializer.scala create mode 100644 compiler/src/dotty/tools/dotc/transform/CoverageTransformMacro.scala create mode 100644 compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala create mode 100644 library/src/scala/runtime/Invoker.scala create mode 100644 tests/coverage/expect/ContextFunctions.scala create mode 100644 tests/coverage/expect/Enum.scala create mode 100644 tests/coverage/expect/MultiversalEquality.scala create mode 100644 tests/coverage/expect/ParameterUntupling.scala create mode 100644 tests/coverage/expect/PatternMatching.scala create mode 100644 tests/coverage/expect/StructuralTypes.scala create mode 100644 tests/coverage/expect/TraitParams.scala create mode 100644 tests/coverage/expect/TypeLambdas.scala create mode 100644 tests/coverage/expect/UnionTypes.scala create mode 100644 tests/coverage/scoverage.coverage.expect diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 44e28bcdd446..1c11267641fd 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -46,6 +46,7 @@ class Compiler { List(new sjs.PrepJSInterop) :: // Additional checks and transformations for Scala.js (Scala.js only) List(new sbt.ExtractAPI) :: // Sends a representation of the API of classes to sbt via callbacks List(new SetRootTree) :: // Set the `rootTreeOrProvider` on class symbols + List(new CoverageTransformMacro) :: // Perform instrumentation for coverage transform (if -coverage is present) Nil /** Phases dealing with TASTY tree pickling and unpickling */ diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 8b163acb1fa9..10e9876db20f 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -116,6 +116,9 @@ trait CommonScalaSettings: val explainTypes: Setting[Boolean] = BooleanSetting("-explain-types", "Explain type errors in more detail (deprecated, use -explain instead).", aliases = List("--explain-types", "-explaintypes")) val unchecked: Setting[Boolean] = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked")) val language: Setting[List[String]] = MultiStringSetting("-language", "feature", "Enable one or more language features.", aliases = List("--language")) + /* Coverage settings */ + val coverageOutputDir = PathSetting("-coverage", "Destination for coverage classfiles and instrumentation data.", "") + val coverageSourceroot = PathSetting("-coverage-sourceroot", "An alternative root dir of your sources used to relativize.", ".") /* Other settings */ val encoding: Setting[String] = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding, aliases = List("--encoding")) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index dc672690702c..b769c4251135 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -13,6 +13,7 @@ import typer.ImportInfo.RootRef import Comments.CommentsContext import Comments.Comment import util.Spans.NoSpan +import Symbols.requiredModuleRef import scala.annotation.tailrec @@ -460,6 +461,8 @@ class Definitions { } def NullType: TypeRef = NullClass.typeRef + @tu lazy val InvokerModuleRef = requiredMethodRef("scala.runtime.Invoker") + @tu lazy val ImplicitScrutineeTypeSym = newPermanentSymbol(ScalaPackageClass, tpnme.IMPLICITkw, EmptyFlags, TypeBounds.empty).entered def ImplicitScrutineeTypeRef: TypeRef = ImplicitScrutineeTypeSym.typeRef diff --git a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala new file mode 100644 index 000000000000..b4365e1c4389 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala @@ -0,0 +1,30 @@ +package dotty.tools.dotc +package coverage + +import scala.collection.mutable + +class Coverage { + private val statementsById = mutable.Map[Int, Statement]() + + def statements = statementsById.values + + def addStatement(stmt: Statement): Unit = statementsById.put(stmt.id, stmt) +} + +case class Statement( + source: String, + location: Location, + id: Int, + start: Int, + end: Int, + line: Int, + desc: String, + symbolName: String, + treeName: String, + branch: Boolean, + var count: Int = 0, + ignored: Boolean = false +) { + def invoked(): Unit = count = count + 1 + def isInvoked = count > 0 +} diff --git a/compiler/src/dotty/tools/dotc/coverage/Location.scala b/compiler/src/dotty/tools/dotc/coverage/Location.scala new file mode 100644 index 000000000000..47f712a49da5 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/coverage/Location.scala @@ -0,0 +1,38 @@ +package dotty.tools.dotc +package coverage + +import ast.tpd._ +import dotty.tools.dotc.core.Contexts.Context + +/** @param packageName + * the name of the encosing package + * @param className + * the name of the closes enclosing class + * @param fullClassName + * the fully qualified name of the closest enclosing class + */ +final case class Location( + packageName: String, + className: String, + fullClassName: String, + classType: String, + method: String, + sourcePath: String +) + +object Location { + def apply(tree: Tree)(using ctx: Context): Location = { + + val packageName = ctx.owner.denot.enclosingPackageClass.name.toSimpleName.toString() + val className = ctx.owner.denot.enclosingClass.name.toSimpleName.toString() + + Location( + packageName, + className, + s"$packageName.$className", + "Class" /* TODO refine this further */, + ctx.owner.denot.enclosingMethod.name.toSimpleName.toString(), + ctx.source.file.absolute.toString() + ) + } +} diff --git a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala new file mode 100644 index 000000000000..43fe45774249 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala @@ -0,0 +1,83 @@ +package dotty.tools.dotc +package coverage + +import java.io._ + +import scala.io.Source + +object Serializer { + + val coverageFileName = "scoverage.coverage" + val coverageDataFormatVersion = "3.0" + // Write out coverage data to the given data directory, using the default coverage filename + def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit = + serialize(coverage, coverageFile(dataDir), new File(sourceRoot)) + + // Write out coverage data to given file. + def serialize(coverage: Coverage, file: File, sourceRoot: File): Unit = { + val writer = new BufferedWriter(new FileWriter(file)) + serialize(coverage, writer, sourceRoot) + writer.close() + } + + def serialize(coverage: Coverage, writer: Writer, sourceRoot: File): Unit = { + + def getRelativePath(filePath: String): String = { + val base = sourceRoot.getCanonicalFile().toPath() + val relPath = base.relativize(new File(filePath).getCanonicalFile().toPath()) + relPath.toString + } + + def writeHeader(writer: Writer): Unit = { + writer.write(s"""# Coverage data, format version: $coverageDataFormatVersion + |# 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) + |# '\f' sign + |# ------------------------------------------ + |""".stripMargin) + } + def writeStatement(stmt: Statement, writer: Writer): Unit = { + writer.write(s"""${stmt.id} + |${getRelativePath(stmt.location.sourcePath)} + |${stmt.location.packageName} + |${stmt.location.className} + |${stmt.location.classType} + |${stmt.location.fullClassName} + |${stmt.location.method} + |${stmt.start} + |${stmt.end} + |${stmt.line} + |${stmt.symbolName} + |${stmt.treeName} + |${stmt.branch} + |${stmt.count} + |${stmt.ignored} + |${stmt.desc} + |\f + |""".stripMargin) + } + + writeHeader(writer) + coverage.statements.toVector + .sortBy(_.id) + .foreach(stmt => writeStatement(stmt, writer)) + } + + def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) + def coverageFile(dataDir: String): File = new File(dataDir, coverageFileName) +} diff --git a/compiler/src/dotty/tools/dotc/transform/CoverageTransformMacro.scala b/compiler/src/dotty/tools/dotc/transform/CoverageTransformMacro.scala new file mode 100644 index 000000000000..2d827dd25cac --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/CoverageTransformMacro.scala @@ -0,0 +1,204 @@ +package dotty.tools.dotc +package transform + +import java.io.File +import java.util.concurrent.atomic.AtomicInteger + +import collection.mutable +import core.Flags.JavaDefined +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer +import dotty.tools.dotc.coverage.Coverage +import dotty.tools.dotc.coverage.Statement +import dotty.tools.dotc.coverage.Serializer +import dotty.tools.dotc.coverage.Location +import dotty.tools.dotc.core.Symbols.defn +import dotty.tools.dotc.core.Symbols.Symbol +import dotty.tools.dotc.core.Decorators.toTermName +import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.core.Constants.Constant +import dotty.tools.dotc.typer.LiftCoverage + +import scala.quoted + +/** Phase that implements code coverage, executed when the "-coverage + * OUTPUT_PATH" is added to the compilation. + */ +class CoverageTransformMacro extends MacroTransform with IdentityDenotTransformer { + import ast.tpd._ + + override def phaseName = "coverage" + + // Atomic counter used for assignation of IDs to difference statements + val statementId = new AtomicInteger(0) + + var outputPath = "" + + // Main class used to store all instrumented statements + val coverage = new Coverage + + override def run(using ctx: Context): Unit = { + + if (ctx.settings.coverageOutputDir.value.nonEmpty) { + outputPath = ctx.settings.coverageOutputDir.value + + // Ensure the dir exists + val dataDir = new File(outputPath) + val newlyCreated = dataDir.mkdirs() + + if (!newlyCreated) { + // If the directory existed before, let's clean it up. + dataDir.listFiles + .filter(_.getName.startsWith("scoverage")) + .foreach(_.delete) + } + + super.run + + + Serializer.serialize(coverage, outputPath, ctx.settings.coverageSourceroot.value) + } + } + + protected def newTransformer(using Context): Transformer = + new CoverageTransormer + + class CoverageTransormer extends Transformer { + var instrumented = false + + override def transform(tree: Tree)(using Context): Tree = { + tree match { + case tree: If => + cpy.If(tree)( + cond = transform(tree.cond), + thenp = instrument(transform(tree.thenp), branch = true), + elsep = instrument(transform(tree.elsep), branch = true) + ) + case tree: Try => + cpy.Try(tree)( + expr = instrument(transform(tree.expr), branch = true), + cases = instrumentCasees(tree.cases), + finalizer = instrument(transform(tree.finalizer), true) + ) + case Apply(fun, _) + if ( + fun.symbol.exists && + fun.symbol.isInstanceOf[Symbol] && + fun.symbol == defn.Boolean_&& || fun.symbol == defn.Boolean_|| + ) => + super.transform(tree) + case tree @ Apply(fun, args) if (fun.isInstanceOf[Apply]) => + // We have nested apply, we have to lift all arguments + // Example: def T(x:Int)(y:Int) + // T(f())(1) // should not be changed to {val $x = f(); T($x)}(1) but to {val $x = f(); val $y = 1; T($x)($y)} + liftApply(tree) + case tree: Apply => + if (LiftCoverage.needsLift(tree)) { + liftApply(tree) + } else { + super.transform(tree) + } + case Select(qual, _) if (qual.symbol.exists && qual.symbol.is(JavaDefined)) => + //Java class can't be used as a value, we can't instrument the + //qualifier ({;System}.xyz() is not possible !) instrument it + //as it is + instrument(tree) + case tree: Select => + if (tree.qualifier.isInstanceOf[New]) { + instrument(tree) + } else { + cpy.Select(tree)(transform(tree.qualifier), tree.name) + } + case tree: CaseDef => instrumentCaseDef(tree) + + case tree: Literal => instrument(tree) + case tree: Ident if (isWildcardArg(tree)) => + // We don't want to instrument wildcard arguments. `var a = _` can't be instrumented + tree + case tree: New => instrument(tree) + case tree: This => instrument(tree) + case tree: Super => instrument(tree) + case tree: PackageDef => + // We don't instrument the pid of the package, but we do instrument the statements + cpy.PackageDef(tree)(tree.pid, transform(tree.stats)) + case tree: Assign => cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) + case tree: Template => + // Don't instrument the parents (extends) of a template since it + // causes problems if the parent constructor takes parameters + cpy.Template(tree)( + constr = super.transformSub(tree.constr), + body = transform(tree.body) + ) + case tree: Import => tree + // Catch EmptyTree since we can't match directly on it + case tree: Thicket if tree.isEmpty => tree + // For everything else just recurse and transform + case _ => + report.warning( + "Unmatched: " + tree.getClass + " " + tree.symbol, + tree.sourcePos + ) + super.transform(tree) + } + } + + def liftApply(tree: Apply)(using Context) = { + val buffer = mutable.ListBuffer[Tree]() + // NOTE: that if only one arg needs to be lifted, we just lift everything + val lifted = LiftCoverage.liftForCoverage(buffer, tree) + val instrumented = buffer.toList.map(transform) + //We can now instrument the apply as it is with a custom position to point to the function + Block( + instrumented, + instrument( + lifted, + tree.sourcePos, + false + ) + ) + } + + def instrumentCasees(cases: List[CaseDef])(using Context): List[CaseDef] = { + cases.map(instrumentCaseDef) + } + + def instrumentCaseDef(tree: CaseDef)(using Context): CaseDef = { + cpy.CaseDef(tree)(tree.pat, transform(tree.guard), transform(tree.body)) + } + + def instrument(tree: Tree, branch: Boolean = false)(using Context): Tree = { + instrument(tree, tree.sourcePos, branch) + } + + def instrument(tree: Tree, pos: SourcePosition, branch: Boolean)(using ctx: Context): Tree = { + if (pos.exists && !pos.span.isZeroExtent && !tree.isType) { + val id = statementId.incrementAndGet() + val statement = new Statement( + source = ctx.source.file.name, + location = Location(tree), + id = id, + start = pos.start, + end = pos.end, + line = ctx.source.offsetToLine(pos.point), + desc = tree.source.content.slice(pos.start, pos.end).mkString, + symbolName = tree.symbol.name.toSimpleName.toString(), + treeName = tree.getClass.getSimpleName, + branch + ) + coverage.addStatement(statement) + Block(List(invokeCall(id)), tree) + } else { + tree + } + } + + def invokeCall(id: Int)(using Context): Tree = { + ref(defn.InvokerModuleRef) + .select("invoked".toTermName) + .appliedToArgs( + List(Literal(Constant(id)), Literal(Constant(outputPath))) + ) + } + } + +} diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index c0c6ede200ed..ab36dd0395df 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -155,6 +155,30 @@ class LiftComplex extends Lifter { } object LiftComplex extends LiftComplex +/** Lift complex + lift the prefixes */ +object LiftCoverage extends LiftComplex { + + var liftEverything = false + + /** Return true if the apply needs a lift in the coverage phase + Return false if the args are empty, if one or more will be lifter by a + complex lifter. + */ + def needsLift(tree: tpd.Apply)(using Context): Boolean = + !tree.args.isEmpty && !tree.args.forall(super.noLift(_)) + + override def noLift(expr: tpd.Tree)(using Context) = + !liftEverything && super.noLift(expr) + + def liftForCoverage(defs: mutable.ListBuffer[tpd.Tree], tree: tpd.Apply)(using Context) = { + val liftedFun = liftApp(defs, tree.fun) + liftEverything = true + val liftedArgs = liftArgs(defs, tree.fun.tpe, tree.args) + liftEverything = false + tpd.cpy.Apply(tree)(liftedFun, liftedArgs) + } +} + object LiftErased extends LiftComplex: override def isErased = true diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala new file mode 100644 index 000000000000..9dde3b9e8221 --- /dev/null +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -0,0 +1,75 @@ +package dotty.tools.dotc.coverage + +import java.util.stream.Collectors +import org.junit.Assert._ +import dotty.BootstrappedOnlyTests +import org.junit.experimental.categories.Category +import org.junit.Test +import java.nio.file.Files +import dotty.tools.dotc.Main +import scala.jdk.CollectionConverters._ + +import java.io.File +import java.nio.file.Path +import java.nio.file.FileSystems +import java.nio.file.Paths +import java.nio.charset.StandardCharsets +import scala.io.Source +import java.io.BufferedOutputStream +import java.io.FileOutputStream + +@main def updateExpect = + CoverageTests().runExpectTest(updateExpectFiles = true) + +@Category(Array(classOf[BootstrappedOnlyTests])) +class CoverageTests { + + val scalaFile = FileSystems.getDefault.getPathMatcher("glob:**.scala") + val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.coverage.test")) + val expectSrc = rootSrc.resolve("expect") + + @Category(Array(classOf[dotty.SlowTests])) + @Test def expectTests: Unit = + if (!scala.util.Properties.isWin) runExpectTest(updateExpectFiles = false) + + def runExpectTest(updateExpectFiles: Boolean): Unit = { + val target = generateCoverage(updateExpectFiles) + val input = Source.fromFile(new File(target.toString, "scoverage.coverage")) + val expectFile = new File(expectSrc.resolveSibling("scoverage.coverage.expect").toUri) + + if (updateExpectFiles) { + val outputStream = new BufferedOutputStream(new FileOutputStream(expectFile)) + try { + input.foreach(outputStream.write(_)) + } finally outputStream.close + } else { + val expected = new String(Files.readAllBytes(expectFile.toPath), StandardCharsets.UTF_8) + val obtained = input.mkString + + assertEquals(expected, obtained) + } + } + + def inputFiles(): List[Path] = { + val ls = Files.walk(expectSrc) + val files = + try ls.filter(p => scalaFile.matches(p)).collect(Collectors.toList).asScala + finally ls.close() + + files.toList + } + + def generateCoverage(updateExpectFiles: Boolean): Path = { + val target = Files.createTempDirectory("coverage") + val args = Array( + "-coverage", + target.toString, + "-coverage-sourceroot", + if (updateExpectFiles) "../" else ".", + "-usejavacp" + ) ++ inputFiles().map(_.toString) + val exit = Main.process(args) + assertFalse(s"dotc errors: ${exit.errorCount}", exit.hasErrors) + target + } +} diff --git a/library/src/scala/runtime/Invoker.scala b/library/src/scala/runtime/Invoker.scala new file mode 100644 index 000000000000..6a22427cbd18 --- /dev/null +++ b/library/src/scala/runtime/Invoker.scala @@ -0,0 +1,74 @@ +package scala.runtime + +import scala.collection.mutable +import java.nio.file.Path +import scala.collection.concurrent.TrieMap +import java.nio.file.Paths +import java.nio.file.Files +import java.nio.file.StandardOpenOption +import java.io.FileWriter +import java.io.File + +object Invoker { + private val runtimeUUID = java.util.UUID.randomUUID() + + private val MeasurementsPrefix = "scoverage.measurements." + private val threadFiles = new ThreadLocal[mutable.HashMap[String, FileWriter]] + + // For each data directory we maintain a thread-safe set tracking the ids + // that we've already seen and recorded. We're using a map as a set, so we + // only care about its keys and can ignore its values. + private val dataDirToIds = TrieMap.empty[String, TrieMap[Int, Any]] + + /** We record that the given id has been invoked by appending its id to the coverage data file. + * + * This will happen concurrently on as many threads as the application is using, so we use one + * file per thread, named for the thread id. + * + * This method is not thread-safe if the threads are in different JVMs, because the thread IDs + * may collide. You may not use `scoverage` on multiple processes in parallel without risking + * corruption of the measurement file. + * + * @param id + * the id of the statement that was invoked + * @param dataDir + * the directory where the measurement data is held + */ + def invoked(id: Int, dataDir: String): Unit = { + // [sam] we can do this simple check to save writing out to a file. + // This won't work across JVMs but since there's no harm in writing out the same id multiple + // times since for coverage we only care about 1 or more, (it just slows things down to + // do it more than once), anything we can do to help is good. This helps especially with code + // that is executed many times quickly, eg tight loops. + if (!dataDirToIds.contains(dataDir)) { + // Guard against SI-7943: "TrieMap method getOrElseUpdate is not thread-safe". + dataDirToIds.synchronized { + if (!dataDirToIds.contains(dataDir)) { + dataDirToIds(dataDir) = TrieMap.empty[Int, Any] + } + } + } + val ids = dataDirToIds(dataDir) + if (!ids.contains(id)) { + // Each thread writes to a separate measurement file, to reduce contention + // and because file appends via FileWriter are not atomic on Windows. + var files = threadFiles.get() + if (files == null) { + files = mutable.HashMap.empty[String, FileWriter] + threadFiles.set(files) + } + val writer = files.getOrElseUpdate( + dataDir, + new FileWriter(measurementFile(dataDir), true) + ) + + writer.append(Integer.toString(id)).append("\n").flush() + ids.put(id, ()) + } + } + + def measurementFile(dataDir: String): File = new File( + dataDir, + MeasurementsPrefix + runtimeUUID + "." + Thread.currentThread.getId + ) +} diff --git a/project/Build.scala b/project/Build.scala index 3a4480dd84e3..05cb63ef80be 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -572,8 +572,10 @@ object Build { ) }, - javaOptions += ( - s"-Ddotty.tools.dotc.semanticdb.test=${(ThisBuild / baseDirectory).value/"tests"/"semanticdb"}" + javaOptions ++= Seq( + s"-Ddotty.tools.dotc.semanticdb.test=${(ThisBuild / baseDirectory).value/"tests"/"semanticdb"}", + s"-Ddotty.tools.dotc.coverage.test=${(ThisBuild / baseDirectory).value/"tests"/"coverage"}", + ), testCompilation := Def.inputTaskDyn { diff --git a/tests/coverage/expect/ContextFunctions.scala b/tests/coverage/expect/ContextFunctions.scala new file mode 100644 index 000000000000..e1338b1a1f75 --- /dev/null +++ b/tests/coverage/expect/ContextFunctions.scala @@ -0,0 +1,30 @@ +package example + +/** + * Intersection Types: https://dotty.epfl.ch/docs/reference/new-types/intersection-types.html + * Taken from https://github.com/scala/scala3-example-project + */ +object IntersectionTypes: + + sealed trait X: + def x: Double + def tpe: X + + sealed trait Y: + def y: Double + def tpe: Y + + type P = Y & X + type PP = X & Y + + final case class Point(x: Double, y: Double) extends X with Y: + override def tpe: X & Y = ??? + + def test(): Unit = + def euclideanDistance(p1: X & Y, p2: X & Y) = + Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) + + val p1: P = Point(3, 4) + val p2: PP = Point(6, 8) + println(euclideanDistance(p1, p2)) + diff --git a/tests/coverage/expect/Enum.scala b/tests/coverage/expect/Enum.scala new file mode 100644 index 000000000000..6f99daae5240 --- /dev/null +++ b/tests/coverage/expect/Enum.scala @@ -0,0 +1,42 @@ +package example + +/** + * Enum Types: https://dotty.epfl.ch/docs/reference/enums/adts.html + * Taken from https://github.com/scala/scala3-example-project + */ +object EnumTypes: + + enum ListEnum[+A]: + case Cons(h: A, t: ListEnum[A]) + case Empty + + + enum Planet(mass: Double, radius: Double): + private final val G = 6.67300E-11 + def surfaceGravity = G * mass / (radius * radius) + def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity + + case Mercury extends Planet(3.303e+23, 2.4397e6) + case Venus extends Planet(4.869e+24, 6.0518e6) + case Earth extends Planet(5.976e+24, 6.37814e6) + case Mars extends Planet(6.421e+23, 3.3972e6) + case Jupiter extends Planet(1.9e+27, 7.1492e7) + case Saturn extends Planet(5.688e+26, 6.0268e7) + case Uranus extends Planet(8.686e+25, 2.5559e7) + case Neptune extends Planet(1.024e+26, 2.4746e7) + end Planet + + def test(): Unit = + val emptyList = ListEnum.Empty + val list = ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) + println("Example 1: \n"+emptyList) + println(s"${list}\n") + + def calculateEarthWeightOnPlanets(earthWeight: Double) = + val mass = earthWeight/Planet.Earth.surfaceGravity + for p <- Planet.values do + println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + + println("Example 2:") + calculateEarthWeightOnPlanets(80) + end test diff --git a/tests/coverage/expect/MultiversalEquality.scala b/tests/coverage/expect/MultiversalEquality.scala new file mode 100644 index 000000000000..ace2fd642c2c --- /dev/null +++ b/tests/coverage/expect/MultiversalEquality.scala @@ -0,0 +1,31 @@ +package example + +import scala.language.strictEquality + +/** + * Multiversal Equality: https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html + * scala.CanEqual definition: https://github.com/lampepfl/dotty/blob/master/library/src/scala/CanEqual.scala + * Taken from https://github.com/scala/scala3-example-project + */ +object MultiversalEquality: + + def test(): Unit = + given CanEqual[Int, String] = CanEqual.derived + println(3 == "3") + + println(3 == 5.1) + + println(List(1, 2) == Vector(1, 2)) + + class A(a: Int) + class B(b: Int) + + val a = A(4) + val b = B(4) + + given CanEqual[A, B] = CanEqual.derived + given CanEqual[B, A] = CanEqual.derived + + println(a != b) + println(b == a) + diff --git a/tests/coverage/expect/ParameterUntupling.scala b/tests/coverage/expect/ParameterUntupling.scala new file mode 100644 index 000000000000..533c4c3f3362 --- /dev/null +++ b/tests/coverage/expect/ParameterUntupling.scala @@ -0,0 +1,19 @@ +package example + +/** + * Parameter Untupling: https://dotty.epfl.ch/docs/reference/other-new-features/parameter-untupling.html + * Taken from https://github.com/scala/scala3-example-project + */ +object ParameterUntupling: + + def test(): Unit = + val xs: List[String] = List("d", "o", "t", "t", "y") + + /** + * Current behaviour in Scala 2.12.2 : + * error: missing parameter type + * Note: The expected type requires a one-argument function accepting a 2-Tuple. + * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` + */ + xs.zipWithIndex.map((s, i) => println(s"$i: $s")) + diff --git a/tests/coverage/expect/PatternMatching.scala b/tests/coverage/expect/PatternMatching.scala new file mode 100644 index 000000000000..e2f0403ef87e --- /dev/null +++ b/tests/coverage/expect/PatternMatching.scala @@ -0,0 +1,87 @@ + +package example + +/** + * Pattern Matching: https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html + * Taken from https://github.com/scala/scala3-example-project + */ +object PatternMatching: + + object booleanPattern: + + object Even: + def unapply(s: String): Boolean = s.length % 2 == 0 + + + object productPattern: + + class Person(name: String, age: Int) extends Product: + // if we not define that, it will give compile error. + // we change the order + def _1 = age + def _2 = name + + // Not used by pattern matching: Product is only used as a marker trait. + def canEqual(that: Any): Boolean = ??? + def productArity: Int = ??? + def productElement(n: Int): Any = ??? + + object Person: + def unapply(a: (String, Int)): Person = Person(a._1, a._2) + + + object seqPattern: + + // adapted from https://danielwestheide.com/blog/the-neophytes-guide-to-scala-part-2-extracting-sequences/ + object Names: + def unapplySeq(name: String): Option[Seq[String]] = + val names = name.trim.split(" ") + if names.size < 2 then None + else Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) + + + object namePattern: + + class Name(val name: String): + def get: String = name + def isEmpty = name.isEmpty + + object Name: + def unapply(s: String): Name = Name(s) + + + def test(): Unit = + import booleanPattern.* + + "even" match + case s @ Even() => println(s"$s has an even number of characters") + case s => println(s"$s has an odd number of characters") + + // https://dotty.epfl.ch/docs/reference/changed-features/vararg-splices.html + def containsConsecutive(list: List[Int]): Boolean = list match + case List(a, b, xs*) => a == b || containsConsecutive(b :: xs.toList) + case Nil | List(_, _*) => false + + println(containsConsecutive(List(1, 2, 3, 4, 5))) + println(containsConsecutive(List(1, 2, 3, 3, 5))) + + import productPattern.* + ("john", 42) match + case Person(n, a) => println(s"name: $n, age: $a") + + import seqPattern.* + + def greet(fullName: String) = fullName match + case Names(lastName, firstName, _*) => "Good morning, " + firstName + " " + lastName + "!" + case _ => "Welcome! Please make sure to fill in your name!" + + println(greet("Alan Turing")) + println(greet("john")) + println(greet("Wolfgang Amadeus Mozart")) + + import namePattern.* + "alice" match + case Name(n) => println(s"name is $n") + case _ => println("empty name") + +end PatternMatching diff --git a/tests/coverage/expect/StructuralTypes.scala b/tests/coverage/expect/StructuralTypes.scala new file mode 100644 index 000000000000..4b2ee1991ce6 --- /dev/null +++ b/tests/coverage/expect/StructuralTypes.scala @@ -0,0 +1,29 @@ +package example + +/** + * Structural Types: https://dotty.epfl.ch/docs/reference/changed-features/structural-types.html + * Taken from https://github.com/scala/scala3-example-project + */ +object StructuralTypes: + + case class Record(elems: (String, Any)*) extends Selectable: + def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2 + + type Person = Record { + val name: String + val age: Int + } + + val person = Record("name" -> "Emma", "age" -> 42, "salary" -> 320L).asInstanceOf[Person] + + val invalidPerson = Record("name" -> "John", "salary" -> 42).asInstanceOf[Person] + + def test(): Unit = + println(person.name) + println(person.age) + + println(invalidPerson.name) + // age field is java.util.NoSuchElementException: None.get + //println(invalidPerson.age) + +end StructuralTypes diff --git a/tests/coverage/expect/TraitParams.scala b/tests/coverage/expect/TraitParams.scala new file mode 100644 index 000000000000..fa98a9b23805 --- /dev/null +++ b/tests/coverage/expect/TraitParams.scala @@ -0,0 +1,22 @@ +package example + +/** + * Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html + * Taken from https://github.com/scala/scala3-example-project + */ +object TraitParams: + + trait Base(val msg: String) + class A extends Base("Hello") + class B extends Base("Dotty!") + + // Union types only exist in Scala 3, so there's no chance that this will accidentally be compiled with Scala 2 + private def printMessages(msgs: (A | B)*) = println(msgs.map(_.msg).mkString(" ")) + + def test(): Unit = + printMessages(new A, new B) + + // Sanity check the classpath: this won't run if the Scala 3 jar is not present. + val x: Int => Int = identity + x(1) + diff --git a/tests/coverage/expect/TypeLambdas.scala b/tests/coverage/expect/TypeLambdas.scala new file mode 100644 index 000000000000..9769869b7805 --- /dev/null +++ b/tests/coverage/expect/TypeLambdas.scala @@ -0,0 +1,19 @@ +package example + +/** + * Type Lambdas: https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html + * Taken from https://github.com/scala/scala3-example-project + */ +object TypeLambdas: + + type M = [X, Y] =>> Map[Y, X] + + type Tuple = [X] =>> (X, X) + + def test(): Unit = + val m: M[String, Int] = Map(1 -> "1") + println(m) + + val tuple: Tuple[String] = ("a", "b") + println(tuple) + diff --git a/tests/coverage/expect/UnionTypes.scala b/tests/coverage/expect/UnionTypes.scala new file mode 100644 index 000000000000..a79d8dd8fca4 --- /dev/null +++ b/tests/coverage/expect/UnionTypes.scala @@ -0,0 +1,44 @@ + +package example + +/** + * Union Types: https://dotty.epfl.ch/docs/reference/new-types/union-types.html + * Taken from https://github.com/scala/scala3-example-project + */ +object UnionTypes: + + sealed trait Division + final case class DivisionByZero(msg: String) extends Division + final case class Success(double: Double) extends Division + + // You can create type aliases for your union types (sum types). + type DivisionResult = DivisionByZero | Success + + sealed trait List[+A] + case object Empty extends List[Nothing] + final case class Cons[+A](h: A, t: List[A]) extends List[A] + + private def safeDivide(a: Double, b: Double): DivisionResult = + if b == 0 then DivisionByZero("DivisionByZeroException") else Success(a / b) + + private def either(division: Division) = division match + case DivisionByZero(m) => Left(m) + case Success(d) => Right(d) + + def test(): Unit = + val divisionResultSuccess: DivisionResult = safeDivide(4, 2) + + // commutative + val divisionResultFailure: Success | DivisionByZero = safeDivide(4, 0) + + // calling `either` function with union typed value. + println(either(divisionResultSuccess)) + + // calling `either` function with union typed value. + println(either(divisionResultFailure)) + + val list: Cons[Int] | Empty.type = Cons(1, Cons(2, Cons(3, Empty))) + val emptyList: Empty.type | Cons[Any] = Empty + println(list) + println(emptyList) + diff --git a/tests/coverage/scoverage.coverage.expect b/tests/coverage/scoverage.coverage.expect new file mode 100644 index 000000000000..93a8107f4c15 --- /dev/null +++ b/tests/coverage/scoverage.coverage.expect @@ -0,0 +1,3030 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +test +276 +279 +9 + +Literal +false +0 +false +"d" + +2 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +test +281 +284 +9 + +Literal +false +0 +false +"o" + +3 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +test +286 +289 +9 + +Literal +false +0 +false +"t" + +4 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +test +291 +294 +9 + +Literal +false +0 +false +"t" + +5 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +test +296 +299 +9 + +Literal +false +0 +false +"y" + +6 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +test +271 +300 +9 +apply +Apply +false +0 +false +List("d", "o", "t", "t", "y") + +7 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +$anonfun +615 +617 +17 + +Literal +false +0 +false +: + +8 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +$anonfun +613 +619 +17 +apply +Apply +false +0 +false +$i: $s + +9 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +$anonfun +611 +620 +17 +s +Apply +false +0 +false +s"$i: $s" + +10 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +$anonfun +603 +621 +17 +println +Apply +false +0 +false +println(s"$i: $s") + +11 +tests/coverage/expect/ParameterUntupling.scala +example +ParameterUntupling$ +Class +example.ParameterUntupling$ +test +573 +622 +17 +map +Apply +false +0 +false +xs.zipWithIndex.map((s, i) => println(s"$i: $s")) + +12 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +450 +451 +13 + +Literal +false +0 +false +3 + +13 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +455 +458 +13 + +Literal +false +0 +false +"3" + +14 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +442 +459 +13 +println +Apply +false +0 +false +println(3 == "3") + +15 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +473 +474 +15 + +Literal +false +0 +false +3 + +16 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +478 +481 +15 + +Literal +false +0 +false +5.1 + +17 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +501 +502 +17 + +Literal +false +0 +false +1 + +18 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +504 +505 +17 + +Literal +false +0 +false +2 + +19 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +496 +506 +17 +apply +Apply +false +0 +false +List(1, 2) + +20 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +517 +518 +17 + +Literal +false +0 +false +1 + +21 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +520 +521 +17 + +Literal +false +0 +false +2 + +22 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +510 +522 +17 +apply +Apply +false +0 +false +Vector(1, 2) + +23 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +496 +522 +17 +== +Apply +false +0 +false +List(1, 2) == Vector(1, 2) + +24 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +488 +523 +17 +println +Apply +false +0 +false +println(List(1, 2) == Vector(1, 2)) + +25 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +578 +579 +22 + +Select +false +0 +false +A + +26 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +580 +581 +22 + +Literal +false +0 +false +4 + +27 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +595 +596 +23 + +Select +false +0 +false +B + +28 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +597 +598 +23 + +Literal +false +0 +false +4 + +29 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +694 +709 +28 +println +Apply +false +0 +false +println(a != b) + +30 +tests/coverage/expect/MultiversalEquality.scala +example +MultiversalEquality$ +Class +example.MultiversalEquality$ +test +714 +729 +29 +println +Apply +false +0 +false +println(b == a) + +31 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +547 +558 +24 +- +Apply +false +0 +false +p2.y - p1.y + +32 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +560 +561 +24 + +Literal +false +0 +false +2 + +33 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +538 +562 +24 +pow +Apply +false +0 +false +Math.pow(p2.y - p1.y, 2) + +34 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +574 +585 +24 +- +Apply +false +0 +false +p2.x - p1.x + +35 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +587 +588 +24 + +Literal +false +0 +false +2 + +36 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +565 +589 +24 +pow +Apply +false +0 +false +Math.pow(p2.x - p1.x, 2) + +37 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +538 +589 +24 ++ +Apply +false +0 +false +Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2) + +38 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +euclideanDistance +528 +590 +24 +sqrt +Apply +false +0 +false +Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) + +39 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +test +614 +615 +26 + +Literal +false +0 +false +3 + +40 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +test +617 +618 +26 + +Literal +false +0 +false +4 + +41 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +test +643 +644 +27 + +Literal +false +0 +false +6 + +42 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +test +646 +647 +27 + +Literal +false +0 +false +8 + +43 +tests/coverage/expect/ContextFunctions.scala +example +IntersectionTypes$ +Class +example.IntersectionTypes$ +test +653 +687 +28 +println +Apply +false +0 +false +println(euclideanDistance(p1, p2)) + +44 +tests/coverage/expect/TypeLambdas.scala +example +TypeLambdas$ +Class +example.TypeLambdas$ +test +310 +311 +13 + +Literal +false +0 +false +1 + +45 +tests/coverage/expect/TypeLambdas.scala +example +TypeLambdas$ +Class +example.TypeLambdas$ +test +315 +318 +13 + +Literal +false +0 +false +"1" + +46 +tests/coverage/expect/TypeLambdas.scala +example +TypeLambdas$ +Class +example.TypeLambdas$ +test +306 +319 +13 +apply +Apply +false +0 +false +Map(1 -> "1") + +47 +tests/coverage/expect/TypeLambdas.scala +example +TypeLambdas$ +Class +example.TypeLambdas$ +test +368 +371 +16 + +Literal +false +0 +false +"a" + +48 +tests/coverage/expect/TypeLambdas.scala +example +TypeLambdas$ +Class +example.TypeLambdas$ +test +373 +376 +16 + +Literal +false +0 +false +"b" + +49 +tests/coverage/expect/StructuralTypes.scala +example +Record +Class +example.Record +selectDynamic +319 +343 +9 +find +Apply +false +0 +false +elems.find(_._1 == name) + +50 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +442 +448 +16 + +Literal +false +0 +false +"name" + +51 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +452 +458 +16 + +Literal +false +0 +false +"Emma" + +52 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +460 +465 +16 + +Literal +false +0 +false +"age" + +53 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +469 +471 +16 + +Literal +false +0 +false +42 + +54 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +473 +481 +16 + +Literal +false +0 +false +"salary" + +55 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +485 +489 +16 + +Literal +false +0 +false +320L + +56 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +435 +490 +16 +apply +Apply +false +0 +false +Record("name" -> "Emma", "age" -> 42, "salary" -> 320L) + +57 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +542 +548 +18 + +Literal +false +0 +false +"name" + +58 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +552 +558 +18 + +Literal +false +0 +false +"John" + +59 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +560 +568 +18 + +Literal +false +0 +false +"salary" + +60 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +572 +574 +18 + +Literal +false +0 +false +42 + +61 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ + +535 +575 +18 +apply +Apply +false +0 +false +Record("name" -> "John", "salary" -> 42) + +62 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ +test +623 +643 +21 +println +Apply +false +0 +false +println(person.name) + +63 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ +test +648 +667 +22 +println +Apply +false +0 +false +println(person.age) + +64 +tests/coverage/expect/StructuralTypes.scala +example +StructuralTypes$ +Class +example.StructuralTypes$ +test +673 +700 +24 +println +Apply +false +0 +false +println(invalidPerson.name) + +65 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +safeDivide +663 +664 +21 + +Literal +false +0 +false +0 + +66 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +safeDivide +685 +710 +21 + +Literal +false +0 +false +"DivisionByZeroException" + +67 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +safeDivide +670 +711 +21 +apply +Apply +true +0 +false +DivisionByZero("DivisionByZeroException") + +68 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +safeDivide +717 +731 +21 +apply +Apply +false +0 +false +Success(a / b) + +69 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +safeDivide +717 +731 +21 + +Block +true +0 +false +Success(a / b) + +70 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +949 +950 +28 + +Literal +false +0 +false +4 + +71 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +952 +953 +28 + +Literal +false +0 +false +2 + +72 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1044 +1045 +31 + +Literal +false +0 +false +4 + +73 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1047 +1048 +31 + +Literal +false +0 +false +0 + +74 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1112 +1150 +34 +println +Apply +false +0 +false +println(either(divisionResultSuccess)) + +75 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1213 +1251 +37 +println +Apply +false +0 +false +println(either(divisionResultFailure)) + +76 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1297 +1298 +39 + +Literal +false +0 +false +1 + +77 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1305 +1306 +39 + +Literal +false +0 +false +2 + +78 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1313 +1314 +39 + +Literal +false +0 +false +3 + +79 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1300 +1323 +39 +apply +Apply +false +0 +false +Cons(2, Cons(3, Empty)) + +80 +tests/coverage/expect/UnionTypes.scala +example +UnionTypes$ +Class +example.UnionTypes$ +test +1292 +1324 +39 +apply +Apply +false +0 +false +Cons(1, Cons(2, Cons(3, Empty))) + +81 +tests/coverage/expect/PatternMatching.scala +example +Even$ +Class +example.Even$ +unapply +296 +306 +12 +% +Select +false +0 +false +s.length % + +82 +tests/coverage/expect/PatternMatching.scala +example +Even$ +Class +example.Even$ +unapply +307 +308 +12 + +Literal +false +0 +false +2 + +83 +tests/coverage/expect/PatternMatching.scala +example +Even$ +Class +example.Even$ +unapply +312 +313 +12 + +Literal +false +0 +false +0 + +84 +tests/coverage/expect/PatternMatching.scala +example +Person$ +Class +example.Person$ +unapply +797 +803 +29 + +Select +false +0 +false +Person + +85 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1047 +1062 +37 +split +Select +false +0 +false +name.trim.split + +86 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1063 +1066 +37 + +Literal +false +0 +false +" " + +87 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1092 +1093 +38 + +Literal +false +0 +false +2 + +88 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1099 +1103 +38 +None +Ident +true +0 +false +None + +89 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1161 +1162 +39 + +Literal +false +0 +false +1 + +90 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1150 +1163 +39 +refArrayOps +Apply +false +0 +false +names.drop(1) + +91 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1174 +1175 +39 + +Literal +false +0 +false +1 + +92 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1150 +1176 +39 +wrapRefArray +Apply +false +0 +false +names.drop(1).dropRight(1) + +93 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1117 +1184 +39 +apply +Apply +false +0 +false +Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) + +94 +tests/coverage/expect/PatternMatching.scala +example +Names$ +Class +example.Names$ +unapplySeq +1117 +1184 +39 + +Block +true +0 +false +Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) + +95 +tests/coverage/expect/PatternMatching.scala +example +Name$ +Class +example.Name$ +unapply +1361 +1365 +49 + +Select +false +0 +false +Name + +96 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1425 +1431 +55 + +Literal +false +0 +false +"even" + +97 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1475 +1508 +56 + +Literal +false +0 +false + has an even number of characters + +98 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1473 +1508 +56 +apply +Apply +false +0 +false +$s has an even number of characters + +99 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1471 +1509 +56 +s +Apply +false +0 +false +s"$s has an even number of characters" + +100 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1463 +1510 +56 +println +Apply +false +0 +false +println(s"$s has an even number of characters") + +101 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1548 +1580 +57 + +Literal +false +0 +false + has an odd number of characters + +102 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1546 +1580 +57 +apply +Apply +false +0 +false +$s has an odd number of characters + +103 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1544 +1581 +57 +s +Apply +false +0 +false +s"$s has an odd number of characters" + +104 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1536 +1582 +57 +println +Apply +false +0 +false +println(s"$s has an odd number of characters") + +105 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +containsConsecutive +1775 +1810 +61 +containsConsecutive +Apply +false +0 +false +containsConsecutive(b :: xs.toList) + +106 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +containsConsecutive +1843 +1848 +62 + +Literal +false +0 +false +false + +107 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1887 +1888 +64 + +Literal +false +0 +false +1 + +108 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1890 +1891 +64 + +Literal +false +0 +false +2 + +109 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1893 +1894 +64 + +Literal +false +0 +false +3 + +110 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1896 +1897 +64 + +Literal +false +0 +false +4 + +111 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1899 +1900 +64 + +Literal +false +0 +false +5 + +112 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1882 +1901 +64 +apply +Apply +false +0 +false +List(1, 2, 3, 4, 5) + +113 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1862 +1902 +64 +containsConsecutive +Apply +false +0 +false +containsConsecutive(List(1, 2, 3, 4, 5)) + +114 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1854 +1903 +64 +println +Apply +false +0 +false +println(containsConsecutive(List(1, 2, 3, 4, 5))) + +115 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1941 +1942 +65 + +Literal +false +0 +false +1 + +116 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1944 +1945 +65 + +Literal +false +0 +false +2 + +117 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1947 +1948 +65 + +Literal +false +0 +false +3 + +118 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1950 +1951 +65 + +Literal +false +0 +false +3 + +119 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1953 +1954 +65 + +Literal +false +0 +false +5 + +120 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1936 +1955 +65 +apply +Apply +false +0 +false +List(1, 2, 3, 3, 5) + +121 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1916 +1956 +65 +containsConsecutive +Apply +false +0 +false +containsConsecutive(List(1, 2, 3, 3, 5)) + +122 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1908 +1957 +65 +println +Apply +false +0 +false +println(containsConsecutive(List(1, 2, 3, 3, 5))) + +123 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +1992 +1998 +68 + +Literal +false +0 +false +"john" + +124 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2000 +2002 +68 + +Literal +false +0 +false +42 + +125 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2048 +2054 +69 + +Literal +false +0 +false +name: + +126 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2056 +2063 +69 + +Literal +false +0 +false +, age: + +127 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2048 +2065 +69 +apply +Apply +false +0 +false +name: $n, age: $a + +128 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2046 +2066 +69 +s +Apply +false +0 +false +s"name: $n, age: $a" + +129 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2038 +2067 +69 +println +Apply +false +0 +false +println(s"name: $n, age: $a") + +130 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +greet +2189 +2205 +74 + +Literal +false +0 +false +"Good morning, " + +131 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +greet +2220 +2223 +74 + +Literal +false +0 +false +" " + +132 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +greet +2237 +2240 +74 + +Literal +false +0 +false +"!" + +133 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +greet +2286 +2335 +75 + +Literal +false +0 +false +"Welcome! Please make sure to fill in your name!" + +134 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2359 +2372 +77 + +Literal +false +0 +false +"Alan Turing" + +135 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2345 +2374 +77 +println +Apply +false +0 +false +println(greet("Alan Turing")) + +136 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2393 +2399 +78 + +Literal +false +0 +false +"john" + +137 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2379 +2401 +78 +println +Apply +false +0 +false +println(greet("john")) + +138 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2420 +2445 +79 + +Literal +false +0 +false +"Wolfgang Amadeus Mozart" + +139 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2406 +2447 +79 +println +Apply +false +0 +false +println(greet("Wolfgang Amadeus Mozart")) + +140 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2478 +2485 +82 + +Literal +false +0 +false +"alice" + +141 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2525 +2533 +83 + +Literal +false +0 +false +name is + +142 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2525 +2535 +83 +apply +Apply +false +0 +false +name is $n + +143 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2523 +2536 +83 +s +Apply +false +0 +false +s"name is $n" + +144 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2515 +2537 +83 +println +Apply +false +0 +false +println(s"name is $n") + +145 +tests/coverage/expect/PatternMatching.scala +example +PatternMatching$ +Class +example.PatternMatching$ +test +2568 +2580 +84 + +Literal +false +0 +false +"empty name" + +146 +tests/coverage/expect/TraitParams.scala +example +TraitParams$ +Class +example.TraitParams$ +printMessages +475 +490 +13 +map +Apply +false +0 +false +msgs.map(_.msg) + +147 +tests/coverage/expect/TraitParams.scala +example +TraitParams$ +Class +example.TraitParams$ +printMessages +500 +503 +13 + +Literal +false +0 +false +" " + +148 +tests/coverage/expect/TraitParams.scala +example +TraitParams$ +Class +example.TraitParams$ +printMessages +467 +505 +13 +println +Apply +false +0 +false +println(msgs.map(_.msg).mkString(" ")) + +149 +tests/coverage/expect/TraitParams.scala +example +TraitParams$ +Class +example.TraitParams$ +test +550 +551 +16 + +Select +false +0 +false +A + +150 +tests/coverage/expect/TraitParams.scala +example +TraitParams$ +Class +example.TraitParams$ +test +557 +558 +16 + +Select +false +0 +false +B + +151 +tests/coverage/expect/TraitParams.scala +example +TraitParams$ +Class +example.TraitParams$ +test +532 +559 +16 +printMessages +Apply +false +0 +false +printMessages(new A, new B) + +152 +tests/coverage/expect/TraitParams.scala +example +TraitParams$ +Class +example.TraitParams$ +test +685 +686 +20 + +Literal +false +0 +false +1 + +153 +tests/coverage/expect/Enum.scala +example +Planet +Class +example.Planet + +326 +337 +14 + +Literal +false +0 +false +6.67300E-11 + +154 +tests/coverage/expect/Enum.scala +example +Planet +Class +example.Planet +surfaceGravity +363 +390 +15 +/ +Apply +false +0 +false +G * mass / (radius * radius + +155 +tests/coverage/expect/Enum.scala +example +Planet +Class +example.Planet +surfaceWeight +436 +462 +16 +* +Apply +false +0 +false +otherMass * surfaceGravity + +156 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +988 +989 +30 + +Literal +false +0 +false +1 + +157 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1005 +1006 +30 + +Literal +false +0 +false +2 + +158 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1022 +1023 +30 + +Literal +false +0 +false +3 + +159 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1008 +1040 +30 +apply +Apply +false +0 +false +ListEnum.Cons(3, ListEnum.Empty) + +160 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +991 +1041 +30 +apply +Apply +false +0 +false +ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty)) + +161 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +974 +1042 +30 +apply +Apply +false +0 +false +ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) + +162 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1055 +1070 +31 + +Literal +false +0 +false +"Example 1: \n" + +163 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1047 +1081 +31 +println +Apply +false +0 +false +println("Example 1: \n"+emptyList) + +164 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1103 +1105 +32 + +Literal +false +0 +false +\n + +165 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1096 +1105 +32 +apply +Apply +false +0 +false +${list}\n + +166 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1094 +1106 +32 +s +Apply +false +0 +false +s"${list}\n" + +167 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1086 +1107 +32 +println +Apply +false +0 +false +println(s"${list}\n") + +168 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +calculateEarthWeightOnPlanets +1187 +1226 +35 +/ +Apply +false +0 +false +earthWeight/Planet.Earth.surfaceGravity + +169 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +calculateEarthWeightOnPlanets +1242 +1255 +36 +refArrayOps +Apply +false +0 +false +Planet.values + +170 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +$anonfun +1277 +1292 +37 + +Literal +false +0 +false +Your weight on + +171 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +$anonfun +1294 +1298 +37 + +Literal +false +0 +false + is + +172 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +$anonfun +1277 +1322 +37 +apply +Apply +false +0 +false +Your weight on $p is ${p.surfaceWeight(mass)} + +173 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +$anonfun +1275 +1323 +37 +s +Apply +false +0 +false +s"Your weight on $p is ${p.surfaceWeight(mass)}" + +174 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +$anonfun +1267 +1324 +37 +println +Apply +false +0 +false +println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + +175 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +calculateEarthWeightOnPlanets +1233 +1324 +36 +foreach +Apply +false +0 +false +for p <- Planet.values do + println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + +176 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1338 +1350 +39 + +Literal +false +0 +false +"Example 2:" + +177 +tests/coverage/expect/Enum.scala +example +EnumTypes$ +Class +example.EnumTypes$ +test +1386 +1388 +40 + +Literal +false +0 +false +80 + From a4549e7c4f45144b142a42372a111399eede1f1c Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Fri, 4 Mar 2022 15:46:56 +0100 Subject: [PATCH 02/15] Move coverage phase to before FirstTransform and handle more trees --- compiler/src/dotty/tools/dotc/Compiler.scala | 2 +- .../dotty/tools/dotc/coverage/Coverage.scala | 17 +- .../dotty/tools/dotc/coverage/Location.scala | 6 +- .../tools/dotc/coverage/Serializer.scala | 42 ++--- ...rmMacro.scala => InstrumentCoverage.scala} | 177 ++++++++++-------- .../dotty/tools/dotc/typer/EtaExpansion.scala | 18 +- library/src/scala/runtime/Invoker.scala | 6 +- 7 files changed, 140 insertions(+), 128 deletions(-) rename compiler/src/dotty/tools/dotc/transform/{CoverageTransformMacro.scala => InstrumentCoverage.scala} (52%) diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 1c11267641fd..8ed6f2a70fe5 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -46,7 +46,6 @@ class Compiler { List(new sjs.PrepJSInterop) :: // Additional checks and transformations for Scala.js (Scala.js only) List(new sbt.ExtractAPI) :: // Sends a representation of the API of classes to sbt via callbacks List(new SetRootTree) :: // Set the `rootTreeOrProvider` on class symbols - List(new CoverageTransformMacro) :: // Perform instrumentation for coverage transform (if -coverage is present) Nil /** Phases dealing with TASTY tree pickling and unpickling */ @@ -60,6 +59,7 @@ class Compiler { /** Phases dealing with the transformation from pickled trees to backend trees */ protected def transformPhases: List[List[Phase]] = + List(new InstrumentCoverage) :: // Perform instrumentation for code coverage (if -coverage setting is set) List(new FirstTransform, // Some transformations to put trees into a canonical form new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars new ElimPackagePrefixes, // Eliminate references to package prefixes in Select nodes diff --git a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala index b4365e1c4389..ceb646e86bca 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala @@ -3,13 +3,12 @@ package coverage import scala.collection.mutable -class Coverage { +class Coverage: private val statementsById = mutable.Map[Int, Statement]() - def statements = statementsById.values + def statements: Iterable[Statement] = statementsById.values - def addStatement(stmt: Statement): Unit = statementsById.put(stmt.id, stmt) -} + def addStatement(stmt: Statement): Unit = statementsById(stmt.id) = stmt case class Statement( source: String, @@ -24,7 +23,9 @@ case class Statement( branch: Boolean, var count: Int = 0, ignored: Boolean = false -) { - def invoked(): Unit = count = count + 1 - def isInvoked = count > 0 -} +): + def invoked(): Unit = + count += 1 + + def isInvoked: Boolean = + count > 0 diff --git a/compiler/src/dotty/tools/dotc/coverage/Location.scala b/compiler/src/dotty/tools/dotc/coverage/Location.scala index 47f712a49da5..65f8d8adb5ee 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Location.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Location.scala @@ -20,8 +20,8 @@ final case class Location( sourcePath: String ) -object Location { - def apply(tree: Tree)(using ctx: Context): Location = { +object Location: + def apply(tree: Tree)(using ctx: Context): Location = val packageName = ctx.owner.denot.enclosingPackageClass.name.toSimpleName.toString() val className = ctx.owner.denot.enclosingClass.name.toSimpleName.toString() @@ -34,5 +34,3 @@ object Location { ctx.owner.denot.enclosingMethod.name.toSimpleName.toString(), ctx.source.file.absolute.toString() ) - } -} diff --git a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala index 43fe45774249..6cc70de72c75 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala @@ -5,31 +5,34 @@ import java.io._ import scala.io.Source -object Serializer { +/** + * Serializes scoverage data. + * @see https://github.com/scoverage/scalac-scoverage-plugin/blob/main/scalac-scoverage-plugin/src/main/scala/scoverage/Serializer.scala + */ +object Serializer: - val coverageFileName = "scoverage.coverage" - val coverageDataFormatVersion = "3.0" - // Write out coverage data to the given data directory, using the default coverage filename + private val CoverageFileName = "scoverage.coverage" + private val CoverageDataFormatVersion = "3.0" + + /** Write out coverage data to the given data directory, using the default coverage filename */ def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit = serialize(coverage, coverageFile(dataDir), new File(sourceRoot)) - // Write out coverage data to given file. - def serialize(coverage: Coverage, file: File, sourceRoot: File): Unit = { - val writer = new BufferedWriter(new FileWriter(file)) + /** Write out coverage data to given file. */ + def serialize(coverage: Coverage, file: File, sourceRoot: File): Unit = + val writer = BufferedWriter(FileWriter(file)) serialize(coverage, writer, sourceRoot) writer.close() - } - def serialize(coverage: Coverage, writer: Writer, sourceRoot: File): Unit = { + def serialize(coverage: Coverage, writer: Writer, sourceRoot: File): Unit = - def getRelativePath(filePath: String): String = { + def getRelativePath(filePath: String): String = val base = sourceRoot.getCanonicalFile().toPath() - val relPath = base.relativize(new File(filePath).getCanonicalFile().toPath()) + val relPath = base.relativize(File(filePath).getCanonicalFile().toPath()) relPath.toString - } - def writeHeader(writer: Writer): Unit = { - writer.write(s"""# Coverage data, format version: $coverageDataFormatVersion + def writeHeader(writer: Writer): Unit = + writer.write(s"""# Coverage data, format version: $CoverageDataFormatVersion |# Statement data: |# - id |# - source path @@ -50,8 +53,8 @@ object Serializer { |# '\f' sign |# ------------------------------------------ |""".stripMargin) - } - def writeStatement(stmt: Statement, writer: Writer): Unit = { + + def writeStatement(stmt: Statement, writer: Writer): Unit = writer.write(s"""${stmt.id} |${getRelativePath(stmt.location.sourcePath)} |${stmt.location.packageName} @@ -70,14 +73,11 @@ object Serializer { |${stmt.desc} |\f |""".stripMargin) - } writeHeader(writer) - coverage.statements.toVector + coverage.statements.toSeq .sortBy(_.id) .foreach(stmt => writeStatement(stmt, writer)) - } def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) - def coverageFile(dataDir: String): File = new File(dataDir, coverageFileName) -} + def coverageFile(dataDir: String): File = File(dataDir, CoverageFileName) diff --git a/compiler/src/dotty/tools/dotc/transform/CoverageTransformMacro.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala similarity index 52% rename from compiler/src/dotty/tools/dotc/transform/CoverageTransformMacro.scala rename to compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 2d827dd25cac..a283382f87d7 100644 --- a/compiler/src/dotty/tools/dotc/transform/CoverageTransformMacro.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -21,53 +21,60 @@ import dotty.tools.dotc.typer.LiftCoverage import scala.quoted -/** Phase that implements code coverage, executed when the "-coverage - * OUTPUT_PATH" is added to the compilation. - */ -class CoverageTransformMacro extends MacroTransform with IdentityDenotTransformer { +/** Implements code coverage by inserting calls to scala.runtime.Invoker + * ("instruments" the source code). + * The result can then be consumed by the Scoverage tool. + */ +class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: import ast.tpd._ - override def phaseName = "coverage" + override def phaseName = InstrumentCoverage.name + + override def description = InstrumentCoverage.description + + // Enabled by argument "-coverage OUTPUT_DIR" + override def isEnabled(using ctx: Context) = + ctx.settings.coverageOutputDir.value.nonEmpty // Atomic counter used for assignation of IDs to difference statements - val statementId = new AtomicInteger(0) + private val statementId = AtomicInteger(0) - var outputPath = "" + private var outputPath = "" // Main class used to store all instrumented statements - val coverage = new Coverage - - override def run(using ctx: Context): Unit = { + private val coverage = Coverage() - if (ctx.settings.coverageOutputDir.value.nonEmpty) { - outputPath = ctx.settings.coverageOutputDir.value + override def run(using ctx: Context): Unit = + outputPath = ctx.settings.coverageOutputDir.value - // Ensure the dir exists - val dataDir = new File(outputPath) - val newlyCreated = dataDir.mkdirs() + // Ensure the dir exists + val dataDir = new File(outputPath) + val newlyCreated = dataDir.mkdirs() - if (!newlyCreated) { - // If the directory existed before, let's clean it up. - dataDir.listFiles - .filter(_.getName.startsWith("scoverage")) - .foreach(_.delete) - } + if (!newlyCreated) { + // If the directory existed before, let's clean it up. + dataDir.listFiles + .filter(_.getName.startsWith("scoverage")) + .foreach(_.delete) + } - super.run + super.run + Serializer.serialize(coverage, outputPath, ctx.settings.coverageSourceroot.value) - Serializer.serialize(coverage, outputPath, ctx.settings.coverageSourceroot.value) - } - } + override protected def newTransformer(using Context) = CoverageTransormer() - protected def newTransformer(using Context): Transformer = - new CoverageTransormer + private class CoverageTransormer extends Transformer: - class CoverageTransormer extends Transformer { - var instrumented = false + override def transform(tree: Tree)(using Context): Tree = + println(tree.show + tree.toString) + tree match + // simple cases + case tree: (Literal | Import | Export) => tree + case tree: (New | This | Super) => instrument(tree) + case tree if (tree.isEmpty || tree.isType) => tree // empty Thicket, Ident, TypTree, ... - override def transform(tree: Tree)(using Context): Tree = { - tree match { + // branches case tree: If => cpy.If(tree)( cond = transform(tree.cond), @@ -77,51 +84,43 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme case tree: Try => cpy.Try(tree)( expr = instrument(transform(tree.expr), branch = true), - cases = instrumentCasees(tree.cases), + cases = instrumentCases(tree.cases), finalizer = instrument(transform(tree.finalizer), true) ) - case Apply(fun, _) - if ( - fun.symbol.exists && - fun.symbol.isInstanceOf[Symbol] && - fun.symbol == defn.Boolean_&& || fun.symbol == defn.Boolean_|| - ) => - super.transform(tree) - case tree @ Apply(fun, args) if (fun.isInstanceOf[Apply]) => - // We have nested apply, we have to lift all arguments - // Example: def T(x:Int)(y:Int) - // T(f())(1) // should not be changed to {val $x = f(); T($x)}(1) but to {val $x = f(); val $y = 1; T($x)($y)} - liftApply(tree) + + // f(args) case tree: Apply => - if (LiftCoverage.needsLift(tree)) { + if needsLift(tree) then liftApply(tree) - } else { + else super.transform(tree) - } + + // (f(x))[args] + case tree @ TypeApply(fun: Apply, args) => + cpy.TypeApply(tree)(transform(fun), args) + + // a.b case Select(qual, _) if (qual.symbol.exists && qual.symbol.is(JavaDefined)) => //Java class can't be used as a value, we can't instrument the //qualifier ({;System}.xyz() is not possible !) instrument it //as it is instrument(tree) case tree: Select => - if (tree.qualifier.isInstanceOf[New]) { + if tree.qualifier.isInstanceOf[New] then instrument(tree) - } else { + else cpy.Select(tree)(transform(tree.qualifier), tree.name) - } + case tree: CaseDef => instrumentCaseDef(tree) + case tree: ValDef => + // only transform the rhs + cpy.ValDef(tree)(rhs = transform(tree.rhs)) - case tree: Literal => instrument(tree) - case tree: Ident if (isWildcardArg(tree)) => - // We don't want to instrument wildcard arguments. `var a = _` can't be instrumented - tree - case tree: New => instrument(tree) - case tree: This => instrument(tree) - case tree: Super => instrument(tree) case tree: PackageDef => - // We don't instrument the pid of the package, but we do instrument the statements + // only transform the statements of the package cpy.PackageDef(tree)(tree.pid, transform(tree.stats)) - case tree: Assign => cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) + case tree: Assign => + cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) case tree: Template => // Don't instrument the parents (extends) of a template since it // causes problems if the parent constructor takes parameters @@ -129,9 +128,7 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme constr = super.transformSub(tree.constr), body = transform(tree.body) ) - case tree: Import => tree - // Catch EmptyTree since we can't match directly on it - case tree: Thicket if tree.isEmpty => tree + // For everything else just recurse and transform case _ => report.warning( @@ -139,15 +136,13 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme tree.sourcePos ) super.transform(tree) - } - } - def liftApply(tree: Apply)(using Context) = { + def liftApply(tree: Apply)(using Context) = val buffer = mutable.ListBuffer[Tree]() // NOTE: that if only one arg needs to be lifted, we just lift everything val lifted = LiftCoverage.liftForCoverage(buffer, tree) val instrumented = buffer.toList.map(transform) - //We can now instrument the apply as it is with a custom position to point to the function + // We can now instrument the apply as it is with a custom position to point to the function Block( instrumented, instrument( @@ -156,22 +151,18 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme false ) ) - } - def instrumentCasees(cases: List[CaseDef])(using Context): List[CaseDef] = { + def instrumentCases(cases: List[CaseDef])(using Context): List[CaseDef] = cases.map(instrumentCaseDef) - } - def instrumentCaseDef(tree: CaseDef)(using Context): CaseDef = { + def instrumentCaseDef(tree: CaseDef)(using Context): CaseDef = cpy.CaseDef(tree)(tree.pat, transform(tree.guard), transform(tree.body)) - } - def instrument(tree: Tree, branch: Boolean = false)(using Context): Tree = { + def instrument(tree: Tree, branch: Boolean = false)(using Context): Tree = instrument(tree, tree.sourcePos, branch) - } - def instrument(tree: Tree, pos: SourcePosition, branch: Boolean)(using ctx: Context): Tree = { - if (pos.exists && !pos.span.isZeroExtent && !tree.isType) { + def instrument(tree: Tree, pos: SourcePosition, branch: Boolean)(using ctx: Context): Tree = + if pos.exists && !pos.span.isZeroExtent then val id = statementId.incrementAndGet() val statement = new Statement( source = ctx.source.file.name, @@ -187,18 +178,40 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme ) coverage.addStatement(statement) Block(List(invokeCall(id)), tree) - } else { + else tree - } - } - def invokeCall(id: Int)(using Context): Tree = { + def invokeCall(id: Int)(using Context): Tree = ref(defn.InvokerModuleRef) .select("invoked".toTermName) .appliedToArgs( List(Literal(Constant(id)), Literal(Constant(outputPath))) ) - } - } -} + /** + * Checks if the apply needs a lift in the coverage phase. + * In case of a nested application, we have to lift all arguments + * Example: + * ``` + * def T(x:Int)(y:Int) + * T(f())(1) + * ``` + * should not be changed to {val $x = f(); T($x)}(1) but to {val $x = f(); val $y = 1; T($x)($y)} + */ + def needsLift(tree: Apply)(using Context): Boolean = + // We don't want to lift a || getB(), to avoid calling getB if a is true. + // Same idea with a && getB(): if a is false, getB shouldn't be called. + def isBooleanOperator(fun: Tree) = + fun.symbol.exists && + fun.symbol.isInstanceOf[Symbol] && + fun.symbol == defn.Boolean_&& || fun.symbol == defn.Boolean_|| + + val fun = tree.fun + + fun.isInstanceOf[Apply] || // nested apply + !isBooleanOperator(fun) || + !tree.args.isEmpty && !tree.args.forall(LiftCoverage.noLift) + +object InstrumentCoverage: + val name: String = "instrumentCoverage" + val description: String = "instrument code for coverage cheking" diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index ab36dd0395df..32427120514a 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -11,6 +11,7 @@ import Symbols._ import Names._ import NameKinds.UniqueName import util.Spans._ +import util.Property import collection.mutable import Trees._ @@ -158,23 +159,20 @@ object LiftComplex extends LiftComplex /** Lift complex + lift the prefixes */ object LiftCoverage extends LiftComplex { - var liftEverything = false + private val LiftEverything = new Property.Key[Boolean] - /** Return true if the apply needs a lift in the coverage phase - Return false if the args are empty, if one or more will be lifter by a - complex lifter. - */ - def needsLift(tree: tpd.Apply)(using Context): Boolean = - !tree.args.isEmpty && !tree.args.forall(super.noLift(_)) + private def liftEverything(using Context): Boolean = + ctx.property(LiftEverything).contains(true) + + private def liftEverythingContext(using Context): Context = + ctx.fresh.setProperty(LiftEverything, true) override def noLift(expr: tpd.Tree)(using Context) = !liftEverything && super.noLift(expr) def liftForCoverage(defs: mutable.ListBuffer[tpd.Tree], tree: tpd.Apply)(using Context) = { val liftedFun = liftApp(defs, tree.fun) - liftEverything = true - val liftedArgs = liftArgs(defs, tree.fun.tpe, tree.args) - liftEverything = false + val liftedArgs = liftArgs(defs, tree.fun.tpe, tree.args)(using liftEverythingContext) tpd.cpy.Apply(tree)(liftedFun, liftedArgs) } } diff --git a/library/src/scala/runtime/Invoker.scala b/library/src/scala/runtime/Invoker.scala index 6a22427cbd18..94e39c2f9348 100644 --- a/library/src/scala/runtime/Invoker.scala +++ b/library/src/scala/runtime/Invoker.scala @@ -62,13 +62,15 @@ object Invoker { new FileWriter(measurementFile(dataDir), true) ) - writer.append(Integer.toString(id)).append("\n").flush() + writer.append(Integer.toString(id)) + writer.append("\n") + writer.flush() ids.put(id, ()) } } def measurementFile(dataDir: String): File = new File( dataDir, - MeasurementsPrefix + runtimeUUID + "." + Thread.currentThread.getId + MeasurementsPrefix + runtimeUUID + "." + Thread.currentThread.nn.getId ) } From b1729229f821950b3a224db47f6d8f0d4b73c983 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Thu, 10 Mar 2022 19:58:12 +0100 Subject: [PATCH 03/15] Improve Invoker performance with a BitSet According to my JMH benchmarks, this improves the performance by at least 40%, even when multiple threads use the Invoker. Details on the benchmark: - 10k calls to Invoker.invoked(id,dir) with a % of ids that are repeted in a loop and a % of ids that appear only once. But this doesn't change the results much. - 1 thread or 4 threads at the same time. The single-thread performance is, as expected, much better (3x). --- library/src/scala/runtime/Invoker.scala | 63 ++++++++----------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/library/src/scala/runtime/Invoker.scala b/library/src/scala/runtime/Invoker.scala index 94e39c2f9348..b1b953b7cbc6 100644 --- a/library/src/scala/runtime/Invoker.scala +++ b/library/src/scala/runtime/Invoker.scala @@ -1,11 +1,8 @@ package scala.runtime -import scala.collection.mutable -import java.nio.file.Path +import scala.collection.mutable.{BitSet, AnyRefMap} import scala.collection.concurrent.TrieMap -import java.nio.file.Paths import java.nio.file.Files -import java.nio.file.StandardOpenOption import java.io.FileWriter import java.io.File @@ -13,12 +10,8 @@ object Invoker { private val runtimeUUID = java.util.UUID.randomUUID() private val MeasurementsPrefix = "scoverage.measurements." - private val threadFiles = new ThreadLocal[mutable.HashMap[String, FileWriter]] - - // For each data directory we maintain a thread-safe set tracking the ids - // that we've already seen and recorded. We're using a map as a set, so we - // only care about its keys and can ignore its values. - private val dataDirToIds = TrieMap.empty[String, TrieMap[Int, Any]] + private val threadFiles = new ThreadLocal[AnyRefMap[String, FileWriter]] + private val dataDirToSet = TrieMap.empty[String, BitSet] /** We record that the given id has been invoked by appending its id to the coverage data file. * @@ -34,40 +27,24 @@ object Invoker { * @param dataDir * the directory where the measurement data is held */ - def invoked(id: Int, dataDir: String): Unit = { - // [sam] we can do this simple check to save writing out to a file. - // This won't work across JVMs but since there's no harm in writing out the same id multiple - // times since for coverage we only care about 1 or more, (it just slows things down to - // do it more than once), anything we can do to help is good. This helps especially with code - // that is executed many times quickly, eg tight loops. - if (!dataDirToIds.contains(dataDir)) { - // Guard against SI-7943: "TrieMap method getOrElseUpdate is not thread-safe". - dataDirToIds.synchronized { - if (!dataDirToIds.contains(dataDir)) { - dataDirToIds(dataDir) = TrieMap.empty[Int, Any] - } - } - } - val ids = dataDirToIds(dataDir) - if (!ids.contains(id)) { - // Each thread writes to a separate measurement file, to reduce contention - // and because file appends via FileWriter are not atomic on Windows. - var files = threadFiles.get() - if (files == null) { - files = mutable.HashMap.empty[String, FileWriter] - threadFiles.set(files) + def invoked(id: Int, dataDir: String): Unit = + val set = dataDirToSet.getOrElseUpdate(dataDir, BitSet.empty) + if !set.contains(id) then + val added = set.synchronized { + set.add(id) } - val writer = files.getOrElseUpdate( - dataDir, - new FileWriter(measurementFile(dataDir), true) - ) - - writer.append(Integer.toString(id)) - writer.append("\n") - writer.flush() - ids.put(id, ()) - } - } + if added then + var writers = threadFiles.get() + if writers == null then + writers = AnyRefMap.empty + threadFiles.set(writers) + val writer = writers.getOrElseUpdate( + dataDir, + FileWriter(measurementFile(dataDir), true) + ) + writer.write(Integer.toString(id)) + writer.write('\n') + writer.flush() def measurementFile(dataDir: String): File = new File( dataDir, From d37d13b15362e752d796256a7f196e8b9cb3cb49 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sat, 12 Mar 2022 16:53:02 +0100 Subject: [PATCH 04/15] Mark Invoker as sharable to bypass -Ycheck-reentrant --- library/src/scala/runtime/Invoker.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/src/scala/runtime/Invoker.scala b/library/src/scala/runtime/Invoker.scala index b1b953b7cbc6..44b0703fb8d2 100644 --- a/library/src/scala/runtime/Invoker.scala +++ b/library/src/scala/runtime/Invoker.scala @@ -5,7 +5,9 @@ import scala.collection.concurrent.TrieMap import java.nio.file.Files import java.io.FileWriter import java.io.File +import scala.annotation.internal.sharable +@sharable // avoids false positive by -Ycheck-reentrant object Invoker { private val runtimeUUID = java.util.UUID.randomUUID() From cb66c7a777ae7ad0eab3ebf17a042edacad34ef8 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Mon, 14 Mar 2022 15:35:18 +0100 Subject: [PATCH 05/15] Cut coverage tests in small parts and avoid lifting literals --- .../tools/dotc/config/ScalaSettings.scala | 2 +- .../dotty/tools/dotc/coverage/Coverage.scala | 2 +- .../tools/dotc/coverage/Serializer.scala | 30 +- .../dotc/transform/InstrumentCoverage.scala | 85 +- .../dotty/tools/dotc/typer/EtaExpansion.scala | 2 +- .../tools/dotc/coverage/CoverageTests.scala | 94 +- .../dotty/tools/vulpix/ParallelTesting.scala | 10 +- docs/_docs/usage/coverage.md | 60 + project/Build.scala | 1 - tests/coverage/expect/ContextFunctions.scala | 30 - tests/coverage/expect/Enum.scala | 5 +- tests/coverage/expect/Enum.scoverage.check | 446 +++ tests/coverage/expect/Givens.scala | 24 + tests/coverage/expect/Givens.scoverage.check | 224 ++ tests/coverage/expect/Lifting.scala | 12 + tests/coverage/expect/Lifting.scoverage.check | 122 + tests/coverage/expect/Literals.scala | 11 + .../coverage/expect/Literals.scoverage.check | 88 + tests/coverage/expect/MatchCaseClasses.scala | 15 + .../expect/MatchCaseClasses.scoverage.check | 139 + tests/coverage/expect/MatchNumbers.scala | 12 + .../expect/MatchNumbers.scoverage.check | 105 + .../coverage/expect/MultiversalEquality.scala | 31 - .../coverage/expect/ParameterUntupling.scala | 19 - .../expect/ParamsAndInterpolation.scala | 11 + .../ParamsAndInterpolation.scoverage.check | 190 ++ tests/coverage/expect/PatternMatching.scala | 87 - tests/coverage/expect/Select.scala | 20 + tests/coverage/expect/Select.scoverage.check | 139 + tests/coverage/expect/StructuralTypes.scala | 21 +- .../expect/StructuralTypes.scoverage.check | 156 + tests/coverage/expect/TraitParams.scala | 22 - tests/coverage/expect/TypeLambdas.scala | 2 +- .../expect/TypeLambdas.scoverage.check | 122 + tests/coverage/expect/UnionTypes.scala | 44 - tests/coverage/scoverage.coverage.expect | 3030 ----------------- 36 files changed, 2019 insertions(+), 3394 deletions(-) create mode 100644 docs/_docs/usage/coverage.md delete mode 100644 tests/coverage/expect/ContextFunctions.scala create mode 100644 tests/coverage/expect/Enum.scoverage.check create mode 100644 tests/coverage/expect/Givens.scala create mode 100644 tests/coverage/expect/Givens.scoverage.check create mode 100644 tests/coverage/expect/Lifting.scala create mode 100644 tests/coverage/expect/Lifting.scoverage.check create mode 100644 tests/coverage/expect/Literals.scala create mode 100644 tests/coverage/expect/Literals.scoverage.check create mode 100644 tests/coverage/expect/MatchCaseClasses.scala create mode 100644 tests/coverage/expect/MatchCaseClasses.scoverage.check create mode 100644 tests/coverage/expect/MatchNumbers.scala create mode 100644 tests/coverage/expect/MatchNumbers.scoverage.check delete mode 100644 tests/coverage/expect/MultiversalEquality.scala delete mode 100644 tests/coverage/expect/ParameterUntupling.scala create mode 100644 tests/coverage/expect/ParamsAndInterpolation.scala create mode 100644 tests/coverage/expect/ParamsAndInterpolation.scoverage.check delete mode 100644 tests/coverage/expect/PatternMatching.scala create mode 100644 tests/coverage/expect/Select.scala create mode 100644 tests/coverage/expect/Select.scoverage.check create mode 100644 tests/coverage/expect/StructuralTypes.scoverage.check delete mode 100644 tests/coverage/expect/TraitParams.scala create mode 100644 tests/coverage/expect/TypeLambdas.scoverage.check delete mode 100644 tests/coverage/expect/UnionTypes.scala delete mode 100644 tests/coverage/scoverage.coverage.expect diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 10e9876db20f..e37168fce20b 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -117,7 +117,7 @@ trait CommonScalaSettings: val unchecked: Setting[Boolean] = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked")) val language: Setting[List[String]] = MultiStringSetting("-language", "feature", "Enable one or more language features.", aliases = List("--language")) /* Coverage settings */ - val coverageOutputDir = PathSetting("-coverage", "Destination for coverage classfiles and instrumentation data.", "") + val coverageOutputDir = PathSetting("-coverage-out", "Destination for coverage classfiles and instrumentation data.", "") val coverageSourceroot = PathSetting("-coverage-sourceroot", "An alternative root dir of your sources used to relativize.", ".") /* Other settings */ diff --git a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala index ceb646e86bca..05ced1075edc 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala @@ -4,7 +4,7 @@ package coverage import scala.collection.mutable class Coverage: - private val statementsById = mutable.Map[Int, Statement]() + private val statementsById = new mutable.LongMap[Statement](256) def statements: Iterable[Statement] = statementsById.values diff --git a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala index 6cc70de72c75..c5e6440afffd 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala @@ -1,9 +1,9 @@ package dotty.tools.dotc package coverage -import java.io._ - -import scala.io.Source +import java.nio.file.{Path, Paths, Files} +import java.io.Writer +import scala.language.unsafeNulls /** * Serializes scoverage data. @@ -16,19 +16,22 @@ object Serializer: /** Write out coverage data to the given data directory, using the default coverage filename */ def serialize(coverage: Coverage, dataDir: String, sourceRoot: String): Unit = - serialize(coverage, coverageFile(dataDir), new File(sourceRoot)) + serialize(coverage, Paths.get(dataDir, CoverageFileName).toAbsolutePath, Paths.get(sourceRoot).toAbsolutePath) - /** Write out coverage data to given file. */ - def serialize(coverage: Coverage, file: File, sourceRoot: File): Unit = - val writer = BufferedWriter(FileWriter(file)) - serialize(coverage, writer, sourceRoot) - writer.close() + /** Write out coverage data to a file. */ + def serialize(coverage: Coverage, file: Path, sourceRoot: Path): Unit = + val writer = Files.newBufferedWriter(file) + try + serialize(coverage, writer, sourceRoot) + finally + writer.close() - def serialize(coverage: Coverage, writer: Writer, sourceRoot: File): Unit = + /** Write out coverage data (info about each statement that can be covered) to a writer. + */ + def serialize(coverage: Coverage, writer: Writer, sourceRoot: Path): Unit = def getRelativePath(filePath: String): String = - val base = sourceRoot.getCanonicalFile().toPath() - val relPath = base.relativize(File(filePath).getCanonicalFile().toPath()) + val relPath = sourceRoot.relativize(Paths.get(filePath).toAbsolutePath) relPath.toString def writeHeader(writer: Writer): Unit = @@ -78,6 +81,3 @@ object Serializer: coverage.statements.toSeq .sortBy(_.id) .foreach(stmt => writeStatement(stmt, writer)) - - def coverageFile(dataDir: File): File = coverageFile(dataDir.getAbsolutePath) - def coverageFile(dataDir: String): File = File(dataDir, CoverageFileName) diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index a283382f87d7..29d2209e1ec3 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -15,12 +15,10 @@ import dotty.tools.dotc.coverage.Location import dotty.tools.dotc.core.Symbols.defn import dotty.tools.dotc.core.Symbols.Symbol import dotty.tools.dotc.core.Decorators.toTermName -import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.util.{SourcePosition, Property} import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.typer.LiftCoverage -import scala.quoted - /** Implements code coverage by inserting calls to scala.runtime.Invoker * ("instruments" the source code). * The result can then be consumed by the Scoverage tool. @@ -51,29 +49,40 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: val dataDir = new File(outputPath) val newlyCreated = dataDir.mkdirs() - if (!newlyCreated) { + if !newlyCreated then // If the directory existed before, let's clean it up. - dataDir.listFiles - .filter(_.getName.startsWith("scoverage")) - .foreach(_.delete) - } - + dataDir.listFiles.nn + .filter(_.nn.getName.nn.startsWith("scoverage")) + .foreach(_.nn.delete()) + end if super.run Serializer.serialize(coverage, outputPath, ctx.settings.coverageSourceroot.value) override protected def newTransformer(using Context) = CoverageTransormer() + /** Transforms trees to insert calls to Invoker.invoked to compute the coverage when the code is called */ private class CoverageTransormer extends Transformer: + private val IgnoreLiterals = new Property.Key[Boolean] + + private def ignoreLiteralsContext(using ctx: Context): Context = + ctx.fresh.setProperty(IgnoreLiterals, true) - override def transform(tree: Tree)(using Context): Tree = - println(tree.show + tree.toString) + override def transform(tree: Tree)(using ctx: Context): Tree = tree match // simple cases - case tree: (Literal | Import | Export) => tree - case tree: (New | This | Super) => instrument(tree) + case tree: (Import | Export | This | Super | New) => tree case tree if (tree.isEmpty || tree.isType) => tree // empty Thicket, Ident, TypTree, ... + // Literals must be instrumented (at least) when returned by a def, + // otherwise `def d = "literal"` is not covered when called from a test. + // They can be left untouched when passed in a parameter of an Apply. + case tree: Literal => + if ctx.property(IgnoreLiterals).contains(true) then + tree + else + instrument(tree) + // branches case tree: If => cpy.If(tree)( @@ -88,28 +97,42 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: finalizer = instrument(transform(tree.finalizer), true) ) + // a.f(args) + case tree @ Apply(fun: Select, args) => + // don't transform the first Select, but do transform `a.b` in `a.b.f(args)` + val transformedFun = cpy.Select(fun)(transform(fun.qualifier), fun.name) + if needsLift(tree) then + val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted + instrumentLifted(transformed)(using ignoreLiteralsContext) + else + val transformed = cpy.Apply(tree)(transformedFun, transform(args)) + instrument(transformed)(using ignoreLiteralsContext) + // f(args) case tree: Apply => if needsLift(tree) then - liftApply(tree) + instrumentLifted(tree)(using ignoreLiteralsContext) // see comment about Literals else - super.transform(tree) + instrument(super.transform(tree)(using ignoreLiteralsContext)) // (f(x))[args] - case tree @ TypeApply(fun: Apply, args) => + case TypeApply(fun: Apply, args) => cpy.TypeApply(tree)(transform(fun), args) // a.b - case Select(qual, _) if (qual.symbol.exists && qual.symbol.is(JavaDefined)) => - //Java class can't be used as a value, we can't instrument the - //qualifier ({;System}.xyz() is not possible !) instrument it - //as it is - instrument(tree) - case tree: Select => - if tree.qualifier.isInstanceOf[New] then + case Select(qual, name) => + if qual.symbol.exists && qual.symbol.is(JavaDefined) then + //Java class can't be used as a value, we can't instrument the + //qualifier ({;System}.xyz() is not possible !) instrument it + //as it is instrument(tree) else - cpy.Select(tree)(transform(tree.qualifier), tree.name) + val transformed = cpy.Select(tree)(transform(qual), name) + if transformed.qualifier.isDef then + // instrument calls to methods without parameter list + instrument(transformed) + else + transformed case tree: CaseDef => instrumentCaseDef(tree) case tree: ValDef => @@ -120,6 +143,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: // only transform the statements of the package cpy.PackageDef(tree)(tree.pid, transform(tree.stats)) case tree: Assign => + // only transform the rhs cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) case tree: Template => // Don't instrument the parents (extends) of a template since it @@ -131,13 +155,9 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: // For everything else just recurse and transform case _ => - report.warning( - "Unmatched: " + tree.getClass + " " + tree.symbol, - tree.sourcePos - ) super.transform(tree) - def liftApply(tree: Apply)(using Context) = + def instrumentLifted(tree: Apply)(using Context) = val buffer = mutable.ListBuffer[Tree]() // NOTE: that if only one arg needs to be lifted, we just lift everything val lifted = LiftCoverage.liftForCoverage(buffer, tree) @@ -170,10 +190,10 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: id = id, start = pos.start, end = pos.end, - line = ctx.source.offsetToLine(pos.point), + line = pos.line, desc = tree.source.content.slice(pos.start, pos.end).mkString, symbolName = tree.symbol.name.toSimpleName.toString(), - treeName = tree.getClass.getSimpleName, + treeName = tree.getClass.getSimpleName.nn, branch ) coverage.addStatement(statement) @@ -209,8 +229,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: val fun = tree.fun fun.isInstanceOf[Apply] || // nested apply - !isBooleanOperator(fun) || - !tree.args.isEmpty && !tree.args.forall(LiftCoverage.noLift) + !isBooleanOperator(fun) && !tree.args.isEmpty && !tree.args.forall(LiftCoverage.noLift) object InstrumentCoverage: val name: String = "instrumentCoverage" diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index 32427120514a..0d955651dbd9 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -161,7 +161,7 @@ object LiftCoverage extends LiftComplex { private val LiftEverything = new Property.Key[Boolean] - private def liftEverything(using Context): Boolean = + private inline def liftEverything(using Context): Boolean = ctx.property(LiftEverything).contains(true) private def liftEverythingContext(using Context): Context = diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index 9dde3b9e8221..4e11957cb034 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -1,75 +1,63 @@ package dotty.tools.dotc.coverage -import java.util.stream.Collectors -import org.junit.Assert._ -import dotty.BootstrappedOnlyTests -import org.junit.experimental.categories.Category import org.junit.Test -import java.nio.file.Files +import org.junit.Assert.* +import org.junit.experimental.categories.Category + +import dotty.BootstrappedOnlyTests import dotty.tools.dotc.Main -import scala.jdk.CollectionConverters._ -import java.io.File +import java.nio.file.Files import java.nio.file.Path import java.nio.file.FileSystems import java.nio.file.Paths -import java.nio.charset.StandardCharsets -import scala.io.Source -import java.io.BufferedOutputStream -import java.io.FileOutputStream +import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.StandardCopyOption @main def updateExpect = - CoverageTests().runExpectTest(updateExpectFiles = true) + CoverageTests().runExpectTest(updateCheckfiles = true) @Category(Array(classOf[BootstrappedOnlyTests])) -class CoverageTests { +class CoverageTests: - val scalaFile = FileSystems.getDefault.getPathMatcher("glob:**.scala") - val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.coverage.test")) - val expectSrc = rootSrc.resolve("expect") + private val scalaFile = FileSystems.getDefault.nn.getPathMatcher("glob:**.scala").nn + private val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.coverage.test")).nn + private val expectDir = rootSrc.resolve("expect").nn @Category(Array(classOf[dotty.SlowTests])) @Test def expectTests: Unit = - if (!scala.util.Properties.isWin) runExpectTest(updateExpectFiles = false) - - def runExpectTest(updateExpectFiles: Boolean): Unit = { - val target = generateCoverage(updateExpectFiles) - val input = Source.fromFile(new File(target.toString, "scoverage.coverage")) - val expectFile = new File(expectSrc.resolveSibling("scoverage.coverage.expect").toUri) - - if (updateExpectFiles) { - val outputStream = new BufferedOutputStream(new FileOutputStream(expectFile)) - try { - input.foreach(outputStream.write(_)) - } finally outputStream.close - } else { - val expected = new String(Files.readAllBytes(expectFile.toPath), StandardCharsets.UTF_8) - val obtained = input.mkString - - assertEquals(expected, obtained) - } - } - - def inputFiles(): List[Path] = { - val ls = Files.walk(expectSrc) - val files = - try ls.filter(p => scalaFile.matches(p)).collect(Collectors.toList).asScala - finally ls.close() - - files.toList - } - - def generateCoverage(updateExpectFiles: Boolean): Path = { + runExpectTest(dotty.Properties.testsUpdateCheckfile) + + /** Runs the tests */ + def runExpectTest(updateCheckfiles: Boolean): Unit = + val sourceRoot = if updateCheckfiles then "../" else "." + + Files.walk(expectDir).nn.filter(scalaFile.matches).nn.forEach(p => { + val path = p.nn + val fileName = path.getFileName.nn.toString.nn.stripSuffix(".scala") + val targetDir = computeCoverageInTmp(Seq(path), sourceRoot).nn + val targetFile = targetDir.resolve(s"scoverage.coverage").nn + val expectFile = expectDir.resolve(s"$fileName.scoverage.check").nn + + if updateCheckfiles then + Files.copy(targetFile, expectFile, StandardCopyOption.REPLACE_EXISTING) + else + val expected = new String(Files.readAllBytes(expectFile), UTF_8) + val obtained = new String(Files.readAllBytes(targetFile), UTF_8) + assertEquals(expected, obtained) + + }) + + /** Generates the coverage report for the given input file, in a temporary directory. */ + def computeCoverageInTmp(inputFiles: Seq[Path], sourceRoot: String): Path = val target = Files.createTempDirectory("coverage") val args = Array( - "-coverage", + "-coverage-out", target.toString, "-coverage-sourceroot", - if (updateExpectFiles) "../" else ".", + sourceRoot, "-usejavacp" - ) ++ inputFiles().map(_.toString) + ) ++ inputFiles.map(_.toString) val exit = Main.process(args) - assertFalse(s"dotc errors: ${exit.errorCount}", exit.hasErrors) - target - } -} + assertFalse(s"Compilation failed, ${exit.errorCount} errors", exit.hasErrors) + target.nn diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 6df8c734ad3e..cf051e5f01ad 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -666,7 +666,7 @@ trait ParallelTesting extends RunnerOrchestration { self => if (didFail) { reportFailed() failedTestSources.toSet.foreach(addFailedTest) - reproduceInstructions.iterator.foreach(addReproduceInstruction) + reproduceInstructions.foreach(addReproduceInstruction) } else reportPassed() } @@ -980,7 +980,7 @@ trait ParallelTesting extends RunnerOrchestration { self => cleanup() if (!shouldFail && test.didFail) { - fail(s"Expected no errors when compiling, failed for the following reason(s):\n${ reasonsForFailure(test) }") + fail(s"Expected no errors when compiling, failed for the following reason(s):\n${reasonsForFailure(test)}\n") } else if (shouldFail && !test.didFail) { fail("Pos test should have failed, but didn't") @@ -1077,14 +1077,16 @@ trait ParallelTesting extends RunnerOrchestration { self => /** Extract `Failure` set and render from `Test` */ private def reasonsForFailure(test: Test): String = { val failureReport = - if (test.failureCount == 0) "" - else s"\n - encountered ${test.failureCount} test failures(s)" + if test.failureCount == 0 then "" + else s"encountered ${test.failureCount} test failure(s):\n" failureReport + test.failureReasons.collect { case test.TimeoutFailure(title) => s" - test '$title' timed out" case test.JavaCompilationFailure(msg) => s" - java compilation failed with:\n${ msg.linesIterator.map(" " + _).mkString("\n") }" + case test.Generic => + " - generic failure (see test output)" }.mkString("\n") } diff --git a/docs/_docs/usage/coverage.md b/docs/_docs/usage/coverage.md new file mode 100644 index 000000000000..838865fcd014 --- /dev/null +++ b/docs/_docs/usage/coverage.md @@ -0,0 +1,60 @@ +--- +layout: doc-page +title: "Code Coverage for Scala 3" +--- + +## Instrument code for coverage analysis + +[PR#13880](https://github.com/lampepfl/dotty/pull/13880) has implemented code coverage support for Dotty. +In general, code coverage works in three steps: +1. The program is "instrumented" at compilation time: code is inserted to record which statement are called. This does not change the behavior of the program. Also, a list of all the coverable statements is produced. +2. The program is run, usually by unit tests, and the instrumentation code saves its measurements. +3. Some tool processes the data to generate a fancy coverage report, for instance a web page. + +In Scala 2, all these steps were performed by external tools. In particular, step 1 was implemented by a compiler plugin. + +In Scala 3, the compiler itself takes care of step 1. To use this feature, add the compile option `-coverage-out:DIR`, where `DIR` is the destination of the measurement files. + +You can also set `-coverage-sourceroot:PATHS_ROOT` to customize how the path of your source files are resolved. + +## How-to with sbt + +For now, the Scoverage sbt plugin doesn't apply the above options automatically. +However, you can easily do it yourself, and use the plugin to generate user-friendly reports. + +1. Add the scoverage sbt plugin by appending this line to your `project/plugins.sbt` +```scala +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.0-M4") +``` + +2. Compile your project with +```scala +Compile/compile/scalacOptions += + s"-coverage-out:target/scala-${scalaVersion.value}/scoverage-data" +``` + +2. Run the tests: `sbt test` +3. Generate xml and html reports: `sbt coverageReport` + +## Details: how the code is instrumented + +When the `-coverage-out` option is set, a new phase `instrumentCoverage` runs, just before `firstTransform`. +For a carefully selected list of tree types, it adds a call to `scala.runtime.Invoker.invoked(statementId, DIR)`. + +For instance, this code: +``` +def method() = + println(f()) +``` + +with `-coverage-out:target/cov` be turned to +``` +def method() = + Invoker.invoked(2, "target/cov") + println({ + Invoker.invoked(1, "target/cov") + f() + }) +``` + +At the end of the phase, the list of all the instrumented statements is serialized to the file `DIR/scoverage.coverage`. diff --git a/project/Build.scala b/project/Build.scala index 05cb63ef80be..64022cde42f8 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -575,7 +575,6 @@ object Build { javaOptions ++= Seq( s"-Ddotty.tools.dotc.semanticdb.test=${(ThisBuild / baseDirectory).value/"tests"/"semanticdb"}", s"-Ddotty.tools.dotc.coverage.test=${(ThisBuild / baseDirectory).value/"tests"/"coverage"}", - ), testCompilation := Def.inputTaskDyn { diff --git a/tests/coverage/expect/ContextFunctions.scala b/tests/coverage/expect/ContextFunctions.scala deleted file mode 100644 index e1338b1a1f75..000000000000 --- a/tests/coverage/expect/ContextFunctions.scala +++ /dev/null @@ -1,30 +0,0 @@ -package example - -/** - * Intersection Types: https://dotty.epfl.ch/docs/reference/new-types/intersection-types.html - * Taken from https://github.com/scala/scala3-example-project - */ -object IntersectionTypes: - - sealed trait X: - def x: Double - def tpe: X - - sealed trait Y: - def y: Double - def tpe: Y - - type P = Y & X - type PP = X & Y - - final case class Point(x: Double, y: Double) extends X with Y: - override def tpe: X & Y = ??? - - def test(): Unit = - def euclideanDistance(p1: X & Y, p2: X & Y) = - Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) - - val p1: P = Point(3, 4) - val p2: PP = Point(6, 8) - println(euclideanDistance(p1, p2)) - diff --git a/tests/coverage/expect/Enum.scala b/tests/coverage/expect/Enum.scala index 6f99daae5240..b5710432f6b6 100644 --- a/tests/coverage/expect/Enum.scala +++ b/tests/coverage/expect/Enum.scala @@ -1,4 +1,4 @@ -package example +package covtest /** * Enum Types: https://dotty.epfl.ch/docs/reference/enums/adts.html @@ -6,10 +6,9 @@ package example */ object EnumTypes: - enum ListEnum[+A]: + enum ListEnum[+A]: case Cons(h: A, t: ListEnum[A]) case Empty - enum Planet(mass: Double, radius: Double): private final val G = 6.67300E-11 diff --git a/tests/coverage/expect/Enum.scoverage.check b/tests/coverage/expect/Enum.scoverage.check new file mode 100644 index 000000000000..001fb41321a1 --- /dev/null +++ b/tests/coverage/expect/Enum.scoverage.check @@ -0,0 +1,446 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Enum.scala +covtest +Planet +Class +covtest.Planet + +322 +333 +13 + +Literal +false +0 +false +6.67300E-11 + +2 +tests/coverage/expect/Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceGravity +359 +367 +14 +* +Apply +false +0 +false +G * mass + +3 +tests/coverage/expect/Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceGravity +359 +367 +14 +* +Apply +false +0 +false +G * mass + +4 +tests/coverage/expect/Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceGravity +371 +386 +14 +* +Apply +false +0 +false +radius * radius + +5 +tests/coverage/expect/Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceGravity +359 +386 +14 +/ +Apply +false +0 +false +G * mass / (radius * radius + +6 +tests/coverage/expect/Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceWeight +432 +458 +15 +* +Apply +false +0 +false +otherMass * surfaceGravity + +7 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1004 +1036 +29 +apply +Apply +false +0 +false +ListEnum.Cons(3, ListEnum.Empty) + +8 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +987 +1037 +29 +apply +Apply +false +0 +false +ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty)) + +9 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +970 +1038 +29 +apply +Apply +false +0 +false +ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) + +10 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1051 +1076 +30 ++ +Apply +false +0 +false +"Example 1: \n"+emptyList + +11 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1043 +1077 +30 +println +Apply +false +0 +false +println("Example 1: \n"+emptyList) + +12 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1092 +1101 +31 +apply +Apply +false +0 +false +${list}\n + +13 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1092 +1101 +31 +apply +Apply +false +0 +false +${list}\n + +14 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1090 +1102 +31 +s +Apply +false +0 +false +s"${list}\n" + +15 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1082 +1103 +31 +println +Apply +false +0 +false +println(s"${list}\n") + +16 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +calculateEarthWeightOnPlanets +1183 +1222 +34 +/ +Apply +false +0 +false +earthWeight/Planet.Earth.surfaceGravity + +17 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +calculateEarthWeightOnPlanets +1238 +1251 +35 +refArrayOps +Apply +false +0 +false +Planet.values + +18 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +$anonfun +1273 +1318 +36 +apply +Apply +false +0 +false +Your weight on $p is ${p.surfaceWeight(mass)} + +19 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +$anonfun +1273 +1318 +36 +apply +Apply +false +0 +false +Your weight on $p is ${p.surfaceWeight(mass)} + +20 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +$anonfun +1296 +1317 +36 +surfaceWeight +Apply +false +0 +false +p.surfaceWeight(mass) + +21 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +$anonfun +1271 +1319 +36 +s +Apply +false +0 +false +s"Your weight on $p is ${p.surfaceWeight(mass)}" + +22 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +$anonfun +1263 +1320 +36 +println +Apply +false +0 +false +println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + +23 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +calculateEarthWeightOnPlanets +1229 +1320 +35 +foreach +Apply +false +0 +false +for p <- Planet.values do + println(s"Your weight on $p is ${p.surfaceWeight(mass)}") + +24 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1326 +1347 +38 +println +Apply +false +0 +false +println("Example 2:") + +25 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Class +covtest.EnumTypes$ +test +1352 +1385 +39 +calculateEarthWeightOnPlanets +Apply +false +0 +false +calculateEarthWeightOnPlanets(80) + diff --git a/tests/coverage/expect/Givens.scala b/tests/coverage/expect/Givens.scala new file mode 100644 index 000000000000..ae29f6eb7f8f --- /dev/null +++ b/tests/coverage/expect/Givens.scala @@ -0,0 +1,24 @@ +package covtest + +import scala.language.strictEquality + +class Context(val id: Int) + +object Givens: + + def test(): Unit = + given CanEqual[Int, String] = CanEqual.derived + println(3 == "3") + println(3 == 5.1) + + def printContext(msg: String)(using ctx: Context): Unit = + println(msg) + println(ctx.id) + + def getMessage(i: Int): String = i.toString + + def test2() = + // TODO FIXME: this does not work if we remove the def declaration (compiler crash in LambdaLift) + given c: Context = Context(0) + printContext("test")(using c) + printContext(getMessage(123)) diff --git a/tests/coverage/expect/Givens.scoverage.check b/tests/coverage/expect/Givens.scoverage.check new file mode 100644 index 000000000000..1235a0387f5c --- /dev/null +++ b/tests/coverage/expect/Givens.scoverage.check @@ -0,0 +1,224 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test +183 +191 +10 +== +Apply +false +0 +false +3 == "3" + +2 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test +175 +192 +10 +println +Apply +false +0 +false +println(3 == "3") + +3 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test +205 +213 +11 +== +Apply +false +0 +false +3 == 5.1 + +4 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test +197 +214 +11 +println +Apply +false +0 +false +println(3 == 5.1) + +5 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +printContext +280 +292 +14 +println +Apply +false +0 +false +println(msg) + +6 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +printContext +297 +312 +15 +println +Apply +false +0 +false +println(ctx.id) + +7 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +getMessage +349 +359 +17 +toString +Apply +false +0 +false +i.toString + +8 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test2 +510 +511 +21 + +Literal +false +0 +false +0 + +9 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test2 +502 +512 +21 + +Apply +false +0 +false +Context(0) + +10 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test2 +517 +546 +22 +printContext +Apply +false +0 +false +printContext("test")(using c) + +11 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test2 +564 +579 +23 +getMessage +Apply +false +0 +false +getMessage(123) + +12 +tests/coverage/expect/Givens.scala +covtest +Givens$ +Class +covtest.Givens$ +test2 +551 +580 +23 +printContext +Apply +false +0 +false +printContext(getMessage(123)) + diff --git a/tests/coverage/expect/Lifting.scala b/tests/coverage/expect/Lifting.scala new file mode 100644 index 000000000000..5e41eb172db3 --- /dev/null +++ b/tests/coverage/expect/Lifting.scala @@ -0,0 +1,12 @@ +package covtest + +class A: + def msg(a: Int, b: Int, c: Int) = "string" + def integer: Int = 0 + def ex: this.type = this + +def test(): Unit = + val a = A() + val i = 123 + a.msg(i, 0, a.integer) + a.ex.msg(i, 0, a.ex.integer) diff --git a/tests/coverage/expect/Lifting.scoverage.check b/tests/coverage/expect/Lifting.scoverage.check new file mode 100644 index 000000000000..b77989de97a1 --- /dev/null +++ b/tests/coverage/expect/Lifting.scoverage.check @@ -0,0 +1,122 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Lifting.scala +covtest +A +Class +covtest.A +msg +62 +70 +3 + +Literal +false +0 +false +"string" + +2 +tests/coverage/expect/Lifting.scala +covtest +A +Class +covtest.A +integer +92 +93 +4 + +Literal +false +0 +false +0 + +3 +tests/coverage/expect/Lifting.scala +covtest +Lifting$package$ +Class +covtest.Lifting$package$ +test +151 +154 +8 + +Apply +false +0 +false +A() + +4 +tests/coverage/expect/Lifting.scala +covtest +Lifting$package$ +Class +covtest.Lifting$package$ +test +165 +168 +9 + +Literal +false +0 +false +123 + +5 +tests/coverage/expect/Lifting.scala +covtest +Lifting$package$ +Class +covtest.Lifting$package$ +test +171 +193 +10 +msg +Apply +false +0 +false +a.msg(i, 0, a.integer) + +6 +tests/coverage/expect/Lifting.scala +covtest +Lifting$package$ +Class +covtest.Lifting$package$ +test +196 +224 +11 +msg +Apply +false +0 +false +a.ex.msg(i, 0, a.ex.integer) + diff --git a/tests/coverage/expect/Literals.scala b/tests/coverage/expect/Literals.scala new file mode 100644 index 000000000000..e8b55349d300 --- /dev/null +++ b/tests/coverage/expect/Literals.scala @@ -0,0 +1,11 @@ + +def mustBeInstrumented = "literal" + +def thisOneToo = + println("not this") // this literal should not be instrumented, only the println call + 12 // this literal must instrumented + +def f(x: Int, y: Int, z: Int)(t: Int) = ??? + +def main: Unit = + f(0,1,2)(3) diff --git a/tests/coverage/expect/Literals.scoverage.check b/tests/coverage/expect/Literals.scoverage.check new file mode 100644 index 000000000000..8087fd68835c --- /dev/null +++ b/tests/coverage/expect/Literals.scoverage.check @@ -0,0 +1,88 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Literals.scala + +Literals$package$ +Class +.Literals$package$ +mustBeInstrumented +26 +35 +1 + +Literal +false +0 +false +"literal" + +2 +tests/coverage/expect/Literals.scala + +Literals$package$ +Class +.Literals$package$ +thisOneToo +56 +75 +4 +println +Apply +false +0 +false +println("not this") + +3 +tests/coverage/expect/Literals.scala + +Literals$package$ +Class +.Literals$package$ +thisOneToo +144 +146 +5 + +Literal +false +0 +false +12 + +4 +tests/coverage/expect/Literals.scala + +Literals$package$ +Class +.Literals$package$ +main +246 +257 +10 +f +Apply +false +0 +false +f(0,1,2)(3) + diff --git a/tests/coverage/expect/MatchCaseClasses.scala b/tests/coverage/expect/MatchCaseClasses.scala new file mode 100644 index 000000000000..9e94be869a37 --- /dev/null +++ b/tests/coverage/expect/MatchCaseClasses.scala @@ -0,0 +1,15 @@ +package covtest + +case class Pat1(x: Int) +case class Pat2(x: Int, y: Any) + +object MatchCaseClasses: + def f(x: Any): Unit = x match + case Pat1(0) => println("a") + case Pat1(_) => println("b") + case p @ Pat2(1, -1) => println("c") + case Pat2(_, y: String) => + println(y) + println("d") + case p: Pat2 => println("e") + case _ => println("other") diff --git a/tests/coverage/expect/MatchCaseClasses.scoverage.check b/tests/coverage/expect/MatchCaseClasses.scoverage.check new file mode 100644 index 000000000000..8a5cb6333f67 --- /dev/null +++ b/tests/coverage/expect/MatchCaseClasses.scoverage.check @@ -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 +# ------------------------------------------ +1 +tests/coverage/expect/MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Class +covtest.MatchCaseClasses$ +f +151 +163 +7 +println +Apply +false +0 +false +println("a") + +2 +tests/coverage/expect/MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Class +covtest.MatchCaseClasses$ +f +184 +196 +8 +println +Apply +false +0 +false +println("b") + +3 +tests/coverage/expect/MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Class +covtest.MatchCaseClasses$ +f +225 +237 +9 +println +Apply +false +0 +false +println("c") + +4 +tests/coverage/expect/MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Class +covtest.MatchCaseClasses$ +f +275 +285 +11 +println +Apply +false +0 +false +println(y) + +5 +tests/coverage/expect/MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Class +covtest.MatchCaseClasses$ +f +292 +304 +12 +println +Apply +false +0 +false +println("d") + +6 +tests/coverage/expect/MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Class +covtest.MatchCaseClasses$ +f +325 +337 +13 +println +Apply +false +0 +false +println("e") + +7 +tests/coverage/expect/MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Class +covtest.MatchCaseClasses$ +f +352 +368 +14 +println +Apply +false +0 +false +println("other") + diff --git a/tests/coverage/expect/MatchNumbers.scala b/tests/coverage/expect/MatchNumbers.scala new file mode 100644 index 000000000000..f160ab883402 --- /dev/null +++ b/tests/coverage/expect/MatchNumbers.scala @@ -0,0 +1,12 @@ +package covtest + +object MatchNumbers: + type Integer = Int | Long + + def f(i: Integer): Int = i match + case x: Int if x < 0 => -1 + case x: Int => x + case y: Long => y.toInt + + f(0) + f(1L) diff --git a/tests/coverage/expect/MatchNumbers.scoverage.check b/tests/coverage/expect/MatchNumbers.scoverage.check new file mode 100644 index 000000000000..78fae5188293 --- /dev/null +++ b/tests/coverage/expect/MatchNumbers.scoverage.check @@ -0,0 +1,105 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/MatchNumbers.scala +covtest +MatchNumbers$ +Class +covtest.MatchNumbers$ +f +125 +126 +6 + +Literal +false +0 +false +0 + +2 +tests/coverage/expect/MatchNumbers.scala +covtest +MatchNumbers$ +Class +covtest.MatchNumbers$ +f +121 +126 +6 +< +Apply +false +0 +false +x < 0 + +3 +tests/coverage/expect/MatchNumbers.scala +covtest +MatchNumbers$ +Class +covtest.MatchNumbers$ +f +130 +132 +6 + +Literal +false +0 +false +-1 + +4 +tests/coverage/expect/MatchNumbers.scala +covtest +MatchNumbers$ +Class +covtest.MatchNumbers$ + +185 +189 +10 +f +Apply +false +0 +false +f(0) + +5 +tests/coverage/expect/MatchNumbers.scala +covtest +MatchNumbers$ +Class +covtest.MatchNumbers$ + +192 +197 +11 +f +Apply +false +0 +false +f(1L) + diff --git a/tests/coverage/expect/MultiversalEquality.scala b/tests/coverage/expect/MultiversalEquality.scala deleted file mode 100644 index ace2fd642c2c..000000000000 --- a/tests/coverage/expect/MultiversalEquality.scala +++ /dev/null @@ -1,31 +0,0 @@ -package example - -import scala.language.strictEquality - -/** - * Multiversal Equality: https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html - * scala.CanEqual definition: https://github.com/lampepfl/dotty/blob/master/library/src/scala/CanEqual.scala - * Taken from https://github.com/scala/scala3-example-project - */ -object MultiversalEquality: - - def test(): Unit = - given CanEqual[Int, String] = CanEqual.derived - println(3 == "3") - - println(3 == 5.1) - - println(List(1, 2) == Vector(1, 2)) - - class A(a: Int) - class B(b: Int) - - val a = A(4) - val b = B(4) - - given CanEqual[A, B] = CanEqual.derived - given CanEqual[B, A] = CanEqual.derived - - println(a != b) - println(b == a) - diff --git a/tests/coverage/expect/ParameterUntupling.scala b/tests/coverage/expect/ParameterUntupling.scala deleted file mode 100644 index 533c4c3f3362..000000000000 --- a/tests/coverage/expect/ParameterUntupling.scala +++ /dev/null @@ -1,19 +0,0 @@ -package example - -/** - * Parameter Untupling: https://dotty.epfl.ch/docs/reference/other-new-features/parameter-untupling.html - * Taken from https://github.com/scala/scala3-example-project - */ -object ParameterUntupling: - - def test(): Unit = - val xs: List[String] = List("d", "o", "t", "t", "y") - - /** - * Current behaviour in Scala 2.12.2 : - * error: missing parameter type - * Note: The expected type requires a one-argument function accepting a 2-Tuple. - * Consider a pattern matching anonymous function, `{ case (s, i) => ... }` - */ - xs.zipWithIndex.map((s, i) => println(s"$i: $s")) - diff --git a/tests/coverage/expect/ParamsAndInterpolation.scala b/tests/coverage/expect/ParamsAndInterpolation.scala new file mode 100644 index 000000000000..34d7ae300811 --- /dev/null +++ b/tests/coverage/expect/ParamsAndInterpolation.scala @@ -0,0 +1,11 @@ +package covtest + +object ParamsAndInterpolation: + + def simple(a: Int, b: String): String = + s"$a, ${b.length}" + + def test(): Unit = + val xs: List[String] = List("d", "o", "t", "t", "y") + + xs.zipWithIndex.map((s, i) => println(s"$i: $s")) diff --git a/tests/coverage/expect/ParamsAndInterpolation.scoverage.check b/tests/coverage/expect/ParamsAndInterpolation.scoverage.check new file mode 100644 index 000000000000..00c61ad22b39 --- /dev/null +++ b/tests/coverage/expect/ParamsAndInterpolation.scoverage.check @@ -0,0 +1,190 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +simple +97 +112 +5 +apply +Apply +false +0 +false +$a, ${b.length} + +2 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +simple +97 +112 +5 +apply +Apply +false +0 +false +$a, ${b.length} + +3 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +simple +103 +111 +5 +length +Apply +false +0 +false +b.length + +4 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +simple +95 +113 +5 +s +Apply +false +0 +false +s"$a, ${b.length}" + +5 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +test +163 +192 +8 +apply +Apply +false +0 +false +List("d", "o", "t", "t", "y") + +6 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +$anonfun +238 +244 +10 +apply +Apply +false +0 +false +$i: $s + +7 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +$anonfun +238 +244 +10 +apply +Apply +false +0 +false +$i: $s + +8 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +$anonfun +236 +245 +10 +s +Apply +false +0 +false +s"$i: $s" + +9 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +$anonfun +228 +246 +10 +println +Apply +false +0 +false +println(s"$i: $s") + +10 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Class +covtest.ParamsAndInterpolation$ +test +198 +247 +10 +map +Apply +false +0 +false +xs.zipWithIndex.map((s, i) => println(s"$i: $s")) + diff --git a/tests/coverage/expect/PatternMatching.scala b/tests/coverage/expect/PatternMatching.scala deleted file mode 100644 index e2f0403ef87e..000000000000 --- a/tests/coverage/expect/PatternMatching.scala +++ /dev/null @@ -1,87 +0,0 @@ - -package example - -/** - * Pattern Matching: https://dotty.epfl.ch/docs/reference/changed-features/pattern-matching.html - * Taken from https://github.com/scala/scala3-example-project - */ -object PatternMatching: - - object booleanPattern: - - object Even: - def unapply(s: String): Boolean = s.length % 2 == 0 - - - object productPattern: - - class Person(name: String, age: Int) extends Product: - // if we not define that, it will give compile error. - // we change the order - def _1 = age - def _2 = name - - // Not used by pattern matching: Product is only used as a marker trait. - def canEqual(that: Any): Boolean = ??? - def productArity: Int = ??? - def productElement(n: Int): Any = ??? - - object Person: - def unapply(a: (String, Int)): Person = Person(a._1, a._2) - - - object seqPattern: - - // adapted from https://danielwestheide.com/blog/the-neophytes-guide-to-scala-part-2-extracting-sequences/ - object Names: - def unapplySeq(name: String): Option[Seq[String]] = - val names = name.trim.split(" ") - if names.size < 2 then None - else Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) - - - object namePattern: - - class Name(val name: String): - def get: String = name - def isEmpty = name.isEmpty - - object Name: - def unapply(s: String): Name = Name(s) - - - def test(): Unit = - import booleanPattern.* - - "even" match - case s @ Even() => println(s"$s has an even number of characters") - case s => println(s"$s has an odd number of characters") - - // https://dotty.epfl.ch/docs/reference/changed-features/vararg-splices.html - def containsConsecutive(list: List[Int]): Boolean = list match - case List(a, b, xs*) => a == b || containsConsecutive(b :: xs.toList) - case Nil | List(_, _*) => false - - println(containsConsecutive(List(1, 2, 3, 4, 5))) - println(containsConsecutive(List(1, 2, 3, 3, 5))) - - import productPattern.* - ("john", 42) match - case Person(n, a) => println(s"name: $n, age: $a") - - import seqPattern.* - - def greet(fullName: String) = fullName match - case Names(lastName, firstName, _*) => "Good morning, " + firstName + " " + lastName + "!" - case _ => "Welcome! Please make sure to fill in your name!" - - println(greet("Alan Turing")) - println(greet("john")) - println(greet("Wolfgang Amadeus Mozart")) - - import namePattern.* - "alice" match - case Name(n) => println(s"name is $n") - case _ => println("empty name") - -end PatternMatching diff --git a/tests/coverage/expect/Select.scala b/tests/coverage/expect/Select.scala new file mode 100644 index 000000000000..2c9e63552586 --- /dev/null +++ b/tests/coverage/expect/Select.scala @@ -0,0 +1,20 @@ +package covtest + +trait T: + def print(): Unit + +class A extends T: + def print() = println("A") + def instance = this + +class B extends A: + override def print() = + super.print() + println(this.instance) + +def test(): Unit = + val a = A() + val aNew = new A + + a.instance.print() // should instrument `a.instance` and `(a.instance).print()` + a.print() diff --git a/tests/coverage/expect/Select.scoverage.check b/tests/coverage/expect/Select.scoverage.check new file mode 100644 index 000000000000..783ef3430a92 --- /dev/null +++ b/tests/coverage/expect/Select.scoverage.check @@ -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 +# ------------------------------------------ +1 +tests/coverage/expect/Select.scala +covtest +A +Class +covtest.A +print +82 +94 +6 +println +Apply +false +0 +false +println("A") + +2 +tests/coverage/expect/Select.scala +covtest +B +Class +covtest.B +print +166 +179 +11 +print +Apply +false +0 +false +super.print() + +3 +tests/coverage/expect/Select.scala +covtest +B +Class +covtest.B +print +184 +206 +12 +println +Apply +false +0 +false +println(this.instance) + +4 +tests/coverage/expect/Select.scala +covtest +Select$package$ +Class +covtest.Select$package$ +test +237 +240 +15 + +Apply +false +0 +false +A() + +5 +tests/coverage/expect/Select.scala +covtest +Select$package$ +Class +covtest.Select$package$ +test +254 +259 +16 + +Apply +false +0 +false +new A + +6 +tests/coverage/expect/Select.scala +covtest +Select$package$ +Class +covtest.Select$package$ +test +263 +281 +18 +print +Apply +false +0 +false +a.instance.print() + +7 +tests/coverage/expect/Select.scala +covtest +Select$package$ +Class +covtest.Select$package$ +test +345 +354 +19 +print +Apply +false +0 +false +a.print() + diff --git a/tests/coverage/expect/StructuralTypes.scala b/tests/coverage/expect/StructuralTypes.scala index 4b2ee1991ce6..f0472345b9d4 100644 --- a/tests/coverage/expect/StructuralTypes.scala +++ b/tests/coverage/expect/StructuralTypes.scala @@ -1,9 +1,5 @@ -package example +package covtest -/** - * Structural Types: https://dotty.epfl.ch/docs/reference/changed-features/structural-types.html - * Taken from https://github.com/scala/scala3-example-project - */ object StructuralTypes: case class Record(elems: (String, Any)*) extends Selectable: @@ -11,19 +7,8 @@ object StructuralTypes: type Person = Record { val name: String - val age: Int } - val person = Record("name" -> "Emma", "age" -> 42, "salary" -> 320L).asInstanceOf[Person] - - val invalidPerson = Record("name" -> "John", "salary" -> 42).asInstanceOf[Person] - def test(): Unit = - println(person.name) - println(person.age) - - println(invalidPerson.name) - // age field is java.util.NoSuchElementException: None.get - //println(invalidPerson.age) - -end StructuralTypes + val person = Record("name" -> "Emma", "age" -> 42).asInstanceOf[Person] + person.name diff --git a/tests/coverage/expect/StructuralTypes.scoverage.check b/tests/coverage/expect/StructuralTypes.scoverage.check new file mode 100644 index 000000000000..1bc6fb449fdc --- /dev/null +++ b/tests/coverage/expect/StructuralTypes.scoverage.check @@ -0,0 +1,156 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/StructuralTypes.scala +covtest +Record +Class +covtest.Record +$anonfun +159 +171 +5 +== +Apply +false +0 +false +_._1 == name + +2 +tests/coverage/expect/StructuralTypes.scala +covtest +Record +Class +covtest.Record +selectDynamic +148 +172 +5 +find +Apply +false +0 +false +elems.find(_._1 == name) + +3 +tests/coverage/expect/StructuralTypes.scala +covtest +StructuralTypes$ +Class +covtest.StructuralTypes$ +test +277 +283 +12 +ArrowAssoc +Apply +false +0 +false +"name" + +4 +tests/coverage/expect/StructuralTypes.scala +covtest +StructuralTypes$ +Class +covtest.StructuralTypes$ +test +277 +293 +12 +-> +Apply +false +0 +false +"name" -> "Emma" + +5 +tests/coverage/expect/StructuralTypes.scala +covtest +StructuralTypes$ +Class +covtest.StructuralTypes$ +test +295 +300 +12 +ArrowAssoc +Apply +false +0 +false +"age" + +6 +tests/coverage/expect/StructuralTypes.scala +covtest +StructuralTypes$ +Class +covtest.StructuralTypes$ +test +295 +306 +12 +-> +Apply +false +0 +false +"age" -> 42 + +7 +tests/coverage/expect/StructuralTypes.scala +covtest +StructuralTypes$ +Class +covtest.StructuralTypes$ +test +270 +307 +12 +apply +Apply +false +0 +false +Record("name" -> "Emma", "age" -> 42) + +8 +tests/coverage/expect/StructuralTypes.scala +covtest +StructuralTypes$ +Class +covtest.StructuralTypes$ +test +333 +344 +13 +selectDynamic +Apply +false +0 +false +person.name + diff --git a/tests/coverage/expect/TraitParams.scala b/tests/coverage/expect/TraitParams.scala deleted file mode 100644 index fa98a9b23805..000000000000 --- a/tests/coverage/expect/TraitParams.scala +++ /dev/null @@ -1,22 +0,0 @@ -package example - -/** - * Trait Parameters: https://dotty.epfl.ch/docs/reference/other-new-features/trait-parameters.html - * Taken from https://github.com/scala/scala3-example-project - */ -object TraitParams: - - trait Base(val msg: String) - class A extends Base("Hello") - class B extends Base("Dotty!") - - // Union types only exist in Scala 3, so there's no chance that this will accidentally be compiled with Scala 2 - private def printMessages(msgs: (A | B)*) = println(msgs.map(_.msg).mkString(" ")) - - def test(): Unit = - printMessages(new A, new B) - - // Sanity check the classpath: this won't run if the Scala 3 jar is not present. - val x: Int => Int = identity - x(1) - diff --git a/tests/coverage/expect/TypeLambdas.scala b/tests/coverage/expect/TypeLambdas.scala index 9769869b7805..9c7641c025e2 100644 --- a/tests/coverage/expect/TypeLambdas.scala +++ b/tests/coverage/expect/TypeLambdas.scala @@ -1,4 +1,4 @@ -package example +package covtest /** * Type Lambdas: https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html diff --git a/tests/coverage/expect/TypeLambdas.scoverage.check b/tests/coverage/expect/TypeLambdas.scoverage.check new file mode 100644 index 000000000000..85b157a52cdd --- /dev/null +++ b/tests/coverage/expect/TypeLambdas.scoverage.check @@ -0,0 +1,122 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/TypeLambdas.scala +covtest +TypeLambdas$ +Class +covtest.TypeLambdas$ +test +310 +311 +13 +ArrowAssoc +Apply +false +0 +false +1 + +2 +tests/coverage/expect/TypeLambdas.scala +covtest +TypeLambdas$ +Class +covtest.TypeLambdas$ +test +310 +318 +13 +-> +Apply +false +0 +false +1 -> "1" + +3 +tests/coverage/expect/TypeLambdas.scala +covtest +TypeLambdas$ +Class +covtest.TypeLambdas$ +test +306 +319 +13 +apply +Apply +false +0 +false +Map(1 -> "1") + +4 +tests/coverage/expect/TypeLambdas.scala +covtest +TypeLambdas$ +Class +covtest.TypeLambdas$ +test +324 +334 +14 +println +Apply +false +0 +false +println(m) + +5 +tests/coverage/expect/TypeLambdas.scala +covtest +TypeLambdas$ +Class +covtest.TypeLambdas$ +test +367 +377 +16 +apply +Apply +false +0 +false +("a", "b") + +6 +tests/coverage/expect/TypeLambdas.scala +covtest +TypeLambdas$ +Class +covtest.TypeLambdas$ +test +382 +396 +17 +println +Apply +false +0 +false +println(tuple) + diff --git a/tests/coverage/expect/UnionTypes.scala b/tests/coverage/expect/UnionTypes.scala deleted file mode 100644 index a79d8dd8fca4..000000000000 --- a/tests/coverage/expect/UnionTypes.scala +++ /dev/null @@ -1,44 +0,0 @@ - -package example - -/** - * Union Types: https://dotty.epfl.ch/docs/reference/new-types/union-types.html - * Taken from https://github.com/scala/scala3-example-project - */ -object UnionTypes: - - sealed trait Division - final case class DivisionByZero(msg: String) extends Division - final case class Success(double: Double) extends Division - - // You can create type aliases for your union types (sum types). - type DivisionResult = DivisionByZero | Success - - sealed trait List[+A] - case object Empty extends List[Nothing] - final case class Cons[+A](h: A, t: List[A]) extends List[A] - - private def safeDivide(a: Double, b: Double): DivisionResult = - if b == 0 then DivisionByZero("DivisionByZeroException") else Success(a / b) - - private def either(division: Division) = division match - case DivisionByZero(m) => Left(m) - case Success(d) => Right(d) - - def test(): Unit = - val divisionResultSuccess: DivisionResult = safeDivide(4, 2) - - // commutative - val divisionResultFailure: Success | DivisionByZero = safeDivide(4, 0) - - // calling `either` function with union typed value. - println(either(divisionResultSuccess)) - - // calling `either` function with union typed value. - println(either(divisionResultFailure)) - - val list: Cons[Int] | Empty.type = Cons(1, Cons(2, Cons(3, Empty))) - val emptyList: Empty.type | Cons[Any] = Empty - println(list) - println(emptyList) - diff --git a/tests/coverage/scoverage.coverage.expect b/tests/coverage/scoverage.coverage.expect deleted file mode 100644 index 93a8107f4c15..000000000000 --- a/tests/coverage/scoverage.coverage.expect +++ /dev/null @@ -1,3030 +0,0 @@ -# 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 -# ------------------------------------------ -1 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -test -276 -279 -9 - -Literal -false -0 -false -"d" - -2 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -test -281 -284 -9 - -Literal -false -0 -false -"o" - -3 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -test -286 -289 -9 - -Literal -false -0 -false -"t" - -4 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -test -291 -294 -9 - -Literal -false -0 -false -"t" - -5 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -test -296 -299 -9 - -Literal -false -0 -false -"y" - -6 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -test -271 -300 -9 -apply -Apply -false -0 -false -List("d", "o", "t", "t", "y") - -7 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -$anonfun -615 -617 -17 - -Literal -false -0 -false -: - -8 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -$anonfun -613 -619 -17 -apply -Apply -false -0 -false -$i: $s - -9 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -$anonfun -611 -620 -17 -s -Apply -false -0 -false -s"$i: $s" - -10 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -$anonfun -603 -621 -17 -println -Apply -false -0 -false -println(s"$i: $s") - -11 -tests/coverage/expect/ParameterUntupling.scala -example -ParameterUntupling$ -Class -example.ParameterUntupling$ -test -573 -622 -17 -map -Apply -false -0 -false -xs.zipWithIndex.map((s, i) => println(s"$i: $s")) - -12 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -450 -451 -13 - -Literal -false -0 -false -3 - -13 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -455 -458 -13 - -Literal -false -0 -false -"3" - -14 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -442 -459 -13 -println -Apply -false -0 -false -println(3 == "3") - -15 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -473 -474 -15 - -Literal -false -0 -false -3 - -16 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -478 -481 -15 - -Literal -false -0 -false -5.1 - -17 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -501 -502 -17 - -Literal -false -0 -false -1 - -18 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -504 -505 -17 - -Literal -false -0 -false -2 - -19 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -496 -506 -17 -apply -Apply -false -0 -false -List(1, 2) - -20 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -517 -518 -17 - -Literal -false -0 -false -1 - -21 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -520 -521 -17 - -Literal -false -0 -false -2 - -22 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -510 -522 -17 -apply -Apply -false -0 -false -Vector(1, 2) - -23 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -496 -522 -17 -== -Apply -false -0 -false -List(1, 2) == Vector(1, 2) - -24 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -488 -523 -17 -println -Apply -false -0 -false -println(List(1, 2) == Vector(1, 2)) - -25 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -578 -579 -22 - -Select -false -0 -false -A - -26 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -580 -581 -22 - -Literal -false -0 -false -4 - -27 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -595 -596 -23 - -Select -false -0 -false -B - -28 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -597 -598 -23 - -Literal -false -0 -false -4 - -29 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -694 -709 -28 -println -Apply -false -0 -false -println(a != b) - -30 -tests/coverage/expect/MultiversalEquality.scala -example -MultiversalEquality$ -Class -example.MultiversalEquality$ -test -714 -729 -29 -println -Apply -false -0 -false -println(b == a) - -31 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -547 -558 -24 -- -Apply -false -0 -false -p2.y - p1.y - -32 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -560 -561 -24 - -Literal -false -0 -false -2 - -33 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -538 -562 -24 -pow -Apply -false -0 -false -Math.pow(p2.y - p1.y, 2) - -34 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -574 -585 -24 -- -Apply -false -0 -false -p2.x - p1.x - -35 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -587 -588 -24 - -Literal -false -0 -false -2 - -36 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -565 -589 -24 -pow -Apply -false -0 -false -Math.pow(p2.x - p1.x, 2) - -37 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -538 -589 -24 -+ -Apply -false -0 -false -Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2) - -38 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -euclideanDistance -528 -590 -24 -sqrt -Apply -false -0 -false -Math.sqrt(Math.pow(p2.y - p1.y, 2) + Math.pow(p2.x - p1.x, 2)) - -39 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -test -614 -615 -26 - -Literal -false -0 -false -3 - -40 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -test -617 -618 -26 - -Literal -false -0 -false -4 - -41 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -test -643 -644 -27 - -Literal -false -0 -false -6 - -42 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -test -646 -647 -27 - -Literal -false -0 -false -8 - -43 -tests/coverage/expect/ContextFunctions.scala -example -IntersectionTypes$ -Class -example.IntersectionTypes$ -test -653 -687 -28 -println -Apply -false -0 -false -println(euclideanDistance(p1, p2)) - -44 -tests/coverage/expect/TypeLambdas.scala -example -TypeLambdas$ -Class -example.TypeLambdas$ -test -310 -311 -13 - -Literal -false -0 -false -1 - -45 -tests/coverage/expect/TypeLambdas.scala -example -TypeLambdas$ -Class -example.TypeLambdas$ -test -315 -318 -13 - -Literal -false -0 -false -"1" - -46 -tests/coverage/expect/TypeLambdas.scala -example -TypeLambdas$ -Class -example.TypeLambdas$ -test -306 -319 -13 -apply -Apply -false -0 -false -Map(1 -> "1") - -47 -tests/coverage/expect/TypeLambdas.scala -example -TypeLambdas$ -Class -example.TypeLambdas$ -test -368 -371 -16 - -Literal -false -0 -false -"a" - -48 -tests/coverage/expect/TypeLambdas.scala -example -TypeLambdas$ -Class -example.TypeLambdas$ -test -373 -376 -16 - -Literal -false -0 -false -"b" - -49 -tests/coverage/expect/StructuralTypes.scala -example -Record -Class -example.Record -selectDynamic -319 -343 -9 -find -Apply -false -0 -false -elems.find(_._1 == name) - -50 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -442 -448 -16 - -Literal -false -0 -false -"name" - -51 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -452 -458 -16 - -Literal -false -0 -false -"Emma" - -52 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -460 -465 -16 - -Literal -false -0 -false -"age" - -53 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -469 -471 -16 - -Literal -false -0 -false -42 - -54 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -473 -481 -16 - -Literal -false -0 -false -"salary" - -55 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -485 -489 -16 - -Literal -false -0 -false -320L - -56 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -435 -490 -16 -apply -Apply -false -0 -false -Record("name" -> "Emma", "age" -> 42, "salary" -> 320L) - -57 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -542 -548 -18 - -Literal -false -0 -false -"name" - -58 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -552 -558 -18 - -Literal -false -0 -false -"John" - -59 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -560 -568 -18 - -Literal -false -0 -false -"salary" - -60 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -572 -574 -18 - -Literal -false -0 -false -42 - -61 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ - -535 -575 -18 -apply -Apply -false -0 -false -Record("name" -> "John", "salary" -> 42) - -62 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ -test -623 -643 -21 -println -Apply -false -0 -false -println(person.name) - -63 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ -test -648 -667 -22 -println -Apply -false -0 -false -println(person.age) - -64 -tests/coverage/expect/StructuralTypes.scala -example -StructuralTypes$ -Class -example.StructuralTypes$ -test -673 -700 -24 -println -Apply -false -0 -false -println(invalidPerson.name) - -65 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -safeDivide -663 -664 -21 - -Literal -false -0 -false -0 - -66 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -safeDivide -685 -710 -21 - -Literal -false -0 -false -"DivisionByZeroException" - -67 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -safeDivide -670 -711 -21 -apply -Apply -true -0 -false -DivisionByZero("DivisionByZeroException") - -68 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -safeDivide -717 -731 -21 -apply -Apply -false -0 -false -Success(a / b) - -69 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -safeDivide -717 -731 -21 - -Block -true -0 -false -Success(a / b) - -70 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -949 -950 -28 - -Literal -false -0 -false -4 - -71 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -952 -953 -28 - -Literal -false -0 -false -2 - -72 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1044 -1045 -31 - -Literal -false -0 -false -4 - -73 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1047 -1048 -31 - -Literal -false -0 -false -0 - -74 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1112 -1150 -34 -println -Apply -false -0 -false -println(either(divisionResultSuccess)) - -75 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1213 -1251 -37 -println -Apply -false -0 -false -println(either(divisionResultFailure)) - -76 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1297 -1298 -39 - -Literal -false -0 -false -1 - -77 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1305 -1306 -39 - -Literal -false -0 -false -2 - -78 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1313 -1314 -39 - -Literal -false -0 -false -3 - -79 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1300 -1323 -39 -apply -Apply -false -0 -false -Cons(2, Cons(3, Empty)) - -80 -tests/coverage/expect/UnionTypes.scala -example -UnionTypes$ -Class -example.UnionTypes$ -test -1292 -1324 -39 -apply -Apply -false -0 -false -Cons(1, Cons(2, Cons(3, Empty))) - -81 -tests/coverage/expect/PatternMatching.scala -example -Even$ -Class -example.Even$ -unapply -296 -306 -12 -% -Select -false -0 -false -s.length % - -82 -tests/coverage/expect/PatternMatching.scala -example -Even$ -Class -example.Even$ -unapply -307 -308 -12 - -Literal -false -0 -false -2 - -83 -tests/coverage/expect/PatternMatching.scala -example -Even$ -Class -example.Even$ -unapply -312 -313 -12 - -Literal -false -0 -false -0 - -84 -tests/coverage/expect/PatternMatching.scala -example -Person$ -Class -example.Person$ -unapply -797 -803 -29 - -Select -false -0 -false -Person - -85 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1047 -1062 -37 -split -Select -false -0 -false -name.trim.split - -86 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1063 -1066 -37 - -Literal -false -0 -false -" " - -87 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1092 -1093 -38 - -Literal -false -0 -false -2 - -88 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1099 -1103 -38 -None -Ident -true -0 -false -None - -89 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1161 -1162 -39 - -Literal -false -0 -false -1 - -90 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1150 -1163 -39 -refArrayOps -Apply -false -0 -false -names.drop(1) - -91 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1174 -1175 -39 - -Literal -false -0 -false -1 - -92 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1150 -1176 -39 -wrapRefArray -Apply -false -0 -false -names.drop(1).dropRight(1) - -93 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1117 -1184 -39 -apply -Apply -false -0 -false -Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) - -94 -tests/coverage/expect/PatternMatching.scala -example -Names$ -Class -example.Names$ -unapplySeq -1117 -1184 -39 - -Block -true -0 -false -Some(names.last :: names.head :: names.drop(1).dropRight(1).toList) - -95 -tests/coverage/expect/PatternMatching.scala -example -Name$ -Class -example.Name$ -unapply -1361 -1365 -49 - -Select -false -0 -false -Name - -96 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1425 -1431 -55 - -Literal -false -0 -false -"even" - -97 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1475 -1508 -56 - -Literal -false -0 -false - has an even number of characters - -98 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1473 -1508 -56 -apply -Apply -false -0 -false -$s has an even number of characters - -99 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1471 -1509 -56 -s -Apply -false -0 -false -s"$s has an even number of characters" - -100 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1463 -1510 -56 -println -Apply -false -0 -false -println(s"$s has an even number of characters") - -101 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1548 -1580 -57 - -Literal -false -0 -false - has an odd number of characters - -102 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1546 -1580 -57 -apply -Apply -false -0 -false -$s has an odd number of characters - -103 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1544 -1581 -57 -s -Apply -false -0 -false -s"$s has an odd number of characters" - -104 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1536 -1582 -57 -println -Apply -false -0 -false -println(s"$s has an odd number of characters") - -105 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -containsConsecutive -1775 -1810 -61 -containsConsecutive -Apply -false -0 -false -containsConsecutive(b :: xs.toList) - -106 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -containsConsecutive -1843 -1848 -62 - -Literal -false -0 -false -false - -107 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1887 -1888 -64 - -Literal -false -0 -false -1 - -108 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1890 -1891 -64 - -Literal -false -0 -false -2 - -109 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1893 -1894 -64 - -Literal -false -0 -false -3 - -110 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1896 -1897 -64 - -Literal -false -0 -false -4 - -111 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1899 -1900 -64 - -Literal -false -0 -false -5 - -112 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1882 -1901 -64 -apply -Apply -false -0 -false -List(1, 2, 3, 4, 5) - -113 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1862 -1902 -64 -containsConsecutive -Apply -false -0 -false -containsConsecutive(List(1, 2, 3, 4, 5)) - -114 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1854 -1903 -64 -println -Apply -false -0 -false -println(containsConsecutive(List(1, 2, 3, 4, 5))) - -115 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1941 -1942 -65 - -Literal -false -0 -false -1 - -116 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1944 -1945 -65 - -Literal -false -0 -false -2 - -117 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1947 -1948 -65 - -Literal -false -0 -false -3 - -118 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1950 -1951 -65 - -Literal -false -0 -false -3 - -119 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1953 -1954 -65 - -Literal -false -0 -false -5 - -120 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1936 -1955 -65 -apply -Apply -false -0 -false -List(1, 2, 3, 3, 5) - -121 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1916 -1956 -65 -containsConsecutive -Apply -false -0 -false -containsConsecutive(List(1, 2, 3, 3, 5)) - -122 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1908 -1957 -65 -println -Apply -false -0 -false -println(containsConsecutive(List(1, 2, 3, 3, 5))) - -123 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -1992 -1998 -68 - -Literal -false -0 -false -"john" - -124 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2000 -2002 -68 - -Literal -false -0 -false -42 - -125 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2048 -2054 -69 - -Literal -false -0 -false -name: - -126 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2056 -2063 -69 - -Literal -false -0 -false -, age: - -127 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2048 -2065 -69 -apply -Apply -false -0 -false -name: $n, age: $a - -128 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2046 -2066 -69 -s -Apply -false -0 -false -s"name: $n, age: $a" - -129 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2038 -2067 -69 -println -Apply -false -0 -false -println(s"name: $n, age: $a") - -130 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -greet -2189 -2205 -74 - -Literal -false -0 -false -"Good morning, " - -131 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -greet -2220 -2223 -74 - -Literal -false -0 -false -" " - -132 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -greet -2237 -2240 -74 - -Literal -false -0 -false -"!" - -133 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -greet -2286 -2335 -75 - -Literal -false -0 -false -"Welcome! Please make sure to fill in your name!" - -134 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2359 -2372 -77 - -Literal -false -0 -false -"Alan Turing" - -135 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2345 -2374 -77 -println -Apply -false -0 -false -println(greet("Alan Turing")) - -136 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2393 -2399 -78 - -Literal -false -0 -false -"john" - -137 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2379 -2401 -78 -println -Apply -false -0 -false -println(greet("john")) - -138 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2420 -2445 -79 - -Literal -false -0 -false -"Wolfgang Amadeus Mozart" - -139 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2406 -2447 -79 -println -Apply -false -0 -false -println(greet("Wolfgang Amadeus Mozart")) - -140 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2478 -2485 -82 - -Literal -false -0 -false -"alice" - -141 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2525 -2533 -83 - -Literal -false -0 -false -name is - -142 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2525 -2535 -83 -apply -Apply -false -0 -false -name is $n - -143 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2523 -2536 -83 -s -Apply -false -0 -false -s"name is $n" - -144 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2515 -2537 -83 -println -Apply -false -0 -false -println(s"name is $n") - -145 -tests/coverage/expect/PatternMatching.scala -example -PatternMatching$ -Class -example.PatternMatching$ -test -2568 -2580 -84 - -Literal -false -0 -false -"empty name" - -146 -tests/coverage/expect/TraitParams.scala -example -TraitParams$ -Class -example.TraitParams$ -printMessages -475 -490 -13 -map -Apply -false -0 -false -msgs.map(_.msg) - -147 -tests/coverage/expect/TraitParams.scala -example -TraitParams$ -Class -example.TraitParams$ -printMessages -500 -503 -13 - -Literal -false -0 -false -" " - -148 -tests/coverage/expect/TraitParams.scala -example -TraitParams$ -Class -example.TraitParams$ -printMessages -467 -505 -13 -println -Apply -false -0 -false -println(msgs.map(_.msg).mkString(" ")) - -149 -tests/coverage/expect/TraitParams.scala -example -TraitParams$ -Class -example.TraitParams$ -test -550 -551 -16 - -Select -false -0 -false -A - -150 -tests/coverage/expect/TraitParams.scala -example -TraitParams$ -Class -example.TraitParams$ -test -557 -558 -16 - -Select -false -0 -false -B - -151 -tests/coverage/expect/TraitParams.scala -example -TraitParams$ -Class -example.TraitParams$ -test -532 -559 -16 -printMessages -Apply -false -0 -false -printMessages(new A, new B) - -152 -tests/coverage/expect/TraitParams.scala -example -TraitParams$ -Class -example.TraitParams$ -test -685 -686 -20 - -Literal -false -0 -false -1 - -153 -tests/coverage/expect/Enum.scala -example -Planet -Class -example.Planet - -326 -337 -14 - -Literal -false -0 -false -6.67300E-11 - -154 -tests/coverage/expect/Enum.scala -example -Planet -Class -example.Planet -surfaceGravity -363 -390 -15 -/ -Apply -false -0 -false -G * mass / (radius * radius - -155 -tests/coverage/expect/Enum.scala -example -Planet -Class -example.Planet -surfaceWeight -436 -462 -16 -* -Apply -false -0 -false -otherMass * surfaceGravity - -156 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -988 -989 -30 - -Literal -false -0 -false -1 - -157 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1005 -1006 -30 - -Literal -false -0 -false -2 - -158 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1022 -1023 -30 - -Literal -false -0 -false -3 - -159 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1008 -1040 -30 -apply -Apply -false -0 -false -ListEnum.Cons(3, ListEnum.Empty) - -160 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -991 -1041 -30 -apply -Apply -false -0 -false -ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty)) - -161 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -974 -1042 -30 -apply -Apply -false -0 -false -ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) - -162 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1055 -1070 -31 - -Literal -false -0 -false -"Example 1: \n" - -163 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1047 -1081 -31 -println -Apply -false -0 -false -println("Example 1: \n"+emptyList) - -164 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1103 -1105 -32 - -Literal -false -0 -false -\n - -165 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1096 -1105 -32 -apply -Apply -false -0 -false -${list}\n - -166 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1094 -1106 -32 -s -Apply -false -0 -false -s"${list}\n" - -167 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1086 -1107 -32 -println -Apply -false -0 -false -println(s"${list}\n") - -168 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -calculateEarthWeightOnPlanets -1187 -1226 -35 -/ -Apply -false -0 -false -earthWeight/Planet.Earth.surfaceGravity - -169 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -calculateEarthWeightOnPlanets -1242 -1255 -36 -refArrayOps -Apply -false -0 -false -Planet.values - -170 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -$anonfun -1277 -1292 -37 - -Literal -false -0 -false -Your weight on - -171 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -$anonfun -1294 -1298 -37 - -Literal -false -0 -false - is - -172 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -$anonfun -1277 -1322 -37 -apply -Apply -false -0 -false -Your weight on $p is ${p.surfaceWeight(mass)} - -173 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -$anonfun -1275 -1323 -37 -s -Apply -false -0 -false -s"Your weight on $p is ${p.surfaceWeight(mass)}" - -174 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -$anonfun -1267 -1324 -37 -println -Apply -false -0 -false -println(s"Your weight on $p is ${p.surfaceWeight(mass)}") - -175 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -calculateEarthWeightOnPlanets -1233 -1324 -36 -foreach -Apply -false -0 -false -for p <- Planet.values do - println(s"Your weight on $p is ${p.surfaceWeight(mass)}") - -176 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1338 -1350 -39 - -Literal -false -0 -false -"Example 2:" - -177 -tests/coverage/expect/Enum.scala -example -EnumTypes$ -Class -example.EnumTypes$ -test -1386 -1388 -40 - -Literal -false -0 -false -80 - From bad8b86903ce9007467e58d2f6f415513b50d3fc Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Thu, 24 Mar 2022 18:23:39 +0100 Subject: [PATCH 06/15] Fix contexts in instrumentCoverage Also add more tests and fix the remaining todo --- .../dotty/tools/dotc/coverage/Location.scala | 13 +- .../dotc/transform/InstrumentCoverage.scala | 89 +++--- .../dotty/tools/dotc/transform/Mixin.scala | 1 + .../tools/dotc/coverage/CoverageTests.scala | 1 + tests/coverage/expect/Constructor.scala | 11 + .../expect/Constructor.scoverage.check | 88 ++++++ tests/coverage/expect/Enum.scoverage.check | 269 ++++++++++++++--- tests/coverage/expect/Givens.scala | 1 - tests/coverage/expect/Givens.scoverage.check | 69 ++--- tests/coverage/expect/Inheritance.scala | 11 + .../expect/Inheritance.scoverage.check | 173 +++++++++++ tests/coverage/expect/Inlined.scala | 8 + tests/coverage/expect/Inlined.scoverage.check | 275 ++++++++++++++++++ tests/coverage/expect/Lifting.scala | 6 + tests/coverage/expect/Lifting.scoverage.check | 156 ++++++++-- .../coverage/expect/Literals.scoverage.check | 8 +- .../expect/MatchCaseClasses.scoverage.check | 14 +- .../expect/MatchNumbers.scoverage.check | 31 +- .../ParamsAndInterpolation.scoverage.check | 70 +++-- tests/coverage/expect/Select.scoverage.check | 35 ++- .../expect/StructuralTypes.scoverage.check | 12 +- tests/coverage/expect/Trait.scala | 15 + tests/coverage/expect/Trait.scoverage.check | 190 ++++++++++++ .../expect/TypeLambdas.scoverage.check | 12 +- 24 files changed, 1328 insertions(+), 230 deletions(-) create mode 100644 tests/coverage/expect/Constructor.scala create mode 100644 tests/coverage/expect/Constructor.scoverage.check create mode 100644 tests/coverage/expect/Inheritance.scala create mode 100644 tests/coverage/expect/Inheritance.scoverage.check create mode 100644 tests/coverage/expect/Inlined.scala create mode 100644 tests/coverage/expect/Inlined.scoverage.check create mode 100644 tests/coverage/expect/Trait.scala create mode 100644 tests/coverage/expect/Trait.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/coverage/Location.scala b/compiler/src/dotty/tools/dotc/coverage/Location.scala index 65f8d8adb5ee..0c0181baa305 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Location.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Location.scala @@ -3,6 +3,7 @@ package coverage import ast.tpd._ import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.Flags.* /** @param packageName * the name of the encosing package @@ -23,14 +24,20 @@ final case class Location( object Location: def apply(tree: Tree)(using ctx: Context): Location = - val packageName = ctx.owner.denot.enclosingPackageClass.name.toSimpleName.toString() - val className = ctx.owner.denot.enclosingClass.name.toSimpleName.toString() + val enclosingClass = ctx.owner.denot.enclosingClass + val packageName = ctx.owner.denot.enclosingPackageClass.name.toSimpleName.toString + val className = enclosingClass.name.toSimpleName.toString + + val classType: String = + if enclosingClass.is(Trait) then "Trait" + else if enclosingClass.is(ModuleClass) then "Object" + else "Class" Location( packageName, className, s"$packageName.$className", - "Class" /* TODO refine this further */, + classType, ctx.owner.denot.enclosingMethod.name.toSimpleName.toString(), ctx.source.file.absolute.toString() ) diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 29d2209e1ec3..761a69613472 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -6,18 +6,16 @@ import java.util.concurrent.atomic.AtomicInteger import collection.mutable import core.Flags.JavaDefined -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer -import dotty.tools.dotc.coverage.Coverage -import dotty.tools.dotc.coverage.Statement -import dotty.tools.dotc.coverage.Serializer -import dotty.tools.dotc.coverage.Location -import dotty.tools.dotc.core.Symbols.defn -import dotty.tools.dotc.core.Symbols.Symbol -import dotty.tools.dotc.core.Decorators.toTermName -import dotty.tools.dotc.util.{SourcePosition, Property} -import dotty.tools.dotc.core.Constants.Constant -import dotty.tools.dotc.typer.LiftCoverage +import core.Contexts.{Context, ctx, inContext} +import core.DenotTransformers.IdentityDenotTransformer +import core.Symbols.{defn, Symbol} +import core.Decorators.{toTermName, i} +import core.Constants.Constant +import typer.LiftCoverage +import util.{SourcePosition, Property} +import util.Spans.Span +import coverage.* +import dotty.tools.dotc.util.SourceFile /** Implements code coverage by inserting calls to scala.runtime.Invoker * ("instruments" the source code). @@ -105,7 +103,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted instrumentLifted(transformed)(using ignoreLiteralsContext) else - val transformed = cpy.Apply(tree)(transformedFun, transform(args)) + val transformed = cpy.Apply(tree)(transformedFun, transform(args)(using ignoreLiteralsContext)) instrument(transformed)(using ignoreLiteralsContext) // f(args) @@ -136,41 +134,47 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: case tree: CaseDef => instrumentCaseDef(tree) case tree: ValDef => - // only transform the rhs - cpy.ValDef(tree)(rhs = transform(tree.rhs)) + // only transform the rhs, in the local context + val rhs = transform(tree.rhs)(using localCtx(tree)) + cpy.ValDef(tree)(rhs=rhs) + + case tree: DefDef => + // only transform the params (for the default values) and the rhs + val defCtx = localCtx(tree) + val paramss = transformParamss(tree.paramss)(using defCtx) + val rhs = transform(tree.rhs)(using defCtx) + cpy.DefDef(tree)(tree.name, paramss, tree.tpt, rhs) case tree: PackageDef => // only transform the statements of the package - cpy.PackageDef(tree)(tree.pid, transform(tree.stats)) + cpy.PackageDef(tree)(tree.pid, transform(tree.stats)(using localCtx(tree))) case tree: Assign => // only transform the rhs cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) - case tree: Template => - // Don't instrument the parents (extends) of a template since it - // causes problems if the parent constructor takes parameters - cpy.Template(tree)( - constr = super.transformSub(tree.constr), - body = transform(tree.body) - ) // For everything else just recurse and transform + // Special care for Templates: it's important to set the owner of the `stats`, like super.transform case _ => super.transform(tree) + /** Lifts and instruments an application. + * Note that if only one arg needs to be lifted, we just lift everything. + */ def instrumentLifted(tree: Apply)(using Context) = - val buffer = mutable.ListBuffer[Tree]() - // NOTE: that if only one arg needs to be lifted, we just lift everything - val lifted = LiftCoverage.liftForCoverage(buffer, tree) - val instrumented = buffer.toList.map(transform) - // We can now instrument the apply as it is with a custom position to point to the function - Block( - instrumented, - instrument( - lifted, - tree.sourcePos, - false - ) - ) + // withSource is necessary to position inlined code properly + inContext(ctx.withSource(tree.source)) { + // lifting + val buffer = mutable.ListBuffer[Tree]() + val liftedApply = LiftCoverage.liftForCoverage(buffer, tree) + + // instrumentation + val instrumentedArgs = buffer.toList.map(transform) + val instrumentedApply = instrument(liftedApply) + Block( + instrumentedArgs, + instrumentedApply + ).withSpan(instrumentedApply.span) + } def instrumentCases(cases: List[CaseDef])(using Context): List[CaseDef] = cases.map(instrumentCaseDef) @@ -197,16 +201,19 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: branch ) coverage.addStatement(statement) - Block(List(invokeCall(id)), tree) + inContext(ctx.withSource(tree.source)) { + val span = Span(pos.start, pos.end) // synthetic span + Block(List(invokeCall(id, span)), tree).withSpan(span) + } else tree - def invokeCall(id: Int)(using Context): Tree = - ref(defn.InvokerModuleRef) - .select("invoked".toTermName) + def invokeCall(id: Int, span: Span)(using Context): Tree = + ref(defn.InvokerModuleRef).withSpan(span) + .select("invoked".toTermName).withSpan(span) .appliedToArgs( List(Literal(Constant(id)), Literal(Constant(outputPath))) - ) + ).withSpan(span) /** * Checks if the apply needs a lift in the coverage phase. diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index b5881d88f5f1..4ab6a5c9a646 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -214,6 +214,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => initFlags = stat.symbol.flags | PrivateLocal ).installAfter(thisPhase) stat.symbol.enteredAfter(thisPhase) + case _ => } (scall, stats ::: inits, args) case _ => diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index 4e11957cb034..6142f1ddb5e1 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -52,6 +52,7 @@ class CoverageTests: def computeCoverageInTmp(inputFiles: Seq[Path], sourceRoot: String): Path = val target = Files.createTempDirectory("coverage") val args = Array( + "-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-coverage-sourceroot", diff --git a/tests/coverage/expect/Constructor.scala b/tests/coverage/expect/Constructor.scala new file mode 100644 index 000000000000..251370ec8e6e --- /dev/null +++ b/tests/coverage/expect/Constructor.scala @@ -0,0 +1,11 @@ +package covtest + +class C: + def f(x: Int) = x + def x = 1 + f(x) + +object O: + def g(y: Int) = y + def y = 1 + g(y) diff --git a/tests/coverage/expect/Constructor.scoverage.check b/tests/coverage/expect/Constructor.scoverage.check new file mode 100644 index 000000000000..ebc833756efc --- /dev/null +++ b/tests/coverage/expect/Constructor.scoverage.check @@ -0,0 +1,88 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Constructor.scala +covtest +C +Class +covtest.C +x +56 +57 +4 + +Literal +false +0 +false +1 + +2 +tests/coverage/expect/Constructor.scala +covtest +C +Class +covtest.C + +60 +64 +5 +f +Apply +false +0 +false +f(x) + +3 +tests/coverage/expect/Constructor.scala +covtest +O$ +Object +covtest.O$ +y +106 +107 +9 + +Literal +false +0 +false +1 + +4 +tests/coverage/expect/Constructor.scala +covtest +O$ +Object +covtest.O$ + +110 +114 +10 +g +Apply +false +0 +false +g(y) + diff --git a/tests/coverage/expect/Enum.scoverage.check b/tests/coverage/expect/Enum.scoverage.check index 001fb41321a1..dbcce91d5301 100644 --- a/tests/coverage/expect/Enum.scoverage.check +++ b/tests/coverage/expect/Enum.scoverage.check @@ -62,7 +62,7 @@ surfaceGravity 359 367 14 -* +invoked Apply false 0 @@ -76,6 +76,23 @@ Planet Class covtest.Planet surfaceGravity +359 +367 +14 +* +Apply +false +0 +false +G * mass + +5 +tests/coverage/expect/Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceGravity 371 386 14 @@ -86,7 +103,7 @@ false false radius * radius -5 +6 tests/coverage/expect/Enum.scala covtest Planet @@ -103,7 +120,7 @@ false false G * mass / (radius * radius -6 +7 tests/coverage/expect/Enum.scala covtest Planet @@ -120,11 +137,147 @@ false false otherMass * surfaceGravity -7 +8 tests/coverage/expect/Enum.scala covtest -EnumTypes$ +$anon +Class +covtest.$anon + +485 +512 +17 + +Apply +false +0 +false +Planet(3.303e+23, 2.4397e6) + +9 +tests/coverage/expect/Enum.scala +covtest +$anon +Class +covtest.$anon + +538 +565 +18 + +Apply +false +0 +false +Planet(4.869e+24, 6.0518e6) + +10 +tests/coverage/expect/Enum.scala +covtest +$anon +Class +covtest.$anon + +591 +619 +19 + +Apply +false +0 +false +Planet(5.976e+24, 6.37814e6) + +11 +tests/coverage/expect/Enum.scala +covtest +$anon +Class +covtest.$anon + +645 +672 +20 + +Apply +false +0 +false +Planet(6.421e+23, 3.3972e6) + +12 +tests/coverage/expect/Enum.scala +covtest +$anon +Class +covtest.$anon + +698 +725 +21 + +Apply +false +0 +false +Planet(1.9e+27, 7.1492e7) + +13 +tests/coverage/expect/Enum.scala +covtest +$anon +Class +covtest.$anon + +751 +778 +22 + +Apply +false +0 +false +Planet(5.688e+26, 6.0268e7) + +14 +tests/coverage/expect/Enum.scala +covtest +$anon +Class +covtest.$anon + +804 +831 +23 + +Apply +false +0 +false +Planet(8.686e+25, 2.5559e7) + +15 +tests/coverage/expect/Enum.scala +covtest +$anon Class +covtest.$anon + +857 +884 +24 + +Apply +false +0 +false +Planet(1.024e+26, 2.4746e7) + +16 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Object covtest.EnumTypes$ test 1004 @@ -137,11 +290,11 @@ false false ListEnum.Cons(3, ListEnum.Empty) -8 +17 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 987 @@ -154,11 +307,11 @@ false false ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty)) -9 +18 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 970 @@ -171,11 +324,11 @@ false false ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) -10 +19 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 1051 @@ -188,11 +341,11 @@ false false "Example 1: \n"+emptyList -11 +20 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 1043 @@ -205,11 +358,11 @@ false false println("Example 1: \n"+emptyList) -12 +21 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 1092 @@ -222,11 +375,28 @@ false false ${list}\n -13 +22 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object +covtest.EnumTypes$ +test +1092 +1101 +31 +invoked +Apply +false +0 +false +${list}\n + +23 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Object covtest.EnumTypes$ test 1092 @@ -239,11 +409,11 @@ false false ${list}\n -14 +24 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 1090 @@ -256,11 +426,11 @@ false false s"${list}\n" -15 +25 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 1082 @@ -273,11 +443,11 @@ false false println(s"${list}\n") -16 +26 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ calculateEarthWeightOnPlanets 1183 @@ -290,11 +460,11 @@ false false earthWeight/Planet.Earth.surfaceGravity -17 +27 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ calculateEarthWeightOnPlanets 1238 @@ -307,11 +477,11 @@ false false Planet.values -18 +28 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ $anonfun 1273 @@ -324,11 +494,28 @@ false false Your weight on $p is ${p.surfaceWeight(mass)} -19 +29 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object +covtest.EnumTypes$ +$anonfun +1273 +1318 +36 +invoked +Apply +false +0 +false +Your weight on $p is ${p.surfaceWeight(mass)} + +30 +tests/coverage/expect/Enum.scala +covtest +EnumTypes$ +Object covtest.EnumTypes$ $anonfun 1273 @@ -341,11 +528,11 @@ false false Your weight on $p is ${p.surfaceWeight(mass)} -20 +31 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ $anonfun 1296 @@ -358,11 +545,11 @@ false false p.surfaceWeight(mass) -21 +32 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ $anonfun 1271 @@ -375,11 +562,11 @@ false false s"Your weight on $p is ${p.surfaceWeight(mass)}" -22 +33 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ $anonfun 1263 @@ -392,11 +579,11 @@ false false println(s"Your weight on $p is ${p.surfaceWeight(mass)}") -23 +34 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ calculateEarthWeightOnPlanets 1229 @@ -410,11 +597,11 @@ false for p <- Planet.values do println(s"Your weight on $p is ${p.surfaceWeight(mass)}") -24 +35 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 1326 @@ -427,11 +614,11 @@ false false println("Example 2:") -25 +36 tests/coverage/expect/Enum.scala covtest EnumTypes$ -Class +Object covtest.EnumTypes$ test 1352 diff --git a/tests/coverage/expect/Givens.scala b/tests/coverage/expect/Givens.scala index ae29f6eb7f8f..34d740e146b9 100644 --- a/tests/coverage/expect/Givens.scala +++ b/tests/coverage/expect/Givens.scala @@ -18,7 +18,6 @@ object Givens: def getMessage(i: Int): String = i.toString def test2() = - // TODO FIXME: this does not work if we remove the def declaration (compiler crash in LambdaLift) given c: Context = Context(0) printContext("test")(using c) printContext(getMessage(123)) diff --git a/tests/coverage/expect/Givens.scoverage.check b/tests/coverage/expect/Givens.scoverage.check index 1235a0387f5c..aec733eca38a 100644 --- a/tests/coverage/expect/Givens.scoverage.check +++ b/tests/coverage/expect/Givens.scoverage.check @@ -22,7 +22,7 @@ tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test 183 @@ -39,7 +39,7 @@ false tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test 175 @@ -56,7 +56,7 @@ println(3 == "3") tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test 205 @@ -73,7 +73,7 @@ false tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test 197 @@ -90,7 +90,7 @@ println(3 == 5.1) tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ printContext 280 @@ -107,7 +107,7 @@ println(msg) tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ printContext 297 @@ -124,7 +124,7 @@ println(ctx.id) tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ getMessage 349 @@ -141,29 +141,12 @@ i.toString tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test2 -510 -511 -21 - -Literal -false -0 -false -0 - -9 -tests/coverage/expect/Givens.scala -covtest -Givens$ -Class -covtest.Givens$ -test2 -502 -512 -21 +400 +410 +20 Apply false @@ -171,16 +154,16 @@ false false Context(0) -10 +9 tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test2 -517 -546 -22 +415 +444 +21 printContext Apply false @@ -188,16 +171,16 @@ false false printContext("test")(using c) -11 +10 tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test2 -564 -579 -23 +462 +477 +22 getMessage Apply false @@ -205,16 +188,16 @@ false false getMessage(123) -12 +11 tests/coverage/expect/Givens.scala covtest Givens$ -Class +Object covtest.Givens$ test2 -551 -580 -23 +449 +478 +22 printContext Apply false diff --git a/tests/coverage/expect/Inheritance.scala b/tests/coverage/expect/Inheritance.scala new file mode 100644 index 000000000000..e90fb87237ea --- /dev/null +++ b/tests/coverage/expect/Inheritance.scala @@ -0,0 +1,11 @@ +package covtest + +class A(val x: Int, val y: Int) +class B(x: Int) extends A(x, 0) +class C1 extends B({println("block"); 1}) +class C2 extends B(A(2,2).x) + +def testInheritance = + println(C1().x) // block + // 1 + println(C2().x) // 2 diff --git a/tests/coverage/expect/Inheritance.scoverage.check b/tests/coverage/expect/Inheritance.scoverage.check new file mode 100644 index 000000000000..8fad938ba60b --- /dev/null +++ b/tests/coverage/expect/Inheritance.scoverage.check @@ -0,0 +1,173 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Inheritance.scala +covtest +B +Class +covtest.B + +73 +80 +3 + +Apply +false +0 +false +A(x, 0) + +2 +tests/coverage/expect/Inheritance.scala +covtest +C1 +Class +covtest.C1 + +101 +117 +4 +println +Apply +false +0 +false +println("block") + +3 +tests/coverage/expect/Inheritance.scala +covtest +C1 +Class +covtest.C1 + +98 +122 +4 + +Apply +false +0 +false +B({println("block"); 1}) + +4 +tests/coverage/expect/Inheritance.scala +covtest +C2 +Class +covtest.C2 + +142 +148 +5 + +Apply +false +0 +false +A(2,2) + +5 +tests/coverage/expect/Inheritance.scala +covtest +C2 +Class +covtest.C2 + +140 +151 +5 + +Apply +false +0 +false +B(A(2,2).x) + +6 +tests/coverage/expect/Inheritance.scala +covtest +Inheritance$package$ +Object +covtest.Inheritance$package$ +testInheritance +185 +189 +8 + +Apply +false +0 +false +C1() + +7 +tests/coverage/expect/Inheritance.scala +covtest +Inheritance$package$ +Object +covtest.Inheritance$package$ +testInheritance +177 +192 +8 +println +Apply +false +0 +false +println(C1().x) + +8 +tests/coverage/expect/Inheritance.scala +covtest +Inheritance$package$ +Object +covtest.Inheritance$package$ +testInheritance +235 +239 +10 + +Apply +false +0 +false +C2() + +9 +tests/coverage/expect/Inheritance.scala +covtest +Inheritance$package$ +Object +covtest.Inheritance$package$ +testInheritance +227 +242 +10 +println +Apply +false +0 +false +println(C2().x) + diff --git a/tests/coverage/expect/Inlined.scala b/tests/coverage/expect/Inlined.scala new file mode 100644 index 000000000000..ebe0503716a7 --- /dev/null +++ b/tests/coverage/expect/Inlined.scala @@ -0,0 +1,8 @@ +package covtest + +// Checks that we use the new positions of the inlined code properly +def testInlined(): Unit = + val l = 1 + assert(l == 1) // scala.Predef.assert is inline in dotty + assert(l == List(l).length) + assert(List(l).length == 1) diff --git a/tests/coverage/expect/Inlined.scoverage.check b/tests/coverage/expect/Inlined.scoverage.check new file mode 100644 index 000000000000..41a8b9e0aadd --- /dev/null +++ b/tests/coverage/expect/Inlined.scoverage.check @@ -0,0 +1,275 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +122 +123 +4 + +Literal +false +0 +false +1 + +2 +library/src/scala/runtime/stdLibPatches/Predef.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +133 +139 +5 +== +Apply +false +0 +false +l == 1 + +3 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +367 +9 +Scala3RunTime +Select +false +0 +false + + +4 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +382 +9 +assertFailed +Apply +false +0 +false + + +5 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +382 +9 + +Block +true +0 +false + + +6 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +197 +204 +6 +apply +Apply +false +0 +false +List(l) + +7 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +192 +211 +6 +== +Apply +false +0 +false +l == List(l).length + +8 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +367 +9 +Scala3RunTime +Select +false +0 +false + + +9 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +382 +9 +assertFailed +Apply +false +0 +false + + +10 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +382 +9 + +Block +true +0 +false + + +11 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +222 +229 +7 +apply +Apply +false +0 +false +List(l) + +12 +library/src/scala/runtime/stdLibPatches/Predef.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +222 +241 +7 +== +Apply +false +0 +false +List(l).length == 1 + +13 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +367 +9 +Scala3RunTime +Select +false +0 +false + + +14 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +382 +9 +assertFailed +Apply +false +0 +false + + +15 +tests/coverage/expect/Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +340 +382 +9 + +Block +true +0 +false + + diff --git a/tests/coverage/expect/Lifting.scala b/tests/coverage/expect/Lifting.scala index 5e41eb172db3..a948e1ad575a 100644 --- a/tests/coverage/expect/Lifting.scala +++ b/tests/coverage/expect/Lifting.scala @@ -1,5 +1,9 @@ package covtest +class Vals: + val l = List(1) + val ll = l :: List(1,2,3) + class A: def msg(a: Int, b: Int, c: Int) = "string" def integer: Int = 0 @@ -8,5 +12,7 @@ class A: def test(): Unit = val a = A() val i = 123 + def f() = -1 a.msg(i, 0, a.integer) a.ex.msg(i, 0, a.ex.integer) + a.msg(f(), 0, i) diff --git a/tests/coverage/expect/Lifting.scoverage.check b/tests/coverage/expect/Lifting.scoverage.check index b77989de97a1..9f99655a0d9e 100644 --- a/tests/coverage/expect/Lifting.scoverage.check +++ b/tests/coverage/expect/Lifting.scoverage.check @@ -21,13 +21,64 @@ 1 tests/coverage/expect/Lifting.scala covtest +Vals +Class +covtest.Vals + +39 +46 +3 +apply +Apply +false +0 +false +List(1) + +2 +tests/coverage/expect/Lifting.scala +covtest +Vals +Class +covtest.Vals + +63 +74 +4 +apply +Apply +false +0 +false +List(1,2,3) + +3 +tests/coverage/expect/Lifting.scala +covtest +Vals +Class +covtest.Vals + +58 +74 +4 +:: +Apply +false +0 +false +l :: List(1,2,3) + +4 +tests/coverage/expect/Lifting.scala +covtest A Class covtest.A msg -62 -70 -3 +121 +129 +7 Literal false @@ -35,16 +86,16 @@ false false "string" -2 +5 tests/coverage/expect/Lifting.scala covtest A Class covtest.A integer -92 -93 -4 +151 +152 +8 Literal false @@ -52,16 +103,16 @@ false false 0 -3 +6 tests/coverage/expect/Lifting.scala covtest Lifting$package$ -Class +Object covtest.Lifting$package$ test -151 -154 -8 +210 +213 +12 Apply false @@ -69,16 +120,16 @@ false false A() -4 +7 tests/coverage/expect/Lifting.scala covtest Lifting$package$ -Class +Object covtest.Lifting$package$ test -165 -168 -9 +224 +227 +13 Literal false @@ -86,16 +137,33 @@ false false 123 -5 +8 tests/coverage/expect/Lifting.scala covtest Lifting$package$ -Class +Object +covtest.Lifting$package$ +f +240 +242 +14 + +Literal +false +0 +false +-1 + +9 +tests/coverage/expect/Lifting.scala +covtest +Lifting$package$ +Object covtest.Lifting$package$ test -171 -193 -10 +245 +267 +15 msg Apply false @@ -103,16 +171,16 @@ false false a.msg(i, 0, a.integer) -6 +10 tests/coverage/expect/Lifting.scala covtest Lifting$package$ -Class +Object covtest.Lifting$package$ test -196 -224 -11 +270 +298 +16 msg Apply false @@ -120,3 +188,37 @@ false false a.ex.msg(i, 0, a.ex.integer) +11 +tests/coverage/expect/Lifting.scala +covtest +Lifting$package$ +Object +covtest.Lifting$package$ +test +307 +310 +17 +f +Apply +false +0 +false +f() + +12 +tests/coverage/expect/Lifting.scala +covtest +Lifting$package$ +Object +covtest.Lifting$package$ +test +301 +317 +17 +msg +Apply +false +0 +false +a.msg(f(), 0, i) + diff --git a/tests/coverage/expect/Literals.scoverage.check b/tests/coverage/expect/Literals.scoverage.check index 8087fd68835c..af2bf08f7f19 100644 --- a/tests/coverage/expect/Literals.scoverage.check +++ b/tests/coverage/expect/Literals.scoverage.check @@ -22,7 +22,7 @@ tests/coverage/expect/Literals.scala Literals$package$ -Class +Object .Literals$package$ mustBeInstrumented 26 @@ -39,7 +39,7 @@ false tests/coverage/expect/Literals.scala Literals$package$ -Class +Object .Literals$package$ thisOneToo 56 @@ -56,7 +56,7 @@ println("not this") tests/coverage/expect/Literals.scala Literals$package$ -Class +Object .Literals$package$ thisOneToo 144 @@ -73,7 +73,7 @@ false tests/coverage/expect/Literals.scala Literals$package$ -Class +Object .Literals$package$ main 246 diff --git a/tests/coverage/expect/MatchCaseClasses.scoverage.check b/tests/coverage/expect/MatchCaseClasses.scoverage.check index 8a5cb6333f67..907eaea2e29f 100644 --- a/tests/coverage/expect/MatchCaseClasses.scoverage.check +++ b/tests/coverage/expect/MatchCaseClasses.scoverage.check @@ -22,7 +22,7 @@ tests/coverage/expect/MatchCaseClasses.scala covtest MatchCaseClasses$ -Class +Object covtest.MatchCaseClasses$ f 151 @@ -39,7 +39,7 @@ println("a") tests/coverage/expect/MatchCaseClasses.scala covtest MatchCaseClasses$ -Class +Object covtest.MatchCaseClasses$ f 184 @@ -56,7 +56,7 @@ println("b") tests/coverage/expect/MatchCaseClasses.scala covtest MatchCaseClasses$ -Class +Object covtest.MatchCaseClasses$ f 225 @@ -73,7 +73,7 @@ println("c") tests/coverage/expect/MatchCaseClasses.scala covtest MatchCaseClasses$ -Class +Object covtest.MatchCaseClasses$ f 275 @@ -90,7 +90,7 @@ println(y) tests/coverage/expect/MatchCaseClasses.scala covtest MatchCaseClasses$ -Class +Object covtest.MatchCaseClasses$ f 292 @@ -107,7 +107,7 @@ println("d") tests/coverage/expect/MatchCaseClasses.scala covtest MatchCaseClasses$ -Class +Object covtest.MatchCaseClasses$ f 325 @@ -124,7 +124,7 @@ println("e") tests/coverage/expect/MatchCaseClasses.scala covtest MatchCaseClasses$ -Class +Object covtest.MatchCaseClasses$ f 352 diff --git a/tests/coverage/expect/MatchNumbers.scoverage.check b/tests/coverage/expect/MatchNumbers.scoverage.check index 78fae5188293..3d2b972ce801 100644 --- a/tests/coverage/expect/MatchNumbers.scoverage.check +++ b/tests/coverage/expect/MatchNumbers.scoverage.check @@ -22,24 +22,7 @@ tests/coverage/expect/MatchNumbers.scala covtest MatchNumbers$ -Class -covtest.MatchNumbers$ -f -125 -126 -6 - -Literal -false -0 -false -0 - -2 -tests/coverage/expect/MatchNumbers.scala -covtest -MatchNumbers$ -Class +Object covtest.MatchNumbers$ f 121 @@ -52,11 +35,11 @@ false false x < 0 -3 +2 tests/coverage/expect/MatchNumbers.scala covtest MatchNumbers$ -Class +Object covtest.MatchNumbers$ f 130 @@ -69,11 +52,11 @@ false false -1 -4 +3 tests/coverage/expect/MatchNumbers.scala covtest MatchNumbers$ -Class +Object covtest.MatchNumbers$ 185 @@ -86,11 +69,11 @@ false false f(0) -5 +4 tests/coverage/expect/MatchNumbers.scala covtest MatchNumbers$ -Class +Object covtest.MatchNumbers$ 192 diff --git a/tests/coverage/expect/ParamsAndInterpolation.scoverage.check b/tests/coverage/expect/ParamsAndInterpolation.scoverage.check index 00c61ad22b39..d4e9725fbec6 100644 --- a/tests/coverage/expect/ParamsAndInterpolation.scoverage.check +++ b/tests/coverage/expect/ParamsAndInterpolation.scoverage.check @@ -22,7 +22,7 @@ tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ simple 97 @@ -39,13 +39,13 @@ $a, ${b.length} tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ simple 97 112 5 -apply +invoked Apply false 0 @@ -56,7 +56,24 @@ $a, ${b.length} tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object +covtest.ParamsAndInterpolation$ +simple +97 +112 +5 +apply +Apply +false +0 +false +$a, ${b.length} + +4 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Object covtest.ParamsAndInterpolation$ simple 103 @@ -69,11 +86,11 @@ false false b.length -4 +5 tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ simple 95 @@ -86,11 +103,11 @@ false false s"$a, ${b.length}" -5 +6 tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ test 163 @@ -103,11 +120,11 @@ false false List("d", "o", "t", "t", "y") -6 +7 tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ $anonfun 238 @@ -120,11 +137,28 @@ false false $i: $s -7 +8 +tests/coverage/expect/ParamsAndInterpolation.scala +covtest +ParamsAndInterpolation$ +Object +covtest.ParamsAndInterpolation$ +$anonfun +238 +244 +10 +invoked +Apply +false +0 +false +$i: $s + +9 tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ $anonfun 238 @@ -137,11 +171,11 @@ false false $i: $s -8 +10 tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ $anonfun 236 @@ -154,11 +188,11 @@ false false s"$i: $s" -9 +11 tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ $anonfun 228 @@ -171,11 +205,11 @@ false false println(s"$i: $s") -10 +12 tests/coverage/expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ -Class +Object covtest.ParamsAndInterpolation$ test 198 diff --git a/tests/coverage/expect/Select.scoverage.check b/tests/coverage/expect/Select.scoverage.check index 783ef3430a92..954a787d02f5 100644 --- a/tests/coverage/expect/Select.scoverage.check +++ b/tests/coverage/expect/Select.scoverage.check @@ -41,6 +41,23 @@ covtest B Class covtest.B + +134 +135 +9 + +Apply +false +0 +false +A + +3 +tests/coverage/expect/Select.scala +covtest +B +Class +covtest.B print 166 179 @@ -52,7 +69,7 @@ false false super.print() -3 +4 tests/coverage/expect/Select.scala covtest B @@ -69,11 +86,11 @@ false false println(this.instance) -4 +5 tests/coverage/expect/Select.scala covtest Select$package$ -Class +Object covtest.Select$package$ test 237 @@ -86,11 +103,11 @@ false false A() -5 +6 tests/coverage/expect/Select.scala covtest Select$package$ -Class +Object covtest.Select$package$ test 254 @@ -103,11 +120,11 @@ false false new A -6 +7 tests/coverage/expect/Select.scala covtest Select$package$ -Class +Object covtest.Select$package$ test 263 @@ -120,11 +137,11 @@ false false a.instance.print() -7 +8 tests/coverage/expect/Select.scala covtest Select$package$ -Class +Object covtest.Select$package$ test 345 diff --git a/tests/coverage/expect/StructuralTypes.scoverage.check b/tests/coverage/expect/StructuralTypes.scoverage.check index 1bc6fb449fdc..b53626df23c3 100644 --- a/tests/coverage/expect/StructuralTypes.scoverage.check +++ b/tests/coverage/expect/StructuralTypes.scoverage.check @@ -56,7 +56,7 @@ elems.find(_._1 == name) tests/coverage/expect/StructuralTypes.scala covtest StructuralTypes$ -Class +Object covtest.StructuralTypes$ test 277 @@ -73,7 +73,7 @@ false tests/coverage/expect/StructuralTypes.scala covtest StructuralTypes$ -Class +Object covtest.StructuralTypes$ test 277 @@ -90,7 +90,7 @@ false tests/coverage/expect/StructuralTypes.scala covtest StructuralTypes$ -Class +Object covtest.StructuralTypes$ test 295 @@ -107,7 +107,7 @@ false tests/coverage/expect/StructuralTypes.scala covtest StructuralTypes$ -Class +Object covtest.StructuralTypes$ test 295 @@ -124,7 +124,7 @@ false tests/coverage/expect/StructuralTypes.scala covtest StructuralTypes$ -Class +Object covtest.StructuralTypes$ test 270 @@ -141,7 +141,7 @@ Record("name" -> "Emma", "age" -> 42) tests/coverage/expect/StructuralTypes.scala covtest StructuralTypes$ -Class +Object covtest.StructuralTypes$ test 333 diff --git a/tests/coverage/expect/Trait.scala b/tests/coverage/expect/Trait.scala new file mode 100644 index 000000000000..90ad91e74284 --- /dev/null +++ b/tests/coverage/expect/Trait.scala @@ -0,0 +1,15 @@ +package covtest + +trait T1: + def x = 0 + +class Impl1 extends T1 + +trait T2(val p: String) +class Impl2 extends T2("test") with T1 +class Impl3 extends T2(Impl2().p) + +def testTrait = + println(Impl1().x) // 0 + println(Impl2().p) // test + println(Impl3().p) // test diff --git a/tests/coverage/expect/Trait.scoverage.check b/tests/coverage/expect/Trait.scoverage.check new file mode 100644 index 000000000000..44570cc0b03b --- /dev/null +++ b/tests/coverage/expect/Trait.scoverage.check @@ -0,0 +1,190 @@ +# 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 +# ------------------------------------------ +1 +tests/coverage/expect/Trait.scala +covtest +T1 +Trait +covtest.T1 +x +37 +38 +3 + +Literal +false +0 +false +0 + +2 +tests/coverage/expect/Trait.scala +covtest +Impl2 +Class +covtest.Impl2 + +108 +118 +8 + +Apply +false +0 +false +T2("test") + +3 +tests/coverage/expect/Trait.scala +covtest +Impl3 +Class +covtest.Impl3 + +150 +157 +9 + +Apply +false +0 +false +Impl2() + +4 +tests/coverage/expect/Trait.scala +covtest +Impl3 +Class +covtest.Impl3 + +147 +160 +9 + +Apply +false +0 +false +T2(Impl2().p) + +5 +tests/coverage/expect/Trait.scala +covtest +Trait$package$ +Object +covtest.Trait$package$ +testTrait +188 +195 +12 + +Apply +false +0 +false +Impl1() + +6 +tests/coverage/expect/Trait.scala +covtest +Trait$package$ +Object +covtest.Trait$package$ +testTrait +180 +198 +12 +println +Apply +false +0 +false +println(Impl1().x) + +7 +tests/coverage/expect/Trait.scala +covtest +Trait$package$ +Object +covtest.Trait$package$ +testTrait +214 +221 +13 + +Apply +false +0 +false +Impl2() + +8 +tests/coverage/expect/Trait.scala +covtest +Trait$package$ +Object +covtest.Trait$package$ +testTrait +206 +224 +13 +println +Apply +false +0 +false +println(Impl2().p) + +9 +tests/coverage/expect/Trait.scala +covtest +Trait$package$ +Object +covtest.Trait$package$ +testTrait +243 +250 +14 + +Apply +false +0 +false +Impl3() + +10 +tests/coverage/expect/Trait.scala +covtest +Trait$package$ +Object +covtest.Trait$package$ +testTrait +235 +253 +14 +println +Apply +false +0 +false +println(Impl3().p) + diff --git a/tests/coverage/expect/TypeLambdas.scoverage.check b/tests/coverage/expect/TypeLambdas.scoverage.check index 85b157a52cdd..76c28db58b0c 100644 --- a/tests/coverage/expect/TypeLambdas.scoverage.check +++ b/tests/coverage/expect/TypeLambdas.scoverage.check @@ -22,7 +22,7 @@ tests/coverage/expect/TypeLambdas.scala covtest TypeLambdas$ -Class +Object covtest.TypeLambdas$ test 310 @@ -39,7 +39,7 @@ false tests/coverage/expect/TypeLambdas.scala covtest TypeLambdas$ -Class +Object covtest.TypeLambdas$ test 310 @@ -56,7 +56,7 @@ false tests/coverage/expect/TypeLambdas.scala covtest TypeLambdas$ -Class +Object covtest.TypeLambdas$ test 306 @@ -73,7 +73,7 @@ Map(1 -> "1") tests/coverage/expect/TypeLambdas.scala covtest TypeLambdas$ -Class +Object covtest.TypeLambdas$ test 324 @@ -90,7 +90,7 @@ println(m) tests/coverage/expect/TypeLambdas.scala covtest TypeLambdas$ -Class +Object covtest.TypeLambdas$ test 367 @@ -107,7 +107,7 @@ false tests/coverage/expect/TypeLambdas.scala covtest TypeLambdas$ -Class +Object covtest.TypeLambdas$ test 382 From a8a643914b98ada8568e3838ee81c98d1ee16ce5 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sat, 26 Mar 2022 12:13:13 +0100 Subject: [PATCH 07/15] Standardize coverage tests Now use scala3-compiler-bootstrapped/testCoverage [--update-checkfiles] --- .../tools/dotc/coverage/CoverageTests.scala | 94 ++++++++++--------- project/Build.scala | 17 ++++ .../expect/Constructor.scoverage.check | 8 +- tests/coverage/expect/Enum.scoverage.check | 72 +++++++------- tests/coverage/expect/Givens.scoverage.check | 22 ++--- .../expect/Inheritance.scoverage.check | 18 ++-- tests/coverage/expect/Inlined.scoverage.check | 48 +++++----- tests/coverage/expect/Lifting.scoverage.check | 24 ++--- .../coverage/expect/Literals.scoverage.check | 8 +- .../expect/MatchCaseClasses.scoverage.check | 14 +-- .../expect/MatchNumbers.scoverage.check | 8 +- .../ParamsAndInterpolation.scoverage.check | 24 ++--- tests/coverage/expect/Select.scoverage.check | 16 ++-- .../expect/StructuralTypes.scoverage.check | 16 ++-- tests/coverage/expect/Trait.scoverage.check | 20 ++-- .../expect/TypeLambdas.scoverage.check | 12 +-- 16 files changed, 224 insertions(+), 197 deletions(-) diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index 6142f1ddb5e1..b8b430aa218b 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -1,64 +1,74 @@ package dotty.tools.dotc.coverage import org.junit.Test +import org.junit.AfterClass import org.junit.Assert.* import org.junit.experimental.categories.Category -import dotty.BootstrappedOnlyTests -import dotty.tools.dotc.Main - -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.FileSystems -import java.nio.file.Paths -import java.nio.charset.StandardCharsets.UTF_8 -import java.nio.file.StandardCopyOption +import dotty.{BootstrappedOnlyTests, Properties} +import dotty.tools.vulpix.TestConfiguration.* +import dotty.tools.vulpix.* -@main def updateExpect = - CoverageTests().runExpectTest(updateCheckfiles = true) +import java.nio.file.{Files, FileSystems, Path, Paths, StandardCopyOption} +import scala.jdk.CollectionConverters.* +import scala.language.unsafeNulls +import dotty.tools.dotc.Main @Category(Array(classOf[BootstrappedOnlyTests])) class CoverageTests: + import CoverageTests.* + import CoverageTests.given - private val scalaFile = FileSystems.getDefault.nn.getPathMatcher("glob:**.scala").nn - private val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.coverage.test")).nn - private val expectDir = rootSrc.resolve("expect").nn - - @Category(Array(classOf[dotty.SlowTests])) - @Test def expectTests: Unit = - runExpectTest(dotty.Properties.testsUpdateCheckfile) + private val scalaFile = FileSystems.getDefault.getPathMatcher("glob:**.scala") + private val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.coverage.test")) + private val expectDir = rootSrc.resolve("expect") - /** Runs the tests */ - def runExpectTest(updateCheckfiles: Boolean): Unit = - val sourceRoot = if updateCheckfiles then "../" else "." + @Test + def checkInstrumentedCode(): Unit = + given TestGroup = TestGroup("instrumentCoverage") + val updateCheckfiles = dotty.Properties.testsUpdateCheckfile + val sourceRoot = rootSrc.toString - Files.walk(expectDir).nn.filter(scalaFile.matches).nn.forEach(p => { - val path = p.nn - val fileName = path.getFileName.nn.toString.nn.stripSuffix(".scala") - val targetDir = computeCoverageInTmp(Seq(path), sourceRoot).nn - val targetFile = targetDir.resolve(s"scoverage.coverage").nn - val expectFile = expectDir.resolve(s"$fileName.scoverage.check").nn + Files.walk(expectDir).filter(scalaFile.matches).forEach(p => { + val path = p + val fileName = path.getFileName.toString.stripSuffix(".scala") + val targetDir = computeCoverageInTmp(path, sourceRoot) + val targetFile = targetDir.resolve(s"scoverage.coverage") + val expectFile = expectDir.resolve(s"$fileName.scoverage.check") if updateCheckfiles then Files.copy(targetFile, expectFile, StandardCopyOption.REPLACE_EXISTING) else - val expected = new String(Files.readAllBytes(expectFile), UTF_8) - val obtained = new String(Files.readAllBytes(targetFile), UTF_8) - assertEquals(expected, obtained) + val expected = Files.readAllLines(expectFile).asScala + val obtained = Files.readAllLines(targetFile).asScala + if expected != obtained then + for ((exp, actual),i) <- expected.zip(obtained).filter(_ != _).zipWithIndex do + Console.err.println(s"wrong line ${i+1}:") + Console.err.println(s" expected: $exp") + Console.err.println(s" actual : $actual") + fail(s"$targetFile differs from expected $expectFile") }) /** Generates the coverage report for the given input file, in a temporary directory. */ - def computeCoverageInTmp(inputFiles: Seq[Path], sourceRoot: String): Path = + def computeCoverageInTmp(inputFile: Path, sourceRoot: String)(using TestGroup): Path = val target = Files.createTempDirectory("coverage") - val args = Array( - "-Ycheck:instrumentCoverage", - "-coverage-out", - target.toString, - "-coverage-sourceroot", - sourceRoot, - "-usejavacp" - ) ++ inputFiles.map(_.toString) - val exit = Main.process(args) - assertFalse(s"Compilation failed, ${exit.errorCount} errors", exit.hasErrors) - target.nn + val options = defaultOptions.and("-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-coverage-sourceroot", sourceRoot) + compileFile(inputFile.toString, options).checkCompile() + target + +object CoverageTests extends ParallelTesting: + import scala.concurrent.duration.* + + def maxDuration = 30.seconds + def numberOfSlaves = 1 + + def safeMode = Properties.testsSafeMode + def testFilter = Properties.testsFilter + def isInteractive = SummaryReport.isInteractive + def updateCheckFiles = Properties.testsUpdateCheckfile + + given summaryReport: SummaryReporting = SummaryReport() + @AfterClass def tearDown(): Unit = + super.cleanup() + summaryReport.echoSummary() diff --git a/project/Build.scala b/project/Build.scala index 64022cde42f8..1ada9d9875f1 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -138,6 +138,9 @@ object Build { // Run tests with filter through vulpix test suite val testCompilation = inputKey[Unit]("runs integration test with the supplied filter") + // Run code coverage instrumentation tests + val testCoverage = inputKey[Unit]("runs code coverage instrumentation test") + // Used to compile files similar to ./bin/scalac script val scalac = inputKey[Unit]("run the compiler using the correct classpath, or the user supplied classpath") @@ -607,6 +610,20 @@ object Build { } }.evaluated, + testCoverage := Def.inputTaskDyn { + val args = spaceDelimited("").parsed + if (args.contains("--help")) { + println("usage: testCoverage [--update-checkfiles]") + (Test / testOnly).toTask(" not.a.test") + } else { + val updateCheckfile = args.contains("--update-checkfiles") + val test = "dotty.tools.dotc.coverage.CoverageTests" + val argUpdateCheckfile = if (updateCheckfile) "-Ddotty.tests.updateCheckfiles=TRUE" else "" + val cmd = s" $test -- $argUpdateCheckfile" + (Test/testOnly).toTask(cmd) + } + }.evaluated, + Compile / mainClass := Some("dotty.tools.dotc.Main"), scala := { diff --git a/tests/coverage/expect/Constructor.scoverage.check b/tests/coverage/expect/Constructor.scoverage.check index ebc833756efc..cf23dd279926 100644 --- a/tests/coverage/expect/Constructor.scoverage.check +++ b/tests/coverage/expect/Constructor.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Constructor.scala +expect/Constructor.scala covtest C Class @@ -36,7 +36,7 @@ false 1 2 -tests/coverage/expect/Constructor.scala +expect/Constructor.scala covtest C Class @@ -53,7 +53,7 @@ false f(x) 3 -tests/coverage/expect/Constructor.scala +expect/Constructor.scala covtest O$ Object @@ -70,7 +70,7 @@ false 1 4 -tests/coverage/expect/Constructor.scala +expect/Constructor.scala covtest O$ Object diff --git a/tests/coverage/expect/Enum.scoverage.check b/tests/coverage/expect/Enum.scoverage.check index dbcce91d5301..b974cb9b57fd 100644 --- a/tests/coverage/expect/Enum.scoverage.check +++ b/tests/coverage/expect/Enum.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest Planet Class @@ -36,7 +36,7 @@ false 6.67300E-11 2 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest Planet Class @@ -53,7 +53,7 @@ false G * mass 3 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest Planet Class @@ -70,7 +70,7 @@ false G * mass 4 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest Planet Class @@ -87,7 +87,7 @@ false G * mass 5 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest Planet Class @@ -104,7 +104,7 @@ false radius * radius 6 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest Planet Class @@ -121,7 +121,7 @@ false G * mass / (radius * radius 7 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest Planet Class @@ -138,7 +138,7 @@ false otherMass * surfaceGravity 8 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -155,7 +155,7 @@ false Planet(3.303e+23, 2.4397e6) 9 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -172,7 +172,7 @@ false Planet(4.869e+24, 6.0518e6) 10 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -189,7 +189,7 @@ false Planet(5.976e+24, 6.37814e6) 11 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -206,7 +206,7 @@ false Planet(6.421e+23, 3.3972e6) 12 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -223,7 +223,7 @@ false Planet(1.9e+27, 7.1492e7) 13 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -240,7 +240,7 @@ false Planet(5.688e+26, 6.0268e7) 14 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -257,7 +257,7 @@ false Planet(8.686e+25, 2.5559e7) 15 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest $anon Class @@ -274,7 +274,7 @@ false Planet(1.024e+26, 2.4746e7) 16 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -291,7 +291,7 @@ false ListEnum.Cons(3, ListEnum.Empty) 17 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -308,7 +308,7 @@ false ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty)) 18 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -325,7 +325,7 @@ false ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) 19 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -342,7 +342,7 @@ false "Example 1: \n"+emptyList 20 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -359,7 +359,7 @@ false println("Example 1: \n"+emptyList) 21 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -376,7 +376,7 @@ false ${list}\n 22 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -393,7 +393,7 @@ false ${list}\n 23 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -410,7 +410,7 @@ false ${list}\n 24 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -427,7 +427,7 @@ false s"${list}\n" 25 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -444,7 +444,7 @@ false println(s"${list}\n") 26 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -461,7 +461,7 @@ false earthWeight/Planet.Earth.surfaceGravity 27 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -478,7 +478,7 @@ false Planet.values 28 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -495,7 +495,7 @@ false Your weight on $p is ${p.surfaceWeight(mass)} 29 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -512,7 +512,7 @@ false Your weight on $p is ${p.surfaceWeight(mass)} 30 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -529,7 +529,7 @@ false Your weight on $p is ${p.surfaceWeight(mass)} 31 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -546,7 +546,7 @@ false p.surfaceWeight(mass) 32 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -563,7 +563,7 @@ false s"Your weight on $p is ${p.surfaceWeight(mass)}" 33 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -580,7 +580,7 @@ false println(s"Your weight on $p is ${p.surfaceWeight(mass)}") 34 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -598,7 +598,7 @@ for p <- Planet.values do println(s"Your weight on $p is ${p.surfaceWeight(mass)}") 35 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object @@ -615,7 +615,7 @@ false println("Example 2:") 36 -tests/coverage/expect/Enum.scala +expect/Enum.scala covtest EnumTypes$ Object diff --git a/tests/coverage/expect/Givens.scoverage.check b/tests/coverage/expect/Givens.scoverage.check index aec733eca38a..93985ded93d9 100644 --- a/tests/coverage/expect/Givens.scoverage.check +++ b/tests/coverage/expect/Givens.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -36,7 +36,7 @@ false 3 == "3" 2 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -53,7 +53,7 @@ false println(3 == "3") 3 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -70,7 +70,7 @@ false 3 == 5.1 4 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -87,7 +87,7 @@ false println(3 == 5.1) 5 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -104,7 +104,7 @@ false println(msg) 6 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -121,7 +121,7 @@ false println(ctx.id) 7 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -138,7 +138,7 @@ false i.toString 8 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -155,7 +155,7 @@ false Context(0) 9 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -172,7 +172,7 @@ false printContext("test")(using c) 10 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object @@ -189,7 +189,7 @@ false getMessage(123) 11 -tests/coverage/expect/Givens.scala +expect/Givens.scala covtest Givens$ Object diff --git a/tests/coverage/expect/Inheritance.scoverage.check b/tests/coverage/expect/Inheritance.scoverage.check index 8fad938ba60b..70acf1456d5e 100644 --- a/tests/coverage/expect/Inheritance.scoverage.check +++ b/tests/coverage/expect/Inheritance.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest B Class @@ -36,7 +36,7 @@ false A(x, 0) 2 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest C1 Class @@ -53,7 +53,7 @@ false println("block") 3 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest C1 Class @@ -70,7 +70,7 @@ false B({println("block"); 1}) 4 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest C2 Class @@ -87,7 +87,7 @@ false A(2,2) 5 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest C2 Class @@ -104,7 +104,7 @@ false B(A(2,2).x) 6 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest Inheritance$package$ Object @@ -121,7 +121,7 @@ false C1() 7 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest Inheritance$package$ Object @@ -138,7 +138,7 @@ false println(C1().x) 8 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest Inheritance$package$ Object @@ -155,7 +155,7 @@ false C2() 9 -tests/coverage/expect/Inheritance.scala +expect/Inheritance.scala covtest Inheritance$package$ Object diff --git a/tests/coverage/expect/Inlined.scoverage.check b/tests/coverage/expect/Inlined.scoverage.check index 41a8b9e0aadd..878bef241f6b 100644 --- a/tests/coverage/expect/Inlined.scoverage.check +++ b/tests/coverage/expect/Inlined.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -36,7 +36,7 @@ false 1 2 -library/src/scala/runtime/stdLibPatches/Predef.scala +../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -53,7 +53,7 @@ false l == 1 3 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -67,10 +67,10 @@ Select false 0 false - +scala.runtime.Scala3RunTime 4 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -84,10 +84,10 @@ Apply false 0 false - +scala.runtime.Scala3RunTime.assertFailed() 5 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -101,10 +101,10 @@ Block true 0 false - +scala.runtime.Scala3RunTime.assertFailed() 6 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -121,7 +121,7 @@ false List(l) 7 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -138,7 +138,7 @@ false l == List(l).length 8 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -152,10 +152,10 @@ Select false 0 false - +scala.runtime.Scala3RunTime 9 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -169,10 +169,10 @@ Apply false 0 false - +scala.runtime.Scala3RunTime.assertFailed() 10 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -186,10 +186,10 @@ Block true 0 false - +scala.runtime.Scala3RunTime.assertFailed() 11 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -206,7 +206,7 @@ false List(l) 12 -library/src/scala/runtime/stdLibPatches/Predef.scala +../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -223,7 +223,7 @@ false List(l).length == 1 13 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -237,10 +237,10 @@ Select false 0 false - +scala.runtime.Scala3RunTime 14 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -254,10 +254,10 @@ Apply false 0 false - +scala.runtime.Scala3RunTime.assertFailed() 15 -tests/coverage/expect/Inlined.scala +expect/Inlined.scala covtest Inlined$package$ Object @@ -271,5 +271,5 @@ Block true 0 false - +scala.runtime.Scala3RunTime.assertFailed() diff --git a/tests/coverage/expect/Lifting.scoverage.check b/tests/coverage/expect/Lifting.scoverage.check index 9f99655a0d9e..32fd554ed5b3 100644 --- a/tests/coverage/expect/Lifting.scoverage.check +++ b/tests/coverage/expect/Lifting.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Vals Class @@ -36,7 +36,7 @@ false List(1) 2 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Vals Class @@ -53,7 +53,7 @@ false List(1,2,3) 3 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Vals Class @@ -70,7 +70,7 @@ false l :: List(1,2,3) 4 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest A Class @@ -87,7 +87,7 @@ false "string" 5 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest A Class @@ -104,7 +104,7 @@ false 0 6 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Lifting$package$ Object @@ -121,7 +121,7 @@ false A() 7 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Lifting$package$ Object @@ -138,7 +138,7 @@ false 123 8 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Lifting$package$ Object @@ -155,7 +155,7 @@ false -1 9 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Lifting$package$ Object @@ -172,7 +172,7 @@ false a.msg(i, 0, a.integer) 10 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Lifting$package$ Object @@ -189,7 +189,7 @@ false a.ex.msg(i, 0, a.ex.integer) 11 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Lifting$package$ Object @@ -206,7 +206,7 @@ false f() 12 -tests/coverage/expect/Lifting.scala +expect/Lifting.scala covtest Lifting$package$ Object diff --git a/tests/coverage/expect/Literals.scoverage.check b/tests/coverage/expect/Literals.scoverage.check index af2bf08f7f19..f748b7823d83 100644 --- a/tests/coverage/expect/Literals.scoverage.check +++ b/tests/coverage/expect/Literals.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Literals.scala +expect/Literals.scala Literals$package$ Object @@ -36,7 +36,7 @@ false "literal" 2 -tests/coverage/expect/Literals.scala +expect/Literals.scala Literals$package$ Object @@ -53,7 +53,7 @@ false println("not this") 3 -tests/coverage/expect/Literals.scala +expect/Literals.scala Literals$package$ Object @@ -70,7 +70,7 @@ false 12 4 -tests/coverage/expect/Literals.scala +expect/Literals.scala Literals$package$ Object diff --git a/tests/coverage/expect/MatchCaseClasses.scoverage.check b/tests/coverage/expect/MatchCaseClasses.scoverage.check index 907eaea2e29f..c83905bcd9f2 100644 --- a/tests/coverage/expect/MatchCaseClasses.scoverage.check +++ b/tests/coverage/expect/MatchCaseClasses.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/MatchCaseClasses.scala +expect/MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -36,7 +36,7 @@ false println("a") 2 -tests/coverage/expect/MatchCaseClasses.scala +expect/MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -53,7 +53,7 @@ false println("b") 3 -tests/coverage/expect/MatchCaseClasses.scala +expect/MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -70,7 +70,7 @@ false println("c") 4 -tests/coverage/expect/MatchCaseClasses.scala +expect/MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -87,7 +87,7 @@ false println(y) 5 -tests/coverage/expect/MatchCaseClasses.scala +expect/MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -104,7 +104,7 @@ false println("d") 6 -tests/coverage/expect/MatchCaseClasses.scala +expect/MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -121,7 +121,7 @@ false println("e") 7 -tests/coverage/expect/MatchCaseClasses.scala +expect/MatchCaseClasses.scala covtest MatchCaseClasses$ Object diff --git a/tests/coverage/expect/MatchNumbers.scoverage.check b/tests/coverage/expect/MatchNumbers.scoverage.check index 3d2b972ce801..ce14acc72194 100644 --- a/tests/coverage/expect/MatchNumbers.scoverage.check +++ b/tests/coverage/expect/MatchNumbers.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/MatchNumbers.scala +expect/MatchNumbers.scala covtest MatchNumbers$ Object @@ -36,7 +36,7 @@ false x < 0 2 -tests/coverage/expect/MatchNumbers.scala +expect/MatchNumbers.scala covtest MatchNumbers$ Object @@ -53,7 +53,7 @@ false -1 3 -tests/coverage/expect/MatchNumbers.scala +expect/MatchNumbers.scala covtest MatchNumbers$ Object @@ -70,7 +70,7 @@ false f(0) 4 -tests/coverage/expect/MatchNumbers.scala +expect/MatchNumbers.scala covtest MatchNumbers$ Object diff --git a/tests/coverage/expect/ParamsAndInterpolation.scoverage.check b/tests/coverage/expect/ParamsAndInterpolation.scoverage.check index d4e9725fbec6..85b06deccd87 100644 --- a/tests/coverage/expect/ParamsAndInterpolation.scoverage.check +++ b/tests/coverage/expect/ParamsAndInterpolation.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -36,7 +36,7 @@ false $a, ${b.length} 2 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -53,7 +53,7 @@ false $a, ${b.length} 3 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -70,7 +70,7 @@ false $a, ${b.length} 4 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -87,7 +87,7 @@ false b.length 5 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -104,7 +104,7 @@ false s"$a, ${b.length}" 6 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -121,7 +121,7 @@ false List("d", "o", "t", "t", "y") 7 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -138,7 +138,7 @@ false $i: $s 8 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -155,7 +155,7 @@ false $i: $s 9 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -172,7 +172,7 @@ false $i: $s 10 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -189,7 +189,7 @@ false s"$i: $s" 11 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object @@ -206,7 +206,7 @@ false println(s"$i: $s") 12 -tests/coverage/expect/ParamsAndInterpolation.scala +expect/ParamsAndInterpolation.scala covtest ParamsAndInterpolation$ Object diff --git a/tests/coverage/expect/Select.scoverage.check b/tests/coverage/expect/Select.scoverage.check index 954a787d02f5..b7e661353b4d 100644 --- a/tests/coverage/expect/Select.scoverage.check +++ b/tests/coverage/expect/Select.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Select.scala +expect/Select.scala covtest A Class @@ -36,7 +36,7 @@ false println("A") 2 -tests/coverage/expect/Select.scala +expect/Select.scala covtest B Class @@ -53,7 +53,7 @@ false A 3 -tests/coverage/expect/Select.scala +expect/Select.scala covtest B Class @@ -70,7 +70,7 @@ false super.print() 4 -tests/coverage/expect/Select.scala +expect/Select.scala covtest B Class @@ -87,7 +87,7 @@ false println(this.instance) 5 -tests/coverage/expect/Select.scala +expect/Select.scala covtest Select$package$ Object @@ -104,7 +104,7 @@ false A() 6 -tests/coverage/expect/Select.scala +expect/Select.scala covtest Select$package$ Object @@ -121,7 +121,7 @@ false new A 7 -tests/coverage/expect/Select.scala +expect/Select.scala covtest Select$package$ Object @@ -138,7 +138,7 @@ false a.instance.print() 8 -tests/coverage/expect/Select.scala +expect/Select.scala covtest Select$package$ Object diff --git a/tests/coverage/expect/StructuralTypes.scoverage.check b/tests/coverage/expect/StructuralTypes.scoverage.check index b53626df23c3..9f5fb0cd014b 100644 --- a/tests/coverage/expect/StructuralTypes.scoverage.check +++ b/tests/coverage/expect/StructuralTypes.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest Record Class @@ -36,7 +36,7 @@ false _._1 == name 2 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest Record Class @@ -53,7 +53,7 @@ false elems.find(_._1 == name) 3 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest StructuralTypes$ Object @@ -70,7 +70,7 @@ false "name" 4 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest StructuralTypes$ Object @@ -87,7 +87,7 @@ false "name" -> "Emma" 5 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest StructuralTypes$ Object @@ -104,7 +104,7 @@ false "age" 6 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest StructuralTypes$ Object @@ -121,7 +121,7 @@ false "age" -> 42 7 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest StructuralTypes$ Object @@ -138,7 +138,7 @@ false Record("name" -> "Emma", "age" -> 42) 8 -tests/coverage/expect/StructuralTypes.scala +expect/StructuralTypes.scala covtest StructuralTypes$ Object diff --git a/tests/coverage/expect/Trait.scoverage.check b/tests/coverage/expect/Trait.scoverage.check index 44570cc0b03b..8a752e0e0686 100644 --- a/tests/coverage/expect/Trait.scoverage.check +++ b/tests/coverage/expect/Trait.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest T1 Trait @@ -36,7 +36,7 @@ false 0 2 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Impl2 Class @@ -53,7 +53,7 @@ false T2("test") 3 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Impl3 Class @@ -70,7 +70,7 @@ false Impl2() 4 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Impl3 Class @@ -87,7 +87,7 @@ false T2(Impl2().p) 5 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Trait$package$ Object @@ -104,7 +104,7 @@ false Impl1() 6 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Trait$package$ Object @@ -121,7 +121,7 @@ false println(Impl1().x) 7 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Trait$package$ Object @@ -138,7 +138,7 @@ false Impl2() 8 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Trait$package$ Object @@ -155,7 +155,7 @@ false println(Impl2().p) 9 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Trait$package$ Object @@ -172,7 +172,7 @@ false Impl3() 10 -tests/coverage/expect/Trait.scala +expect/Trait.scala covtest Trait$package$ Object diff --git a/tests/coverage/expect/TypeLambdas.scoverage.check b/tests/coverage/expect/TypeLambdas.scoverage.check index 76c28db58b0c..51cd040d8b3b 100644 --- a/tests/coverage/expect/TypeLambdas.scoverage.check +++ b/tests/coverage/expect/TypeLambdas.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -tests/coverage/expect/TypeLambdas.scala +expect/TypeLambdas.scala covtest TypeLambdas$ Object @@ -36,7 +36,7 @@ false 1 2 -tests/coverage/expect/TypeLambdas.scala +expect/TypeLambdas.scala covtest TypeLambdas$ Object @@ -53,7 +53,7 @@ false 1 -> "1" 3 -tests/coverage/expect/TypeLambdas.scala +expect/TypeLambdas.scala covtest TypeLambdas$ Object @@ -70,7 +70,7 @@ false Map(1 -> "1") 4 -tests/coverage/expect/TypeLambdas.scala +expect/TypeLambdas.scala covtest TypeLambdas$ Object @@ -87,7 +87,7 @@ false println(m) 5 -tests/coverage/expect/TypeLambdas.scala +expect/TypeLambdas.scala covtest TypeLambdas$ Object @@ -104,7 +104,7 @@ false ("a", "b") 6 -tests/coverage/expect/TypeLambdas.scala +expect/TypeLambdas.scala covtest TypeLambdas$ Object From 570aa503240ecc24a6d9cfa41a14a91cbb673863 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sat, 26 Mar 2022 19:00:28 +0100 Subject: [PATCH 08/15] Fix coverage instrumentation for curried and context functions --- .../dotc/transform/InstrumentCoverage.scala | 72 +++-- tests/coverage/expect/ContextFunctions.scala | 14 + .../expect/ContextFunctions.scoverage.check | 173 ++++++++++++ tests/coverage/expect/Currying.scala | 16 ++ .../coverage/expect/Currying.scoverage.check | 258 ++++++++++++++++++ tests/coverage/expect/Givens.scala | 2 +- tests/coverage/expect/Givens.scoverage.check | 110 ++++---- 7 files changed, 572 insertions(+), 73 deletions(-) create mode 100644 tests/coverage/expect/ContextFunctions.scala create mode 100644 tests/coverage/expect/ContextFunctions.scoverage.check create mode 100644 tests/coverage/expect/Currying.scala create mode 100644 tests/coverage/expect/Currying.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 761a69613472..a04e4c98e9a9 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -5,17 +5,18 @@ import java.io.File import java.util.concurrent.atomic.AtomicInteger import collection.mutable -import core.Flags.JavaDefined +import core.Flags.* import core.Contexts.{Context, ctx, inContext} import core.DenotTransformers.IdentityDenotTransformer import core.Symbols.{defn, Symbol} import core.Decorators.{toTermName, i} import core.Constants.Constant +import core.NameOps.isContextFunction +import core.Types.* import typer.LiftCoverage import util.{SourcePosition, Property} import util.Spans.Span import coverage.* -import dotty.tools.dotc.util.SourceFile /** Implements code coverage by inserting calls to scala.runtime.Invoker * ("instruments" the source code). @@ -98,20 +99,26 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: // a.f(args) case tree @ Apply(fun: Select, args) => // don't transform the first Select, but do transform `a.b` in `a.b.f(args)` - val transformedFun = cpy.Select(fun)(transform(fun.qualifier), fun.name) - if needsLift(tree) then - val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted - instrumentLifted(transformed)(using ignoreLiteralsContext) + if canInstrumentApply(tree) then + val transformedFun = cpy.Select(fun)(transform(fun.qualifier), fun.name) + if needsLift(tree) then + val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted + instrumentLifted(transformed)(using ignoreLiteralsContext) + else + val transformed = cpy.Apply(tree)(transformedFun, transform(args)(using ignoreLiteralsContext)) + instrument(transformed)(using ignoreLiteralsContext) else - val transformed = cpy.Apply(tree)(transformedFun, transform(args)(using ignoreLiteralsContext)) - instrument(transformed)(using ignoreLiteralsContext) + tree // f(args) case tree: Apply => - if needsLift(tree) then - instrumentLifted(tree)(using ignoreLiteralsContext) // see comment about Literals + if canInstrumentApply(tree) then + if needsLift(tree) then + instrumentLifted(tree)(using ignoreLiteralsContext) // see comment about Literals + else + instrument(super.transform(tree)(using ignoreLiteralsContext)) else - instrument(super.transform(tree)(using ignoreLiteralsContext)) + tree // (f(x))[args] case TypeApply(fun: Apply, args) => @@ -226,18 +233,49 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: * should not be changed to {val $x = f(); T($x)}(1) but to {val $x = f(); val $y = 1; T($x)($y)} */ def needsLift(tree: Apply)(using Context): Boolean = - // We don't want to lift a || getB(), to avoid calling getB if a is true. - // Same idea with a && getB(): if a is false, getB shouldn't be called. def isBooleanOperator(fun: Tree) = - fun.symbol.exists && - fun.symbol.isInstanceOf[Symbol] && - fun.symbol == defn.Boolean_&& || fun.symbol == defn.Boolean_|| + // We don't want to lift a || getB(), to avoid calling getB if a is true. + // Same idea with a && getB(): if a is false, getB shouldn't be called. + val sym = fun.symbol + sym.exists && + sym == defn.Boolean_&& || sym == defn.Boolean_|| + + def isContextual(fun: Apply): Boolean = + val args = fun.args + args.nonEmpty && args.head.symbol.isAllOf(Given | Implicit) val fun = tree.fun + val nestedApplyNeedsLift = fun match + case a: Apply => needsLift(a) + case _ => false - fun.isInstanceOf[Apply] || // nested apply + nestedApplyNeedsLift || !isBooleanOperator(fun) && !tree.args.isEmpty && !tree.args.forall(LiftCoverage.noLift) + def canInstrumentApply(tree: Apply)(using Context): Boolean = + val tpe = tree.typeOpt + tpe match + case AppliedType(tycon: NamedType, _) => + /* If the last expression in a block is a context function, we'll try to + summon its arguments at the current point, even if the expected type + is a function application. Therefore, this is not valid: + ``` + def f = (t: Exception) ?=> (c: String) ?=> result + + ({ + invoked() + f(using e) + })(using s) + ``` + */ + !tycon.name.isContextFunction + case m: MethodType => + // def f(a: Ta)(b: Tb) + // f(a)(b) cannot be rewritten to {invoked();f(a)}(b) + false + case _ => + true + object InstrumentCoverage: val name: String = "instrumentCoverage" val description: String = "instrument code for coverage cheking" diff --git a/tests/coverage/expect/ContextFunctions.scala b/tests/coverage/expect/ContextFunctions.scala new file mode 100644 index 000000000000..04f5b6768c6c --- /dev/null +++ b/tests/coverage/expect/ContextFunctions.scala @@ -0,0 +1,14 @@ +package covtest + +class OnError(op: Exception => Any): + def onError(fallback: Any): Any = fallback + +class Imperative: + + def readName2 = (t: Exception) ?=> (c: String) ?=> { + "name" + } + + def readPerson(s: String) = + val e: Exception = null + OnError((e) => readName2(using e)(using s)).onError(None) diff --git a/tests/coverage/expect/ContextFunctions.scoverage.check b/tests/coverage/expect/ContextFunctions.scoverage.check new file mode 100644 index 000000000000..4dd4e4b3b583 --- /dev/null +++ b/tests/coverage/expect/ContextFunctions.scoverage.check @@ -0,0 +1,173 @@ +# 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 +# ------------------------------------------ +1 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +$anonfun +178 +184 +8 + +Literal +false +0 +false +"name" + +2 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +readPerson +243 +247 +12 + +Literal +false +0 +false +null + +3 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +$anonfun +267 +294 +13 +apply +Apply +false +0 +false +readName2(using e)(using s) + +4 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +readPerson +252 +295 +13 + +Apply +false +0 +false +OnError((e) => readName2(using e)(using s)) + +5 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +$anonfun +267 +294 +13 +invoked +Apply +false +0 +false +readName2(using e)(using s) + +6 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +$anonfun +267 +294 +13 +apply +Apply +false +0 +false +readName2(using e)(using s) + +7 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +readPerson +252 +295 +13 +invoked +Apply +false +0 +false +OnError((e) => readName2(using e)(using s)) + +8 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +readPerson +252 +295 +13 + +Apply +false +0 +false +OnError((e) => readName2(using e)(using s)) + +9 +expect/ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +readPerson +252 +309 +13 +onError +Apply +false +0 +false +OnError((e) => readName2(using e)(using s)).onError(None) + diff --git a/tests/coverage/expect/Currying.scala b/tests/coverage/expect/Currying.scala new file mode 100644 index 000000000000..12842cd181e1 --- /dev/null +++ b/tests/coverage/expect/Currying.scala @@ -0,0 +1,16 @@ +package covtest + +class ContextFunctions2: + def f1(a: Int)(b: Int)(c: Int) = a+b+c + def f2 = (a: Int) => (b: Int) => (c: Int) => + a+b+c + + def g1 = (a: Int) ?=> (b: Int) ?=> (c: Int) ?=> + a+b+c + + def g2(using a: Int)(using b: Int)(using c: Int) = a+b+c + + f1(0)(1)(2) + f2(0)(1)(2) + g1(using 0)(using 1)(using 2) + g2(using 0)(using 1)(using 2) diff --git a/tests/coverage/expect/Currying.scoverage.check b/tests/coverage/expect/Currying.scoverage.check new file mode 100644 index 000000000000..246db9966247 --- /dev/null +++ b/tests/coverage/expect/Currying.scoverage.check @@ -0,0 +1,258 @@ +# 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 +# ------------------------------------------ +1 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +f1 +77 +80 +3 ++ +Apply +false +0 +false +a+b + +2 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +f1 +77 +82 +3 ++ +Apply +false +0 +false +a+b+c + +3 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +$anonfun +134 +137 +5 ++ +Apply +false +0 +false +a+b + +4 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +$anonfun +134 +139 +5 ++ +Apply +false +0 +false +a+b+c + +5 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +$anonfun +195 +198 +8 ++ +Apply +false +0 +false +a+b + +6 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +$anonfun +195 +200 +8 ++ +Apply +false +0 +false +a+b+c + +7 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +g2 +255 +258 +10 ++ +Apply +false +0 +false +a+b + +8 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 +g2 +255 +260 +10 ++ +Apply +false +0 +false +a+b+c + +9 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 + +264 +275 +12 +f1 +Apply +false +0 +false +f1(0)(1)(2) + +10 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 + +278 +283 +13 +apply +Apply +false +0 +false +f2(0) + +11 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 + +278 +286 +13 +apply +Apply +false +0 +false +f2(0)(1) + +12 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 + +278 +289 +13 +apply +Apply +false +0 +false +f2(0)(1)(2) + +13 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 + +292 +321 +14 +apply +Apply +false +0 +false +g1(using 0)(using 1)(using 2) + +14 +expect/Currying.scala +covtest +ContextFunctions2 +Class +covtest.ContextFunctions2 + +324 +353 +15 +g2 +Apply +false +0 +false +g2(using 0)(using 1)(using 2) + diff --git a/tests/coverage/expect/Givens.scala b/tests/coverage/expect/Givens.scala index 34d740e146b9..2f9cbdfd1169 100644 --- a/tests/coverage/expect/Givens.scala +++ b/tests/coverage/expect/Givens.scala @@ -4,7 +4,7 @@ import scala.language.strictEquality class Context(val id: Int) -object Givens: +class Givens: def test(): Unit = given CanEqual[Int, String] = CanEqual.derived diff --git a/tests/coverage/expect/Givens.scoverage.check b/tests/coverage/expect/Givens.scoverage.check index 93985ded93d9..432b85fcf59a 100644 --- a/tests/coverage/expect/Givens.scoverage.check +++ b/tests/coverage/expect/Givens.scoverage.check @@ -21,12 +21,12 @@ 1 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test -183 -191 +182 +190 10 == Apply @@ -38,12 +38,12 @@ false 2 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test -175 -192 +174 +191 10 println Apply @@ -55,12 +55,12 @@ println(3 == "3") 3 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test -205 -213 +204 +212 11 == Apply @@ -72,12 +72,12 @@ false 4 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test -197 -214 +196 +213 11 println Apply @@ -89,12 +89,12 @@ println(3 == 5.1) 5 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens printContext -280 -292 +279 +291 14 println Apply @@ -106,12 +106,12 @@ println(msg) 6 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens printContext -297 -312 +296 +311 15 println Apply @@ -123,12 +123,12 @@ println(ctx.id) 7 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens getMessage -349 -359 +348 +358 17 toString Apply @@ -140,12 +140,12 @@ i.toString 8 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test2 -400 -410 +399 +409 20 Apply @@ -157,12 +157,12 @@ Context(0) 9 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test2 -415 -444 +414 +443 21 printContext Apply @@ -174,12 +174,12 @@ printContext("test")(using c) 10 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test2 -462 -477 +461 +476 22 getMessage Apply @@ -191,12 +191,12 @@ getMessage(123) 11 expect/Givens.scala covtest -Givens$ -Object -covtest.Givens$ +Givens +Class +covtest.Givens test2 -449 -478 +448 +477 22 printContext Apply From 9c01e86631094116fd0e6de4235c25ebbdc8d10c Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sun, 27 Mar 2022 11:40:24 +0200 Subject: [PATCH 09/15] Add aliases to coverage options --- compiler/src/dotty/tools/dotc/Compiler.scala | 2 +- compiler/src/dotty/tools/dotc/config/ScalaSettings.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 8ed6f2a70fe5..51891beef79f 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -59,7 +59,7 @@ class Compiler { /** Phases dealing with the transformation from pickled trees to backend trees */ protected def transformPhases: List[List[Phase]] = - List(new InstrumentCoverage) :: // Perform instrumentation for code coverage (if -coverage setting is set) + List(new InstrumentCoverage) :: // Perform instrumentation for code coverage (if -coverage-out is set) List(new FirstTransform, // Some transformations to put trees into a canonical form new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars new ElimPackagePrefixes, // Eliminate references to package prefixes in Select nodes diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index e37168fce20b..a1ce1591e9af 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -117,8 +117,8 @@ trait CommonScalaSettings: val unchecked: Setting[Boolean] = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked")) val language: Setting[List[String]] = MultiStringSetting("-language", "feature", "Enable one or more language features.", aliases = List("--language")) /* Coverage settings */ - val coverageOutputDir = PathSetting("-coverage-out", "Destination for coverage classfiles and instrumentation data.", "") - val coverageSourceroot = PathSetting("-coverage-sourceroot", "An alternative root dir of your sources used to relativize.", ".") + val coverageOutputDir = PathSetting("-coverage-out", "Destination for coverage classfiles and instrumentation data.", "", aliases = List("--coverage-out")) + val coverageSourceroot = PathSetting("-coverage-sourceroot", "An alternative root dir of your sources used to relativize.", ".", aliases = List("--coverage-sourceroot")) /* Other settings */ val encoding: Setting[String] = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding, aliases = List("--encoding")) From 0d9bf9aa06d1965eb53a111bb778901413b9e3d4 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sun, 27 Mar 2022 11:45:59 +0200 Subject: [PATCH 10/15] Move Invoker to scala.runtime.coverage --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 +- library/src/scala/runtime/{ => coverage}/Invoker.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename library/src/scala/runtime/{ => coverage}/Invoker.scala (98%) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index b769c4251135..47780b302c8c 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -461,7 +461,7 @@ class Definitions { } def NullType: TypeRef = NullClass.typeRef - @tu lazy val InvokerModuleRef = requiredMethodRef("scala.runtime.Invoker") + @tu lazy val InvokerModuleRef = requiredModuleRef("scala.runtime.coverage.Invoker") @tu lazy val ImplicitScrutineeTypeSym = newPermanentSymbol(ScalaPackageClass, tpnme.IMPLICITkw, EmptyFlags, TypeBounds.empty).entered diff --git a/library/src/scala/runtime/Invoker.scala b/library/src/scala/runtime/coverage/Invoker.scala similarity index 98% rename from library/src/scala/runtime/Invoker.scala rename to library/src/scala/runtime/coverage/Invoker.scala index 44b0703fb8d2..ee37a477cbe6 100644 --- a/library/src/scala/runtime/Invoker.scala +++ b/library/src/scala/runtime/coverage/Invoker.scala @@ -1,4 +1,4 @@ -package scala.runtime +package scala.runtime.coverage import scala.collection.mutable.{BitSet, AnyRefMap} import scala.collection.concurrent.TrieMap From c2bc0a0b9e709302ca5caa6afd68a7579d71a7da Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sun, 27 Mar 2022 13:43:50 +0200 Subject: [PATCH 11/15] Check the runtime output of some coverage tests --- .../tools/dotc/coverage/CoverageTests.scala | 35 +- project/Build.scala | 6 +- .../coverage/expect/Currying.scoverage.check | 258 ------------- tests/coverage/expect/Lifting.scala | 18 - tests/coverage/expect/Lifting.scoverage.check | 224 ----------- .../ParamsAndInterpolation.scoverage.check | 224 ----------- .../{expect => pos}/Constructor.scala | 0 .../Constructor.scoverage.check | 8 +- .../{expect => pos}/ContextFunctions.scala | 0 .../ContextFunctions.scoverage.check | 18 +- tests/coverage/{expect => pos}/Enum.scala | 0 .../{expect => pos}/Enum.scoverage.check | 72 ++-- tests/coverage/{expect => pos}/Givens.scala | 0 .../{expect => pos}/Givens.scoverage.check | 22 +- tests/coverage/{expect => pos}/Inlined.scala | 0 .../{expect => pos}/Inlined.scoverage.check | 30 +- tests/coverage/{expect => pos}/Literals.scala | 2 +- .../{expect => pos}/Literals.scoverage.check | 12 +- .../{expect => pos}/MatchCaseClasses.scala | 0 .../MatchCaseClasses.scoverage.check | 14 +- .../{expect => pos}/MatchNumbers.scala | 0 .../MatchNumbers.scoverage.check | 8 +- tests/coverage/{expect => pos}/Select.scala | 0 .../{expect => pos}/Select.scoverage.check | 16 +- .../{expect => pos}/StructuralTypes.scala | 0 .../StructuralTypes.scoverage.check | 16 +- .../{expect => pos}/TypeLambdas.scala | 0 .../TypeLambdas.scoverage.check | 12 +- tests/coverage/run/currying/test.check | 4 + .../currying/test.scala} | 13 +- .../run/currying/test.scoverage.check | 326 ++++++++++++++++ tests/coverage/run/inheritance/test.check | 3 + .../inheritance/test.scala} | 5 +- .../inheritance/test.scoverage.check} | 124 +++--- tests/coverage/run/interpolation/test.check | 5 + .../interpolation/test.scala} | 6 +- .../run/interpolation/test.scoverage.check | 224 +++++++++++ tests/coverage/run/lifting/test.check | 3 + tests/coverage/run/lifting/test.scala | 20 + .../coverage/run/lifting/test.scoverage.check | 360 ++++++++++++++++++ tests/coverage/run/trait/test.check | 3 + .../Trait.scala => run/trait/test.scala} | 5 +- .../trait/test.scoverage.check} | 144 +++---- 43 files changed, 1234 insertions(+), 1006 deletions(-) delete mode 100644 tests/coverage/expect/Currying.scoverage.check delete mode 100644 tests/coverage/expect/Lifting.scala delete mode 100644 tests/coverage/expect/Lifting.scoverage.check delete mode 100644 tests/coverage/expect/ParamsAndInterpolation.scoverage.check rename tests/coverage/{expect => pos}/Constructor.scala (100%) rename tests/coverage/{expect => pos}/Constructor.scoverage.check (87%) rename tests/coverage/{expect => pos}/ContextFunctions.scala (100%) rename tests/coverage/{expect => pos}/ContextFunctions.scoverage.check (85%) rename tests/coverage/{expect => pos}/Enum.scala (100%) rename tests/coverage/{expect => pos}/Enum.scoverage.check (88%) rename tests/coverage/{expect => pos}/Givens.scala (100%) rename tests/coverage/{expect => pos}/Givens.scoverage.check (87%) rename tests/coverage/{expect => pos}/Inlined.scala (100%) rename tests/coverage/{expect => pos}/Inlined.scoverage.check (86%) rename tests/coverage/{expect => pos}/Literals.scala (83%) rename tests/coverage/{expect => pos}/Literals.scoverage.check (90%) rename tests/coverage/{expect => pos}/MatchCaseClasses.scala (100%) rename tests/coverage/{expect => pos}/MatchCaseClasses.scoverage.check (85%) rename tests/coverage/{expect => pos}/MatchNumbers.scala (100%) rename tests/coverage/{expect => pos}/MatchNumbers.scoverage.check (88%) rename tests/coverage/{expect => pos}/Select.scala (100%) rename tests/coverage/{expect => pos}/Select.scoverage.check (88%) rename tests/coverage/{expect => pos}/StructuralTypes.scala (100%) rename tests/coverage/{expect => pos}/StructuralTypes.scoverage.check (85%) rename tests/coverage/{expect => pos}/TypeLambdas.scala (100%) rename tests/coverage/{expect => pos}/TypeLambdas.scoverage.check (87%) create mode 100644 tests/coverage/run/currying/test.check rename tests/coverage/{expect/Currying.scala => run/currying/test.scala} (53%) create mode 100644 tests/coverage/run/currying/test.scoverage.check create mode 100644 tests/coverage/run/inheritance/test.check rename tests/coverage/{expect/Inheritance.scala => run/inheritance/test.scala} (84%) rename tests/coverage/{expect/Inheritance.scoverage.check => run/inheritance/test.scoverage.check} (56%) create mode 100644 tests/coverage/run/interpolation/test.check rename tests/coverage/{expect/ParamsAndInterpolation.scala => run/interpolation/test.scala} (72%) create mode 100644 tests/coverage/run/interpolation/test.scoverage.check create mode 100644 tests/coverage/run/lifting/test.check create mode 100644 tests/coverage/run/lifting/test.scala create mode 100644 tests/coverage/run/lifting/test.scoverage.check create mode 100644 tests/coverage/run/trait/test.check rename tests/coverage/{expect/Trait.scala => run/trait/test.scala} (87%) rename tests/coverage/{expect/Trait.scoverage.check => run/trait/test.scoverage.check} (58%) diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index b8b430aa218b..c431d6358b5a 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -16,27 +16,28 @@ import dotty.tools.dotc.Main @Category(Array(classOf[BootstrappedOnlyTests])) class CoverageTests: - import CoverageTests.* - import CoverageTests.given + import CoverageTests.{*, given} private val scalaFile = FileSystems.getDefault.getPathMatcher("glob:**.scala") private val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.coverage.test")) - private val expectDir = rootSrc.resolve("expect") @Test - def checkInstrumentedCode(): Unit = - given TestGroup = TestGroup("instrumentCoverage") - val updateCheckfiles = dotty.Properties.testsUpdateCheckfile - val sourceRoot = rootSrc.toString + def checkCoverageStatements(): Unit = + checkCoverageIn(rootSrc.resolve("pos"), false) - Files.walk(expectDir).filter(scalaFile.matches).forEach(p => { + @Test + def checkInstrumentedRuns(): Unit = + checkCoverageIn(rootSrc.resolve("run"), true) + + def checkCoverageIn(dir: Path, run: Boolean)(using TestGroup): Unit = + Files.walk(dir).filter(scalaFile.matches).forEach(p => { val path = p val fileName = path.getFileName.toString.stripSuffix(".scala") - val targetDir = computeCoverageInTmp(path, sourceRoot) + val targetDir = computeCoverageInTmp(path, dir, run) val targetFile = targetDir.resolve(s"scoverage.coverage") - val expectFile = expectDir.resolve(s"$fileName.scoverage.check") + val expectFile = p.resolveSibling(s"$fileName.scoverage.check") - if updateCheckfiles then + if updateCheckFiles then Files.copy(targetFile, expectFile, StandardCopyOption.REPLACE_EXISTING) else val expected = Files.readAllLines(expectFile).asScala @@ -51,10 +52,14 @@ class CoverageTests: }) /** Generates the coverage report for the given input file, in a temporary directory. */ - def computeCoverageInTmp(inputFile: Path, sourceRoot: String)(using TestGroup): Path = + def computeCoverageInTmp(inputFile: Path, sourceRoot: Path, run: Boolean)(using TestGroup): Path = val target = Files.createTempDirectory("coverage") - val options = defaultOptions.and("-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-coverage-sourceroot", sourceRoot) - compileFile(inputFile.toString, options).checkCompile() + val options = defaultOptions.and("-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-coverage-sourceroot", sourceRoot.toString) + val test = compileFile(inputFile.toString, options) + if run then + test.checkRuns() + else + test.checkCompile() target object CoverageTests extends ParallelTesting: @@ -72,3 +77,5 @@ object CoverageTests extends ParallelTesting: @AfterClass def tearDown(): Unit = super.cleanup() summaryReport.echoSummary() + + given TestGroup = TestGroup("instrumentCoverage") diff --git a/project/Build.scala b/project/Build.scala index 1ada9d9875f1..c754f7ff1464 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -613,13 +613,15 @@ object Build { testCoverage := Def.inputTaskDyn { val args = spaceDelimited("").parsed if (args.contains("--help")) { - println("usage: testCoverage [--update-checkfiles]") + println("usage: testCoverage [--update-checkfiles] []") (Test / testOnly).toTask(" not.a.test") } else { val updateCheckfile = args.contains("--update-checkfiles") + val otherArgs = args.filter(_ != "--update-checkfiles") val test = "dotty.tools.dotc.coverage.CoverageTests" val argUpdateCheckfile = if (updateCheckfile) "-Ddotty.tests.updateCheckfiles=TRUE" else "" - val cmd = s" $test -- $argUpdateCheckfile" + val argCustom = if (otherArgs.nonEmpty) otherArgs.mkString(" ") else "" + val cmd = s" $test -- $argUpdateCheckfile $argCustom" (Test/testOnly).toTask(cmd) } }.evaluated, diff --git a/tests/coverage/expect/Currying.scoverage.check b/tests/coverage/expect/Currying.scoverage.check deleted file mode 100644 index 246db9966247..000000000000 --- a/tests/coverage/expect/Currying.scoverage.check +++ /dev/null @@ -1,258 +0,0 @@ -# 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 -# ------------------------------------------ -1 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -f1 -77 -80 -3 -+ -Apply -false -0 -false -a+b - -2 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -f1 -77 -82 -3 -+ -Apply -false -0 -false -a+b+c - -3 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -$anonfun -134 -137 -5 -+ -Apply -false -0 -false -a+b - -4 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -$anonfun -134 -139 -5 -+ -Apply -false -0 -false -a+b+c - -5 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -$anonfun -195 -198 -8 -+ -Apply -false -0 -false -a+b - -6 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -$anonfun -195 -200 -8 -+ -Apply -false -0 -false -a+b+c - -7 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -g2 -255 -258 -10 -+ -Apply -false -0 -false -a+b - -8 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 -g2 -255 -260 -10 -+ -Apply -false -0 -false -a+b+c - -9 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 - -264 -275 -12 -f1 -Apply -false -0 -false -f1(0)(1)(2) - -10 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 - -278 -283 -13 -apply -Apply -false -0 -false -f2(0) - -11 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 - -278 -286 -13 -apply -Apply -false -0 -false -f2(0)(1) - -12 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 - -278 -289 -13 -apply -Apply -false -0 -false -f2(0)(1)(2) - -13 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 - -292 -321 -14 -apply -Apply -false -0 -false -g1(using 0)(using 1)(using 2) - -14 -expect/Currying.scala -covtest -ContextFunctions2 -Class -covtest.ContextFunctions2 - -324 -353 -15 -g2 -Apply -false -0 -false -g2(using 0)(using 1)(using 2) - diff --git a/tests/coverage/expect/Lifting.scala b/tests/coverage/expect/Lifting.scala deleted file mode 100644 index a948e1ad575a..000000000000 --- a/tests/coverage/expect/Lifting.scala +++ /dev/null @@ -1,18 +0,0 @@ -package covtest - -class Vals: - val l = List(1) - val ll = l :: List(1,2,3) - -class A: - def msg(a: Int, b: Int, c: Int) = "string" - def integer: Int = 0 - def ex: this.type = this - -def test(): Unit = - val a = A() - val i = 123 - def f() = -1 - a.msg(i, 0, a.integer) - a.ex.msg(i, 0, a.ex.integer) - a.msg(f(), 0, i) diff --git a/tests/coverage/expect/Lifting.scoverage.check b/tests/coverage/expect/Lifting.scoverage.check deleted file mode 100644 index 32fd554ed5b3..000000000000 --- a/tests/coverage/expect/Lifting.scoverage.check +++ /dev/null @@ -1,224 +0,0 @@ -# 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 -# ------------------------------------------ -1 -expect/Lifting.scala -covtest -Vals -Class -covtest.Vals - -39 -46 -3 -apply -Apply -false -0 -false -List(1) - -2 -expect/Lifting.scala -covtest -Vals -Class -covtest.Vals - -63 -74 -4 -apply -Apply -false -0 -false -List(1,2,3) - -3 -expect/Lifting.scala -covtest -Vals -Class -covtest.Vals - -58 -74 -4 -:: -Apply -false -0 -false -l :: List(1,2,3) - -4 -expect/Lifting.scala -covtest -A -Class -covtest.A -msg -121 -129 -7 - -Literal -false -0 -false -"string" - -5 -expect/Lifting.scala -covtest -A -Class -covtest.A -integer -151 -152 -8 - -Literal -false -0 -false -0 - -6 -expect/Lifting.scala -covtest -Lifting$package$ -Object -covtest.Lifting$package$ -test -210 -213 -12 - -Apply -false -0 -false -A() - -7 -expect/Lifting.scala -covtest -Lifting$package$ -Object -covtest.Lifting$package$ -test -224 -227 -13 - -Literal -false -0 -false -123 - -8 -expect/Lifting.scala -covtest -Lifting$package$ -Object -covtest.Lifting$package$ -f -240 -242 -14 - -Literal -false -0 -false --1 - -9 -expect/Lifting.scala -covtest -Lifting$package$ -Object -covtest.Lifting$package$ -test -245 -267 -15 -msg -Apply -false -0 -false -a.msg(i, 0, a.integer) - -10 -expect/Lifting.scala -covtest -Lifting$package$ -Object -covtest.Lifting$package$ -test -270 -298 -16 -msg -Apply -false -0 -false -a.ex.msg(i, 0, a.ex.integer) - -11 -expect/Lifting.scala -covtest -Lifting$package$ -Object -covtest.Lifting$package$ -test -307 -310 -17 -f -Apply -false -0 -false -f() - -12 -expect/Lifting.scala -covtest -Lifting$package$ -Object -covtest.Lifting$package$ -test -301 -317 -17 -msg -Apply -false -0 -false -a.msg(f(), 0, i) - diff --git a/tests/coverage/expect/ParamsAndInterpolation.scoverage.check b/tests/coverage/expect/ParamsAndInterpolation.scoverage.check deleted file mode 100644 index 85b06deccd87..000000000000 --- a/tests/coverage/expect/ParamsAndInterpolation.scoverage.check +++ /dev/null @@ -1,224 +0,0 @@ -# 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 -# ------------------------------------------ -1 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -simple -97 -112 -5 -apply -Apply -false -0 -false -$a, ${b.length} - -2 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -simple -97 -112 -5 -invoked -Apply -false -0 -false -$a, ${b.length} - -3 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -simple -97 -112 -5 -apply -Apply -false -0 -false -$a, ${b.length} - -4 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -simple -103 -111 -5 -length -Apply -false -0 -false -b.length - -5 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -simple -95 -113 -5 -s -Apply -false -0 -false -s"$a, ${b.length}" - -6 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -test -163 -192 -8 -apply -Apply -false -0 -false -List("d", "o", "t", "t", "y") - -7 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -$anonfun -238 -244 -10 -apply -Apply -false -0 -false -$i: $s - -8 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -$anonfun -238 -244 -10 -invoked -Apply -false -0 -false -$i: $s - -9 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -$anonfun -238 -244 -10 -apply -Apply -false -0 -false -$i: $s - -10 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -$anonfun -236 -245 -10 -s -Apply -false -0 -false -s"$i: $s" - -11 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -$anonfun -228 -246 -10 -println -Apply -false -0 -false -println(s"$i: $s") - -12 -expect/ParamsAndInterpolation.scala -covtest -ParamsAndInterpolation$ -Object -covtest.ParamsAndInterpolation$ -test -198 -247 -10 -map -Apply -false -0 -false -xs.zipWithIndex.map((s, i) => println(s"$i: $s")) - diff --git a/tests/coverage/expect/Constructor.scala b/tests/coverage/pos/Constructor.scala similarity index 100% rename from tests/coverage/expect/Constructor.scala rename to tests/coverage/pos/Constructor.scala diff --git a/tests/coverage/expect/Constructor.scoverage.check b/tests/coverage/pos/Constructor.scoverage.check similarity index 87% rename from tests/coverage/expect/Constructor.scoverage.check rename to tests/coverage/pos/Constructor.scoverage.check index cf23dd279926..91a3331b002f 100644 --- a/tests/coverage/expect/Constructor.scoverage.check +++ b/tests/coverage/pos/Constructor.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/Constructor.scala +Constructor.scala covtest C Class @@ -36,7 +36,7 @@ false 1 2 -expect/Constructor.scala +Constructor.scala covtest C Class @@ -53,7 +53,7 @@ false f(x) 3 -expect/Constructor.scala +Constructor.scala covtest O$ Object @@ -70,7 +70,7 @@ false 1 4 -expect/Constructor.scala +Constructor.scala covtest O$ Object diff --git a/tests/coverage/expect/ContextFunctions.scala b/tests/coverage/pos/ContextFunctions.scala similarity index 100% rename from tests/coverage/expect/ContextFunctions.scala rename to tests/coverage/pos/ContextFunctions.scala diff --git a/tests/coverage/expect/ContextFunctions.scoverage.check b/tests/coverage/pos/ContextFunctions.scoverage.check similarity index 85% rename from tests/coverage/expect/ContextFunctions.scoverage.check rename to tests/coverage/pos/ContextFunctions.scoverage.check index 4dd4e4b3b583..df4ae8c780f1 100644 --- a/tests/coverage/expect/ContextFunctions.scoverage.check +++ b/tests/coverage/pos/ContextFunctions.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -36,7 +36,7 @@ false "name" 2 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -53,7 +53,7 @@ false null 3 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -70,7 +70,7 @@ false readName2(using e)(using s) 4 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -87,7 +87,7 @@ false OnError((e) => readName2(using e)(using s)) 5 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -104,7 +104,7 @@ false readName2(using e)(using s) 6 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -121,7 +121,7 @@ false readName2(using e)(using s) 7 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -138,7 +138,7 @@ false OnError((e) => readName2(using e)(using s)) 8 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class @@ -155,7 +155,7 @@ false OnError((e) => readName2(using e)(using s)) 9 -expect/ContextFunctions.scala +ContextFunctions.scala covtest Imperative Class diff --git a/tests/coverage/expect/Enum.scala b/tests/coverage/pos/Enum.scala similarity index 100% rename from tests/coverage/expect/Enum.scala rename to tests/coverage/pos/Enum.scala diff --git a/tests/coverage/expect/Enum.scoverage.check b/tests/coverage/pos/Enum.scoverage.check similarity index 88% rename from tests/coverage/expect/Enum.scoverage.check rename to tests/coverage/pos/Enum.scoverage.check index b974cb9b57fd..1e41a1732a6b 100644 --- a/tests/coverage/expect/Enum.scoverage.check +++ b/tests/coverage/pos/Enum.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/Enum.scala +Enum.scala covtest Planet Class @@ -36,7 +36,7 @@ false 6.67300E-11 2 -expect/Enum.scala +Enum.scala covtest Planet Class @@ -53,7 +53,7 @@ false G * mass 3 -expect/Enum.scala +Enum.scala covtest Planet Class @@ -70,7 +70,7 @@ false G * mass 4 -expect/Enum.scala +Enum.scala covtest Planet Class @@ -87,7 +87,7 @@ false G * mass 5 -expect/Enum.scala +Enum.scala covtest Planet Class @@ -104,7 +104,7 @@ false radius * radius 6 -expect/Enum.scala +Enum.scala covtest Planet Class @@ -121,7 +121,7 @@ false G * mass / (radius * radius 7 -expect/Enum.scala +Enum.scala covtest Planet Class @@ -138,7 +138,7 @@ false otherMass * surfaceGravity 8 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -155,7 +155,7 @@ false Planet(3.303e+23, 2.4397e6) 9 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -172,7 +172,7 @@ false Planet(4.869e+24, 6.0518e6) 10 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -189,7 +189,7 @@ false Planet(5.976e+24, 6.37814e6) 11 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -206,7 +206,7 @@ false Planet(6.421e+23, 3.3972e6) 12 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -223,7 +223,7 @@ false Planet(1.9e+27, 7.1492e7) 13 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -240,7 +240,7 @@ false Planet(5.688e+26, 6.0268e7) 14 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -257,7 +257,7 @@ false Planet(8.686e+25, 2.5559e7) 15 -expect/Enum.scala +Enum.scala covtest $anon Class @@ -274,7 +274,7 @@ false Planet(1.024e+26, 2.4746e7) 16 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -291,7 +291,7 @@ false ListEnum.Cons(3, ListEnum.Empty) 17 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -308,7 +308,7 @@ false ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty)) 18 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -325,7 +325,7 @@ false ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) 19 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -342,7 +342,7 @@ false "Example 1: \n"+emptyList 20 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -359,7 +359,7 @@ false println("Example 1: \n"+emptyList) 21 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -376,7 +376,7 @@ false ${list}\n 22 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -393,7 +393,7 @@ false ${list}\n 23 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -410,7 +410,7 @@ false ${list}\n 24 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -427,7 +427,7 @@ false s"${list}\n" 25 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -444,7 +444,7 @@ false println(s"${list}\n") 26 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -461,7 +461,7 @@ false earthWeight/Planet.Earth.surfaceGravity 27 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -478,7 +478,7 @@ false Planet.values 28 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -495,7 +495,7 @@ false Your weight on $p is ${p.surfaceWeight(mass)} 29 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -512,7 +512,7 @@ false Your weight on $p is ${p.surfaceWeight(mass)} 30 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -529,7 +529,7 @@ false Your weight on $p is ${p.surfaceWeight(mass)} 31 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -546,7 +546,7 @@ false p.surfaceWeight(mass) 32 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -563,7 +563,7 @@ false s"Your weight on $p is ${p.surfaceWeight(mass)}" 33 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -580,7 +580,7 @@ false println(s"Your weight on $p is ${p.surfaceWeight(mass)}") 34 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -598,7 +598,7 @@ for p <- Planet.values do println(s"Your weight on $p is ${p.surfaceWeight(mass)}") 35 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object @@ -615,7 +615,7 @@ false println("Example 2:") 36 -expect/Enum.scala +Enum.scala covtest EnumTypes$ Object diff --git a/tests/coverage/expect/Givens.scala b/tests/coverage/pos/Givens.scala similarity index 100% rename from tests/coverage/expect/Givens.scala rename to tests/coverage/pos/Givens.scala diff --git a/tests/coverage/expect/Givens.scoverage.check b/tests/coverage/pos/Givens.scoverage.check similarity index 87% rename from tests/coverage/expect/Givens.scoverage.check rename to tests/coverage/pos/Givens.scoverage.check index 432b85fcf59a..9cae23846460 100644 --- a/tests/coverage/expect/Givens.scoverage.check +++ b/tests/coverage/pos/Givens.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -36,7 +36,7 @@ false 3 == "3" 2 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -53,7 +53,7 @@ false println(3 == "3") 3 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -70,7 +70,7 @@ false 3 == 5.1 4 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -87,7 +87,7 @@ false println(3 == 5.1) 5 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -104,7 +104,7 @@ false println(msg) 6 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -121,7 +121,7 @@ false println(ctx.id) 7 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -138,7 +138,7 @@ false i.toString 8 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -155,7 +155,7 @@ false Context(0) 9 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -172,7 +172,7 @@ false printContext("test")(using c) 10 -expect/Givens.scala +Givens.scala covtest Givens Class @@ -189,7 +189,7 @@ false getMessage(123) 11 -expect/Givens.scala +Givens.scala covtest Givens Class diff --git a/tests/coverage/expect/Inlined.scala b/tests/coverage/pos/Inlined.scala similarity index 100% rename from tests/coverage/expect/Inlined.scala rename to tests/coverage/pos/Inlined.scala diff --git a/tests/coverage/expect/Inlined.scoverage.check b/tests/coverage/pos/Inlined.scoverage.check similarity index 86% rename from tests/coverage/expect/Inlined.scoverage.check rename to tests/coverage/pos/Inlined.scoverage.check index 878bef241f6b..0f5b03f6e2f5 100644 --- a/tests/coverage/expect/Inlined.scoverage.check +++ b/tests/coverage/pos/Inlined.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -36,7 +36,7 @@ false 1 2 -../../library/src/scala/runtime/stdLibPatches/Predef.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -53,7 +53,7 @@ false l == 1 3 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -70,7 +70,7 @@ false scala.runtime.Scala3RunTime 4 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -87,7 +87,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 5 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -104,7 +104,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 6 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -121,7 +121,7 @@ false List(l) 7 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -138,7 +138,7 @@ false l == List(l).length 8 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -155,7 +155,7 @@ false scala.runtime.Scala3RunTime 9 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -172,7 +172,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 10 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -189,7 +189,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 11 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -206,7 +206,7 @@ false List(l) 12 -../../library/src/scala/runtime/stdLibPatches/Predef.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -223,7 +223,7 @@ false List(l).length == 1 13 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -240,7 +240,7 @@ false scala.runtime.Scala3RunTime 14 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object @@ -257,7 +257,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 15 -expect/Inlined.scala +Inlined.scala covtest Inlined$package$ Object diff --git a/tests/coverage/expect/Literals.scala b/tests/coverage/pos/Literals.scala similarity index 83% rename from tests/coverage/expect/Literals.scala rename to tests/coverage/pos/Literals.scala index e8b55349d300..62297793bb70 100644 --- a/tests/coverage/expect/Literals.scala +++ b/tests/coverage/pos/Literals.scala @@ -3,7 +3,7 @@ def mustBeInstrumented = "literal" def thisOneToo = println("not this") // this literal should not be instrumented, only the println call - 12 // this literal must instrumented + 12 // this literal must be instrumented def f(x: Int, y: Int, z: Int)(t: Int) = ??? diff --git a/tests/coverage/expect/Literals.scoverage.check b/tests/coverage/pos/Literals.scoverage.check similarity index 90% rename from tests/coverage/expect/Literals.scoverage.check rename to tests/coverage/pos/Literals.scoverage.check index f748b7823d83..25bd06e3e4ac 100644 --- a/tests/coverage/expect/Literals.scoverage.check +++ b/tests/coverage/pos/Literals.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/Literals.scala +Literals.scala Literals$package$ Object @@ -36,7 +36,7 @@ false "literal" 2 -expect/Literals.scala +Literals.scala Literals$package$ Object @@ -53,7 +53,7 @@ false println("not this") 3 -expect/Literals.scala +Literals.scala Literals$package$ Object @@ -70,14 +70,14 @@ false 12 4 -expect/Literals.scala +Literals.scala Literals$package$ Object .Literals$package$ main -246 -257 +249 +260 10 f Apply diff --git a/tests/coverage/expect/MatchCaseClasses.scala b/tests/coverage/pos/MatchCaseClasses.scala similarity index 100% rename from tests/coverage/expect/MatchCaseClasses.scala rename to tests/coverage/pos/MatchCaseClasses.scala diff --git a/tests/coverage/expect/MatchCaseClasses.scoverage.check b/tests/coverage/pos/MatchCaseClasses.scoverage.check similarity index 85% rename from tests/coverage/expect/MatchCaseClasses.scoverage.check rename to tests/coverage/pos/MatchCaseClasses.scoverage.check index c83905bcd9f2..51a7e2f6ec42 100644 --- a/tests/coverage/expect/MatchCaseClasses.scoverage.check +++ b/tests/coverage/pos/MatchCaseClasses.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/MatchCaseClasses.scala +MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -36,7 +36,7 @@ false println("a") 2 -expect/MatchCaseClasses.scala +MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -53,7 +53,7 @@ false println("b") 3 -expect/MatchCaseClasses.scala +MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -70,7 +70,7 @@ false println("c") 4 -expect/MatchCaseClasses.scala +MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -87,7 +87,7 @@ false println(y) 5 -expect/MatchCaseClasses.scala +MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -104,7 +104,7 @@ false println("d") 6 -expect/MatchCaseClasses.scala +MatchCaseClasses.scala covtest MatchCaseClasses$ Object @@ -121,7 +121,7 @@ false println("e") 7 -expect/MatchCaseClasses.scala +MatchCaseClasses.scala covtest MatchCaseClasses$ Object diff --git a/tests/coverage/expect/MatchNumbers.scala b/tests/coverage/pos/MatchNumbers.scala similarity index 100% rename from tests/coverage/expect/MatchNumbers.scala rename to tests/coverage/pos/MatchNumbers.scala diff --git a/tests/coverage/expect/MatchNumbers.scoverage.check b/tests/coverage/pos/MatchNumbers.scoverage.check similarity index 88% rename from tests/coverage/expect/MatchNumbers.scoverage.check rename to tests/coverage/pos/MatchNumbers.scoverage.check index ce14acc72194..c7fa7c83f015 100644 --- a/tests/coverage/expect/MatchNumbers.scoverage.check +++ b/tests/coverage/pos/MatchNumbers.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/MatchNumbers.scala +MatchNumbers.scala covtest MatchNumbers$ Object @@ -36,7 +36,7 @@ false x < 0 2 -expect/MatchNumbers.scala +MatchNumbers.scala covtest MatchNumbers$ Object @@ -53,7 +53,7 @@ false -1 3 -expect/MatchNumbers.scala +MatchNumbers.scala covtest MatchNumbers$ Object @@ -70,7 +70,7 @@ false f(0) 4 -expect/MatchNumbers.scala +MatchNumbers.scala covtest MatchNumbers$ Object diff --git a/tests/coverage/expect/Select.scala b/tests/coverage/pos/Select.scala similarity index 100% rename from tests/coverage/expect/Select.scala rename to tests/coverage/pos/Select.scala diff --git a/tests/coverage/expect/Select.scoverage.check b/tests/coverage/pos/Select.scoverage.check similarity index 88% rename from tests/coverage/expect/Select.scoverage.check rename to tests/coverage/pos/Select.scoverage.check index b7e661353b4d..5419667a50ad 100644 --- a/tests/coverage/expect/Select.scoverage.check +++ b/tests/coverage/pos/Select.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/Select.scala +Select.scala covtest A Class @@ -36,7 +36,7 @@ false println("A") 2 -expect/Select.scala +Select.scala covtest B Class @@ -53,7 +53,7 @@ false A 3 -expect/Select.scala +Select.scala covtest B Class @@ -70,7 +70,7 @@ false super.print() 4 -expect/Select.scala +Select.scala covtest B Class @@ -87,7 +87,7 @@ false println(this.instance) 5 -expect/Select.scala +Select.scala covtest Select$package$ Object @@ -104,7 +104,7 @@ false A() 6 -expect/Select.scala +Select.scala covtest Select$package$ Object @@ -121,7 +121,7 @@ false new A 7 -expect/Select.scala +Select.scala covtest Select$package$ Object @@ -138,7 +138,7 @@ false a.instance.print() 8 -expect/Select.scala +Select.scala covtest Select$package$ Object diff --git a/tests/coverage/expect/StructuralTypes.scala b/tests/coverage/pos/StructuralTypes.scala similarity index 100% rename from tests/coverage/expect/StructuralTypes.scala rename to tests/coverage/pos/StructuralTypes.scala diff --git a/tests/coverage/expect/StructuralTypes.scoverage.check b/tests/coverage/pos/StructuralTypes.scoverage.check similarity index 85% rename from tests/coverage/expect/StructuralTypes.scoverage.check rename to tests/coverage/pos/StructuralTypes.scoverage.check index 9f5fb0cd014b..77616e0b1134 100644 --- a/tests/coverage/expect/StructuralTypes.scoverage.check +++ b/tests/coverage/pos/StructuralTypes.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/StructuralTypes.scala +StructuralTypes.scala covtest Record Class @@ -36,7 +36,7 @@ false _._1 == name 2 -expect/StructuralTypes.scala +StructuralTypes.scala covtest Record Class @@ -53,7 +53,7 @@ false elems.find(_._1 == name) 3 -expect/StructuralTypes.scala +StructuralTypes.scala covtest StructuralTypes$ Object @@ -70,7 +70,7 @@ false "name" 4 -expect/StructuralTypes.scala +StructuralTypes.scala covtest StructuralTypes$ Object @@ -87,7 +87,7 @@ false "name" -> "Emma" 5 -expect/StructuralTypes.scala +StructuralTypes.scala covtest StructuralTypes$ Object @@ -104,7 +104,7 @@ false "age" 6 -expect/StructuralTypes.scala +StructuralTypes.scala covtest StructuralTypes$ Object @@ -121,7 +121,7 @@ false "age" -> 42 7 -expect/StructuralTypes.scala +StructuralTypes.scala covtest StructuralTypes$ Object @@ -138,7 +138,7 @@ false Record("name" -> "Emma", "age" -> 42) 8 -expect/StructuralTypes.scala +StructuralTypes.scala covtest StructuralTypes$ Object diff --git a/tests/coverage/expect/TypeLambdas.scala b/tests/coverage/pos/TypeLambdas.scala similarity index 100% rename from tests/coverage/expect/TypeLambdas.scala rename to tests/coverage/pos/TypeLambdas.scala diff --git a/tests/coverage/expect/TypeLambdas.scoverage.check b/tests/coverage/pos/TypeLambdas.scoverage.check similarity index 87% rename from tests/coverage/expect/TypeLambdas.scoverage.check rename to tests/coverage/pos/TypeLambdas.scoverage.check index 51cd040d8b3b..9485c5170872 100644 --- a/tests/coverage/expect/TypeLambdas.scoverage.check +++ b/tests/coverage/pos/TypeLambdas.scoverage.check @@ -19,7 +19,7 @@ # ' ' sign # ------------------------------------------ 1 -expect/TypeLambdas.scala +TypeLambdas.scala covtest TypeLambdas$ Object @@ -36,7 +36,7 @@ false 1 2 -expect/TypeLambdas.scala +TypeLambdas.scala covtest TypeLambdas$ Object @@ -53,7 +53,7 @@ false 1 -> "1" 3 -expect/TypeLambdas.scala +TypeLambdas.scala covtest TypeLambdas$ Object @@ -70,7 +70,7 @@ false Map(1 -> "1") 4 -expect/TypeLambdas.scala +TypeLambdas.scala covtest TypeLambdas$ Object @@ -87,7 +87,7 @@ false println(m) 5 -expect/TypeLambdas.scala +TypeLambdas.scala covtest TypeLambdas$ Object @@ -104,7 +104,7 @@ false ("a", "b") 6 -expect/TypeLambdas.scala +TypeLambdas.scala covtest TypeLambdas$ Object diff --git a/tests/coverage/run/currying/test.check b/tests/coverage/run/currying/test.check new file mode 100644 index 000000000000..d21dbd35bc5c --- /dev/null +++ b/tests/coverage/run/currying/test.check @@ -0,0 +1,4 @@ +3 +3 +3 +3 \ No newline at end of file diff --git a/tests/coverage/expect/Currying.scala b/tests/coverage/run/currying/test.scala similarity index 53% rename from tests/coverage/expect/Currying.scala rename to tests/coverage/run/currying/test.scala index 12842cd181e1..4776b6bde855 100644 --- a/tests/coverage/expect/Currying.scala +++ b/tests/coverage/run/currying/test.scala @@ -1,6 +1,4 @@ -package covtest - -class ContextFunctions2: +object Test: def f1(a: Int)(b: Int)(c: Int) = a+b+c def f2 = (a: Int) => (b: Int) => (c: Int) => a+b+c @@ -10,7 +8,8 @@ class ContextFunctions2: def g2(using a: Int)(using b: Int)(using c: Int) = a+b+c - f1(0)(1)(2) - f2(0)(1)(2) - g1(using 0)(using 1)(using 2) - g2(using 0)(using 1)(using 2) + def main(args: Array[String]): Unit = + println(f1(0)(1)(2)) + println(f2(0)(1)(2)) + println(g1(using 0)(using 1)(using 2)) + println(g2(using 0)(using 1)(using 2)) diff --git a/tests/coverage/run/currying/test.scoverage.check b/tests/coverage/run/currying/test.scoverage.check new file mode 100644 index 000000000000..89ea9c4008c1 --- /dev/null +++ b/tests/coverage/run/currying/test.scoverage.check @@ -0,0 +1,326 @@ +# 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 +# ------------------------------------------ +1 +currying/test.scala + +Test$ +Object +.Test$ +f1 +48 +51 +1 ++ +Apply +false +0 +false +a+b + +2 +currying/test.scala + +Test$ +Object +.Test$ +f1 +48 +53 +1 ++ +Apply +false +0 +false +a+b+c + +3 +currying/test.scala + +Test$ +Object +.Test$ +$anonfun +105 +108 +3 ++ +Apply +false +0 +false +a+b + +4 +currying/test.scala + +Test$ +Object +.Test$ +$anonfun +105 +110 +3 ++ +Apply +false +0 +false +a+b+c + +5 +currying/test.scala + +Test$ +Object +.Test$ +$anonfun +166 +169 +6 ++ +Apply +false +0 +false +a+b + +6 +currying/test.scala + +Test$ +Object +.Test$ +$anonfun +166 +171 +6 ++ +Apply +false +0 +false +a+b+c + +7 +currying/test.scala + +Test$ +Object +.Test$ +g2 +226 +229 +8 ++ +Apply +false +0 +false +a+b + +8 +currying/test.scala + +Test$ +Object +.Test$ +g2 +226 +231 +8 ++ +Apply +false +0 +false +a+b+c + +9 +currying/test.scala + +Test$ +Object +.Test$ +main +285 +296 +11 +f1 +Apply +false +0 +false +f1(0)(1)(2) + +10 +currying/test.scala + +Test$ +Object +.Test$ +main +277 +297 +11 +println +Apply +false +0 +false +println(f1(0)(1)(2)) + +11 +currying/test.scala + +Test$ +Object +.Test$ +main +310 +315 +12 +apply +Apply +false +0 +false +f2(0) + +12 +currying/test.scala + +Test$ +Object +.Test$ +main +310 +318 +12 +apply +Apply +false +0 +false +f2(0)(1) + +13 +currying/test.scala + +Test$ +Object +.Test$ +main +310 +321 +12 +apply +Apply +false +0 +false +f2(0)(1)(2) + +14 +currying/test.scala + +Test$ +Object +.Test$ +main +302 +322 +12 +println +Apply +false +0 +false +println(f2(0)(1)(2)) + +15 +currying/test.scala + +Test$ +Object +.Test$ +main +335 +364 +13 +apply +Apply +false +0 +false +g1(using 0)(using 1)(using 2) + +16 +currying/test.scala + +Test$ +Object +.Test$ +main +327 +365 +13 +println +Apply +false +0 +false +println(g1(using 0)(using 1)(using 2)) + +17 +currying/test.scala + +Test$ +Object +.Test$ +main +378 +407 +14 +g2 +Apply +false +0 +false +g2(using 0)(using 1)(using 2) + +18 +currying/test.scala + +Test$ +Object +.Test$ +main +370 +408 +14 +println +Apply +false +0 +false +println(g2(using 0)(using 1)(using 2)) + diff --git a/tests/coverage/run/inheritance/test.check b/tests/coverage/run/inheritance/test.check new file mode 100644 index 000000000000..59fbc504fb8c --- /dev/null +++ b/tests/coverage/run/inheritance/test.check @@ -0,0 +1,3 @@ +block +1 +2 \ No newline at end of file diff --git a/tests/coverage/expect/Inheritance.scala b/tests/coverage/run/inheritance/test.scala similarity index 84% rename from tests/coverage/expect/Inheritance.scala rename to tests/coverage/run/inheritance/test.scala index e90fb87237ea..b5be83a378ea 100644 --- a/tests/coverage/expect/Inheritance.scala +++ b/tests/coverage/run/inheritance/test.scala @@ -1,11 +1,10 @@ -package covtest - class A(val x: Int, val y: Int) class B(x: Int) extends A(x, 0) class C1 extends B({println("block"); 1}) class C2 extends B(A(2,2).x) -def testInheritance = +@main +def Test: Unit = println(C1().x) // block // 1 println(C2().x) // 2 diff --git a/tests/coverage/expect/Inheritance.scoverage.check b/tests/coverage/run/inheritance/test.scoverage.check similarity index 56% rename from tests/coverage/expect/Inheritance.scoverage.check rename to tests/coverage/run/inheritance/test.scoverage.check index 70acf1456d5e..a714673ea3b5 100644 --- a/tests/coverage/expect/Inheritance.scoverage.check +++ b/tests/coverage/run/inheritance/test.scoverage.check @@ -19,15 +19,15 @@ # ' ' sign # ------------------------------------------ 1 -expect/Inheritance.scala -covtest +inheritance/test.scala + B Class -covtest.B +.B -73 -80 -3 +56 +63 +1 Apply false @@ -36,15 +36,15 @@ false A(x, 0) 2 -expect/Inheritance.scala -covtest +inheritance/test.scala + C1 Class -covtest.C1 +.C1 -101 -117 -4 +84 +100 +2 println Apply false @@ -53,15 +53,15 @@ false println("block") 3 -expect/Inheritance.scala -covtest +inheritance/test.scala + C1 Class -covtest.C1 +.C1 -98 -122 -4 +81 +105 +2 Apply false @@ -70,15 +70,15 @@ false B({println("block"); 1}) 4 -expect/Inheritance.scala -covtest +inheritance/test.scala + C2 Class -covtest.C2 +.C2 -142 -148 -5 +125 +131 +3 Apply false @@ -87,15 +87,15 @@ false A(2,2) 5 -expect/Inheritance.scala -covtest +inheritance/test.scala + C2 Class -covtest.C2 +.C2 -140 -151 -5 +123 +134 +3 Apply false @@ -104,15 +104,15 @@ false B(A(2,2).x) 6 -expect/Inheritance.scala -covtest -Inheritance$package$ +inheritance/test.scala + +test$package$ Object -covtest.Inheritance$package$ -testInheritance -185 -189 -8 +.test$package$ +Test +169 +173 +7 Apply false @@ -121,15 +121,15 @@ false C1() 7 -expect/Inheritance.scala -covtest -Inheritance$package$ +inheritance/test.scala + +test$package$ Object -covtest.Inheritance$package$ -testInheritance -177 -192 -8 +.test$package$ +Test +161 +176 +7 println Apply false @@ -138,15 +138,15 @@ false println(C1().x) 8 -expect/Inheritance.scala -covtest -Inheritance$package$ +inheritance/test.scala + +test$package$ Object -covtest.Inheritance$package$ -testInheritance -235 -239 -10 +.test$package$ +Test +219 +223 +9 Apply false @@ -155,15 +155,15 @@ false C2() 9 -expect/Inheritance.scala -covtest -Inheritance$package$ +inheritance/test.scala + +test$package$ Object -covtest.Inheritance$package$ -testInheritance -227 -242 -10 +.test$package$ +Test +211 +226 +9 println Apply false diff --git a/tests/coverage/run/interpolation/test.check b/tests/coverage/run/interpolation/test.check new file mode 100644 index 000000000000..9ce4b367db49 --- /dev/null +++ b/tests/coverage/run/interpolation/test.check @@ -0,0 +1,5 @@ +0: d +1: o +2: t +3: t +4: y diff --git a/tests/coverage/expect/ParamsAndInterpolation.scala b/tests/coverage/run/interpolation/test.scala similarity index 72% rename from tests/coverage/expect/ParamsAndInterpolation.scala rename to tests/coverage/run/interpolation/test.scala index 34d7ae300811..3745367b593d 100644 --- a/tests/coverage/expect/ParamsAndInterpolation.scala +++ b/tests/coverage/run/interpolation/test.scala @@ -1,11 +1,9 @@ -package covtest - -object ParamsAndInterpolation: +object Test: def simple(a: Int, b: String): String = s"$a, ${b.length}" - def test(): Unit = + def main(args: Array[String]): Unit = val xs: List[String] = List("d", "o", "t", "t", "y") xs.zipWithIndex.map((s, i) => println(s"$i: $s")) diff --git a/tests/coverage/run/interpolation/test.scoverage.check b/tests/coverage/run/interpolation/test.scoverage.check new file mode 100644 index 000000000000..de100e7c116e --- /dev/null +++ b/tests/coverage/run/interpolation/test.scoverage.check @@ -0,0 +1,224 @@ +# 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 +# ------------------------------------------ +1 +interpolation/test.scala + +Test$ +Object +.Test$ +simple +62 +77 +3 +apply +Apply +false +0 +false +$a, ${b.length} + +2 +interpolation/test.scala + +Test$ +Object +.Test$ +simple +62 +77 +3 +invoked +Apply +false +0 +false +$a, ${b.length} + +3 +interpolation/test.scala + +Test$ +Object +.Test$ +simple +62 +77 +3 +apply +Apply +false +0 +false +$a, ${b.length} + +4 +interpolation/test.scala + +Test$ +Object +.Test$ +simple +68 +76 +3 +length +Apply +false +0 +false +b.length + +5 +interpolation/test.scala + +Test$ +Object +.Test$ +simple +60 +78 +3 +s +Apply +false +0 +false +s"$a, ${b.length}" + +6 +interpolation/test.scala + +Test$ +Object +.Test$ +main +147 +176 +6 +apply +Apply +false +0 +false +List("d", "o", "t", "t", "y") + +7 +interpolation/test.scala + +Test$ +Object +.Test$ +$anonfun +222 +228 +8 +apply +Apply +false +0 +false +$i: $s + +8 +interpolation/test.scala + +Test$ +Object +.Test$ +$anonfun +222 +228 +8 +invoked +Apply +false +0 +false +$i: $s + +9 +interpolation/test.scala + +Test$ +Object +.Test$ +$anonfun +222 +228 +8 +apply +Apply +false +0 +false +$i: $s + +10 +interpolation/test.scala + +Test$ +Object +.Test$ +$anonfun +220 +229 +8 +s +Apply +false +0 +false +s"$i: $s" + +11 +interpolation/test.scala + +Test$ +Object +.Test$ +$anonfun +212 +230 +8 +println +Apply +false +0 +false +println(s"$i: $s") + +12 +interpolation/test.scala + +Test$ +Object +.Test$ +main +182 +231 +8 +map +Apply +false +0 +false +xs.zipWithIndex.map((s, i) => println(s"$i: $s")) + diff --git a/tests/coverage/run/lifting/test.check b/tests/coverage/run/lifting/test.check new file mode 100644 index 000000000000..fe4a8088d523 --- /dev/null +++ b/tests/coverage/run/lifting/test.check @@ -0,0 +1,3 @@ +string123.0.0 +string123.0.0 +string-1.0.123 diff --git a/tests/coverage/run/lifting/test.scala b/tests/coverage/run/lifting/test.scala new file mode 100644 index 000000000000..2b44168e3aed --- /dev/null +++ b/tests/coverage/run/lifting/test.scala @@ -0,0 +1,20 @@ +class Vals: + val l = List(1) + val ll = l :: List(1,2,3) + +class A: + def msg(a: Int, b: Int, c: Int) = "string" + a + "." + b + "." + c + def integer: Int = 0 + def ex: this.type = this + +@main +def Test: Unit = + val a = A() + val i = 123 + def f() = -1 + var x = a.msg(i, 0, a.integer) + println(x) + x = a.ex.msg(i, 0, a.ex.integer) + println(x) + x = a.msg(f(), 0, i) + println(x) diff --git a/tests/coverage/run/lifting/test.scoverage.check b/tests/coverage/run/lifting/test.scoverage.check new file mode 100644 index 000000000000..701110a58615 --- /dev/null +++ b/tests/coverage/run/lifting/test.scoverage.check @@ -0,0 +1,360 @@ +# 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 +# ------------------------------------------ +1 +lifting/test.scala + +Vals +Class +.Vals + +22 +29 +1 +apply +Apply +false +0 +false +List(1) + +2 +lifting/test.scala + +Vals +Class +.Vals + +46 +57 +2 +apply +Apply +false +0 +false +List(1,2,3) + +3 +lifting/test.scala + +Vals +Class +.Vals + +41 +57 +2 +:: +Apply +false +0 +false +l :: List(1,2,3) + +4 +lifting/test.scala + +A +Class +.A +msg +104 +112 +5 + +Literal +false +0 +false +"string" + +5 +lifting/test.scala + +A +Class +.A +msg +104 +116 +5 ++ +Apply +false +0 +false +"string" + a + +6 +lifting/test.scala + +A +Class +.A +msg +104 +122 +5 ++ +Apply +false +0 +false +"string" + a + "." + +7 +lifting/test.scala + +A +Class +.A +msg +104 +126 +5 ++ +Apply +false +0 +false +"string" + a + "." + b + +8 +lifting/test.scala + +A +Class +.A +msg +104 +132 +5 ++ +Apply +false +0 +false +"string" + a + "." + b + "." + +9 +lifting/test.scala + +A +Class +.A +msg +104 +136 +5 ++ +Apply +false +0 +false +"string" + a + "." + b + "." + c + +10 +lifting/test.scala + +A +Class +.A +integer +158 +159 +6 + +Literal +false +0 +false +0 + +11 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +221 +224 +11 + +Apply +false +0 +false +A() + +12 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +235 +238 +12 + +Literal +false +0 +false +123 + +13 +lifting/test.scala + +test$package$ +Object +.test$package$ +f +251 +253 +13 + +Literal +false +0 +false +-1 + +14 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +264 +286 +14 +msg +Apply +false +0 +false +a.msg(i, 0, a.integer) + +15 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +289 +299 +15 +println +Apply +false +0 +false +println(x) + +16 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +306 +334 +16 +msg +Apply +false +0 +false +a.ex.msg(i, 0, a.ex.integer) + +17 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +337 +347 +17 +println +Apply +false +0 +false +println(x) + +18 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +360 +363 +18 +f +Apply +false +0 +false +f() + +19 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +354 +370 +18 +msg +Apply +false +0 +false +a.msg(f(), 0, i) + +20 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +373 +383 +19 +println +Apply +false +0 +false +println(x) + diff --git a/tests/coverage/run/trait/test.check b/tests/coverage/run/trait/test.check new file mode 100644 index 000000000000..8c9ca6a4ce24 --- /dev/null +++ b/tests/coverage/run/trait/test.check @@ -0,0 +1,3 @@ +0 +test +test diff --git a/tests/coverage/expect/Trait.scala b/tests/coverage/run/trait/test.scala similarity index 87% rename from tests/coverage/expect/Trait.scala rename to tests/coverage/run/trait/test.scala index 90ad91e74284..54166d77c17e 100644 --- a/tests/coverage/expect/Trait.scala +++ b/tests/coverage/run/trait/test.scala @@ -1,5 +1,3 @@ -package covtest - trait T1: def x = 0 @@ -9,7 +7,8 @@ trait T2(val p: String) class Impl2 extends T2("test") with T1 class Impl3 extends T2(Impl2().p) -def testTrait = +@main +def Test: Unit = println(Impl1().x) // 0 println(Impl2().p) // test println(Impl3().p) // test diff --git a/tests/coverage/expect/Trait.scoverage.check b/tests/coverage/run/trait/test.scoverage.check similarity index 58% rename from tests/coverage/expect/Trait.scoverage.check rename to tests/coverage/run/trait/test.scoverage.check index 8a752e0e0686..ac6000132788 100644 --- a/tests/coverage/expect/Trait.scoverage.check +++ b/tests/coverage/run/trait/test.scoverage.check @@ -19,15 +19,15 @@ # ' ' sign # ------------------------------------------ 1 -expect/Trait.scala -covtest +trait/test.scala + T1 Trait -covtest.T1 +.T1 x -37 -38 -3 +20 +21 +1 Literal false @@ -36,15 +36,15 @@ false 0 2 -expect/Trait.scala -covtest +trait/test.scala + Impl2 Class -covtest.Impl2 +.Impl2 -108 -118 -8 +91 +101 +6 Apply false @@ -53,15 +53,15 @@ false T2("test") 3 -expect/Trait.scala -covtest +trait/test.scala + Impl3 Class -covtest.Impl3 +.Impl3 -150 -157 -9 +133 +140 +7 Apply false @@ -70,15 +70,15 @@ false Impl2() 4 -expect/Trait.scala -covtest +trait/test.scala + Impl3 Class -covtest.Impl3 +.Impl3 -147 -160 -9 +130 +143 +7 Apply false @@ -87,15 +87,15 @@ false T2(Impl2().p) 5 -expect/Trait.scala -covtest -Trait$package$ +trait/test.scala + +test$package$ Object -covtest.Trait$package$ -testTrait -188 -195 -12 +.test$package$ +Test +178 +185 +11 Apply false @@ -104,15 +104,15 @@ false Impl1() 6 -expect/Trait.scala -covtest -Trait$package$ +trait/test.scala + +test$package$ Object -covtest.Trait$package$ -testTrait -180 -198 -12 +.test$package$ +Test +170 +188 +11 println Apply false @@ -121,15 +121,15 @@ false println(Impl1().x) 7 -expect/Trait.scala -covtest -Trait$package$ +trait/test.scala + +test$package$ Object -covtest.Trait$package$ -testTrait -214 -221 -13 +.test$package$ +Test +204 +211 +12 Apply false @@ -138,15 +138,15 @@ false Impl2() 8 -expect/Trait.scala -covtest -Trait$package$ +trait/test.scala + +test$package$ Object -covtest.Trait$package$ -testTrait -206 -224 -13 +.test$package$ +Test +196 +214 +12 println Apply false @@ -155,15 +155,15 @@ false println(Impl2().p) 9 -expect/Trait.scala -covtest -Trait$package$ +trait/test.scala + +test$package$ Object -covtest.Trait$package$ -testTrait -243 -250 -14 +.test$package$ +Test +233 +240 +13 Apply false @@ -172,15 +172,15 @@ false Impl3() 10 -expect/Trait.scala -covtest -Trait$package$ +trait/test.scala + +test$package$ Object -covtest.Trait$package$ -testTrait -235 -253 -14 +.test$package$ +Test +225 +243 +13 println Apply false From a1d0e641f29c7f5c6a013265875e8d77d91523ab Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Tue, 29 Mar 2022 11:44:59 +0200 Subject: [PATCH 12/15] Cleanup coverage instrumentation --- NOTICE.md | 5 + compiler/src/dotty/tools/dotc/ast/Trees.scala | 16 +- .../tools/dotc/config/ScalaSettings.scala | 2 +- .../dotty/tools/dotc/core/Definitions.scala | 3 +- .../dotty/tools/dotc/coverage/Coverage.scala | 3 + .../dotty/tools/dotc/coverage/Location.scala | 20 +- .../tools/dotc/coverage/Serializer.scala | 4 +- .../dotc/transform/InstrumentCoverage.scala | 244 +++++++++--------- .../tools/dotc/coverage/CoverageTests.scala | 9 +- project/Build.scala | 1 - tests/coverage/pos/Inlined.scoverage.check | 22 +- 11 files changed, 172 insertions(+), 157 deletions(-) diff --git a/NOTICE.md b/NOTICE.md index 64b5f9122db7..64ebae49efe5 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -88,6 +88,10 @@ major authors were omitted by oversight. docs/js/. Please refer to the license header of the concerned files for details. + * dotty.tools.dotc.coverage: Coverage instrumentation utilities have been + adapted from the scoverage plugin for scala 2 [5], which is under the + Apache 2.0 license. + * The Dotty codebase contains parts which are derived from the ScalaPB protobuf library [4], which is under the Apache 2.0 license. @@ -96,3 +100,4 @@ major authors were omitted by oversight. [2] https://github.com/adriaanm/scala/tree/sbt-api-consolidate/src/compiler/scala/tools/sbt [3] https://github.com/sbt/sbt/tree/0.13/compile/interface/src/main/scala/xsbt [4] https://github.com/lampepfl/dotty/pull/5783/files +[5] https://github.com/scoverage/scalac-scoverage-plugin diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index cb20a7c9da37..67464e4b063a 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1367,13 +1367,19 @@ object Trees { /** The context to use when mapping or accumulating over a tree */ def localCtx(tree: Tree)(using Context): Context + /** The context to use when transforming a tree. + * It ensures that the source information is correct. + * TODO: ensure transform is always called with the correct context as argument + * @see https://github.com/lampepfl/dotty/pull/13880#discussion_r836395977 + */ + def transformCtx(tree: Tree)(using Context): Context = + if tree.source.exists && tree.source != ctx.source + then ctx.withSource(tree.source) + else ctx + abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { self => def transform(tree: Tree)(using Context): Tree = { - inContext( - if tree.source != ctx.source && tree.source.exists - then ctx.withSource(tree.source) - else ctx - ){ + inContext(transformCtx(tree)){ Stats.record(s"TreeMap.transform/$getClass") if (skipTransform(tree)) tree else tree match { diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index a1ce1591e9af..7a00c1d5e3ed 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -116,9 +116,9 @@ trait CommonScalaSettings: val explainTypes: Setting[Boolean] = BooleanSetting("-explain-types", "Explain type errors in more detail (deprecated, use -explain instead).", aliases = List("--explain-types", "-explaintypes")) val unchecked: Setting[Boolean] = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked")) val language: Setting[List[String]] = MultiStringSetting("-language", "feature", "Enable one or more language features.", aliases = List("--language")) + /* Coverage settings */ val coverageOutputDir = PathSetting("-coverage-out", "Destination for coverage classfiles and instrumentation data.", "", aliases = List("--coverage-out")) - val coverageSourceroot = PathSetting("-coverage-sourceroot", "An alternative root dir of your sources used to relativize.", ".", aliases = List("--coverage-sourceroot")) /* Other settings */ val encoding: Setting[String] = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding, aliases = List("--encoding")) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 47780b302c8c..5eb1ccb0f957 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -461,7 +461,8 @@ class Definitions { } def NullType: TypeRef = NullClass.typeRef - @tu lazy val InvokerModuleRef = requiredModuleRef("scala.runtime.coverage.Invoker") + @tu lazy val InvokerModule = requiredModule("scala.runtime.coverage.Invoker") + @tu lazy val InvokedMethodRef = InvokerModule.requiredMethodRef("invoked") @tu lazy val ImplicitScrutineeTypeSym = newPermanentSymbol(ScalaPackageClass, tpnme.IMPLICITkw, EmptyFlags, TypeBounds.empty).entered diff --git a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala index 05ced1075edc..6140c937171e 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala @@ -3,6 +3,7 @@ package coverage import scala.collection.mutable +/** Holds a list of statements to include in the coverage reports. */ class Coverage: private val statementsById = new mutable.LongMap[Statement](256) @@ -10,6 +11,7 @@ class Coverage: def addStatement(stmt: Statement): Unit = statementsById(stmt.id) = stmt +/** A statement that can be invoked, and thus counted as "covered" by code coverage tools. */ case class Statement( source: String, location: Location, @@ -24,6 +26,7 @@ case class Statement( var count: Int = 0, ignored: Boolean = false ): + /** Records that this statement has been invoked one more time. */ def invoked(): Unit = count += 1 diff --git a/compiler/src/dotty/tools/dotc/coverage/Location.scala b/compiler/src/dotty/tools/dotc/coverage/Location.scala index 0c0181baa305..faf1e97d0c01 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Location.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Location.scala @@ -4,13 +4,16 @@ package coverage import ast.tpd._ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Flags.* +import java.nio.file.Path -/** @param packageName - * the name of the encosing package - * @param className - * the name of the closes enclosing class - * @param fullClassName - * the fully qualified name of the closest enclosing class +/** Information about the location of a coverable piece of code. + * + * @param packageName name of the enclosing package + * @param className name of the closest enclosing class + * @param fullClassName fully qualified name of the closest enclosing class + * @param classType "type" of the closest enclosing class: Class, Trait or Object + * @param method name of the closest enclosing method + * @param sourcePath absolute path of the source file */ final case class Location( packageName: String, @@ -18,10 +21,11 @@ final case class Location( fullClassName: String, classType: String, method: String, - sourcePath: String + sourcePath: Path ) object Location: + /** Extracts the location info of a Tree. */ def apply(tree: Tree)(using ctx: Context): Location = val enclosingClass = ctx.owner.denot.enclosingClass @@ -39,5 +43,5 @@ object Location: s"$packageName.$className", classType, ctx.owner.denot.enclosingMethod.name.toSimpleName.toString(), - ctx.source.file.absolute.toString() + ctx.source.file.absolute.jpath ) diff --git a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala index c5e6440afffd..c4f633dcdfa2 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala @@ -30,8 +30,8 @@ object Serializer: */ def serialize(coverage: Coverage, writer: Writer, sourceRoot: Path): Unit = - def getRelativePath(filePath: String): String = - val relPath = sourceRoot.relativize(Paths.get(filePath).toAbsolutePath) + def getRelativePath(filePath: Path): String = + val relPath = sourceRoot.relativize(filePath) relPath.toString def writeHeader(writer: Writer): Unit = diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index a04e4c98e9a9..cf18f09b044c 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -18,7 +18,7 @@ import util.{SourcePosition, Property} import util.Spans.Span import coverage.* -/** Implements code coverage by inserting calls to scala.runtime.Invoker +/** Implements code coverage by inserting calls to scala.runtime.coverage.Invoker * ("instruments" the source code). * The result can then be consumed by the Scoverage tool. */ @@ -29,20 +29,18 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: override def description = InstrumentCoverage.description - // Enabled by argument "-coverage OUTPUT_DIR" + // Enabled by argument "-coverage-out OUTPUT_DIR" override def isEnabled(using ctx: Context) = ctx.settings.coverageOutputDir.value.nonEmpty - // Atomic counter used for assignation of IDs to difference statements - private val statementId = AtomicInteger(0) + // counter to assign a unique id to each statement + private var statementId = 0 - private var outputPath = "" - - // Main class used to store all instrumented statements + // stores all instrumented statements private val coverage = Coverage() override def run(using ctx: Context): Unit = - outputPath = ctx.settings.coverageOutputDir.value + val outputPath = ctx.settings.coverageOutputDir.value // Ensure the dir exists val dataDir = new File(outputPath) @@ -56,132 +54,131 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: end if super.run - Serializer.serialize(coverage, outputPath, ctx.settings.coverageSourceroot.value) + Serializer.serialize(coverage, outputPath, ctx.settings.sourceroot.value) - override protected def newTransformer(using Context) = CoverageTransormer() + override protected def newTransformer(using Context) = CoverageTransformer() /** Transforms trees to insert calls to Invoker.invoked to compute the coverage when the code is called */ - private class CoverageTransormer extends Transformer: + private class CoverageTransformer extends Transformer: private val IgnoreLiterals = new Property.Key[Boolean] private def ignoreLiteralsContext(using ctx: Context): Context = ctx.fresh.setProperty(IgnoreLiterals, true) override def transform(tree: Tree)(using ctx: Context): Tree = - tree match - // simple cases - case tree: (Import | Export | This | Super | New) => tree - case tree if (tree.isEmpty || tree.isType) => tree // empty Thicket, Ident, TypTree, ... - - // Literals must be instrumented (at least) when returned by a def, - // otherwise `def d = "literal"` is not covered when called from a test. - // They can be left untouched when passed in a parameter of an Apply. - case tree: Literal => - if ctx.property(IgnoreLiterals).contains(true) then - tree - else - instrument(tree) - - // branches - case tree: If => - cpy.If(tree)( - cond = transform(tree.cond), - thenp = instrument(transform(tree.thenp), branch = true), - elsep = instrument(transform(tree.elsep), branch = true) - ) - case tree: Try => - cpy.Try(tree)( - expr = instrument(transform(tree.expr), branch = true), - cases = instrumentCases(tree.cases), - finalizer = instrument(transform(tree.finalizer), true) - ) - - // a.f(args) - case tree @ Apply(fun: Select, args) => - // don't transform the first Select, but do transform `a.b` in `a.b.f(args)` - if canInstrumentApply(tree) then - val transformedFun = cpy.Select(fun)(transform(fun.qualifier), fun.name) - if needsLift(tree) then - val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted - instrumentLifted(transformed)(using ignoreLiteralsContext) + inContext(transformCtx(tree)) { // necessary to position inlined code properly + tree match + // simple cases + case tree: (Import | Export | This | Super | New) => tree + case tree if tree.isEmpty || tree.isType => tree // empty Thicket, Ident, TypTree, ... + + // Literals must be instrumented (at least) when returned by a def, + // otherwise `def d = "literal"` is not covered when called from a test. + // They can be left untouched when passed in a parameter of an Apply. + case tree: Literal => + if ctx.property(IgnoreLiterals).contains(true) then + tree else - val transformed = cpy.Apply(tree)(transformedFun, transform(args)(using ignoreLiteralsContext)) - instrument(transformed)(using ignoreLiteralsContext) - else - tree - - // f(args) - case tree: Apply => - if canInstrumentApply(tree) then - if needsLift(tree) then - instrumentLifted(tree)(using ignoreLiteralsContext) // see comment about Literals + instrument(tree) + + // branches + case tree: If => + cpy.If(tree)( + cond = transform(tree.cond), + thenp = instrument(transform(tree.thenp), branch = true), + elsep = instrument(transform(tree.elsep), branch = true) + ) + case tree: Try => + cpy.Try(tree)( + expr = instrument(transform(tree.expr), branch = true), + cases = instrumentCases(tree.cases), + finalizer = instrument(transform(tree.finalizer), true) + ) + + // a.f(args) + case tree @ Apply(fun: Select, args) => + // don't transform the first Select, but do transform `a.b` in `a.b.f(args)` + if canInstrumentApply(tree) then + val transformedFun = cpy.Select(fun)(transform(fun.qualifier), fun.name) + if needsLift(tree) then + val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted + instrumentLifted(transformed)(using ignoreLiteralsContext) + else + val transformed = cpy.Apply(tree)(transformedFun, transform(args)(using ignoreLiteralsContext)) + instrument(transformed)(using ignoreLiteralsContext) else - instrument(super.transform(tree)(using ignoreLiteralsContext)) - else - tree - - // (f(x))[args] - case TypeApply(fun: Apply, args) => - cpy.TypeApply(tree)(transform(fun), args) - - // a.b - case Select(qual, name) => - if qual.symbol.exists && qual.symbol.is(JavaDefined) then - //Java class can't be used as a value, we can't instrument the - //qualifier ({;System}.xyz() is not possible !) instrument it - //as it is - instrument(tree) - else - val transformed = cpy.Select(tree)(transform(qual), name) - if transformed.qualifier.isDef then - // instrument calls to methods without parameter list - instrument(transformed) + tree + + // f(args) + case tree: Apply => + if canInstrumentApply(tree) then + if needsLift(tree) then + instrumentLifted(tree)(using ignoreLiteralsContext) // see comment about Literals + else + instrument(super.transform(tree)(using ignoreLiteralsContext)) else - transformed - - case tree: CaseDef => instrumentCaseDef(tree) - case tree: ValDef => - // only transform the rhs, in the local context - val rhs = transform(tree.rhs)(using localCtx(tree)) - cpy.ValDef(tree)(rhs=rhs) - - case tree: DefDef => - // only transform the params (for the default values) and the rhs - val defCtx = localCtx(tree) - val paramss = transformParamss(tree.paramss)(using defCtx) - val rhs = transform(tree.rhs)(using defCtx) - cpy.DefDef(tree)(tree.name, paramss, tree.tpt, rhs) - - case tree: PackageDef => - // only transform the statements of the package - cpy.PackageDef(tree)(tree.pid, transform(tree.stats)(using localCtx(tree))) - case tree: Assign => - // only transform the rhs - cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) - - // For everything else just recurse and transform - // Special care for Templates: it's important to set the owner of the `stats`, like super.transform - case _ => - super.transform(tree) + tree + + // (f(x))[args] + case TypeApply(fun: Apply, args) => + cpy.TypeApply(tree)(transform(fun), args) + + // a.b + case Select(qual, name) => + if qual.symbol.exists && qual.symbol.is(JavaDefined) then + //Java class can't be used as a value, we can't instrument the + //qualifier ({;System}.xyz() is not possible !) instrument it + //as it is + instrument(tree) + else + val transformed = cpy.Select(tree)(transform(qual), name) + if transformed.qualifier.isDef then + // instrument calls to methods without parameter list + instrument(transformed) + else + transformed + + case tree: CaseDef => instrumentCaseDef(tree) + case tree: ValDef => + // only transform the rhs, in the local context + val rhs = transform(tree.rhs)(using localCtx(tree)) + cpy.ValDef(tree)(rhs=rhs) + + case tree: DefDef => + // only transform the params (for the default values) and the rhs + val defCtx = localCtx(tree) + val paramss = transformParamss(tree.paramss)(using defCtx) + val rhs = transform(tree.rhs)(using defCtx) + cpy.DefDef(tree)(tree.name, paramss, tree.tpt, rhs) + + case tree: PackageDef => + // only transform the statements of the package + cpy.PackageDef(tree)(tree.pid, transform(tree.stats)(using localCtx(tree))) + case tree: Assign => + // only transform the rhs + cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) + + // For everything else just recurse and transform + // Special care for Templates: it's important to set the owner of the `stats`, like super.transform + case _ => + super.transform(tree) + } /** Lifts and instruments an application. * Note that if only one arg needs to be lifted, we just lift everything. */ def instrumentLifted(tree: Apply)(using Context) = - // withSource is necessary to position inlined code properly - inContext(ctx.withSource(tree.source)) { - // lifting - val buffer = mutable.ListBuffer[Tree]() - val liftedApply = LiftCoverage.liftForCoverage(buffer, tree) - - // instrumentation - val instrumentedArgs = buffer.toList.map(transform) - val instrumentedApply = instrument(liftedApply) - Block( - instrumentedArgs, - instrumentedApply - ).withSpan(instrumentedApply.span) - } + // lifting + val buffer = mutable.ListBuffer[Tree]() + val liftedApply = LiftCoverage.liftForCoverage(buffer, tree) + + // instrumentation + val instrumentedArgs = buffer.toList.map(transform) + val instrumentedApply = instrument(liftedApply) + Block( + instrumentedArgs, + instrumentedApply + ).withSpan(instrumentedApply.span) def instrumentCases(cases: List[CaseDef])(using Context): List[CaseDef] = cases.map(instrumentCaseDef) @@ -194,7 +191,8 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: def instrument(tree: Tree, pos: SourcePosition, branch: Boolean)(using ctx: Context): Tree = if pos.exists && !pos.span.isZeroExtent then - val id = statementId.incrementAndGet() + statementId += 1 + val id = statementId val statement = new Statement( source = ctx.source.file.name, location = Location(tree), @@ -208,16 +206,14 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: branch ) coverage.addStatement(statement) - inContext(ctx.withSource(tree.source)) { - val span = Span(pos.start, pos.end) // synthetic span - Block(List(invokeCall(id, span)), tree).withSpan(span) - } + val span = Span(pos.start, pos.end) // synthetic span + Block(List(invokeCall(id, span)), tree).withSpan(span) else tree def invokeCall(id: Int, span: Span)(using Context): Tree = - ref(defn.InvokerModuleRef).withSpan(span) - .select("invoked".toTermName).withSpan(span) + val outputPath = ctx.settings.coverageOutputDir.value + ref(defn.InvokedMethodRef).withSpan(span) .appliedToArgs( List(Literal(Constant(id)), Literal(Constant(outputPath))) ).withSpan(span) diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index c431d6358b5a..84e07003cf0d 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -6,20 +6,21 @@ import org.junit.Assert.* import org.junit.experimental.categories.Category import dotty.{BootstrappedOnlyTests, Properties} -import dotty.tools.vulpix.TestConfiguration.* import dotty.tools.vulpix.* +import dotty.tools.vulpix.TestConfiguration.* +import dotty.tools.dotc.Main import java.nio.file.{Files, FileSystems, Path, Paths, StandardCopyOption} import scala.jdk.CollectionConverters.* +import scala.util.Properties.userDir import scala.language.unsafeNulls -import dotty.tools.dotc.Main @Category(Array(classOf[BootstrappedOnlyTests])) class CoverageTests: import CoverageTests.{*, given} private val scalaFile = FileSystems.getDefault.getPathMatcher("glob:**.scala") - private val rootSrc = Paths.get(System.getProperty("dotty.tools.dotc.coverage.test")) + private val rootSrc = Paths.get(userDir, "tests", "coverage") @Test def checkCoverageStatements(): Unit = @@ -54,7 +55,7 @@ class CoverageTests: /** Generates the coverage report for the given input file, in a temporary directory. */ def computeCoverageInTmp(inputFile: Path, sourceRoot: Path, run: Boolean)(using TestGroup): Path = val target = Files.createTempDirectory("coverage") - val options = defaultOptions.and("-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-coverage-sourceroot", sourceRoot.toString) + val options = defaultOptions.and("-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-sourceroot", sourceRoot.toString) val test = compileFile(inputFile.toString, options) if run then test.checkRuns() diff --git a/project/Build.scala b/project/Build.scala index c754f7ff1464..abe42e6a640f 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -577,7 +577,6 @@ object Build { javaOptions ++= Seq( s"-Ddotty.tools.dotc.semanticdb.test=${(ThisBuild / baseDirectory).value/"tests"/"semanticdb"}", - s"-Ddotty.tools.dotc.coverage.test=${(ThisBuild / baseDirectory).value/"tests"/"coverage"}", ), testCompilation := Def.inputTaskDyn { diff --git a/tests/coverage/pos/Inlined.scoverage.check b/tests/coverage/pos/Inlined.scoverage.check index 0f5b03f6e2f5..016e3ef56ad5 100644 --- a/tests/coverage/pos/Inlined.scoverage.check +++ b/tests/coverage/pos/Inlined.scoverage.check @@ -36,7 +36,7 @@ false 1 2 -../../../library/src/scala/runtime/stdLibPatches/Predef.scala +Inlined.scala covtest Inlined$package$ Object @@ -53,7 +53,7 @@ false l == 1 3 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -70,7 +70,7 @@ false scala.runtime.Scala3RunTime 4 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -87,7 +87,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 5 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -138,7 +138,7 @@ false l == List(l).length 8 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -155,7 +155,7 @@ false scala.runtime.Scala3RunTime 9 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -172,7 +172,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 10 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -206,7 +206,7 @@ false List(l) 12 -../../../library/src/scala/runtime/stdLibPatches/Predef.scala +Inlined.scala covtest Inlined$package$ Object @@ -223,7 +223,7 @@ false List(l).length == 1 13 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -240,7 +240,7 @@ false scala.runtime.Scala3RunTime 14 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object @@ -257,7 +257,7 @@ false scala.runtime.Scala3RunTime.assertFailed() 15 -Inlined.scala +../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ Object From 169593dfd12b761f2a8f84867336dbc53f04e251 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Tue, 29 Mar 2022 16:37:37 +0200 Subject: [PATCH 13/15] Make Trees.transformCtx return the local context if needed --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 46 ++++++++----------- .../dotc/transform/InstrumentCoverage.scala | 13 +++--- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 67464e4b063a..5afbb7f416ed 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1368,18 +1368,25 @@ object Trees { def localCtx(tree: Tree)(using Context): Context /** The context to use when transforming a tree. - * It ensures that the source information is correct. + * It ensures that the source is correct, and that the local context is used if + * that's necessary for transforming the whole tree. * TODO: ensure transform is always called with the correct context as argument * @see https://github.com/lampepfl/dotty/pull/13880#discussion_r836395977 */ def transformCtx(tree: Tree)(using Context): Context = - if tree.source.exists && tree.source != ctx.source - then ctx.withSource(tree.source) - else ctx + val sourced = + if tree.source.exists && tree.source != ctx.source + then ctx.withSource(tree.source) + else ctx + tree match + case t: (MemberDef | PackageDef | LambdaTypeTree | TermLambdaTypeTree) => + localCtx(t)(using sourced) + case _ => + sourced abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { self => def transform(tree: Tree)(using Context): Tree = { - inContext(transformCtx(tree)){ + inContext(transformCtx(tree)) { Stats.record(s"TreeMap.transform/$getClass") if (skipTransform(tree)) tree else tree match { @@ -1436,13 +1443,9 @@ object Trees { case AppliedTypeTree(tpt, args) => cpy.AppliedTypeTree(tree)(transform(tpt), transform(args)) case LambdaTypeTree(tparams, body) => - inContext(localCtx(tree)) { - cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body)) - } + cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body)) case TermLambdaTypeTree(params, body) => - inContext(localCtx(tree)) { - cpy.TermLambdaTypeTree(tree)(transformSub(params), transform(body)) - } + cpy.TermLambdaTypeTree(tree)(transformSub(params), transform(body)) case MatchTypeTree(bound, selector, cases) => cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases)) case ByNameTypeTree(result) => @@ -1458,19 +1461,13 @@ object Trees { case EmptyValDef => tree case tree @ ValDef(name, tpt, _) => - inContext(localCtx(tree)) { - val tpt1 = transform(tpt) - val rhs1 = transform(tree.rhs) - cpy.ValDef(tree)(name, tpt1, rhs1) - } + val tpt1 = transform(tpt) + val rhs1 = transform(tree.rhs) + cpy.ValDef(tree)(name, tpt1, rhs1) case tree @ DefDef(name, paramss, tpt, _) => - inContext(localCtx(tree)) { - cpy.DefDef(tree)(name, transformParamss(paramss), transform(tpt), transform(tree.rhs)) - } + cpy.DefDef(tree)(name, transformParamss(paramss), transform(tpt), transform(tree.rhs)) case tree @ TypeDef(name, rhs) => - inContext(localCtx(tree)) { - cpy.TypeDef(tree)(name, transform(rhs)) - } + cpy.TypeDef(tree)(name, transform(rhs)) case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty => cpy.Template(tree)(transformSub(constr), transform(tree.parents), Nil, transformSub(self), transformStats(tree.body, tree.symbol)) case Import(expr, selectors) => @@ -1478,10 +1475,7 @@ object Trees { case Export(expr, selectors) => cpy.Export(tree)(transform(expr), selectors) case PackageDef(pid, stats) => - val pid1 = transformSub(pid) - inContext(localCtx(tree)) { - cpy.PackageDef(tree)(pid1, transformStats(stats, ctx.owner)) - } + cpy.PackageDef(tree)(transformSub(pid), transformStats(stats, ctx.owner)) case Annotated(arg, annot) => cpy.Annotated(tree)(transform(arg), transform(annot)) case Thicket(trees) => diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index cf18f09b044c..3a88ba6af382 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -140,20 +140,21 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: case tree: CaseDef => instrumentCaseDef(tree) case tree: ValDef => - // only transform the rhs, in the local context - val rhs = transform(tree.rhs)(using localCtx(tree)) + // only transform the rhs + val rhs = transform(tree.rhs) cpy.ValDef(tree)(rhs=rhs) case tree: DefDef => // only transform the params (for the default values) and the rhs - val defCtx = localCtx(tree) - val paramss = transformParamss(tree.paramss)(using defCtx) - val rhs = transform(tree.rhs)(using defCtx) + // force instrumentation of literals and other small trees in the rhs, + // to ensure that the method call are recorded + val paramss = transformParamss(tree.paramss) + val rhs = transform(tree.rhs) cpy.DefDef(tree)(tree.name, paramss, tree.tpt, rhs) case tree: PackageDef => // only transform the statements of the package - cpy.PackageDef(tree)(tree.pid, transform(tree.stats)(using localCtx(tree))) + cpy.PackageDef(tree)(tree.pid, transform(tree.stats)) case tree: Assign => // only transform the rhs cpy.Assign(tree)(tree.lhs, transform(tree.rhs)) From 3f71cd767be2797de40c60714f744c8c1b918df2 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Wed, 30 Mar 2022 14:09:02 +0200 Subject: [PATCH 14/15] Ensure that cases and DefDefs are always instrumented for coverage --- .../src/dotty/tools/dotc/ast/Desugar.scala | 3 +- .../dotty/tools/dotc/ast/MainProxies.scala | 6 +- compiler/src/dotty/tools/dotc/ast/Trees.scala | 2 +- .../dotty/tools/dotc/coverage/Coverage.scala | 9 +- .../tools/dotc/coverage/Serializer.scala | 3 +- .../dotc/transform/InstrumentCoverage.scala | 177 ++++++++---- docs/_docs/usage/coverage.md | 3 +- .../coverage/pos/Constructor.scoverage.check | 56 +++- .../pos/ContextFunctions.scoverage.check | 67 +++-- tests/coverage/pos/Enum.scoverage.check | 270 ++++++------------ tests/coverage/pos/Givens.scoverage.check | 84 +++++- tests/coverage/pos/Inlined.scoverage.check | 60 ++-- tests/coverage/pos/Literals.scala | 9 +- tests/coverage/pos/Literals.scoverage.check | 83 +++--- .../pos/MatchCaseClasses.scoverage.check | 129 ++++++++- .../coverage/pos/MatchNumbers.scoverage.check | 63 +++- tests/coverage/pos/Select.scoverage.check | 82 +++++- tests/coverage/pos/SimpleMethods.scala | 23 ++ .../pos/SimpleMethods.scoverage.check | 241 ++++++++++++++++ .../pos/StructuralTypes.scoverage.check | 73 ++--- .../coverage/pos/TypeLambdas.scoverage.check | 47 +-- .../run/currying/test.scoverage.check | 115 +++++++- .../run/inheritance/test.scoverage.check | 36 ++- .../run/interpolation/test.scoverage.check | 138 +++------ .../coverage/run/lifting/test.scoverage.check | 136 +++++---- tests/coverage/run/trait/test.scoverage.check | 48 +++- 26 files changed, 1295 insertions(+), 668 deletions(-) create mode 100644 tests/coverage/pos/SimpleMethods.scala create mode 100644 tests/coverage/pos/SimpleMethods.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 0cb2ed4d7acc..117c5217f15e 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1437,6 +1437,7 @@ object desugar { ValDef(param.name, param.tpt, selector(idx)) .withSpan(param.span) .withAttachment(UntupledParam, ()) + .withFlags(Synthetic) } Function(param :: Nil, Block(vdefs, body)) } @@ -1693,7 +1694,7 @@ object desugar { case (p, n) => makeSyntheticParameter(n + 1, p).withAddedFlags(mods.flags) } RefinedTypeTree(polyFunctionTpt, List( - DefDef(nme.apply, applyTParams :: applyVParams :: Nil, res, EmptyTree) + DefDef(nme.apply, applyTParams :: applyVParams :: Nil, res, EmptyTree).withFlags(Synthetic) )) } else { diff --git a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala index ea41984c5766..183854f3aede 100644 --- a/compiler/src/dotty/tools/dotc/ast/MainProxies.scala +++ b/compiler/src/dotty/tools/dotc/ast/MainProxies.scala @@ -105,12 +105,14 @@ object MainProxies { .filterNot(_.matches(defn.MainAnnot)) .map(annot => insertTypeSplices.transform(annot.tree)) val mainMeth = DefDef(nme.main, (mainArg :: Nil) :: Nil, TypeTree(defn.UnitType), body) - .withFlags(JavaStatic) + .withFlags(JavaStatic | Synthetic) .withAnnotations(annots) val mainTempl = Template(emptyConstructor, Nil, Nil, EmptyValDef, mainMeth :: Nil) val mainCls = TypeDef(mainFun.name.toTypeName, mainTempl) .withFlags(Final | Invisible) - if (!ctx.reporter.hasErrors) result = mainCls.withSpan(mainAnnotSpan.toSynthetic) :: Nil + + if (!ctx.reporter.hasErrors) + result = mainCls.withSpan(mainAnnotSpan.toSynthetic) :: Nil } result } diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 5afbb7f416ed..c3e826578906 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -610,7 +610,7 @@ object Trees { override def toString = s"InlineMatch($selector, $cases)" } - /** case pat if guard => body; only appears as child of a Match */ + /** case pat if guard => body */ case class CaseDef[-T >: Untyped] private[ast] (pat: Tree[T], guard: Tree[T], body: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] { type ThisTree[-T >: Untyped] = CaseDef[T] diff --git a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala index 6140c937171e..8ae249c1f5a3 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Coverage.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Coverage.scala @@ -23,12 +23,5 @@ case class Statement( symbolName: String, treeName: String, branch: Boolean, - var count: Int = 0, ignored: Boolean = false -): - /** Records that this statement has been invoked one more time. */ - def invoked(): Unit = - count += 1 - - def isInvoked: Boolean = - count > 0 +) \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala index c4f633dcdfa2..4bd0d89a0b84 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala @@ -58,6 +58,7 @@ object Serializer: |""".stripMargin) def writeStatement(stmt: Statement, writer: Writer): Unit = + // Note: we write 0 for the count because we have not measured the actual coverage at this point writer.write(s"""${stmt.id} |${getRelativePath(stmt.location.sourcePath)} |${stmt.location.packageName} @@ -71,7 +72,7 @@ object Serializer: |${stmt.symbolName} |${stmt.treeName} |${stmt.branch} - |${stmt.count} + |0 |${stmt.ignored} |${stmt.desc} |\f diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 3a88ba6af382..442bf27d9f6b 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -60,27 +60,13 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: /** Transforms trees to insert calls to Invoker.invoked to compute the coverage when the code is called */ private class CoverageTransformer extends Transformer: - private val IgnoreLiterals = new Property.Key[Boolean] - - private def ignoreLiteralsContext(using ctx: Context): Context = - ctx.fresh.setProperty(IgnoreLiterals, true) - override def transform(tree: Tree)(using ctx: Context): Tree = inContext(transformCtx(tree)) { // necessary to position inlined code properly tree match // simple cases - case tree: (Import | Export | This | Super | New) => tree + case tree: (Import | Export | Literal | This | Super | New) => tree case tree if tree.isEmpty || tree.isType => tree // empty Thicket, Ident, TypTree, ... - // Literals must be instrumented (at least) when returned by a def, - // otherwise `def d = "literal"` is not covered when called from a test. - // They can be left untouched when passed in a parameter of an Apply. - case tree: Literal => - if ctx.property(IgnoreLiterals).contains(true) then - tree - else - instrument(tree) - // branches case tree: If => cpy.If(tree)( @@ -92,32 +78,32 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: cpy.Try(tree)( expr = instrument(transform(tree.expr), branch = true), cases = instrumentCases(tree.cases), - finalizer = instrument(transform(tree.finalizer), true) + finalizer = instrument(transform(tree.finalizer), branch = true) ) // a.f(args) case tree @ Apply(fun: Select, args) => // don't transform the first Select, but do transform `a.b` in `a.b.f(args)` + val transformedFun = cpy.Select(fun)(transform(fun.qualifier), fun.name) if canInstrumentApply(tree) then - val transformedFun = cpy.Select(fun)(transform(fun.qualifier), fun.name) if needsLift(tree) then val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted - instrumentLifted(transformed)(using ignoreLiteralsContext) + instrumentLifted(transformed) else - val transformed = cpy.Apply(tree)(transformedFun, transform(args)(using ignoreLiteralsContext)) - instrument(transformed)(using ignoreLiteralsContext) + val transformed = transformApply(tree, transformedFun) + instrument(transformed) else - tree + transformApply(tree, transformedFun) // f(args) case tree: Apply => if canInstrumentApply(tree) then if needsLift(tree) then - instrumentLifted(tree)(using ignoreLiteralsContext) // see comment about Literals + instrumentLifted(tree) else - instrument(super.transform(tree)(using ignoreLiteralsContext)) + instrument(transformApply(tree)) else - tree + transformApply(tree) // (f(x))[args] case TypeApply(fun: Apply, args) => @@ -142,15 +128,19 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: case tree: ValDef => // only transform the rhs val rhs = transform(tree.rhs) - cpy.ValDef(tree)(rhs=rhs) + cpy.ValDef(tree)(rhs = rhs) case tree: DefDef => - // only transform the params (for the default values) and the rhs - // force instrumentation of literals and other small trees in the rhs, - // to ensure that the method call are recorded + // Only transform the params (for the default values) and the rhs. val paramss = transformParamss(tree.paramss) val rhs = transform(tree.rhs) - cpy.DefDef(tree)(tree.name, paramss, tree.tpt, rhs) + val finalRhs = + if canInstrumentDefDef(tree) then + // Ensure that the rhs is always instrumented, if possible + instrumentBody(tree, rhs) + else + rhs + cpy.DefDef(tree)(tree.name, paramss, tree.tpt, finalRhs) case tree: PackageDef => // only transform the statements of the package @@ -168,7 +158,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: /** Lifts and instruments an application. * Note that if only one arg needs to be lifted, we just lift everything. */ - def instrumentLifted(tree: Apply)(using Context) = + private def instrumentLifted(tree: Apply)(using Context) = // lifting val buffer = mutable.ListBuffer[Tree]() val liftedApply = LiftCoverage.liftForCoverage(buffer, tree) @@ -179,40 +169,93 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: Block( instrumentedArgs, instrumentedApply - ).withSpan(instrumentedApply.span) + ) - def instrumentCases(cases: List[CaseDef])(using Context): List[CaseDef] = - cases.map(instrumentCaseDef) + private inline def transformApply(tree: Apply)(using Context): Apply = + transformApply(tree, transform(tree.fun)) - def instrumentCaseDef(tree: CaseDef)(using Context): CaseDef = - cpy.CaseDef(tree)(tree.pat, transform(tree.guard), transform(tree.body)) + private inline def transformApply(tree: Apply, transformedFun: Tree)(using Context): Apply = + cpy.Apply(tree)(transformedFun, transform(tree.args)) - def instrument(tree: Tree, branch: Boolean = false)(using Context): Tree = + private inline def instrumentCases(cases: List[CaseDef])(using Context): List[CaseDef] = + cases.map(instrumentCaseDef) + + private def instrumentCaseDef(tree: CaseDef)(using Context): CaseDef = + val pat = tree.pat + val guard = tree.guard + val friendlyEnd = if guard.span.exists then guard.span.end else pat.span.end + val pos = tree.sourcePos.withSpan(tree.span.withEnd(friendlyEnd)) // user-friendly span + // ensure that the body is always instrumented by inserting a call to Invoker.invoked at its beginning + val instrumentedBody = instrument(transform(tree.body), pos, false) + cpy.CaseDef(tree)(tree.pat, transform(tree.guard), instrumentedBody) + + /** Records information about a new coverable statement. Generates a unique id for it. + * @return the statement's id + */ + private def recordStatement(tree: Tree, pos: SourcePosition, branch: Boolean)(using ctx: Context): Int = + val id = statementId + statementId += 1 + val statement = new Statement( + source = ctx.source.file.name, + location = Location(tree), + id = id, + start = pos.start, + end = pos.end, + line = pos.line, + desc = tree.source.content.slice(pos.start, pos.end).mkString, + symbolName = tree.symbol.name.toSimpleName.toString, + treeName = tree.getClass.getSimpleName.nn, + branch + ) + coverage.addStatement(statement) + id + + private inline def syntheticSpan(pos: SourcePosition): Span = pos.span.toSynthetic + + /** Shortcut for instrument(tree, tree.sourcePos, branch) */ + private inline def instrument(tree: Tree, branch: Boolean = false)(using Context): Tree = instrument(tree, tree.sourcePos, branch) - def instrument(tree: Tree, pos: SourcePosition, branch: Boolean)(using ctx: Context): Tree = + /** Instruments a statement, if it has a position. */ + private def instrument(tree: Tree, pos: SourcePosition, branch: Boolean)(using Context): Tree = if pos.exists && !pos.span.isZeroExtent then - statementId += 1 - val id = statementId - val statement = new Statement( - source = ctx.source.file.name, - location = Location(tree), - id = id, - start = pos.start, - end = pos.end, - line = pos.line, - desc = tree.source.content.slice(pos.start, pos.end).mkString, - symbolName = tree.symbol.name.toSimpleName.toString(), - treeName = tree.getClass.getSimpleName.nn, - branch - ) - coverage.addStatement(statement) - val span = Span(pos.start, pos.end) // synthetic span - Block(List(invokeCall(id, span)), tree).withSpan(span) + val statementId = recordStatement(tree, pos, branch) + insertInvokeCall(tree, pos, statementId) else tree - def invokeCall(id: Int, span: Span)(using Context): Tree = + /** Instruments the body of a DefDef. Handles corner cases. */ + private def instrumentBody(parent: DefDef, body: Tree)(using Context): Tree = + /* recurse on closures, so that we insert the call at the leaf: + + def g: (a: Ta) ?=> (b: Tb) = { + // nothing here <-- not here! + def $anonfun(using a: Ta) = + Invoked.invoked(id, DIR) <-- here + + closure($anonfun) + } + */ + body match + case b @ Block((meth: DefDef) :: Nil, closure: Closure) + if meth.symbol == closure.meth.symbol && defn.isContextFunctionType(body.tpe) => + val instr = cpy.DefDef(meth)(rhs = instrumentBody(parent, meth.rhs)) + cpy.Block(b)(instr :: Nil, closure) + case _ => + // compute user-friendly position to highlight more text in the coverage UI + val namePos = parent.namePos + val pos = namePos.withSpan(namePos.span.withStart(parent.span.start)) + // record info and insert call to Invoker.invoked + val statementId = recordStatement(parent, pos, false) + insertInvokeCall(body, pos, statementId) + + /** Returns the tree, prepended by a call to Invoker.invoker */ + private def insertInvokeCall(tree: Tree, pos: SourcePosition, statementId: Int)(using Context): Tree = + val callSpan = syntheticSpan(pos) + Block(invokeCall(statementId, callSpan) :: Nil, tree).withSpan(callSpan.union(tree.span)) + + /** Generates Invoked.invoked(id, DIR) */ + private def invokeCall(id: Int, span: Span)(using Context): Tree = val outputPath = ctx.settings.coverageOutputDir.value ref(defn.InvokedMethodRef).withSpan(span) .appliedToArgs( @@ -229,7 +272,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: * ``` * should not be changed to {val $x = f(); T($x)}(1) but to {val $x = f(); val $y = 1; T($x)($y)} */ - def needsLift(tree: Apply)(using Context): Boolean = + private def needsLift(tree: Apply)(using Context): Boolean = def isBooleanOperator(fun: Tree) = // We don't want to lift a || getB(), to avoid calling getB if a is true. // Same idea with a && getB(): if a is false, getB shouldn't be called. @@ -249,9 +292,17 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: nestedApplyNeedsLift || !isBooleanOperator(fun) && !tree.args.isEmpty && !tree.args.forall(LiftCoverage.noLift) - def canInstrumentApply(tree: Apply)(using Context): Boolean = - val tpe = tree.typeOpt - tpe match + /** Check if the body of a DefDef can be instrumented with instrumentBody. */ + private def canInstrumentDefDef(tree: DefDef)(using Context): Boolean = + // No need to force the instrumentation of synthetic definitions + // (it would work, but it looks better without). + !tree.symbol.isOneOf(Accessor | Synthetic | Artifact) && + !tree.rhs.isEmpty + + /** Check if an Apply can be instrumented. Prevents this phase from generating incorrect code. */ + private def canInstrumentApply(tree: Apply)(using Context): Boolean = + !tree.symbol.isOneOf(Synthetic | Artifact) && // no need to instrument synthetic apply + (tree.typeOpt match case AppliedType(tycon: NamedType, _) => /* If the last expression in a block is a context function, we'll try to summon its arguments at the current point, even if the expected type @@ -267,11 +318,15 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: */ !tycon.name.isContextFunction case m: MethodType => - // def f(a: Ta)(b: Tb) - // f(a)(b) cannot be rewritten to {invoked();f(a)}(b) + /* def f(a: Ta)(b: Tb) + f(a)(b) + + Here, f(a)(b) cannot be rewritten to {invoked();f(a)}(b) + */ false case _ => true + ) object InstrumentCoverage: val name: String = "instrumentCoverage" diff --git a/docs/_docs/usage/coverage.md b/docs/_docs/usage/coverage.md index 838865fcd014..2e24b08ea29e 100644 --- a/docs/_docs/usage/coverage.md +++ b/docs/_docs/usage/coverage.md @@ -15,7 +15,8 @@ In Scala 2, all these steps were performed by external tools. In particular, ste In Scala 3, the compiler itself takes care of step 1. To use this feature, add the compile option `-coverage-out:DIR`, where `DIR` is the destination of the measurement files. -You can also set `-coverage-sourceroot:PATHS_ROOT` to customize how the path of your source files are resolved. +You can also set `-sourceroot:PATHS_ROOT` to customize how the path of your source files are resolved. +Note that `-sourceroot` also sets the root path of the SemanticDB files. ## How-to with sbt diff --git a/tests/coverage/pos/Constructor.scoverage.check b/tests/coverage/pos/Constructor.scoverage.check index 91a3331b002f..b6223734b1a8 100644 --- a/tests/coverage/pos/Constructor.scoverage.check +++ b/tests/coverage/pos/Constructor.scoverage.check @@ -18,6 +18,23 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ +0 +Constructor.scala +covtest +C +Class +covtest.C +f +28 +33 +3 +f +DefDef +false +0 +false +def f + 1 Constructor.scala covtest @@ -25,15 +42,15 @@ C Class covtest.C x -56 -57 +48 +53 4 - -Literal +x +DefDef false 0 false -1 +def x 2 Constructor.scala @@ -58,18 +75,35 @@ covtest O$ Object covtest.O$ +g +78 +83 +8 +g +DefDef +false +0 +false +def g + +4 +Constructor.scala +covtest +O$ +Object +covtest.O$ y -106 -107 +98 +103 9 - -Literal +y +DefDef false 0 false -1 +def y -4 +5 Constructor.scala covtest O$ diff --git a/tests/coverage/pos/ContextFunctions.scoverage.check b/tests/coverage/pos/ContextFunctions.scoverage.check index df4ae8c780f1..74a76df8bbf4 100644 --- a/tests/coverage/pos/ContextFunctions.scoverage.check +++ b/tests/coverage/pos/ContextFunctions.scoverage.check @@ -18,41 +18,41 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 ContextFunctions.scala covtest -Imperative +OnError Class -covtest.Imperative -$anonfun -178 -184 -8 - -Literal +covtest.OnError +onError +56 +67 +3 +onError +DefDef false 0 false -"name" +def onError -2 +1 ContextFunctions.scala covtest Imperative Class covtest.Imperative -readPerson -243 -247 -12 - -Literal +readName2 +121 +134 +7 +readName2 +DefDef false 0 false -null +def readName2 -3 +2 ContextFunctions.scala covtest Imperative @@ -69,7 +69,7 @@ false false readName2(using e)(using s) -4 +3 ContextFunctions.scala covtest Imperative @@ -86,7 +86,7 @@ false false OnError((e) => readName2(using e)(using s)) -5 +4 ContextFunctions.scala covtest Imperative @@ -103,7 +103,7 @@ false false readName2(using e)(using s) -6 +5 ContextFunctions.scala covtest Imperative @@ -120,7 +120,7 @@ false false readName2(using e)(using s) -7 +6 ContextFunctions.scala covtest Imperative @@ -137,7 +137,7 @@ false false OnError((e) => readName2(using e)(using s)) -8 +7 ContextFunctions.scala covtest Imperative @@ -154,7 +154,7 @@ false false OnError((e) => readName2(using e)(using s)) -9 +8 ContextFunctions.scala covtest Imperative @@ -171,3 +171,20 @@ false false OnError((e) => readName2(using e)(using s)).onError(None) +9 +ContextFunctions.scala +covtest +Imperative +Class +covtest.Imperative +readPerson +192 +206 +11 +readPerson +DefDef +false +0 +false +def readPerson + diff --git a/tests/coverage/pos/Enum.scoverage.check b/tests/coverage/pos/Enum.scoverage.check index 1e41a1732a6b..d76c749275e7 100644 --- a/tests/coverage/pos/Enum.scoverage.check +++ b/tests/coverage/pos/Enum.scoverage.check @@ -18,24 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 -Enum.scala -covtest -Planet -Class -covtest.Planet - -322 -333 -13 - -Literal -false 0 -false -6.67300E-11 - -2 Enum.scala covtest Planet @@ -52,7 +35,7 @@ false false G * mass -3 +1 Enum.scala covtest Planet @@ -69,7 +52,7 @@ false false G * mass -4 +2 Enum.scala covtest Planet @@ -86,7 +69,7 @@ false false G * mass -5 +3 Enum.scala covtest Planet @@ -103,7 +86,7 @@ false false radius * radius -6 +4 Enum.scala covtest Planet @@ -120,7 +103,24 @@ false false G * mass / (radius * radius -7 +5 +Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceGravity +338 +356 +14 +surfaceGravity +DefDef +false +0 +false +def surfaceGravity + +6 Enum.scala covtest Planet @@ -137,6 +137,23 @@ false false otherMass * surfaceGravity +7 +Enum.scala +covtest +Planet +Class +covtest.Planet +surfaceWeight +392 +409 +15 +surfaceWeight +DefDef +false +0 +false +def surfaceWeight + 8 Enum.scala covtest @@ -280,57 +297,6 @@ EnumTypes$ Object covtest.EnumTypes$ test -1004 -1036 -29 -apply -Apply -false -0 -false -ListEnum.Cons(3, ListEnum.Empty) - -17 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -test -987 -1037 -29 -apply -Apply -false -0 -false -ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty)) - -18 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -test -970 -1038 -29 -apply -Apply -false -0 -false -ListEnum.Cons(1, ListEnum.Cons(2, ListEnum.Cons(3, ListEnum.Empty))) - -19 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -test 1051 1076 30 @@ -341,7 +307,7 @@ false false "Example 1: \n"+emptyList -20 +17 Enum.scala covtest EnumTypes$ @@ -358,58 +324,7 @@ false false println("Example 1: \n"+emptyList) -21 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -test -1092 -1101 -31 -apply -Apply -false -0 -false -${list}\n - -22 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -test -1092 -1101 -31 -invoked -Apply -false -0 -false -${list}\n - -23 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -test -1092 -1101 -31 -apply -Apply -false -0 -false -${list}\n - -24 +18 Enum.scala covtest EnumTypes$ @@ -426,7 +341,7 @@ false false s"${list}\n" -25 +19 Enum.scala covtest EnumTypes$ @@ -443,7 +358,7 @@ false false println(s"${list}\n") -26 +20 Enum.scala covtest EnumTypes$ @@ -460,7 +375,7 @@ false false earthWeight/Planet.Earth.surfaceGravity -27 +21 Enum.scala covtest EnumTypes$ @@ -477,58 +392,7 @@ false false Planet.values -28 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -$anonfun -1273 -1318 -36 -apply -Apply -false -0 -false -Your weight on $p is ${p.surfaceWeight(mass)} - -29 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -$anonfun -1273 -1318 -36 -invoked -Apply -false -0 -false -Your weight on $p is ${p.surfaceWeight(mass)} - -30 -Enum.scala -covtest -EnumTypes$ -Object -covtest.EnumTypes$ -$anonfun -1273 -1318 -36 -apply -Apply -false -0 -false -Your weight on $p is ${p.surfaceWeight(mass)} - -31 +22 Enum.scala covtest EnumTypes$ @@ -545,7 +409,7 @@ false false p.surfaceWeight(mass) -32 +23 Enum.scala covtest EnumTypes$ @@ -562,7 +426,7 @@ false false s"Your weight on $p is ${p.surfaceWeight(mass)}" -33 +24 Enum.scala covtest EnumTypes$ @@ -579,7 +443,7 @@ false false println(s"Your weight on $p is ${p.surfaceWeight(mass)}") -34 +25 Enum.scala covtest EnumTypes$ @@ -597,7 +461,24 @@ false for p <- Planet.values do println(s"Your weight on $p is ${p.surfaceWeight(mass)}") -35 +26 +Enum.scala +covtest +EnumTypes$ +Object +covtest.EnumTypes$ +calculateEarthWeightOnPlanets +1109 +1142 +33 +calculateEarthWeightOnPlanets +DefDef +false +0 +false +def calculateEarthWeightOnPlanets + +27 Enum.scala covtest EnumTypes$ @@ -614,7 +495,7 @@ false false println("Example 2:") -36 +28 Enum.scala covtest EnumTypes$ @@ -631,3 +512,20 @@ false false calculateEarthWeightOnPlanets(80) +29 +Enum.scala +covtest +EnumTypes$ +Object +covtest.EnumTypes$ +test +901 +909 +27 +test +DefDef +false +0 +false +def test + diff --git a/tests/coverage/pos/Givens.scoverage.check b/tests/coverage/pos/Givens.scoverage.check index 9cae23846460..389713521448 100644 --- a/tests/coverage/pos/Givens.scoverage.check +++ b/tests/coverage/pos/Givens.scoverage.check @@ -18,7 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 Givens.scala covtest Givens @@ -35,7 +35,7 @@ false false 3 == "3" -2 +1 Givens.scala covtest Givens @@ -52,7 +52,7 @@ false false println(3 == "3") -3 +2 Givens.scala covtest Givens @@ -69,7 +69,7 @@ false false 3 == 5.1 -4 +3 Givens.scala covtest Givens @@ -86,6 +86,23 @@ false false println(3 == 5.1) +4 +Givens.scala +covtest +Givens +Class +covtest.Givens +test +100 +108 +8 +test +DefDef +false +0 +false +def test + 5 Givens.scala covtest @@ -126,6 +143,23 @@ covtest Givens Class covtest.Givens +printContext +217 +233 +13 +printContext +DefDef +false +0 +false +def printContext + +8 +Givens.scala +covtest +Givens +Class +covtest.Givens getMessage 348 358 @@ -137,7 +171,24 @@ false false i.toString -8 +9 +Givens.scala +covtest +Givens +Class +covtest.Givens +getMessage +315 +329 +17 +getMessage +DefDef +false +0 +false +def getMessage + +10 Givens.scala covtest Givens @@ -154,7 +205,7 @@ false false Context(0) -9 +11 Givens.scala covtest Givens @@ -171,7 +222,7 @@ false false printContext("test")(using c) -10 +12 Givens.scala covtest Givens @@ -188,7 +239,7 @@ false false getMessage(123) -11 +13 Givens.scala covtest Givens @@ -205,3 +256,20 @@ false false printContext(getMessage(123)) +14 +Givens.scala +covtest +Givens +Class +covtest.Givens +test2 +362 +371 +19 +test2 +DefDef +false +0 +false +def test2 + diff --git a/tests/coverage/pos/Inlined.scoverage.check b/tests/coverage/pos/Inlined.scoverage.check index 016e3ef56ad5..f3cb3b5d9026 100644 --- a/tests/coverage/pos/Inlined.scoverage.check +++ b/tests/coverage/pos/Inlined.scoverage.check @@ -18,24 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 -Inlined.scala -covtest -Inlined$package$ -Object -covtest.Inlined$package$ -testInlined -122 -123 -4 - -Literal -false 0 -false -1 - -2 Inlined.scala covtest Inlined$package$ @@ -52,7 +35,7 @@ false false l == 1 -3 +1 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -69,7 +52,7 @@ false false scala.runtime.Scala3RunTime -4 +2 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -86,7 +69,7 @@ false false scala.runtime.Scala3RunTime.assertFailed() -5 +3 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -103,7 +86,7 @@ true false scala.runtime.Scala3RunTime.assertFailed() -6 +4 Inlined.scala covtest Inlined$package$ @@ -120,7 +103,7 @@ false false List(l) -7 +5 Inlined.scala covtest Inlined$package$ @@ -137,7 +120,7 @@ false false l == List(l).length -8 +6 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -154,7 +137,7 @@ false false scala.runtime.Scala3RunTime -9 +7 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -171,7 +154,7 @@ false false scala.runtime.Scala3RunTime.assertFailed() -10 +8 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -188,7 +171,7 @@ true false scala.runtime.Scala3RunTime.assertFailed() -11 +9 Inlined.scala covtest Inlined$package$ @@ -205,7 +188,7 @@ false false List(l) -12 +10 Inlined.scala covtest Inlined$package$ @@ -222,7 +205,7 @@ false false List(l).length == 1 -13 +11 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -239,7 +222,7 @@ false false scala.runtime.Scala3RunTime -14 +12 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -256,7 +239,7 @@ false false scala.runtime.Scala3RunTime.assertFailed() -15 +13 ../../../library/src/scala/runtime/stdLibPatches/Predef.scala covtest Inlined$package$ @@ -273,3 +256,20 @@ true false scala.runtime.Scala3RunTime.assertFailed() +14 +Inlined.scala +covtest +Inlined$package$ +Object +covtest.Inlined$package$ +testInlined +86 +101 +3 +testInlined +DefDef +false +0 +false +def testInlined + diff --git a/tests/coverage/pos/Literals.scala b/tests/coverage/pos/Literals.scala index 62297793bb70..4b61238b2015 100644 --- a/tests/coverage/pos/Literals.scala +++ b/tests/coverage/pos/Literals.scala @@ -1,9 +1,10 @@ +package covtest -def mustBeInstrumented = "literal" - -def thisOneToo = +def block = println("not this") // this literal should not be instrumented, only the println call - 12 // this literal must be instrumented + 12 + true + null def f(x: Int, y: Int, z: Int)(t: Int) = ??? diff --git a/tests/coverage/pos/Literals.scoverage.check b/tests/coverage/pos/Literals.scoverage.check index 25bd06e3e4ac..bda71a49f3b1 100644 --- a/tests/coverage/pos/Literals.scoverage.check +++ b/tests/coverage/pos/Literals.scoverage.check @@ -18,71 +18,88 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ +0 +Literals.scala +covtest +Literals$package$ +Object +covtest.Literals$package$ +block +31 +50 +3 +println +Apply +false +0 +false +println("not this") + 1 Literals.scala - +covtest Literals$package$ Object -.Literals$package$ -mustBeInstrumented +covtest.Literals$package$ +block +17 26 -35 -1 - -Literal +2 +block +DefDef false 0 false -"literal" +def block 2 Literals.scala - +covtest Literals$package$ Object -.Literals$package$ -thisOneToo -56 -75 -4 -println -Apply +covtest.Literals$package$ +f +137 +142 +8 +f +DefDef false 0 false -println("not this") +def f 3 Literals.scala - +covtest Literals$package$ Object -.Literals$package$ -thisOneToo -144 -146 -5 - -Literal +covtest.Literals$package$ +main +201 +212 +11 +f +Apply false 0 false -12 +f(0,1,2)(3) 4 Literals.scala - +covtest Literals$package$ Object -.Literals$package$ +covtest.Literals$package$ main -249 -260 +182 +190 10 -f -Apply +main +DefDef false 0 false -f(0,1,2)(3) +def main diff --git a/tests/coverage/pos/MatchCaseClasses.scoverage.check b/tests/coverage/pos/MatchCaseClasses.scoverage.check index 51a7e2f6ec42..0e469fc86b7c 100644 --- a/tests/coverage/pos/MatchCaseClasses.scoverage.check +++ b/tests/coverage/pos/MatchCaseClasses.scoverage.check @@ -18,7 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 MatchCaseClasses.scala covtest MatchCaseClasses$ @@ -35,6 +35,23 @@ false false println("a") +1 +MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Object +covtest.MatchCaseClasses$ +f +135 +147 +7 + +Block +false +0 +false +case Pat1(0) + 2 MatchCaseClasses.scala covtest @@ -59,6 +76,23 @@ MatchCaseClasses$ Object covtest.MatchCaseClasses$ f +168 +180 +8 + +Block +false +0 +false +case Pat1(_) + +4 +MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Object +covtest.MatchCaseClasses$ +f 225 237 9 @@ -69,7 +103,24 @@ false false println("c") -4 +5 +MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Object +covtest.MatchCaseClasses$ +f +201 +221 +9 + +Block +false +0 +false +case p @ Pat2(1, -1) + +6 MatchCaseClasses.scala covtest MatchCaseClasses$ @@ -86,7 +137,7 @@ false false println(y) -5 +7 MatchCaseClasses.scala covtest MatchCaseClasses$ @@ -103,7 +154,24 @@ false false println("d") -6 +8 +MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Object +covtest.MatchCaseClasses$ +f +242 +265 +10 + +Block +false +0 +false +case Pat2(_, y: String) + +9 MatchCaseClasses.scala covtest MatchCaseClasses$ @@ -120,7 +188,24 @@ false false println("e") -7 +10 +MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Object +covtest.MatchCaseClasses$ +f +309 +321 +13 + +Block +false +0 +false +case p: Pat2 + +11 MatchCaseClasses.scala covtest MatchCaseClasses$ @@ -137,3 +222,37 @@ false false println("other") +12 +MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Object +covtest.MatchCaseClasses$ +f +342 +348 +14 + +Block +false +0 +false +case _ + +13 +MatchCaseClasses.scala +covtest +MatchCaseClasses$ +Object +covtest.MatchCaseClasses$ +f +101 +106 +6 +f +DefDef +false +0 +false +def f + diff --git a/tests/coverage/pos/MatchNumbers.scoverage.check b/tests/coverage/pos/MatchNumbers.scoverage.check index c7fa7c83f015..f16c11031784 100644 --- a/tests/coverage/pos/MatchNumbers.scoverage.check +++ b/tests/coverage/pos/MatchNumbers.scoverage.check @@ -18,6 +18,23 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ +0 +MatchNumbers.scala +covtest +MatchNumbers$ +Object +covtest.MatchNumbers$ +f +106 +126 +6 + +Block +false +0 +false +case x: Int if x < 0 + 1 MatchNumbers.scala covtest @@ -42,15 +59,15 @@ MatchNumbers$ Object covtest.MatchNumbers$ f -130 -132 -6 +137 +148 +7 -Literal +Block false 0 false --1 +case x: Int 3 MatchNumbers.scala @@ -58,6 +75,40 @@ covtest MatchNumbers$ Object covtest.MatchNumbers$ +f +158 +170 +8 + +Block +false +0 +false +case y: Long + +4 +MatchNumbers.scala +covtest +MatchNumbers$ +Object +covtest.MatchNumbers$ +f +69 +74 +5 +f +DefDef +false +0 +false +def f + +5 +MatchNumbers.scala +covtest +MatchNumbers$ +Object +covtest.MatchNumbers$ 185 189 @@ -69,7 +120,7 @@ false false f(0) -4 +6 MatchNumbers.scala covtest MatchNumbers$ diff --git a/tests/coverage/pos/Select.scoverage.check b/tests/coverage/pos/Select.scoverage.check index 5419667a50ad..ef2831ee1013 100644 --- a/tests/coverage/pos/Select.scoverage.check +++ b/tests/coverage/pos/Select.scoverage.check @@ -18,7 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 Select.scala covtest A @@ -35,9 +35,43 @@ false false println("A") +1 +Select.scala +covtest +A +Class +covtest.A +print +68 +77 +6 +print +DefDef +false +0 +false +def print + 2 Select.scala covtest +A +Class +covtest.A +instance +97 +109 +7 +instance +DefDef +false +0 +false +def instance + +3 +Select.scala +covtest B Class covtest.B @@ -52,7 +86,7 @@ false false A -3 +4 Select.scala covtest B @@ -69,7 +103,7 @@ false false super.print() -4 +5 Select.scala covtest B @@ -86,7 +120,24 @@ false false println(this.instance) -5 +6 +Select.scala +covtest +B +Class +covtest.B +print +139 +157 +10 +print +DefDef +false +0 +false +override def print + +7 Select.scala covtest Select$package$ @@ -103,7 +154,7 @@ false false A() -6 +8 Select.scala covtest Select$package$ @@ -120,7 +171,7 @@ false false new A -7 +9 Select.scala covtest Select$package$ @@ -137,7 +188,7 @@ false false a.instance.print() -8 +10 Select.scala covtest Select$package$ @@ -154,3 +205,20 @@ false false a.print() +11 +Select.scala +covtest +Select$package$ +Object +covtest.Select$package$ +test +208 +216 +14 +test +DefDef +false +0 +false +def test + diff --git a/tests/coverage/pos/SimpleMethods.scala b/tests/coverage/pos/SimpleMethods.scala new file mode 100644 index 000000000000..510a86799b32 --- /dev/null +++ b/tests/coverage/pos/SimpleMethods.scala @@ -0,0 +1,23 @@ +package covtest + +class C: + def a: C = this + def b: Unit = return + def c: Unit = () + def d: Int = 12 + def e: Null = null + + def block: Int = + "literal" + 0 + + def cond: Boolean = + if false then true + else false + + def new1: C = new {} + + def tryCatch: Unit = + try () + catch + case e: Exception => 1 diff --git a/tests/coverage/pos/SimpleMethods.scoverage.check b/tests/coverage/pos/SimpleMethods.scoverage.check new file mode 100644 index 000000000000..f2d9d61a1cd4 --- /dev/null +++ b/tests/coverage/pos/SimpleMethods.scoverage.check @@ -0,0 +1,241 @@ +# 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 +SimpleMethods.scala +covtest +C +Class +covtest.C +a +28 +33 +3 +a +DefDef +false +0 +false +def a + +1 +SimpleMethods.scala +covtest +C +Class +covtest.C +b +46 +51 +4 +b +DefDef +false +0 +false +def b + +2 +SimpleMethods.scala +covtest +C +Class +covtest.C +c +69 +74 +5 +c +DefDef +false +0 +false +def c + +3 +SimpleMethods.scala +covtest +C +Class +covtest.C +d +88 +93 +6 +d +DefDef +false +0 +false +def d + +4 +SimpleMethods.scala +covtest +C +Class +covtest.C +e +106 +111 +7 +e +DefDef +false +0 +false +def e + +5 +SimpleMethods.scala +covtest +C +Class +covtest.C +block +128 +137 +9 +block +DefDef +false +0 +false +def block + +6 +SimpleMethods.scala +covtest +C +Class +covtest.C +cond +206 +210 +14 + +Literal +true +0 +false +true + +7 +SimpleMethods.scala +covtest +C +Class +covtest.C +cond +220 +225 +15 + +Literal +true +0 +false +false + +8 +SimpleMethods.scala +covtest +C +Class +covtest.C +cond +168 +176 +13 +cond +DefDef +false +0 +false +def cond + +9 +SimpleMethods.scala +covtest +C +Class +covtest.C +new1 +229 +237 +17 +new1 +DefDef +false +0 +false +def new1 + +10 +SimpleMethods.scala +covtest +C +Class +covtest.C +tryCatch +282 +284 +20 + +Literal +true +0 +false +() + +11 +SimpleMethods.scala +covtest +C +Class +covtest.C +tryCatch +301 +318 +22 + +Block +false +0 +false +case e: Exception + +12 +SimpleMethods.scala +covtest +C +Class +covtest.C +tryCatch +253 +265 +19 +tryCatch +DefDef +false +0 +false +def tryCatch + diff --git a/tests/coverage/pos/StructuralTypes.scoverage.check b/tests/coverage/pos/StructuralTypes.scoverage.check index 77616e0b1134..43ddfd7715b8 100644 --- a/tests/coverage/pos/StructuralTypes.scoverage.check +++ b/tests/coverage/pos/StructuralTypes.scoverage.check @@ -18,7 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 StructuralTypes.scala covtest Record @@ -35,7 +35,7 @@ false false _._1 == name -2 +1 StructuralTypes.scala covtest Record @@ -52,24 +52,24 @@ false false elems.find(_._1 == name) -3 +2 StructuralTypes.scala covtest -StructuralTypes$ -Object -covtest.StructuralTypes$ -test -277 -283 -12 -ArrowAssoc -Apply +Record +Class +covtest.Record +selectDynamic +109 +126 +5 +selectDynamic +DefDef false 0 false -"name" +def selectDynamic -4 +3 StructuralTypes.scala covtest StructuralTypes$ @@ -86,24 +86,7 @@ false false "name" -> "Emma" -5 -StructuralTypes.scala -covtest -StructuralTypes$ -Object -covtest.StructuralTypes$ -test -295 -300 -12 -ArrowAssoc -Apply -false -0 -false -"age" - -6 +4 StructuralTypes.scala covtest StructuralTypes$ @@ -120,37 +103,37 @@ false false "age" -> 42 -7 +5 StructuralTypes.scala covtest StructuralTypes$ Object covtest.StructuralTypes$ test -270 -307 -12 -apply +333 +344 +13 +selectDynamic Apply false 0 false -Record("name" -> "Emma", "age" -> 42) +person.name -8 +6 StructuralTypes.scala covtest StructuralTypes$ Object covtest.StructuralTypes$ test -333 -344 -13 -selectDynamic -Apply +234 +242 +11 +test +DefDef false 0 false -person.name +def test diff --git a/tests/coverage/pos/TypeLambdas.scoverage.check b/tests/coverage/pos/TypeLambdas.scoverage.check index 9485c5170872..f97d5285cf06 100644 --- a/tests/coverage/pos/TypeLambdas.scoverage.check +++ b/tests/coverage/pos/TypeLambdas.scoverage.check @@ -18,24 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 -TypeLambdas.scala -covtest -TypeLambdas$ -Object -covtest.TypeLambdas$ -test -310 -311 -13 -ArrowAssoc -Apply -false 0 -false -1 - -2 TypeLambdas.scala covtest TypeLambdas$ @@ -52,7 +35,7 @@ false false 1 -> "1" -3 +1 TypeLambdas.scala covtest TypeLambdas$ @@ -69,7 +52,7 @@ false false Map(1 -> "1") -4 +2 TypeLambdas.scala covtest TypeLambdas$ @@ -86,37 +69,37 @@ false false println(m) -5 +3 TypeLambdas.scala covtest TypeLambdas$ Object covtest.TypeLambdas$ test -367 -377 -16 -apply +382 +396 +17 +println Apply false 0 false -("a", "b") +println(tuple) -6 +4 TypeLambdas.scala covtest TypeLambdas$ Object covtest.TypeLambdas$ test -382 -396 -17 -println -Apply +259 +267 +12 +test +DefDef false 0 false -println(tuple) +def test diff --git a/tests/coverage/run/currying/test.scoverage.check b/tests/coverage/run/currying/test.scoverage.check index 89ea9c4008c1..688c75b42933 100644 --- a/tests/coverage/run/currying/test.scoverage.check +++ b/tests/coverage/run/currying/test.scoverage.check @@ -18,7 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 currying/test.scala Test$ @@ -35,7 +35,7 @@ false false a+b -2 +1 currying/test.scala Test$ @@ -52,6 +52,23 @@ false false a+b+c +2 +currying/test.scala + +Test$ +Object +.Test$ +f1 +15 +21 +1 +f1 +DefDef +false +0 +false +def f1 + 3 currying/test.scala @@ -92,6 +109,23 @@ currying/test.scala Test$ Object .Test$ +f2 +56 +62 +2 +f2 +DefDef +false +0 +false +def f2 + +6 +currying/test.scala + +Test$ +Object +.Test$ $anonfun 166 169 @@ -103,7 +137,7 @@ false false a+b -6 +7 currying/test.scala Test$ @@ -120,7 +154,24 @@ false false a+b+c -7 +8 +currying/test.scala + +Test$ +Object +.Test$ +g1 +114 +120 +5 +g1 +DefDef +false +0 +false +def g1 + +9 currying/test.scala Test$ @@ -137,7 +188,7 @@ false false a+b -8 +10 currying/test.scala Test$ @@ -154,7 +205,24 @@ false false a+b+c -9 +11 +currying/test.scala + +Test$ +Object +.Test$ +g2 +175 +181 +8 +g2 +DefDef +false +0 +false +def g2 + +12 currying/test.scala Test$ @@ -171,7 +239,7 @@ false false f1(0)(1)(2) -10 +13 currying/test.scala Test$ @@ -188,7 +256,7 @@ false false println(f1(0)(1)(2)) -11 +14 currying/test.scala Test$ @@ -205,7 +273,7 @@ false false f2(0) -12 +15 currying/test.scala Test$ @@ -222,7 +290,7 @@ false false f2(0)(1) -13 +16 currying/test.scala Test$ @@ -239,7 +307,7 @@ false false f2(0)(1)(2) -14 +17 currying/test.scala Test$ @@ -256,7 +324,7 @@ false false println(f2(0)(1)(2)) -15 +18 currying/test.scala Test$ @@ -273,7 +341,7 @@ false false g1(using 0)(using 1)(using 2) -16 +19 currying/test.scala Test$ @@ -290,7 +358,7 @@ false false println(g1(using 0)(using 1)(using 2)) -17 +20 currying/test.scala Test$ @@ -307,7 +375,7 @@ false false g2(using 0)(using 1)(using 2) -18 +21 currying/test.scala Test$ @@ -324,3 +392,20 @@ false false println(g2(using 0)(using 1)(using 2)) +22 +currying/test.scala + +Test$ +Object +.Test$ +main +235 +243 +10 +main +DefDef +false +0 +false +def main + diff --git a/tests/coverage/run/inheritance/test.scoverage.check b/tests/coverage/run/inheritance/test.scoverage.check index a714673ea3b5..5744f4b5eb3b 100644 --- a/tests/coverage/run/inheritance/test.scoverage.check +++ b/tests/coverage/run/inheritance/test.scoverage.check @@ -18,7 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 inheritance/test.scala B @@ -35,7 +35,7 @@ false false A(x, 0) -2 +1 inheritance/test.scala C1 @@ -52,7 +52,7 @@ false false println("block") -3 +2 inheritance/test.scala C1 @@ -69,7 +69,7 @@ false false B({println("block"); 1}) -4 +3 inheritance/test.scala C2 @@ -86,7 +86,7 @@ false false A(2,2) -5 +4 inheritance/test.scala C2 @@ -103,7 +103,7 @@ false false B(A(2,2).x) -6 +5 inheritance/test.scala test$package$ @@ -120,7 +120,7 @@ false false C1() -7 +6 inheritance/test.scala test$package$ @@ -137,7 +137,7 @@ false false println(C1().x) -8 +7 inheritance/test.scala test$package$ @@ -154,7 +154,7 @@ false false C2() -9 +8 inheritance/test.scala test$package$ @@ -171,3 +171,21 @@ false false println(C2().x) +9 +inheritance/test.scala + +test$package$ +Object +.test$package$ +Test +136 +150 +6 +Test +DefDef +false +0 +false +@main +def Test + diff --git a/tests/coverage/run/interpolation/test.scoverage.check b/tests/coverage/run/interpolation/test.scoverage.check index de100e7c116e..9c93d58f182c 100644 --- a/tests/coverage/run/interpolation/test.scoverage.check +++ b/tests/coverage/run/interpolation/test.scoverage.check @@ -18,58 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 -interpolation/test.scala - -Test$ -Object -.Test$ -simple -62 -77 -3 -apply -Apply -false 0 -false -$a, ${b.length} - -2 -interpolation/test.scala - -Test$ -Object -.Test$ -simple -62 -77 -3 -invoked -Apply -false -0 -false -$a, ${b.length} - -3 -interpolation/test.scala - -Test$ -Object -.Test$ -simple -62 -77 -3 -apply -Apply -false -0 -false -$a, ${b.length} - -4 interpolation/test.scala Test$ @@ -86,7 +35,7 @@ false false b.length -5 +1 interpolation/test.scala Test$ @@ -103,75 +52,41 @@ false false s"$a, ${b.length}" -6 -interpolation/test.scala - -Test$ -Object -.Test$ -main -147 -176 -6 -apply -Apply -false -0 -false -List("d", "o", "t", "t", "y") - -7 -interpolation/test.scala - -Test$ -Object -.Test$ -$anonfun -222 -228 -8 -apply -Apply -false -0 -false -$i: $s - -8 +2 interpolation/test.scala Test$ Object .Test$ -$anonfun -222 -228 -8 -invoked -Apply +simple +16 +26 +2 +simple +DefDef false 0 false -$i: $s +def simple -9 +3 interpolation/test.scala Test$ Object .Test$ -$anonfun -222 -228 -8 +main +147 +176 +6 apply Apply false 0 false -$i: $s +List("d", "o", "t", "t", "y") -10 +4 interpolation/test.scala Test$ @@ -188,7 +103,7 @@ false false s"$i: $s" -11 +5 interpolation/test.scala Test$ @@ -205,7 +120,7 @@ false false println(s"$i: $s") -12 +6 interpolation/test.scala Test$ @@ -222,3 +137,20 @@ false false xs.zipWithIndex.map((s, i) => println(s"$i: $s")) +7 +interpolation/test.scala + +Test$ +Object +.Test$ +main +82 +90 +5 +main +DefDef +false +0 +false +def main + diff --git a/tests/coverage/run/lifting/test.scoverage.check b/tests/coverage/run/lifting/test.scoverage.check index 701110a58615..7729e7515734 100644 --- a/tests/coverage/run/lifting/test.scoverage.check +++ b/tests/coverage/run/lifting/test.scoverage.check @@ -18,7 +18,7 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 lifting/test.scala Vals @@ -35,7 +35,7 @@ false false List(1) -2 +1 lifting/test.scala Vals @@ -52,7 +52,7 @@ false false List(1,2,3) -3 +2 lifting/test.scala Vals @@ -69,24 +69,7 @@ false false l :: List(1,2,3) -4 -lifting/test.scala - -A -Class -.A -msg -104 -112 -5 - -Literal -false -0 -false -"string" - -5 +3 lifting/test.scala A @@ -103,7 +86,7 @@ false false "string" + a -6 +4 lifting/test.scala A @@ -120,7 +103,7 @@ false false "string" + a + "." -7 +5 lifting/test.scala A @@ -137,7 +120,7 @@ false false "string" + a + "." + b -8 +6 lifting/test.scala A @@ -154,7 +137,7 @@ false false "string" + a + "." + b + "." -9 +7 lifting/test.scala A @@ -171,22 +154,56 @@ false false "string" + a + "." + b + "." + c -10 +8 +lifting/test.scala + +A +Class +.A +msg +70 +77 +5 +msg +DefDef +false +0 +false +def msg + +9 lifting/test.scala A Class .A integer -158 -159 +139 +150 6 - -Literal +integer +DefDef false 0 false +def integer + +10 +lifting/test.scala + +A +Class +.A +ex +162 +168 +7 +ex +DefDef +false 0 +false +def ex 11 lifting/test.scala @@ -211,35 +228,18 @@ lifting/test.scala test$package$ Object .test$package$ -Test -235 -238 -12 - -Literal -false -0 -false -123 - -13 -lifting/test.scala - -test$package$ -Object -.test$package$ f -251 -253 +241 +246 13 - -Literal +f +DefDef false 0 false --1 +def f -14 +13 lifting/test.scala test$package$ @@ -256,7 +256,7 @@ false false a.msg(i, 0, a.integer) -15 +14 lifting/test.scala test$package$ @@ -273,7 +273,7 @@ false false println(x) -16 +15 lifting/test.scala test$package$ @@ -290,7 +290,7 @@ false false a.ex.msg(i, 0, a.ex.integer) -17 +16 lifting/test.scala test$package$ @@ -307,7 +307,7 @@ false false println(x) -18 +17 lifting/test.scala test$package$ @@ -324,7 +324,7 @@ false false f() -19 +18 lifting/test.scala test$package$ @@ -341,7 +341,7 @@ false false a.msg(f(), 0, i) -20 +19 lifting/test.scala test$package$ @@ -358,3 +358,21 @@ false false println(x) +20 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +188 +202 +10 +Test +DefDef +false +0 +false +@main +def Test + diff --git a/tests/coverage/run/trait/test.scoverage.check b/tests/coverage/run/trait/test.scoverage.check index ac6000132788..dcc93e2a7809 100644 --- a/tests/coverage/run/trait/test.scoverage.check +++ b/tests/coverage/run/trait/test.scoverage.check @@ -18,24 +18,24 @@ # - description (can be multi-line) # ' ' sign # ------------------------------------------ -1 +0 trait/test.scala T1 Trait .T1 x -20 -21 +12 +17 1 - -Literal +x +DefDef false 0 false -0 +def x -2 +1 trait/test.scala Impl2 @@ -52,7 +52,7 @@ false false T2("test") -3 +2 trait/test.scala Impl3 @@ -69,7 +69,7 @@ false false Impl2() -4 +3 trait/test.scala Impl3 @@ -86,7 +86,7 @@ false false T2(Impl2().p) -5 +4 trait/test.scala test$package$ @@ -103,7 +103,7 @@ false false Impl1() -6 +5 trait/test.scala test$package$ @@ -120,7 +120,7 @@ false false println(Impl1().x) -7 +6 trait/test.scala test$package$ @@ -137,7 +137,7 @@ false false Impl2() -8 +7 trait/test.scala test$package$ @@ -154,7 +154,7 @@ false false println(Impl2().p) -9 +8 trait/test.scala test$package$ @@ -171,7 +171,7 @@ false false Impl3() -10 +9 trait/test.scala test$package$ @@ -188,3 +188,21 @@ false false println(Impl3().p) +10 +trait/test.scala + +test$package$ +Object +.test$package$ +Test +145 +159 +10 +Test +DefDef +false +0 +false +@main +def Test + From 2fc33a36ea19752920d17596b5a6194c815a1873 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Tue, 5 Apr 2022 18:03:30 +0200 Subject: [PATCH 15/15] Make testCompilation run coverage tests --- project/Build.scala | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index abe42e6a640f..f3e8957fb258 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -138,9 +138,6 @@ object Build { // Run tests with filter through vulpix test suite val testCompilation = inputKey[Unit]("runs integration test with the supplied filter") - // Run code coverage instrumentation tests - val testCoverage = inputKey[Unit]("runs code coverage instrumentation test") - // Used to compile files similar to ./bin/scalac script val scalac = inputKey[Unit]("run the compiler using the correct classpath, or the user supplied classpath") @@ -586,7 +583,8 @@ object Build { s""" |usage: testCompilation [--help] [--from-tasty] [--update-checkfiles] [] | - |By default runs tests in dotty.tools.dotc.*CompilationTests excluding tests tagged with dotty.SlowTests. + |By default runs tests in dotty.tools.dotc.*CompilationTests and dotty.tools.dotc.coverage.*, + |excluding tests tagged with dotty.SlowTests. | | --help show this message | --from-tasty runs tests in dotty.tools.dotc.FromTastyTests @@ -601,7 +599,7 @@ object Build { val updateCheckfile = args.contains("--update-checkfiles") val fromTasty = args.contains("--from-tasty") val args1 = if (updateCheckfile | fromTasty) args.filter(x => x != "--update-checkfiles" && x != "--from-tasty") else args - val test = if (fromTasty) "dotty.tools.dotc.FromTastyTests" else "dotty.tools.dotc.*CompilationTests" + val test = if (fromTasty) "dotty.tools.dotc.FromTastyTests" else "dotty.tools.dotc.*CompilationTests dotty.tools.dotc.coverage.*" val cmd = s" $test -- --exclude-categories=dotty.SlowTests" + (if (updateCheckfile) " -Ddotty.tests.updateCheckfiles=TRUE" else "") + (if (args1.nonEmpty) " -Ddotty.tests.filter=" + args1.mkString(" ") else "") @@ -609,22 +607,6 @@ object Build { } }.evaluated, - testCoverage := Def.inputTaskDyn { - val args = spaceDelimited("").parsed - if (args.contains("--help")) { - println("usage: testCoverage [--update-checkfiles] []") - (Test / testOnly).toTask(" not.a.test") - } else { - val updateCheckfile = args.contains("--update-checkfiles") - val otherArgs = args.filter(_ != "--update-checkfiles") - val test = "dotty.tools.dotc.coverage.CoverageTests" - val argUpdateCheckfile = if (updateCheckfile) "-Ddotty.tests.updateCheckfiles=TRUE" else "" - val argCustom = if (otherArgs.nonEmpty) otherArgs.mkString(" ") else "" - val cmd = s" $test -- $argUpdateCheckfile $argCustom" - (Test/testOnly).toTask(cmd) - } - }.evaluated, - Compile / mainClass := Some("dotty.tools.dotc.Main"), scala := {