@@ -21,53 +21,54 @@ import dotty.tools.dotc.typer.LiftCoverage
2121
2222import scala .quoted
2323
24- /** Phase that implements code coverage, executed when the "-coverage
25- * OUTPUT_PATH" is added to the compilation.
26- */
27- class CoverageTransformMacro extends MacroTransform with IdentityDenotTransformer {
24+ /** Implements code coverage by inserting calls to scala.runtime.Invoker
25+ * ("instruments" the source code).
26+ * The result can then be consumed by the Scoverage tool.
27+ */
28+ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer :
2829 import ast .tpd ._
2930
30- override def phaseName = " coverage "
31+ override def phaseName = InstrumentCoverage .name
3132
32- // Atomic counter used for assignation of IDs to difference statements
33- val statementId = new AtomicInteger (0 )
33+ override def description = InstrumentCoverage .description
3434
35- var outputPath = " "
35+ // Enabled by argument "-coverage OUTPUT_DIR"
36+ override def isEnabled (using ctx : Context ) =
37+ ctx.settings.coverageOutputDir.value.nonEmpty
3638
37- // Main class used to store all instrumented statements
38- val coverage = new Coverage
39+ // Atomic counter used for assignation of IDs to difference statements
40+ private val statementId = AtomicInteger ( 0 )
3941
40- override def run ( using ctx : Context ) : Unit = {
42+ private var outputPath = " "
4143
42- if (ctx.settings.coverageOutputDir.value.nonEmpty) {
43- outputPath = ctx.settings.coverageOutputDir.value
44+ // Main class used to store all instrumented statements
45+ private val coverage = Coverage ()
4446
45- // Ensure the dir exists
46- val dataDir = new File (outputPath)
47- val newlyCreated = dataDir.mkdirs()
47+ override def run (using ctx : Context ): Unit =
48+ outputPath = ctx.settings.coverageOutputDir.value
4849
49- if (! newlyCreated) {
50- // If the directory existed before, let's clean it up.
51- dataDir.listFiles
52- .filter(_.getName.startsWith(" scoverage" ))
53- .foreach(_.delete)
54- }
50+ // Ensure the dir exists
51+ val dataDir = new File (outputPath)
52+ val newlyCreated = dataDir.mkdirs()
5553
56- super .run
54+ if (! newlyCreated) {
55+ // If the directory existed before, let's clean it up.
56+ dataDir.listFiles
57+ .filter(_.getName.startsWith(" scoverage" ))
58+ .foreach(_.delete)
59+ }
5760
61+ super .run
5862
59- Serializer .serialize(coverage, outputPath, ctx.settings.coverageSourceroot.value)
60- }
61- }
63+ Serializer .serialize(coverage, outputPath, ctx.settings.coverageSourceroot.value)
6264
63- protected def newTransformer (using Context ): Transformer =
64- new CoverageTransormer
65+ override protected def newTransformer (using Context ) = CoverageTransormer ()
6566
66- class CoverageTransormer extends Transformer {
67+ class CoverageTransormer extends Transformer :
6768 var instrumented = false
6869
69- override def transform (tree : Tree )(using Context ): Tree = {
70- tree match {
70+ override def transform (tree : Tree )(using Context ): Tree =
71+ tree match
7172 case tree : If =>
7273 cpy.If (tree)(
7374 cond = transform(tree.cond),
@@ -139,10 +140,8 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme
139140 tree.sourcePos
140141 )
141142 super .transform(tree)
142- }
143- }
144143
145- def liftApply (tree : Apply )(using Context ) = {
144+ def liftApply (tree : Apply )(using Context ) =
146145 val buffer = mutable.ListBuffer [Tree ]()
147146 // NOTE: that if only one arg needs to be lifted, we just lift everything
148147 val lifted = LiftCoverage .liftForCoverage(buffer, tree)
@@ -156,22 +155,18 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme
156155 false
157156 )
158157 )
159- }
160158
161- def instrumentCasees (cases : List [CaseDef ])(using Context ): List [CaseDef ] = {
159+ def instrumentCasees (cases : List [CaseDef ])(using Context ): List [CaseDef ] =
162160 cases.map(instrumentCaseDef)
163- }
164161
165- def instrumentCaseDef (tree : CaseDef )(using Context ): CaseDef = {
162+ def instrumentCaseDef (tree : CaseDef )(using Context ): CaseDef =
166163 cpy.CaseDef (tree)(tree.pat, transform(tree.guard), transform(tree.body))
167- }
168164
169- def instrument (tree : Tree , branch : Boolean = false )(using Context ): Tree = {
165+ def instrument (tree : Tree , branch : Boolean = false )(using Context ): Tree =
170166 instrument(tree, tree.sourcePos, branch)
171- }
172167
173- def instrument (tree : Tree , pos : SourcePosition , branch : Boolean )(using ctx : Context ): Tree = {
174- if (pos.exists && ! pos.span.isZeroExtent && ! tree.isType) {
168+ def instrument (tree : Tree , pos : SourcePosition , branch : Boolean )(using ctx : Context ): Tree =
169+ if (pos.exists && ! pos.span.isZeroExtent && ! tree.isType)
175170 val id = statementId.incrementAndGet()
176171 val statement = new Statement (
177172 source = ctx.source.file.name,
@@ -187,18 +182,16 @@ class CoverageTransformMacro extends MacroTransform with IdentityDenotTransforme
187182 )
188183 coverage.addStatement(statement)
189184 Block (List (invokeCall(id)), tree)
190- } else {
185+ else
191186 tree
192- }
193- }
194187
195- def invokeCall (id : Int )(using Context ): Tree = {
188+ def invokeCall (id : Int )(using Context ): Tree =
196189 ref(defn.InvokerModuleRef )
197190 .select(" invoked" .toTermName)
198191 .appliedToArgs(
199192 List (Literal (Constant (id)), Literal (Constant (outputPath)))
200193 )
201- }
202- }
203194
204- }
195+ object InstrumentCoverage :
196+ val name : String = " instrumentCoverage"
197+ val description : String = " instrument code for coverage cheking"
0 commit comments