From 503325bec7920a2e5e4f123e2dd798213a91be6f Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Mon, 11 Jul 2022 18:05:00 +0200 Subject: [PATCH 1/5] Fix diff printing in CoverageTests --- .../test/dotty/tools/dotc/coverage/CoverageTests.scala | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index 6db6a330f55e..1a9248c49a82 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -15,6 +15,7 @@ import scala.jdk.CollectionConverters.* import scala.util.Properties.userDir import scala.language.unsafeNulls import scala.collection.mutable.Buffer +import dotty.tools.dotc.util.DiffUtil @Category(Array(classOf[BootstrappedOnlyTests])) class CoverageTests: @@ -56,12 +57,8 @@ class CoverageTests: val expected = fixWindowsPaths(Files.readAllLines(expectFile).asScala) val obtained = fixWindowsPaths(Files.readAllLines(targetFile).asScala) if expected != obtained then - // FIXME: zip will drop part of the output if one is shorter (i.e. will not print anything of one is a refix of the other) - 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") + val instructions = FileDiff.diffMessage(expectFile.toString, targetFile.toString) + fail(s"Coverage report differs from expected data.\n$instructions") }) From 13cfcea7bfa7b30e8643024cd833359014ae9f98 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Mon, 11 Jul 2022 18:05:39 +0200 Subject: [PATCH 2/5] Fix coverage instrumentation of java and parameterless methods 1. Select and TypeApply trees weren't properly handled for JavaDefined symbols, leading to a crash when selecting a static method with parameter types. 2. Select and Ident trees weren't properly handled, and many occurences of parameterless methods were missed. 3. Some methods like asInstanceOf and isInstanceOf must not be instrumented, otherwise it crashes in Erasure. --- .../dotc/transform/InstrumentCoverage.scala | 84 +++-- .../coverage/pos/Constructor.scoverage.check | 40 +- .../pos/ContextFunctions.scoverage.check | 104 +----- tests/coverage/pos/Enum.scoverage.check | 149 ++------ tests/coverage/pos/Givens.scoverage.check | 73 +--- tests/coverage/pos/Inlined.scoverage.check | 100 +---- tests/coverage/pos/Literals.scoverage.check | 21 +- .../coverage/pos/MatchNumbers.scoverage.check | 25 +- tests/coverage/pos/Select.scoverage.check | 46 ++- .../pos/StructuralTypes.scoverage.check | 50 ++- .../run/currying/test.scoverage.check | 198 +++------- .../run/inline-def/test.scoverage.check | 19 +- .../run/interpolation/test.scoverage.check | 35 +- .../coverage/run/java-methods/JavaObject.java | 7 + .../run/java-methods/StaticMethods.java | 6 + tests/coverage/run/java-methods/test.check | 2 + tests/coverage/run/java-methods/test.scala | 10 + .../run/java-methods/test.scoverage.check | 157 ++++++++ .../run/lifting-bool/test.scoverage.check | 213 ++--------- .../coverage/run/lifting/test.scoverage.check | 82 ++++- tests/coverage/run/parameterless/test.check | 10 + tests/coverage/run/parameterless/test.scala | 25 ++ .../run/parameterless/test.scoverage.check | 344 ++++++++++++++++++ tests/coverage/run/trait/test.scoverage.check | 27 +- 24 files changed, 1028 insertions(+), 799 deletions(-) create mode 100644 tests/coverage/run/java-methods/JavaObject.java create mode 100644 tests/coverage/run/java-methods/StaticMethods.java create mode 100644 tests/coverage/run/java-methods/test.check create mode 100644 tests/coverage/run/java-methods/test.scala create mode 100644 tests/coverage/run/java-methods/test.scoverage.check create mode 100644 tests/coverage/run/parameterless/test.check create mode 100644 tests/coverage/run/parameterless/test.scala create mode 100644 tests/coverage/run/parameterless/test.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 3c7f6e0e8a7a..edc1f5af5668 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -10,7 +10,6 @@ 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.* @@ -18,7 +17,7 @@ import typer.LiftCoverage import util.{SourcePosition, Property} import util.Spans.Span import coverage.* -import localopt.StringInterpolatorOpt.isCompilerIntrinsic +import localopt.StringInterpolatorOpt /** Implements code coverage by inserting calls to scala.runtime.coverage.Invoker * ("instruments" the source code). @@ -66,7 +65,16 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: tree match // simple cases case tree: (Import | Export | Literal | This | Super | New) => tree - case tree if tree.isEmpty || tree.isType => tree // empty Thicket, Ident, TypTree, ... + case tree if tree.isEmpty || tree.isType => tree // empty Thicket, Ident (referring to a type), TypeTree, ... + + // identifier + case tree: Ident => + val sym = tree.symbol + if canInstrumentParameterless(sym) then + // call to a local parameterless method f + instrument(tree) + else + tree // branches case tree: If => @@ -82,20 +90,6 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: 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 - if needsLift(tree) then - val transformed = cpy.Apply(tree)(transformedFun, args) // args will be transformed in instrumentLifted - instrumentLifted(transformed) - else - val transformed = transformApply(tree, transformedFun) - instrument(transformed) - else - transformApply(tree, transformedFun) - // f(args) case tree: Apply => if canInstrumentApply(tree) then @@ -106,24 +100,19 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: else transformApply(tree) - // (f(x))[args] - case TypeApply(fun: Apply, args) => + // (fun)[args] + case TypeApply(fun, 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) + val transformed = cpy.Select(tree)(transform(qual), name) + val sym = tree.symbol + if canInstrumentParameterless(sym) then + // call to a parameterless method + instrument(transformed) 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 + transformed case tree: CaseDef => instrumentCaseDef(tree) case tree: ValDef => @@ -142,7 +131,9 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: val rhs = transform(tree.rhs) val finalRhs = if canInstrumentDefDef(tree) then - // Ensure that the rhs is always instrumented, if possible + // Ensure that the rhs is always instrumented, if possible. + // This is useful because methods can be stored and called later, or called by reflection, + // and if the rhs is too simple to be instrumented (like `def f = this`), the method won't show up as covered. instrumentBody(tree, rhs) else rhs @@ -162,7 +153,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. + * Note that if only one arg needs to be lifted, we just lift everything (see LiftCoverage). */ private def instrumentLifted(tree: Apply)(using Context) = // lifting @@ -178,10 +169,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: ) private inline def transformApply(tree: Apply)(using Context): Apply = - transformApply(tree, transform(tree.fun)) - - private inline def transformApply(tree: Apply, transformedFun: Tree)(using Context): Apply = - cpy.Apply(tree)(transformedFun, transform(tree.args)) + cpy.Apply(tree)(transform(tree.fun), transform(tree.args)) private inline def instrumentCases(cases: List[CaseDef])(using Context): List[CaseDef] = cases.map(instrumentCaseDef) @@ -292,7 +280,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: * they shouldn't be lifted. */ val sym = fun.symbol - sym.exists && (isShortCircuitedOp(sym) || isCompilerIntrinsic(sym)) + sym.exists && (isShortCircuitedOp(sym) || StringInterpolatorOpt.isCompilerIntrinsic(sym)) end val fun = tree.fun @@ -312,7 +300,9 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: /** 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 + val sym = tree.symbol + !sym.isOneOf(Synthetic | Artifact) && // no need to instrument synthetic apply + !isCompilerIntrinsicMethod(sym) && (tree.typeOpt match case AppliedType(tycon: NamedType, _) => /* If the last expression in a block is a context function, we'll try to @@ -339,6 +329,24 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: true ) + /** Is this the symbol of a parameterless method that we can instrument? + * Note: it is crucial that `asInstanceOf` and `isInstanceOf`, among others, + * do NOT get instrumented, because that would generate invalid code and crash + * in post-erasure checking. + */ + private def canInstrumentParameterless(sym: Symbol)(using Context): Boolean = + sym.is(Method, butNot = Synthetic | Artifact) && + sym.info.isParameterless && + !isCompilerIntrinsicMethod(sym) + + /** Does sym refer to a "compiler intrinsic" method, which only exist during compilation, + * like Any.isInstanceOf? + * If this returns true, the call souldn't be instrumented. + */ + private def isCompilerIntrinsicMethod(sym: Symbol)(using Context): Boolean = + val owner = sym.maybeOwner + owner.eq(defn.AnyClass) || owner.isPrimitiveValueClass + object InstrumentCoverage: val name: String = "instrumentCoverage" val description: String = "instrument code for coverage checking" diff --git a/tests/coverage/pos/Constructor.scoverage.check b/tests/coverage/pos/Constructor.scoverage.check index b6223734b1a8..1aaf414006cd 100644 --- a/tests/coverage/pos/Constructor.scoverage.check +++ b/tests/coverage/pos/Constructor.scoverage.check @@ -59,6 +59,23 @@ C Class covtest.C +62 +63 +5 +x +Select +false +0 +false +x + +3 +Constructor.scala +covtest +C +Class +covtest.C + 60 64 5 @@ -69,7 +86,7 @@ false false f(x) -3 +4 Constructor.scala covtest O$ @@ -86,7 +103,7 @@ false false def g -4 +5 Constructor.scala covtest O$ @@ -103,7 +120,24 @@ false false def y -5 +6 +Constructor.scala +covtest +O$ +Object +covtest.O$ + +112 +113 +10 +y +Ident +false +0 +false +y + +7 Constructor.scala covtest O$ diff --git a/tests/coverage/pos/ContextFunctions.scoverage.check b/tests/coverage/pos/ContextFunctions.scoverage.check index 9c2ed02d8b44..26391cfad536 100644 --- a/tests/coverage/pos/ContextFunctions.scoverage.check +++ b/tests/coverage/pos/ContextFunctions.scoverage.check @@ -58,108 +58,6 @@ covtest Imperative Class covtest.Imperative -$anonfun -267 -294 -13 -apply -Apply -false -0 -false -readName2(using e)(using s) - -3 -ContextFunctions.scala -covtest -Imperative -Class -covtest.Imperative -readPerson -252 -295 -13 - -Apply -false -0 -false -OnError((e) => readName2(using e)(using s)) - -4 -ContextFunctions.scala -covtest -Imperative -Class -covtest.Imperative -readPerson -252 -295 -13 -invoked -Apply -false -0 -false -OnError((e) => readName2(using e)(using s)) - -5 -ContextFunctions.scala -covtest -Imperative -Class -covtest.Imperative -$anonfun -267 -294 -13 -invoked -Apply -false -0 -false -readName2(using e)(using s) - -6 -ContextFunctions.scala -covtest -Imperative -Class -covtest.Imperative -$anonfun -267 -294 -13 -apply -Apply -false -0 -false -readName2(using e)(using s) - -7 -ContextFunctions.scala -covtest -Imperative -Class -covtest.Imperative -readPerson -252 -295 -13 - -Apply -false -0 -false -OnError((e) => readName2(using e)(using s)) - -8 -ContextFunctions.scala -covtest -Imperative -Class -covtest.Imperative readPerson 252 309 @@ -171,7 +69,7 @@ false false OnError((e) => readName2(using e)(using s)).onError(None) -9 +3 ContextFunctions.scala covtest Imperative diff --git a/tests/coverage/pos/Enum.scoverage.check b/tests/coverage/pos/Enum.scoverage.check index d76c749275e7..b5bf6e7ed6a9 100644 --- a/tests/coverage/pos/Enum.scoverage.check +++ b/tests/coverage/pos/Enum.scoverage.check @@ -25,91 +25,6 @@ Planet Class covtest.Planet surfaceGravity -359 -367 -14 -* -Apply -false -0 -false -G * mass - -1 -Enum.scala -covtest -Planet -Class -covtest.Planet -surfaceGravity -359 -367 -14 -invoked -Apply -false -0 -false -G * mass - -2 -Enum.scala -covtest -Planet -Class -covtest.Planet -surfaceGravity -359 -367 -14 -* -Apply -false -0 -false -G * mass - -3 -Enum.scala -covtest -Planet -Class -covtest.Planet -surfaceGravity -371 -386 -14 -* -Apply -false -0 -false -radius * radius - -4 -Enum.scala -covtest -Planet -Class -covtest.Planet -surfaceGravity -359 -386 -14 -/ -Apply -false -0 -false -G * mass / (radius * radius - -5 -Enum.scala -covtest -Planet -Class -covtest.Planet -surfaceGravity 338 356 14 @@ -120,24 +35,24 @@ false false def surfaceGravity -6 +1 Enum.scala covtest Planet Class covtest.Planet surfaceWeight -432 +444 458 15 -* -Apply +surfaceGravity +Select false 0 false -otherMass * surfaceGravity +surfaceGravity -7 +2 Enum.scala covtest Planet @@ -154,7 +69,7 @@ false false def surfaceWeight -8 +3 Enum.scala covtest $anon @@ -171,7 +86,7 @@ false false Planet(3.303e+23, 2.4397e6) -9 +4 Enum.scala covtest $anon @@ -188,7 +103,7 @@ false false Planet(4.869e+24, 6.0518e6) -10 +5 Enum.scala covtest $anon @@ -205,7 +120,7 @@ false false Planet(5.976e+24, 6.37814e6) -11 +6 Enum.scala covtest $anon @@ -222,7 +137,7 @@ false false Planet(6.421e+23, 3.3972e6) -12 +7 Enum.scala covtest $anon @@ -239,7 +154,7 @@ false false Planet(1.9e+27, 7.1492e7) -13 +8 Enum.scala covtest $anon @@ -256,7 +171,7 @@ false false Planet(5.688e+26, 6.0268e7) -14 +9 Enum.scala covtest $anon @@ -273,7 +188,7 @@ false false Planet(8.686e+25, 2.5559e7) -15 +10 Enum.scala covtest $anon @@ -290,7 +205,7 @@ false false Planet(1.024e+26, 2.4746e7) -16 +11 Enum.scala covtest EnumTypes$ @@ -307,7 +222,7 @@ false false "Example 1: \n"+emptyList -17 +12 Enum.scala covtest EnumTypes$ @@ -324,7 +239,7 @@ false false println("Example 1: \n"+emptyList) -18 +13 Enum.scala covtest EnumTypes$ @@ -341,7 +256,7 @@ false false s"${list}\n" -19 +14 Enum.scala covtest EnumTypes$ @@ -358,24 +273,24 @@ false false println(s"${list}\n") -20 +15 Enum.scala covtest EnumTypes$ Object covtest.EnumTypes$ calculateEarthWeightOnPlanets -1183 +1195 1222 34 -/ -Apply +surfaceGravity +Select false 0 false -earthWeight/Planet.Earth.surfaceGravity +Planet.Earth.surfaceGravity -21 +16 Enum.scala covtest EnumTypes$ @@ -392,7 +307,7 @@ false false Planet.values -22 +17 Enum.scala covtest EnumTypes$ @@ -409,7 +324,7 @@ false false p.surfaceWeight(mass) -23 +18 Enum.scala covtest EnumTypes$ @@ -426,7 +341,7 @@ false false s"Your weight on $p is ${p.surfaceWeight(mass)}" -24 +19 Enum.scala covtest EnumTypes$ @@ -443,7 +358,7 @@ false false println(s"Your weight on $p is ${p.surfaceWeight(mass)}") -25 +20 Enum.scala covtest EnumTypes$ @@ -461,7 +376,7 @@ false for p <- Planet.values do println(s"Your weight on $p is ${p.surfaceWeight(mass)}") -26 +21 Enum.scala covtest EnumTypes$ @@ -478,7 +393,7 @@ false false def calculateEarthWeightOnPlanets -27 +22 Enum.scala covtest EnumTypes$ @@ -495,7 +410,7 @@ false false println("Example 2:") -28 +23 Enum.scala covtest EnumTypes$ @@ -512,7 +427,7 @@ false false calculateEarthWeightOnPlanets(80) -29 +24 Enum.scala covtest EnumTypes$ diff --git a/tests/coverage/pos/Givens.scoverage.check b/tests/coverage/pos/Givens.scoverage.check index 389713521448..ac8fcd9e379e 100644 --- a/tests/coverage/pos/Givens.scoverage.check +++ b/tests/coverage/pos/Givens.scoverage.check @@ -25,23 +25,6 @@ Givens Class covtest.Givens test -182 -190 -10 -== -Apply -false -0 -false -3 == "3" - -1 -Givens.scala -covtest -Givens -Class -covtest.Givens -test 174 191 10 @@ -52,24 +35,7 @@ false false println(3 == "3") -2 -Givens.scala -covtest -Givens -Class -covtest.Givens -test -204 -212 -11 -== -Apply -false -0 -false -3 == 5.1 - -3 +1 Givens.scala covtest Givens @@ -86,7 +52,7 @@ false false println(3 == 5.1) -4 +2 Givens.scala covtest Givens @@ -103,7 +69,7 @@ false false def test -5 +3 Givens.scala covtest Givens @@ -120,7 +86,7 @@ false false println(msg) -6 +4 Givens.scala covtest Givens @@ -137,7 +103,7 @@ false false println(ctx.id) -7 +5 Givens.scala covtest Givens @@ -154,24 +120,7 @@ false false def printContext -8 -Givens.scala -covtest -Givens -Class -covtest.Givens -getMessage -348 -358 -17 -toString -Apply -false -0 -false -i.toString - -9 +6 Givens.scala covtest Givens @@ -188,7 +137,7 @@ false false def getMessage -10 +7 Givens.scala covtest Givens @@ -205,7 +154,7 @@ false false Context(0) -11 +8 Givens.scala covtest Givens @@ -222,7 +171,7 @@ false false printContext("test")(using c) -12 +9 Givens.scala covtest Givens @@ -239,7 +188,7 @@ false false getMessage(123) -13 +10 Givens.scala covtest Givens @@ -256,7 +205,7 @@ false false printContext(getMessage(123)) -14 +11 Givens.scala covtest Givens diff --git a/tests/coverage/pos/Inlined.scoverage.check b/tests/coverage/pos/Inlined.scoverage.check index 4be4446e0d91..6a4aac8ced8d 100644 --- a/tests/coverage/pos/Inlined.scoverage.check +++ b/tests/coverage/pos/Inlined.scoverage.check @@ -25,40 +25,6 @@ Inlined$package$ Object covtest.Inlined$package$ testInlined -133 -139 -5 -== -Apply -false -0 -false -l == 1 - -1 -Inlined.scala -covtest -Inlined$package$ -Object -covtest.Inlined$package$ -testInlined -288 -315 -10 -Scala3RunTime -Select -false -0 -false -scala.runtime.Scala3RunTime - -2 -Inlined.scala -covtest -Inlined$package$ -Object -covtest.Inlined$package$ -testInlined 288 330 10 @@ -69,7 +35,7 @@ false false scala.runtime.Scala3RunTime.assertFailed() -3 +1 Inlined.scala covtest Inlined$package$ @@ -86,7 +52,7 @@ true false scala.runtime.Scala3RunTime.assertFailed() -4 +2 Inlined.scala covtest Inlined$package$ @@ -103,41 +69,24 @@ false false List(l) -5 +3 Inlined.scala covtest Inlined$package$ Object covtest.Inlined$package$ testInlined -150 +155 169 6 -== -Apply -false -0 -false -l == List(l).length - -6 -Inlined.scala -covtest -Inlined$package$ -Object -covtest.Inlined$package$ -testInlined -288 -315 -10 -Scala3RunTime +length Select false 0 false -scala.runtime.Scala3RunTime +List(l).length -7 +4 Inlined.scala covtest Inlined$package$ @@ -154,7 +103,7 @@ false false scala.runtime.Scala3RunTime.assertFailed() -8 +5 Inlined.scala covtest Inlined$package$ @@ -171,7 +120,7 @@ true false scala.runtime.Scala3RunTime.assertFailed() -9 +6 Inlined.scala covtest Inlined$package$ @@ -188,7 +137,7 @@ false false List(l) -10 +7 Inlined.scala covtest Inlined$package$ @@ -196,33 +145,16 @@ Object covtest.Inlined$package$ testInlined 180 -199 +194 7 -== -Apply -false -0 -false -List(l).length == 1 - -11 -Inlined.scala -covtest -Inlined$package$ -Object -covtest.Inlined$package$ -testInlined -288 -315 -10 -Scala3RunTime +length Select false 0 false -scala.runtime.Scala3RunTime +List(l).length -12 +8 Inlined.scala covtest Inlined$package$ @@ -239,7 +171,7 @@ false false scala.runtime.Scala3RunTime.assertFailed() -13 +9 Inlined.scala covtest Inlined$package$ @@ -256,7 +188,7 @@ true false scala.runtime.Scala3RunTime.assertFailed() -14 +10 Inlined.scala covtest Inlined$package$ diff --git a/tests/coverage/pos/Literals.scoverage.check b/tests/coverage/pos/Literals.scoverage.check index bda71a49f3b1..e890f0978074 100644 --- a/tests/coverage/pos/Literals.scoverage.check +++ b/tests/coverage/pos/Literals.scoverage.check @@ -59,6 +59,23 @@ Literals$package$ Object covtest.Literals$package$ f +177 +180 +8 +??? +Ident +false +0 +false +??? + +3 +Literals.scala +covtest +Literals$package$ +Object +covtest.Literals$package$ +f 137 142 8 @@ -69,7 +86,7 @@ false false def f -3 +4 Literals.scala covtest Literals$package$ @@ -86,7 +103,7 @@ false false f(0,1,2)(3) -4 +5 Literals.scala covtest Literals$package$ diff --git a/tests/coverage/pos/MatchNumbers.scoverage.check b/tests/coverage/pos/MatchNumbers.scoverage.check index f16c11031784..0421cf77002a 100644 --- a/tests/coverage/pos/MatchNumbers.scoverage.check +++ b/tests/coverage/pos/MatchNumbers.scoverage.check @@ -42,23 +42,6 @@ MatchNumbers$ Object covtest.MatchNumbers$ f -121 -126 -6 -< -Apply -false -0 -false -x < 0 - -2 -MatchNumbers.scala -covtest -MatchNumbers$ -Object -covtest.MatchNumbers$ -f 137 148 7 @@ -69,7 +52,7 @@ false false case x: Int -3 +2 MatchNumbers.scala covtest MatchNumbers$ @@ -86,7 +69,7 @@ false false case y: Long -4 +3 MatchNumbers.scala covtest MatchNumbers$ @@ -103,7 +86,7 @@ false false def f -5 +4 MatchNumbers.scala covtest MatchNumbers$ @@ -120,7 +103,7 @@ false false f(0) -6 +5 MatchNumbers.scala covtest MatchNumbers$ diff --git a/tests/coverage/pos/Select.scoverage.check b/tests/coverage/pos/Select.scoverage.check index ef2831ee1013..94b693f0e639 100644 --- a/tests/coverage/pos/Select.scoverage.check +++ b/tests/coverage/pos/Select.scoverage.check @@ -110,6 +110,23 @@ B Class covtest.B print +192 +205 +12 +instance +Select +false +0 +false +this.instance + +6 +Select.scala +covtest +B +Class +covtest.B +print 184 206 12 @@ -120,7 +137,7 @@ false false println(this.instance) -6 +7 Select.scala covtest B @@ -137,7 +154,7 @@ false false override def print -7 +8 Select.scala covtest Select$package$ @@ -154,7 +171,7 @@ false false A() -8 +9 Select.scala covtest Select$package$ @@ -171,7 +188,24 @@ false false new A -9 +10 +Select.scala +covtest +Select$package$ +Object +covtest.Select$package$ +test +263 +273 +18 +instance +Select +false +0 +false +a.instance + +11 Select.scala covtest Select$package$ @@ -188,7 +222,7 @@ false false a.instance.print() -10 +12 Select.scala covtest Select$package$ @@ -205,7 +239,7 @@ false false a.print() -11 +13 Select.scala covtest Select$package$ diff --git a/tests/coverage/pos/StructuralTypes.scoverage.check b/tests/coverage/pos/StructuralTypes.scoverage.check index 43ddfd7715b8..1e9650ce17a3 100644 --- a/tests/coverage/pos/StructuralTypes.scoverage.check +++ b/tests/coverage/pos/StructuralTypes.scoverage.check @@ -26,14 +26,14 @@ Class covtest.Record $anonfun 159 -171 +163 5 -== -Apply +_1 +Select false 0 false -_._1 == name +_._1 1 StructuralTypes.scala @@ -59,6 +59,40 @@ Record Class covtest.Record selectDynamic +148 +176 +5 +get +Select +false +0 +false +elems.find(_._1 == name).get + +3 +StructuralTypes.scala +covtest +Record +Class +covtest.Record +selectDynamic +148 +179 +5 +_2 +Select +false +0 +false +elems.find(_._1 == name).get._2 + +4 +StructuralTypes.scala +covtest +Record +Class +covtest.Record +selectDynamic 109 126 5 @@ -69,7 +103,7 @@ false false def selectDynamic -3 +5 StructuralTypes.scala covtest StructuralTypes$ @@ -86,7 +120,7 @@ false false "name" -> "Emma" -4 +6 StructuralTypes.scala covtest StructuralTypes$ @@ -103,7 +137,7 @@ false false "age" -> 42 -5 +7 StructuralTypes.scala covtest StructuralTypes$ @@ -120,7 +154,7 @@ false false person.name -6 +8 StructuralTypes.scala covtest StructuralTypes$ diff --git a/tests/coverage/run/currying/test.scoverage.check b/tests/coverage/run/currying/test.scoverage.check index 688c75b42933..d60d2f088a78 100644 --- a/tests/coverage/run/currying/test.scoverage.check +++ b/tests/coverage/run/currying/test.scoverage.check @@ -25,40 +25,6 @@ Test$ Object .Test$ f1 -48 -51 -1 -+ -Apply -false -0 -false -a+b - -1 -currying/test.scala - -Test$ -Object -.Test$ -f1 -48 -53 -1 -+ -Apply -false -0 -false -a+b+c - -2 -currying/test.scala - -Test$ -Object -.Test$ -f1 15 21 1 @@ -69,41 +35,7 @@ false false def f1 -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 +1 currying/test.scala Test$ @@ -120,41 +52,7 @@ false false def f2 -6 -currying/test.scala - -Test$ -Object -.Test$ -$anonfun -166 -169 -6 -+ -Apply -false -0 -false -a+b - -7 -currying/test.scala - -Test$ -Object -.Test$ -$anonfun -166 -171 -6 -+ -Apply -false -0 -false -a+b+c - -8 +2 currying/test.scala Test$ @@ -171,41 +69,7 @@ false false def g1 -9 -currying/test.scala - -Test$ -Object -.Test$ -g2 -226 -229 -8 -+ -Apply -false -0 -false -a+b - -10 -currying/test.scala - -Test$ -Object -.Test$ -g2 -226 -231 -8 -+ -Apply -false -0 -false -a+b+c - -11 +3 currying/test.scala Test$ @@ -222,7 +86,7 @@ false false def g2 -12 +4 currying/test.scala Test$ @@ -239,7 +103,7 @@ false false f1(0)(1)(2) -13 +5 currying/test.scala Test$ @@ -256,7 +120,24 @@ false false println(f1(0)(1)(2)) -14 +6 +currying/test.scala + +Test$ +Object +.Test$ +main +310 +312 +12 +f2 +Ident +false +0 +false +f2 + +7 currying/test.scala Test$ @@ -273,7 +154,7 @@ false false f2(0) -15 +8 currying/test.scala Test$ @@ -290,7 +171,7 @@ false false f2(0)(1) -16 +9 currying/test.scala Test$ @@ -307,7 +188,7 @@ false false f2(0)(1)(2) -17 +10 currying/test.scala Test$ @@ -324,7 +205,24 @@ false false println(f2(0)(1)(2)) -18 +11 +currying/test.scala + +Test$ +Object +.Test$ +main +335 +337 +13 +g1 +Ident +false +0 +false +g1 + +12 currying/test.scala Test$ @@ -341,7 +239,7 @@ false false g1(using 0)(using 1)(using 2) -19 +13 currying/test.scala Test$ @@ -358,7 +256,7 @@ false false println(g1(using 0)(using 1)(using 2)) -20 +14 currying/test.scala Test$ @@ -375,7 +273,7 @@ false false g2(using 0)(using 1)(using 2) -21 +15 currying/test.scala Test$ @@ -392,7 +290,7 @@ false false println(g2(using 0)(using 1)(using 2)) -22 +16 currying/test.scala Test$ diff --git a/tests/coverage/run/inline-def/test.scoverage.check b/tests/coverage/run/inline-def/test.scoverage.check index 42ecf6d9b9a4..ec336127385a 100644 --- a/tests/coverage/run/inline-def/test.scoverage.check +++ b/tests/coverage/run/inline-def/test.scoverage.check @@ -178,6 +178,23 @@ test$package$ Object .test$package$ Test +303 +308 +17 +foo +Select +false +0 +false +b.foo + +10 +inline-def/test.scala + +test$package$ +Object +.test$package$ +Test 295 309 17 @@ -188,7 +205,7 @@ false false println(b.foo) -10 +11 inline-def/test.scala test$package$ diff --git a/tests/coverage/run/interpolation/test.scoverage.check b/tests/coverage/run/interpolation/test.scoverage.check index f30b391d20e5..1f16d03cc7df 100644 --- a/tests/coverage/run/interpolation/test.scoverage.check +++ b/tests/coverage/run/interpolation/test.scoverage.check @@ -126,6 +126,23 @@ interpolation/test.scala Test$ Object .Test$ +main +229 +244 +10 +zipWithIndex +Select +false +0 +false +xs.zipWithIndex + +7 +interpolation/test.scala + +Test$ +Object +.Test$ $anonfun 267 276 @@ -137,7 +154,7 @@ false false s"$i: $s" -7 +8 interpolation/test.scala Test$ @@ -154,7 +171,7 @@ false false println(s"$i: $s") -8 +9 interpolation/test.scala Test$ @@ -171,7 +188,7 @@ false false xs.zipWithIndex.map((s, i) => println(s"$i: $s")) -9 +10 interpolation/test.scala Test$ @@ -188,7 +205,7 @@ false false simple(1, "abc") -10 +11 interpolation/test.scala Test$ @@ -205,7 +222,7 @@ false false println(simple(1, "abc")) -11 +12 interpolation/test.scala Test$ @@ -222,7 +239,7 @@ false false hexa(127) -12 +13 interpolation/test.scala Test$ @@ -239,7 +256,7 @@ false false println(hexa(127)) -13 +14 interpolation/test.scala Test$ @@ -256,7 +273,7 @@ false false raw"a\nb" -14 +15 interpolation/test.scala Test$ @@ -273,7 +290,7 @@ false false println(raw"a\nb") -15 +16 interpolation/test.scala Test$ diff --git a/tests/coverage/run/java-methods/JavaObject.java b/tests/coverage/run/java-methods/JavaObject.java new file mode 100644 index 000000000000..528f92f2db33 --- /dev/null +++ b/tests/coverage/run/java-methods/JavaObject.java @@ -0,0 +1,7 @@ +class JavaObject { + void f() {} + + T identity(T t) { + return t; + } +} diff --git a/tests/coverage/run/java-methods/StaticMethods.java b/tests/coverage/run/java-methods/StaticMethods.java new file mode 100644 index 000000000000..d2051d342bba --- /dev/null +++ b/tests/coverage/run/java-methods/StaticMethods.java @@ -0,0 +1,6 @@ +import java.util.function.Consumer; + +public class StaticMethods { + public static void simple() {} + public static void withTypeParam(Consumer method) {} +} \ No newline at end of file diff --git a/tests/coverage/run/java-methods/test.check b/tests/coverage/run/java-methods/test.check new file mode 100644 index 000000000000..adee8f10ea00 --- /dev/null +++ b/tests/coverage/run/java-methods/test.check @@ -0,0 +1,2 @@ +0 +ok! \ No newline at end of file diff --git a/tests/coverage/run/java-methods/test.scala b/tests/coverage/run/java-methods/test.scala new file mode 100644 index 000000000000..fd155397de8a --- /dev/null +++ b/tests/coverage/run/java-methods/test.scala @@ -0,0 +1,10 @@ +import java.util.function.Consumer + +@main +def Test: Unit = + StaticMethods.simple() + StaticMethods.withTypeParam[Any](a => ()) + val obj = JavaObject() + obj.f() + println(obj.identity[Int](0)) + println("ok!") diff --git a/tests/coverage/run/java-methods/test.scoverage.check b/tests/coverage/run/java-methods/test.scoverage.check new file mode 100644 index 000000000000..c1038d4a4dad --- /dev/null +++ b/tests/coverage/run/java-methods/test.scoverage.check @@ -0,0 +1,157 @@ +# 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 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +61 +83 +4 +simple +Apply +false +0 +false +StaticMethods.simple() + +1 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +86 +127 +5 +withTypeParam +Apply +false +0 +false +StaticMethods.withTypeParam[Any](a => ()) + +2 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +140 +152 +6 + +Apply +false +0 +false +JavaObject() + +3 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +155 +162 +7 +f +Apply +false +0 +false +obj.f() + +4 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +173 +193 +8 +identity +Apply +false +0 +false +obj.identity[Int](0) + +5 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +165 +194 +8 +println +Apply +false +0 +false +println(obj.identity[Int](0)) + +6 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +197 +211 +9 +println +Apply +false +0 +false +println("ok!") + +7 +java-methods/test.scala + +test$package$ +Object +.test$package$ +Test +36 +50 +3 +Test +DefDef +false +0 +false +@main +def Test + diff --git a/tests/coverage/run/lifting-bool/test.scoverage.check b/tests/coverage/run/lifting-bool/test.scoverage.check index 49f83b4eecc8..93321474a6a7 100644 --- a/tests/coverage/run/lifting-bool/test.scoverage.check +++ b/tests/coverage/run/lifting-bool/test.scoverage.check @@ -25,6 +25,23 @@ test$package$ Object .test$package$ notCalled +19 +22 +1 +??? +Ident +false +0 +false +??? + +1 +lifting-bool/test.scala + +test$package$ +Object +.test$package$ +notCalled 1 14 1 @@ -35,7 +52,7 @@ false false def notCalled -1 +2 lifting-bool/test.scala test$package$ @@ -52,7 +69,7 @@ false false def f -2 +3 lifting-bool/test.scala test$package$ @@ -69,23 +86,6 @@ false false notCalled() -3 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -101 -120 -7 -|| -Apply -false -0 -false -true || notCalled() - 4 lifting-bool/test.scala @@ -110,40 +110,6 @@ test$package$ Object .test$package$ Test -150 -170 -8 -&& -Apply -false -0 -false -false && notCalled() - -6 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -201 -214 -9 -|| -Apply -false -0 -false -true || false - -7 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test 219 230 9 @@ -154,24 +120,7 @@ false false notCalled() -8 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -200 -230 -9 -|| -Apply -false -0 -false -(true || false) || notCalled() - -9 +6 lifting-bool/test.scala test$package$ @@ -188,58 +137,7 @@ false false notCalled() -10 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -258 -278 -10 -&& -Apply -false -0 -false -false && notCalled() - -11 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -249 -278 -10 -&& -Apply -false -0 -false -true && (false && notCalled() - -12 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -300 -313 -11 -&& -Apply -false -0 -false -true && false - -13 +7 lifting-bool/test.scala test$package$ @@ -256,24 +154,7 @@ false false notCalled() -14 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -299 -329 -11 -&& -Apply -false -0 -false -(true && false) && notCalled() - -15 +8 lifting-bool/test.scala test$package$ @@ -290,7 +171,7 @@ false false s"$a $b $c $d $e" -16 +9 lifting-bool/test.scala test$package$ @@ -307,7 +188,7 @@ false false println(s"$a $b $c $d $e") -17 +10 lifting-bool/test.scala test$package$ @@ -324,7 +205,7 @@ false false f(true, false) -18 +11 lifting-bool/test.scala test$package$ @@ -341,7 +222,7 @@ false false println(x) -19 +12 lifting-bool/test.scala test$package$ @@ -358,24 +239,7 @@ false false notCalled() -20 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -424 -443 -17 -|| -Apply -false -0 -false -true || notCalled() - -21 +13 lifting-bool/test.scala test$package$ @@ -392,24 +256,7 @@ false false notCalled() -22 -lifting-bool/test.scala - -test$package$ -Object -.test$package$ -Test -445 -465 -17 -&& -Apply -false -0 -false -false && notCalled() - -23 +14 lifting-bool/test.scala test$package$ @@ -426,7 +273,7 @@ false false f(true || notCalled(), false && notCalled()) -24 +15 lifting-bool/test.scala test$package$ @@ -443,7 +290,7 @@ false false println(x) -25 +16 lifting-bool/test.scala test$package$ diff --git a/tests/coverage/run/lifting/test.scoverage.check b/tests/coverage/run/lifting/test.scoverage.check index 7729e7515734..e8b470202d40 100644 --- a/tests/coverage/run/lifting/test.scoverage.check +++ b/tests/coverage/run/lifting/test.scoverage.check @@ -246,6 +246,23 @@ test$package$ Object .test$package$ Test +276 +285 +14 +integer +Select +false +0 +false +a.integer + +14 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test 264 286 14 @@ -256,7 +273,7 @@ false false a.msg(i, 0, a.integer) -14 +15 lifting/test.scala test$package$ @@ -273,7 +290,58 @@ false false println(x) -15 +16 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +306 +310 +16 +ex +Select +false +0 +false +a.ex + +17 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +321 +325 +16 +ex +Select +false +0 +false +a.ex + +18 +lifting/test.scala + +test$package$ +Object +.test$package$ +Test +321 +333 +16 +integer +Select +false +0 +false +a.ex.integer + +19 lifting/test.scala test$package$ @@ -290,7 +358,7 @@ false false a.ex.msg(i, 0, a.ex.integer) -16 +20 lifting/test.scala test$package$ @@ -307,7 +375,7 @@ false false println(x) -17 +21 lifting/test.scala test$package$ @@ -324,7 +392,7 @@ false false f() -18 +22 lifting/test.scala test$package$ @@ -341,7 +409,7 @@ false false a.msg(f(), 0, i) -19 +23 lifting/test.scala test$package$ @@ -358,7 +426,7 @@ false false println(x) -20 +24 lifting/test.scala test$package$ diff --git a/tests/coverage/run/parameterless/test.check b/tests/coverage/run/parameterless/test.check new file mode 100644 index 000000000000..842109596ac2 --- /dev/null +++ b/tests/coverage/run/parameterless/test.check @@ -0,0 +1,10 @@ +f +g +f +f_res +g +g_res +O.f +O.f_res +O.g +O.g_res \ No newline at end of file diff --git a/tests/coverage/run/parameterless/test.scala b/tests/coverage/run/parameterless/test.scala new file mode 100644 index 000000000000..1de9f739d507 --- /dev/null +++ b/tests/coverage/run/parameterless/test.scala @@ -0,0 +1,25 @@ +object O: + def f: String = + println("O.f") + "O.f_res" + + def g[T]: String = + println("O.g") + "O.g_res" + +@main +def Test: Unit = + def f: String = + println("f") + "f_res" + + def g[T]: String = + println("g") + "g_res" + + val x = f + val y = g + println(f) + println(g) + println(O.f) + println(O.g) diff --git a/tests/coverage/run/parameterless/test.scoverage.check b/tests/coverage/run/parameterless/test.scoverage.check new file mode 100644 index 000000000000..dae3f6775e60 --- /dev/null +++ b/tests/coverage/run/parameterless/test.scoverage.check @@ -0,0 +1,344 @@ +# 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 +parameterless/test.scala + +O$ +Object +.O$ +f +32 +46 +2 +println +Apply +false +0 +false +println("O.f") + +1 +parameterless/test.scala + +O$ +Object +.O$ +f +12 +17 +1 +f +DefDef +false +0 +false +def f + +2 +parameterless/test.scala + +O$ +Object +.O$ +g +87 +101 +6 +println +Apply +false +0 +false +println("O.g") + +3 +parameterless/test.scala + +O$ +Object +.O$ +g +64 +69 +5 +g +DefDef +false +0 +false +def g + +4 +parameterless/test.scala + +test$package$ +Object +.test$package$ +f +162 +174 +12 +println +Apply +false +0 +false +println("f") + +5 +parameterless/test.scala + +test$package$ +Object +.test$package$ +f +142 +147 +11 +f +DefDef +false +0 +false +def f + +6 +parameterless/test.scala + +test$package$ +Object +.test$package$ +g +213 +225 +16 +println +Apply +false +0 +false +println("g") + +7 +parameterless/test.scala + +test$package$ +Object +.test$package$ +g +190 +195 +15 +g +DefDef +false +0 +false +def g + +8 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +249 +250 +19 +f +Ident +false +0 +false +f + +9 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +261 +262 +20 +g +Ident +false +0 +false +g + +10 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +273 +274 +21 +f +Ident +false +0 +false +f + +11 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +265 +275 +21 +println +Apply +false +0 +false +println(f) + +12 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +286 +287 +22 +g +Ident +false +0 +false +g + +13 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +278 +288 +22 +println +Apply +false +0 +false +println(g) + +14 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +299 +302 +23 +f +Select +false +0 +false +O.f + +15 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +291 +303 +23 +println +Apply +false +0 +false +println(O.f) + +16 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +314 +317 +24 +g +Select +false +0 +false +O.g + +17 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +306 +318 +24 +println +Apply +false +0 +false +println(O.g) + +18 +parameterless/test.scala + +test$package$ +Object +.test$package$ +Test +117 +131 +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 dcc93e2a7809..d48e14eacf08 100644 --- a/tests/coverage/run/trait/test.scoverage.check +++ b/tests/coverage/run/trait/test.scoverage.check @@ -110,6 +110,23 @@ test$package$ Object .test$package$ Test +178 +187 +11 +x +Select +false +0 +false +Impl1().x + +6 +trait/test.scala + +test$package$ +Object +.test$package$ +Test 170 188 11 @@ -120,7 +137,7 @@ false false println(Impl1().x) -6 +7 trait/test.scala test$package$ @@ -137,7 +154,7 @@ false false Impl2() -7 +8 trait/test.scala test$package$ @@ -154,7 +171,7 @@ false false println(Impl2().p) -8 +9 trait/test.scala test$package$ @@ -171,7 +188,7 @@ false false Impl3() -9 +10 trait/test.scala test$package$ @@ -188,7 +205,7 @@ false false println(Impl3().p) -10 +11 trait/test.scala test$package$ From 955db89fc579aa1d30242d919cfd1b307429b623 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Tue, 12 Jul 2022 11:08:02 +0200 Subject: [PATCH 3/5] Code cleanup --- .../dotty/tools/dotc/transform/InstrumentCoverage.scala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index edc1f5af5668..1d619e24b4dd 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -2,7 +2,6 @@ package dotty.tools.dotc package transform import java.io.File -import java.util.concurrent.atomic.AtomicInteger import ast.tpd.* import collection.mutable @@ -13,10 +12,10 @@ import core.Symbols.{defn, Symbol} import core.Constants.Constant import core.NameOps.isContextFunction import core.Types.* +import coverage.* import typer.LiftCoverage -import util.{SourcePosition, Property} +import util.SourcePosition import util.Spans.Span -import coverage.* import localopt.StringInterpolatorOpt /** Implements code coverage by inserting calls to scala.runtime.coverage.Invoker @@ -43,7 +42,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: val outputPath = ctx.settings.coverageOutputDir.value // Ensure the dir exists - val dataDir = new File(outputPath) + val dataDir = File(outputPath) val newlyCreated = dataDir.mkdirs() if !newlyCreated then @@ -189,7 +188,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: private def recordStatement(tree: Tree, pos: SourcePosition, branch: Boolean)(using ctx: Context): Int = val id = statementId statementId += 1 - val statement = new Statement( + val statement = Statement( source = ctx.source.file.name, location = Location(tree), id = id, From c9eceb493244433c2d5c66080295da78e7bcc8f1 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Fri, 22 Jul 2022 15:01:03 +0200 Subject: [PATCH 4/5] Exclude methods of scala.compiletime from coverage instrumentation --- .../dotc/transform/InstrumentCoverage.scala | 6 +++++- .../pos/CompiletimeUninitialized.scala | 5 +++++ .../CompiletimeUninitialized.scoverage.check | 20 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/coverage/pos/CompiletimeUninitialized.scala create mode 100644 tests/coverage/pos/CompiletimeUninitialized.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 1d619e24b4dd..28ac9b890fd3 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -344,7 +344,11 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: */ private def isCompilerIntrinsicMethod(sym: Symbol)(using Context): Boolean = val owner = sym.maybeOwner - owner.eq(defn.AnyClass) || owner.isPrimitiveValueClass + owner.exists && ( + owner.eq(defn.AnyClass) || + owner.isPrimitiveValueClass || + owner.maybeOwner == defn.CompiletimePackageClass + ) object InstrumentCoverage: val name: String = "instrumentCoverage" diff --git a/tests/coverage/pos/CompiletimeUninitialized.scala b/tests/coverage/pos/CompiletimeUninitialized.scala new file mode 100644 index 000000000000..f5ea8eb153fe --- /dev/null +++ b/tests/coverage/pos/CompiletimeUninitialized.scala @@ -0,0 +1,5 @@ +package covtest + +import scala.compiletime.uninitialized +class Foo: + var x: AnyRef = uninitialized diff --git a/tests/coverage/pos/CompiletimeUninitialized.scoverage.check b/tests/coverage/pos/CompiletimeUninitialized.scoverage.check new file mode 100644 index 000000000000..1bdba951d6ae --- /dev/null +++ b/tests/coverage/pos/CompiletimeUninitialized.scoverage.check @@ -0,0 +1,20 @@ +# 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 +# ------------------------------------------ From ff50a800c1caee52076b3c9364924c37502b0fb0 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sat, 23 Jul 2022 18:25:47 +0200 Subject: [PATCH 5/5] Keep fun and args together when instrumenting TypeApply, fixes #15705 --- .../dotc/transform/InstrumentCoverage.scala | 35 +++++- .../coverage/pos/PolymorphicExtensions.scala | 11 ++ .../pos/PolymorphicExtensions.scoverage.check | 105 ++++++++++++++++++ tests/coverage/pos/PolymorphicMethods.scala | 10 ++ .../pos/PolymorphicMethods.scoverage.check | 105 ++++++++++++++++++ 5 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 tests/coverage/pos/PolymorphicExtensions.scala create mode 100644 tests/coverage/pos/PolymorphicExtensions.scoverage.check create mode 100644 tests/coverage/pos/PolymorphicMethods.scala create mode 100644 tests/coverage/pos/PolymorphicMethods.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 28ac9b890fd3..1cc1340ad7c7 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -101,7 +101,24 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: // (fun)[args] case TypeApply(fun, args) => - cpy.TypeApply(tree)(transform(fun), args) + val tfun = transform(fun) + tfun match + case InstrumentCoverage.InstrumentedBlock(invokeCall, expr) => + // expr[T] shouldn't be transformed to + // {invoked(...), expr}[T] + // + // but to + // {invoked(...), expr[T]} + // + // This is especially important for trees like (expr[T])(args), + // for which the wrong transformation crashes the compiler. + // See tests/coverage/pos/PolymorphicExtensions.scala + Block( + invokeCall :: Nil, + cpy.TypeApply(tree)(expr, args) + ) + case _ => + cpy.TypeApply(tree)(tfun, args) // a.b case Select(qual, name) => @@ -242,12 +259,12 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: val statementId = recordStatement(parent, pos, false) insertInvokeCall(body, pos, statementId) - /** Returns the tree, prepended by a call to Invoker.invoker */ + /** Returns the tree, prepended by a call to Invoker.invoked */ 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) */ + /** Generates Invoker.invoked(id, DIR) */ private def invokeCall(id: Int, span: Span)(using Context): Tree = val outputPath = ctx.settings.coverageOutputDir.value ref(defn.InvokedMethodRef).withSpan(span) @@ -353,3 +370,15 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: object InstrumentCoverage: val name: String = "instrumentCoverage" val description: String = "instrument code for coverage checking" + + /** Extractor object for trees produced by `insertInvokeCall`. */ + object InstrumentedBlock: + private def isInvokedCall(app: Apply)(using Context): Boolean = + app.span.isSynthetic && app.symbol == defn.InvokedMethodRef.symbol + + def unapply(t: Tree)(using Context): Option[(Apply, Tree)] = + t match + case Block((app: Apply) :: Nil, expr) if isInvokedCall(app) => + Some((app, expr)) + case _ => + None diff --git a/tests/coverage/pos/PolymorphicExtensions.scala b/tests/coverage/pos/PolymorphicExtensions.scala new file mode 100644 index 000000000000..a2bafc451606 --- /dev/null +++ b/tests/coverage/pos/PolymorphicExtensions.scala @@ -0,0 +1,11 @@ +package covtest + +object PolyExt: + extension (s: String) + def foo[A](x: A): A = x + + extension [A](i: Int) + def get(x: A): A = x + + "str".foo(0) // ({foo("str")}[type])(0) i.e. Apply(TypeApply( Apply(foo, "str"), type ), List(0)) + 123.get(0) // {(get[type])(123)}(0) i.e. Apply(Apply(TypeApply(...), List(123)), List(0)) diff --git a/tests/coverage/pos/PolymorphicExtensions.scoverage.check b/tests/coverage/pos/PolymorphicExtensions.scoverage.check new file mode 100644 index 000000000000..e244b529ce0a --- /dev/null +++ b/tests/coverage/pos/PolymorphicExtensions.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 +# ------------------------------------------ +0 +PolymorphicExtensions.scala +covtest +PolyExt$ +Object +covtest.PolyExt$ +foo +61 +68 +4 +foo +DefDef +false +0 +false +def foo + +1 +PolymorphicExtensions.scala +covtest +PolyExt$ +Object +covtest.PolyExt$ +get +114 +121 +7 +get +DefDef +false +0 +false +def get + +2 +PolymorphicExtensions.scala +covtest +PolyExt$ +Object +covtest.PolyExt$ + +138 +147 +9 +foo +Apply +false +0 +false +"str".foo + +3 +PolymorphicExtensions.scala +covtest +PolyExt$ +Object +covtest.PolyExt$ + +138 +150 +9 + +Apply +false +0 +false +"str".foo(0) + +4 +PolymorphicExtensions.scala +covtest +PolyExt$ +Object +covtest.PolyExt$ + +238 +248 +10 +get +Apply +false +0 +false +123.get(0) + diff --git a/tests/coverage/pos/PolymorphicMethods.scala b/tests/coverage/pos/PolymorphicMethods.scala new file mode 100644 index 000000000000..a0cbf102bd5c --- /dev/null +++ b/tests/coverage/pos/PolymorphicMethods.scala @@ -0,0 +1,10 @@ +package covtest + +object PolyMeth: + def f[A](x: A): A = x + this.f(0) // (this.f[type])(0) i.e. Apply(TypeApply(Select(this,f), type), List(0)) + + C[String]().f("str", 0) + +class C[T1]: + def f[T2](p1: T1, p2: T2): Unit = () diff --git a/tests/coverage/pos/PolymorphicMethods.scoverage.check b/tests/coverage/pos/PolymorphicMethods.scoverage.check new file mode 100644 index 000000000000..77615cc6f0bc --- /dev/null +++ b/tests/coverage/pos/PolymorphicMethods.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 +# ------------------------------------------ +0 +PolymorphicMethods.scala +covtest +PolyMeth$ +Object +covtest.PolyMeth$ +f +36 +41 +3 +f +DefDef +false +0 +false +def f + +1 +PolymorphicMethods.scala +covtest +PolyMeth$ +Object +covtest.PolyMeth$ + +60 +69 +4 +f +Apply +false +0 +false +this.f(0) + +2 +PolymorphicMethods.scala +covtest +PolyMeth$ +Object +covtest.PolyMeth$ + +147 +158 +6 + +Apply +false +0 +false +C[String]() + +3 +PolymorphicMethods.scala +covtest +PolyMeth$ +Object +covtest.PolyMeth$ + +147 +170 +6 +f +Apply +false +0 +false +C[String]().f("str", 0) + +4 +PolymorphicMethods.scala +covtest +C +Class +covtest.C +f +187 +192 +9 +f +DefDef +false +0 +false +def f +