JVM_IR: fix source file name for mutlifile class facades

This commit is contained in:
Dmitry Petrov
2020-07-24 15:46:49 +03:00
parent 89a0b3e944
commit 43fcb2330e
15 changed files with 128 additions and 26 deletions
@@ -726,7 +726,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
public SourceMapper getOrCreateSourceMapper() {
if (sourceMapper == null) {
// note: this is used in InlineCodegen and the element is always physical (KtElement) there
sourceMapper = new SourceMapper(SourceInfo.Companion.createInfo((KtElement)element, getClassName()));
sourceMapper = new SourceMapper(SourceInfo.Companion.createFromPsi((KtElement)element, getClassName()));
}
return sourceMapper;
}
@@ -21,28 +21,26 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
data class SourceInfo(val source: String, val pathOrCleanFQN: String, val linesInFile: Int) {
data class SourceInfo(
val sourceFileName: String?,
val pathOrCleanFQN: String,
val linesInFile: Int
) {
companion object {
fun createInfo(element: KtElement?, internalClassName: String): SourceInfo {
fun createFromPsi(element: KtElement?, internalClassName: String): SourceInfo {
assert(element != null) { "Couldn't create source mapper for null element $internalClassName" }
val lineNumbers = CodegenUtil.getLineNumberForElement(element!!.containingFile, true)
?: error("Couldn't extract line count in ${element.containingFile}")
?: error("Couldn't extract line count in ${element.containingFile}")
//TODO hack condition for package parts cleaning
val isTopLevel = element is KtFile || (element is KtNamedFunction && element.getParent() is KtFile)
val cleanedClassFqName = if (!isTopLevel) internalClassName else internalClassName.substringBefore('$')
return SourceInfo(element.containingKtFile.name, cleanedClassFqName, lineNumbers)
val fileName = element.containingKtFile.name
return SourceInfo(fileName, cleanedClassFqName, lineNumbers)
}
fun createInfoForIr(lineNumbers: Int, internalClassName: String, containingFileName: String): SourceInfo {
//TODO cut topLevel names
// val isTopLevel = element is KtFile || (element is KtNamedFunction && element.getParent() is KtFile)
// val cleanedClassFqName = if (!isTopLevel) internalClassName else internalClassName.substringBefore('$')
return SourceInfo(containingFileName, internalClassName, lineNumbers)
}
}
}
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.incremental.components.ScopeKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -28,10 +27,8 @@ import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
@@ -233,7 +230,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
)
val sourceInfo = sourceMapper.sourceInfo!!
val callSite = SourcePosition(codegen.lastLineNumber, sourceInfo.source, sourceInfo.pathOrCleanFQN)
val callSite = SourcePosition(codegen.lastLineNumber, sourceInfo.sourceFileName!!, sourceInfo.pathOrCleanFQN)
val inliner = MethodInliner(
node, parameters, info, FieldRemapper(null, null, parameters), isSameModule,
"Method inlining " + sourceCompiler.callElementText,
@@ -85,9 +85,14 @@ class SourceMapper(val sourceInfo: SourceInfo?) {
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 fewer ranges.
getOrRegisterNewSource(it.source, it.pathOrCleanFQN).mapNewInterval(1, 1, it.linesInFile)
sourceInfo?.let { sourceInfo ->
// If 'sourceFileName' is null, this class doesn't have debug information
// (e.g., multi-file class facade with multiple parts).
sourceInfo.sourceFileName?.let { sourceFileName ->
// Explicitly map the file to itself -- we'll probably need a lot of lines from it, so this will produce fewer ranges.
getOrRegisterNewSource(sourceFileName, sourceInfo.pathOrCleanFQN)
.mapNewInterval(1, 1, sourceInfo.linesInFile)
}
}
}
@@ -153,7 +153,9 @@ abstract class ClassCodegen protected constructor(
if (withinInline || !smap.isTrivial) {
visitor.visitSMAP(smap, !context.state.languageVersionSettings.supportsFeature(LanguageFeature.CorrectSourceMappingSyntax))
} else {
visitor.visitSource(smap.sourceInfo!!.source, null)
smap.sourceInfo!!.sourceFileName?.let {
visitor.visitSource(it, null)
}
}
visitor.done()
@@ -87,15 +87,19 @@ fun JvmBackendContext.getSourceMapper(declaration: IrClass): SourceMapper {
// NOTE: apparently inliner requires the source range to cover the
// whole file the class is declared in rather than the class only.
// TODO: revise
val endLineNumber = when {
fileEntry is MultifileFacadeFileEntry -> 0
val endLineNumber = when (fileEntry) {
is MultifileFacadeFileEntry -> 0
else -> fileEntry?.getSourceRangeInfo(0, fileEntry.maxOffset)?.endLineNumber ?: 0
}
val sourceFileName = when (fileEntry) {
is MultifileFacadeFileEntry -> fileEntry.partFiles.singleOrNull()?.name
else -> declaration.fileParent.name
}
return SourceMapper(
SourceInfo.createInfoForIr(
endLineNumber + 1,
SourceInfo(
sourceFileName,
typeMapper.mapClass(declaration).internalName,
declaration.fileParent.name
endLineNumber + 1
)
)
}
@@ -1,6 +1,6 @@
@kotlin.Metadata
public final class Hello/Foo {
// source: 'Foo>'
// source: 'multifileSuspend.kt'
public final static method main(@org.jetbrains.annotations.NotNull p0: java.lang.String[]): void
public final static @org.jetbrains.annotations.Nullable method main(@org.jetbrains.annotations.NotNull p0: java.lang.String[], @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
// FILE: part1.kt
@file:JvmMultifileClass
@file:JvmName("MultiFileClass")
fun foo() {}
// FILE: part2.kt
@file:JvmMultifileClass
@file:JvmName("MultiFileClass")
fun bar() {}
@@ -0,0 +1,17 @@
@kotlin.Metadata
public final class MultiFileClass {
public final static method bar(): void
public final static method foo(): void
}
@kotlin.Metadata
synthetic final class MultiFileClass__Part1Kt {
// source: 'part1.kt'
public final static method foo(): void
}
@kotlin.Metadata
synthetic final class MultiFileClass__Part2Kt {
// source: 'part2.kt'
public final static method bar(): void
}
@@ -0,0 +1,19 @@
@kotlin.Metadata
public final class MultiFileClass {
public final static method bar(): void
public final static method foo(): void
}
@kotlin.Metadata
@kotlin.jvm.JvmName
synthetic final class MultiFileClass__Part1Kt {
// source: 'part1.kt'
public final static method foo(): void
}
@kotlin.Metadata
@kotlin.jvm.JvmName
synthetic final class MultiFileClass__Part2Kt {
// source: 'part2.kt'
public final static method bar(): void
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
@file:JvmMultifileClass
@file:JvmName("MultiFileClass")
fun foo() {}
@@ -0,0 +1,11 @@
@kotlin.Metadata
public final class MultiFileClass {
// source: 'multiClassPartSourceSinglePart.kt'
public final static method foo(): void
}
@kotlin.Metadata
synthetic final class MultiFileClass__MultiClassPartSourceSinglePartKt {
// source: 'multiClassPartSourceSinglePart.kt'
public final static method foo(): void
}
@@ -0,0 +1,12 @@
@kotlin.Metadata
public final class MultiFileClass {
// source: 'multiClassPartSourceSinglePart.kt'
public final static method foo(): void
}
@kotlin.Metadata
@kotlin.jvm.JvmName
synthetic final class MultiFileClass__MultiClassPartSourceSinglePartKt {
// source: 'multiClassPartSourceSinglePart.kt'
public final static method foo(): void
}
@@ -104,6 +104,16 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
}
@TestMetadata("multiClassPartSourceMultipleParts.kt")
public void testMultiClassPartSourceMultipleParts() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/multiClassPartSourceMultipleParts.kt");
}
@TestMetadata("multiClassPartSourceSinglePart.kt")
public void testMultiClassPartSourceSinglePart() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/multiClassPartSourceSinglePart.kt");
}
@TestMetadata("noCollectionStubMethodsInInterface.kt")
public void testNoCollectionStubMethodsInInterface() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/noCollectionStubMethodsInInterface.kt");
@@ -104,6 +104,16 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
}
@TestMetadata("multiClassPartSourceMultipleParts.kt")
public void testMultiClassPartSourceMultipleParts() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/multiClassPartSourceMultipleParts.kt");
}
@TestMetadata("multiClassPartSourceSinglePart.kt")
public void testMultiClassPartSourceSinglePart() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/multiClassPartSourceSinglePart.kt");
}
@TestMetadata("noCollectionStubMethodsInInterface.kt")
public void testNoCollectionStubMethodsInInterface() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/noCollectionStubMethodsInInterface.kt");