JVM: keep call site markers when inlining lambdas into objects

A follow-up for KT-35006:

    fun f() = foo {
        bar()
    }
    inline fun foo(crossinline x: () -> Unit) = { x() }()
    inline fun bar() = TODO()

does not provide the option to navigate to bar's call site at all.
This commit is contained in:
pyos
2020-04-01 09:33:47 +02:00
committed by max-kammerer
parent 5feadd56ef
commit 86b28b95ca
8 changed files with 29 additions and 23 deletions
@@ -290,7 +290,7 @@ class AnonymousObjectTransformer(
remapper,
isSameModule,
"Transformer for " + transformationInfo.oldClassName,
SourceMapCopier(sourceMapper, sourceMap, keepCallSites = inliningContext.isInliningLambda),
SourceMapCopier(sourceMapper, sourceMap),
InlineCallSiteInfo(
transformationInfo.oldClassName,
sourceNode.name,
@@ -72,7 +72,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
var activeLambda: LambdaInfo? = null
protected set
private val defaultSourceMapper = sourceCompiler.lazySourceMapper
private val sourceMapper = sourceCompiler.lazySourceMapper
protected var delayedHiddenWriting: Function0<Unit>? = null
@@ -208,7 +208,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean, isCallOfFunctionInCorrespondingDefaultDispatch: Boolean): InlineResult {
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
if (!isCallOfFunctionInCorrespondingDefaultDispatch) defaultSourceMapper.callSiteMarker = codegen.lastLineNumber
val node = nodeAndSmap.node
if (inlineDefaultLambda) {
for (lambda in extractDefaultLambdas(node)) {
@@ -230,11 +229,13 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
sourceCompiler, sourceCompiler.inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings
)
val sourceInfo = sourceMapper.sourceInfo!!
val callSite = SourcePosition(codegen.lastLineNumber, sourceInfo.source, sourceInfo.pathOrCleanFQN)
val inliner = MethodInliner(
node, parameters, info, FieldRemapper(null, null, parameters), isSameModule,
"Method inlining " + sourceCompiler.callElementText,
SourceMapCopier(defaultSourceMapper, nodeAndSmap.classSMAP), info.callSiteInfo,
if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null,
SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite.takeIf { !isCallOfFunctionInCorrespondingDefaultDispatch }),
info.callSiteInfo, if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null,
!isInlinedToInlineFunInKotlinRuntime()
) //with captured
@@ -269,9 +270,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
if (shouldSpillStack) {
addInlineMarker(codegen.v, false)
}
if (!isCallOfFunctionInCorrespondingDefaultDispatch) defaultSourceMapper.callSiteMarker = null
return result
}
@@ -42,7 +42,7 @@ class InlineCodegenForDefaultBody(
val nodeAndSmap = InlineCodegen.createInlineMethodNode(
function, methodOwner, jvmSignature, callDefault, null, codegen.typeSystem, state, sourceCompilerForInline
)
val childSourceMapper = SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, keepCallSites = true)
val childSourceMapper = SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP)
val node = nodeAndSmap.node
val transformedMethod = MethodNode(
@@ -289,16 +289,13 @@ class MethodInliner(
setLambdaInlining(true)
// TODO we cannot keep call site markers when inlining lambdas into objects because AnonymousObjectTransformer
// uses the original's source info, thus KotlinDebug would point to the file with the inline function
// instead of the one with the call.
val sameFile = info !is DefaultLambda && (!inliningContext.classRegeneration || inliningContext.isInliningLambda)
val callSite = sourceMapper.callSite.takeIf { info is DefaultLambda }
val inliner = MethodInliner(
info.node.node, lambdaParameters, inliningContext.subInlineLambda(info),
newCapturedRemapper,
if (info is DefaultLambda) isSameModule else true /*cause all nested objects in same module as lambda*/,
"Lambda inlining " + info.lambdaClassType.internalName,
SourceMapCopier(sourceMapper.parent, info.node.classSMAP, sameFile), inlineCallSiteInfo, null
SourceMapCopier(sourceMapper.parent, info.node.classSMAP, callSite), inlineCallSiteInfo, null
)
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
@@ -58,7 +58,7 @@ object SMAPBuilder {
lineMappings.joinToString("") { it.toSMAP(id, mapToFirstLine) }
}
class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, private val keepCallSites: Boolean = false) {
class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, val callSite: SourcePosition? = null) {
private val visitedLines = TIntIntHashMap()
private var lastVisitedRange: RangeMapping? = null
@@ -79,10 +79,7 @@ class SourceMapCopier(val parent: SourceMapper, private val smap: SMAP, private
if (inlineSource.line < 0) {
return -1
}
val inlineCallSite = if (keepCallSites) range.callSite else parent.callSiteMarker?.let {
SourcePosition(it, parent.sourceInfo!!.source, parent.sourceInfo.pathOrCleanFQN)
}
val newLineNumber = parent.mapLineNumber(inlineSource, inlineCallSite)
val newLineNumber = parent.mapLineNumber(inlineSource, callSite ?: range.callSite)
visitedLines.put(lineNumber, newLineNumber)
lastVisitedRange = range
return newLineNumber
@@ -95,14 +92,12 @@ class SourceMapper(val sourceInfo: SourceInfo?) {
private var maxUsedValue: Int = sourceInfo?.linesInFile ?: 0
private var fileMappings: LinkedHashMap<Pair<String, String>, FileMapping> = linkedMapOf()
var callSiteMarker: Int? = null
val resultMappings: List<FileMapping>
get() = fileMappings.values.toList()
init {
sourceInfo?.let {
// Explicitly map the file to itself -- we'll probably need a lot of lines from it, so this will produce less ranges.
// Explicitly map the file to itself -- we'll probably need a lot of lines from it, so this will produce fewer ranges.
getOrRegisterNewSource(it.source, it.pathOrCleanFQN).mapNewInterval(1, 1, it.linesInFile)
}
}
@@ -281,7 +281,7 @@ abstract class ClassCodegen protected constructor(
method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE
)
val mv = with(node) { visitor.newMethod(method.OtherOrigin, access, name, desc, signature, exceptions.toTypedArray()) }
val smapCopier = SourceMapCopier(classSMAP, smap, keepCallSites = true)
val smapCopier = SourceMapCopier(classSMAP, smap)
val smapCopyingVisitor = object : MethodVisitor(Opcodes.API_VERSION, mv) {
override fun visitLineNumber(line: Int, start: Label) =
super.visitLineNumber(smapCopier.mapLineNumber(line), start)
@@ -73,4 +73,12 @@ _2Kt
10#2:20
15#2:22
7#3:21
*E
*S KotlinDebug
*F
+ 1 1.kt
test/_1Kt$annotatedWith2$1
*L
6#1:19
6#1:22
*E
@@ -94,3 +94,11 @@ _2Kt
9#2:24
9#3,2:22
*E
*S KotlinDebug
*F
+ 1 1.kt
test/_1Kt$test$1
*L
14#1,2:20
14#1:24
*E