-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add in initial support for code coverage #13880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
28bc87e
Add in initial support for code coverage.
ckipp01 a4549e7
Move coverage phase to before FirstTransform and handle more trees
TheElectronWill b172922
Improve Invoker performance with a BitSet
TheElectronWill d37d13b
Mark Invoker as sharable to bypass -Ycheck-reentrant
TheElectronWill cb66c7a
Cut coverage tests in small parts and avoid lifting literals
TheElectronWill bad8b86
Fix contexts in instrumentCoverage
TheElectronWill a8a6439
Standardize coverage tests
TheElectronWill 570aa50
Fix coverage instrumentation for curried and context functions
TheElectronWill 9c01e86
Add aliases to coverage options
TheElectronWill 0d9bf9a
Move Invoker to scala.runtime.coverage
TheElectronWill c2bc0a0
Check the runtime output of some coverage tests
TheElectronWill a1d0e64
Cleanup coverage instrumentation
TheElectronWill 169593d
Make Trees.transformCtx return the local context if needed
TheElectronWill 3f71cd7
Ensure that cases and DefDefs are always instrumented for coverage
TheElectronWill 2fc33a3
Make testCompilation run coverage tests
TheElectronWill File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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: | ||
TheElectronWill marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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 hidden or 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 = | ||
TheElectronWill marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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 hidden or 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 | ||
TheElectronWill marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.