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:
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+8
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user