@@ -6,18 +6,16 @@ import java.util.concurrent.atomic.AtomicInteger
6
6
7
7
import collection .mutable
8
8
import core .Flags .JavaDefined
9
- import dotty .tools .dotc .core .Contexts .Context
10
- import dotty .tools .dotc .core .DenotTransformers .IdentityDenotTransformer
11
- import dotty .tools .dotc .coverage .Coverage
12
- import dotty .tools .dotc .coverage .Statement
13
- import dotty .tools .dotc .coverage .Serializer
14
- import dotty .tools .dotc .coverage .Location
15
- import dotty .tools .dotc .core .Symbols .defn
16
- import dotty .tools .dotc .core .Symbols .Symbol
17
- import dotty .tools .dotc .core .Decorators .toTermName
18
- import dotty .tools .dotc .util .{SourcePosition , Property }
19
- import dotty .tools .dotc .core .Constants .Constant
20
- import dotty .tools .dotc .typer .LiftCoverage
9
+ import core .Contexts .{Context , ctx , inContext }
10
+ import core .DenotTransformers .IdentityDenotTransformer
11
+ import core .Symbols .{defn , Symbol }
12
+ import core .Decorators .{toTermName , i }
13
+ import core .Constants .Constant
14
+ import typer .LiftCoverage
15
+ import util .{SourcePosition , Property }
16
+ import util .Spans .Span
17
+ import coverage .*
18
+ import dotty .tools .dotc .util .SourceFile
21
19
22
20
/** Implements code coverage by inserting calls to scala.runtime.Invoker
23
21
* ("instruments" the source code).
@@ -105,7 +103,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
105
103
val transformed = cpy.Apply (tree)(transformedFun, args) // args will be transformed in instrumentLifted
106
104
instrumentLifted(transformed)(using ignoreLiteralsContext)
107
105
else
108
- val transformed = cpy.Apply (tree)(transformedFun, transform(args))
106
+ val transformed = cpy.Apply (tree)(transformedFun, transform(args)( using ignoreLiteralsContext) )
109
107
instrument(transformed)(using ignoreLiteralsContext)
110
108
111
109
// f(args)
@@ -136,41 +134,47 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
136
134
137
135
case tree : CaseDef => instrumentCaseDef(tree)
138
136
case tree : ValDef =>
139
- // only transform the rhs
140
- cpy.ValDef (tree)(rhs = transform(tree.rhs))
137
+ // only transform the rhs, in the local context
138
+ val rhs = transform(tree.rhs)(using localCtx(tree))
139
+ cpy.ValDef (tree)(rhs= rhs)
140
+
141
+ case tree : DefDef =>
142
+ // only transform the params (for the default values) and the rhs
143
+ val defCtx = localCtx(tree)
144
+ val paramss = transformParamss(tree.paramss)(using defCtx)
145
+ val rhs = transform(tree.rhs)(using defCtx)
146
+ cpy.DefDef (tree)(tree.name, paramss, tree.tpt, rhs)
141
147
142
148
case tree : PackageDef =>
143
149
// only transform the statements of the package
144
- cpy.PackageDef (tree)(tree.pid, transform(tree.stats))
150
+ cpy.PackageDef (tree)(tree.pid, transform(tree.stats)( using localCtx(tree)) )
145
151
case tree : Assign =>
146
152
// only transform the rhs
147
153
cpy.Assign (tree)(tree.lhs, transform(tree.rhs))
148
- case tree : Template =>
149
- // Don't instrument the parents (extends) of a template since it
150
- // causes problems if the parent constructor takes parameters
151
- cpy.Template (tree)(
152
- constr = super .transformSub(tree.constr),
153
- body = transform(tree.body)
154
- )
155
154
156
155
// For everything else just recurse and transform
156
+ // Special care for Templates: it's important to set the owner of the `stats`, like super.transform
157
157
case _ =>
158
158
super .transform(tree)
159
159
160
+ /** Lifts and instruments an application.
161
+ * Note that if only one arg needs to be lifted, we just lift everything.
162
+ */
160
163
def instrumentLifted (tree : Apply )(using Context ) =
161
- val buffer = mutable.ListBuffer [Tree ]()
162
- // NOTE: that if only one arg needs to be lifted, we just lift everything
163
- val lifted = LiftCoverage .liftForCoverage(buffer, tree)
164
- val instrumented = buffer.toList.map(transform)
165
- // We can now instrument the apply as it is with a custom position to point to the function
166
- Block (
167
- instrumented,
168
- instrument(
169
- lifted,
170
- tree.sourcePos,
171
- false
172
- )
173
- )
164
+ // withSource is necessary to position inlined code properly
165
+ inContext(ctx.withSource(tree.source)) {
166
+ // lifting
167
+ val buffer = mutable.ListBuffer [Tree ]()
168
+ val liftedApply = LiftCoverage .liftForCoverage(buffer, tree)
169
+
170
+ // instrumentation
171
+ val instrumentedArgs = buffer.toList.map(transform)
172
+ val instrumentedApply = instrument(liftedApply)
173
+ Block (
174
+ instrumentedArgs,
175
+ instrumentedApply
176
+ ).withSpan(instrumentedApply.span)
177
+ }
174
178
175
179
def instrumentCases (cases : List [CaseDef ])(using Context ): List [CaseDef ] =
176
180
cases.map(instrumentCaseDef)
@@ -197,16 +201,19 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
197
201
branch
198
202
)
199
203
coverage.addStatement(statement)
200
- Block (List (invokeCall(id)), tree)
204
+ inContext(ctx.withSource(tree.source)) {
205
+ val span = Span (pos.start, pos.end) // synthetic span
206
+ Block (List (invokeCall(id, span)), tree).withSpan(span)
207
+ }
201
208
else
202
209
tree
203
210
204
- def invokeCall (id : Int )(using Context ): Tree =
205
- ref(defn.InvokerModuleRef )
206
- .select(" invoked" .toTermName)
211
+ def invokeCall (id : Int , span : Span )(using Context ): Tree =
212
+ ref(defn.InvokerModuleRef ).withSpan(span)
213
+ .select(" invoked" .toTermName).withSpan(span)
207
214
.appliedToArgs(
208
215
List (Literal (Constant (id)), Literal (Constant (outputPath)))
209
- )
216
+ ).withSpan(span)
210
217
211
218
/**
212
219
* Checks if the apply needs a lift in the coverage phase.
0 commit comments