Skip to content

Commit a1d0e64

Browse files
TheElectronWillsmarter
authored andcommitted
Cleanup coverage instrumentation
1 parent c2bc0a0 commit a1d0e64

File tree

11 files changed

+172
-157
lines changed

11 files changed

+172
-157
lines changed

NOTICE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ major authors were omitted by oversight.
8888
docs/js/. Please refer to the license header of the concerned files for
8989
details.
9090

91+
* dotty.tools.dotc.coverage: Coverage instrumentation utilities have been
92+
adapted from the scoverage plugin for scala 2 [5], which is under the
93+
Apache 2.0 license.
94+
9195
* The Dotty codebase contains parts which are derived from
9296
the ScalaPB protobuf library [4], which is under the Apache 2.0 license.
9397

@@ -96,3 +100,4 @@ major authors were omitted by oversight.
96100
[2] https://github.com/adriaanm/scala/tree/sbt-api-consolidate/src/compiler/scala/tools/sbt
97101
[3] https://github.com/sbt/sbt/tree/0.13/compile/interface/src/main/scala/xsbt
98102
[4] https://github.com/lampepfl/dotty/pull/5783/files
103+
[5] https://github.com/scoverage/scalac-scoverage-plugin

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,13 +1367,19 @@ object Trees {
13671367
/** The context to use when mapping or accumulating over a tree */
13681368
def localCtx(tree: Tree)(using Context): Context
13691369

1370+
/** The context to use when transforming a tree.
1371+
* It ensures that the source information is correct.
1372+
* TODO: ensure transform is always called with the correct context as argument
1373+
* @see https://github.com/lampepfl/dotty/pull/13880#discussion_r836395977
1374+
*/
1375+
def transformCtx(tree: Tree)(using Context): Context =
1376+
if tree.source.exists && tree.source != ctx.source
1377+
then ctx.withSource(tree.source)
1378+
else ctx
1379+
13701380
abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { self =>
13711381
def transform(tree: Tree)(using Context): Tree = {
1372-
inContext(
1373-
if tree.source != ctx.source && tree.source.exists
1374-
then ctx.withSource(tree.source)
1375-
else ctx
1376-
){
1382+
inContext(transformCtx(tree)){
13771383
Stats.record(s"TreeMap.transform/$getClass")
13781384
if (skipTransform(tree)) tree
13791385
else tree match {

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ trait CommonScalaSettings:
116116
val explainTypes: Setting[Boolean] = BooleanSetting("-explain-types", "Explain type errors in more detail (deprecated, use -explain instead).", aliases = List("--explain-types", "-explaintypes"))
117117
val unchecked: Setting[Boolean] = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked"))
118118
val language: Setting[List[String]] = MultiStringSetting("-language", "feature", "Enable one or more language features.", aliases = List("--language"))
119+
119120
/* Coverage settings */
120121
val coverageOutputDir = PathSetting("-coverage-out", "Destination for coverage classfiles and instrumentation data.", "", aliases = List("--coverage-out"))
121-
val coverageSourceroot = PathSetting("-coverage-sourceroot", "An alternative root dir of your sources used to relativize.", ".", aliases = List("--coverage-sourceroot"))
122122

123123
/* Other settings */
124124
val encoding: Setting[String] = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding, aliases = List("--encoding"))

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,8 @@ class Definitions {
461461
}
462462
def NullType: TypeRef = NullClass.typeRef
463463

464-
@tu lazy val InvokerModuleRef = requiredModuleRef("scala.runtime.coverage.Invoker")
464+
@tu lazy val InvokerModule = requiredModule("scala.runtime.coverage.Invoker")
465+
@tu lazy val InvokedMethodRef = InvokerModule.requiredMethodRef("invoked")
465466

466467
@tu lazy val ImplicitScrutineeTypeSym =
467468
newPermanentSymbol(ScalaPackageClass, tpnme.IMPLICITkw, EmptyFlags, TypeBounds.empty).entered

compiler/src/dotty/tools/dotc/coverage/Coverage.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package coverage
33

44
import scala.collection.mutable
55

6+
/** Holds a list of statements to include in the coverage reports. */
67
class Coverage:
78
private val statementsById = new mutable.LongMap[Statement](256)
89

910
def statements: Iterable[Statement] = statementsById.values
1011

1112
def addStatement(stmt: Statement): Unit = statementsById(stmt.id) = stmt
1213

14+
/** A statement that can be invoked, and thus counted as "covered" by code coverage tools. */
1315
case class Statement(
1416
source: String,
1517
location: Location,
@@ -24,6 +26,7 @@ case class Statement(
2426
var count: Int = 0,
2527
ignored: Boolean = false
2628
):
29+
/** Records that this statement has been invoked one more time. */
2730
def invoked(): Unit =
2831
count += 1
2932

compiler/src/dotty/tools/dotc/coverage/Location.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,28 @@ package coverage
44
import ast.tpd._
55
import dotty.tools.dotc.core.Contexts.Context
66
import dotty.tools.dotc.core.Flags.*
7+
import java.nio.file.Path
78

8-
/** @param packageName
9-
* the name of the encosing package
10-
* @param className
11-
* the name of the closes enclosing class
12-
* @param fullClassName
13-
* the fully qualified name of the closest enclosing class
9+
/** Information about the location of a coverable piece of code.
10+
*
11+
* @param packageName name of the enclosing package
12+
* @param className name of the closest enclosing class
13+
* @param fullClassName fully qualified name of the closest enclosing class
14+
* @param classType "type" of the closest enclosing class: Class, Trait or Object
15+
* @param method name of the closest enclosing method
16+
* @param sourcePath absolute path of the source file
1417
*/
1518
final case class Location(
1619
packageName: String,
1720
className: String,
1821
fullClassName: String,
1922
classType: String,
2023
method: String,
21-
sourcePath: String
24+
sourcePath: Path
2225
)
2326

2427
object Location:
28+
/** Extracts the location info of a Tree. */
2529
def apply(tree: Tree)(using ctx: Context): Location =
2630

2731
val enclosingClass = ctx.owner.denot.enclosingClass
@@ -39,5 +43,5 @@ object Location:
3943
s"$packageName.$className",
4044
classType,
4145
ctx.owner.denot.enclosingMethod.name.toSimpleName.toString(),
42-
ctx.source.file.absolute.toString()
46+
ctx.source.file.absolute.jpath
4347
)

compiler/src/dotty/tools/dotc/coverage/Serializer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ object Serializer:
3030
*/
3131
def serialize(coverage: Coverage, writer: Writer, sourceRoot: Path): Unit =
3232

33-
def getRelativePath(filePath: String): String =
34-
val relPath = sourceRoot.relativize(Paths.get(filePath).toAbsolutePath)
33+
def getRelativePath(filePath: Path): String =
34+
val relPath = sourceRoot.relativize(filePath)
3535
relPath.toString
3636

3737
def writeHeader(writer: Writer): Unit =

0 commit comments

Comments
 (0)