-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13880 from ckipp01/coverage
Add in initial support for code coverage
- Loading branch information
Showing
57 changed files
with
5,015 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package dotty.tools.dotc | ||
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) | ||
|
||
def statements: Iterable[Statement] = statementsById.values | ||
|
||
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, | ||
id: Int, | ||
start: Int, | ||
end: Int, | ||
line: Int, | ||
desc: String, | ||
symbolName: String, | ||
treeName: String, | ||
branch: Boolean, | ||
ignored: Boolean = false | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package dotty.tools.dotc | ||
package coverage | ||
|
||
import ast.tpd._ | ||
import dotty.tools.dotc.core.Contexts.Context | ||
import dotty.tools.dotc.core.Flags.* | ||
import java.nio.file.Path | ||
|
||
/** 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, | ||
className: String, | ||
fullClassName: String, | ||
classType: String, | ||
method: 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 | ||
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", | ||
classType, | ||
ctx.owner.denot.enclosingMethod.name.toSimpleName.toString(), | ||
ctx.source.file.absolute.jpath | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package dotty.tools.dotc | ||
package coverage | ||
|
||
import java.nio.file.{Path, Paths, Files} | ||
import java.io.Writer | ||
import scala.language.unsafeNulls | ||
|
||
/** | ||
* Serializes scoverage data. | ||
* @see https://github.com/scoverage/scalac-scoverage-plugin/blob/main/scalac-scoverage-plugin/src/main/scala/scoverage/Serializer.scala | ||
*/ | ||
object Serializer: | ||
|
||
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, Paths.get(dataDir, CoverageFileName).toAbsolutePath, Paths.get(sourceRoot).toAbsolutePath) | ||
|
||
/** 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() | ||
|
||
/** 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: Path): String = | ||
val relPath = sourceRoot.relativize(filePath) | ||
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 = | ||
// 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} | ||
|${stmt.location.className} | ||
|${stmt.location.classType} | ||
|${stmt.location.fullClassName} | ||
|${stmt.location.method} | ||
|${stmt.start} | ||
|${stmt.end} | ||
|${stmt.line} | ||
|${stmt.symbolName} | ||
|${stmt.treeName} | ||
|${stmt.branch} | ||
|0 | ||
|${stmt.ignored} | ||
|${stmt.desc} | ||
|\f | ||
|""".stripMargin) | ||
|
||
writeHeader(writer) | ||
coverage.statements.toSeq | ||
.sortBy(_.id) | ||
.foreach(stmt => writeStatement(stmt, writer)) |
Oops, something went wrong.