Skip to content

Commit 8e8ec25

Browse files
committed
Fixed inlines in scoverage not being repositioned
1 parent 9fee541 commit 8e8ec25

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import util.{SourcePosition, SourceFile}
1919
import util.Spans.Span
2020
import localopt.StringInterpolatorOpt
2121
import inlines.Inlines
22+
import dotty.tools.dotc.ast.tpd
23+
import dotty.tools.dotc.ast.untpd
2224

2325
/** Implements code coverage by inserting calls to scala.runtime.coverage.Invoker
2426
* ("instruments" the source code).
@@ -300,7 +302,64 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer:
300302
// But PostTyper simplifies tree.call, so we can't report the actual method that was inlined.
301303
// In any case, the subtrees need to be repositioned right now, otherwise the
302304
// coverage statement will point to a potentially unreachable source file.
303-
val dropped = Inlines.dropInlined(tree) // drop and reposition
305+
306+
/** Replace `Inlined` node by a block that contains its bindings and expansion */
307+
def dropInlinedInstrumentaton(inlined: Inlined)(using Context): Tree =
308+
val tree1 =
309+
if inlined.bindings.isEmpty then inlined.expansion
310+
else cpy.Block(inlined)(inlined.bindings, inlined.expansion)
311+
// Reposition in the outer most inlined call
312+
if (enclosingInlineds.nonEmpty) tree1 else reposition(tree1, inlined.span)
313+
314+
def reposition(tree: Tree, callSpan: Span)(using Context): Tree =
315+
// Reference test tests/run/i4947b
316+
317+
val curSource = ctx.compilationUnit.source
318+
319+
// Tree copier that changes the source of all trees to `curSource`
320+
val cpyWithNewSource = new TypedTreeCopier {
321+
override protected def sourceFile(tree: tpd.Tree): SourceFile = curSource
322+
override protected val untpdCpy: untpd.UntypedTreeCopier = new untpd.UntypedTreeCopier {
323+
override protected def sourceFile(tree: untpd.Tree): SourceFile = curSource
324+
}
325+
}
326+
327+
/** Removes all Inlined trees, replacing them with blocks.
328+
* Repositions all trees directly inside an inlined expansion of a non empty call to the position of the call.
329+
* Any tree directly inside an empty call (inlined in the inlined code) retains their position.
330+
*
331+
* Until we implement JSR-45, we cannot represent in output positions in other source files.
332+
* So, reposition inlined code from other files with the call position.
333+
*/
334+
class Reposition extends TreeMap(cpyWithNewSource) {
335+
336+
override def transform(tree: Tree)(using Context): Tree = {
337+
def fixSpan[T <: untpd.Tree](copied: T): T =
338+
copied.withSpan(if tree.source == curSource then tree.span else callSpan)
339+
def finalize(copied: untpd.Tree) =
340+
fixSpan(copied).withAttachmentsFrom(tree).withTypeUnchecked(tree.tpe)
341+
342+
inContext(ctx.withSource(curSource)) {
343+
tree match
344+
case tree: Ident => finalize(untpd.Ident(tree.name)(curSource))
345+
case tree: Literal => finalize(untpd.Literal(tree.const)(curSource))
346+
case tree: This => finalize(untpd.This(tree.qual)(curSource))
347+
case tree: JavaSeqLiteral => finalize(untpd.JavaSeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource))
348+
case tree: SeqLiteral => finalize(untpd.SeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource))
349+
case tree: Bind => finalize(untpd.Bind(tree.name, transform(tree.body))(curSource))
350+
case tree: TypeTree => finalize(tpd.TypeTree(tree.tpe))
351+
case tree: DefTree => super.transform(tree).setDefTree
352+
case EmptyTree => tree
353+
case _ => fixSpan(super.transform(tree))
354+
}
355+
}
356+
}
357+
358+
(new Reposition).transform(tree)
359+
end reposition
360+
361+
362+
val dropped = dropInlinedInstrumentaton(tree) // drop and reposition
304363
transform(dropped) // transform the content of the Inlined
305364

306365
// For everything else just recurse and transform

0 commit comments

Comments
 (0)