Generate classes in MultifileClassCodegen exactly the same as in PackageCodegen
Two known issues with generateNonPartClassDeclarations that was here before were the fact that we didn't sort sealed classes and its subclasses which led to NoSuchMethodError (KT-27097), and the fact that we didn't skip expect classes which led to incorrect duplicate JVM class name diagnostic (KT-30843) #KT-27097 Fixed #KT-30843 Fixed
This commit is contained in:
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.psi.KtTypeAlias
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||
@@ -199,7 +198,7 @@ class MultifileClassCodegenImpl(
|
||||
val partType = Type.getObjectType(JvmFileClassUtil.getFileClassInternalName(file))
|
||||
val partContext = state.rootContext.intoMultifileClassPart(packageFragment, facadeClassType, partType, file)
|
||||
|
||||
generateNonPartClassDeclarations(file, partContext)
|
||||
PackageCodegenImpl.generateClassesAndObjectsInFile(file, partContext, state)
|
||||
|
||||
if (!state.generateDeclaredClassFilter.shouldGeneratePackagePart(file) || !file.hasDeclarationsForPartClass()) return
|
||||
|
||||
@@ -214,21 +213,6 @@ class MultifileClassCodegenImpl(
|
||||
addDelegateGenerationTasksForDeclarationsInFile(file, packageFragment, partType)
|
||||
}
|
||||
|
||||
private fun generateNonPartClassDeclarations(file: KtFile, partContext: FieldOwnerContext<PackageFragmentDescriptor>) {
|
||||
for (declaration in file.declarations) {
|
||||
when (declaration) {
|
||||
is KtClassOrObject ->
|
||||
if (state.generateDeclaredClassFilter.shouldGenerateClass(declaration)) {
|
||||
generateClassOrObject(declaration, partContext)
|
||||
}
|
||||
is KtScript ->
|
||||
if (state.generateDeclaredClassFilter.shouldGenerateScript(declaration)) {
|
||||
ScriptCodegen.createScriptCodegen(declaration, state, partContext).generate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDelegateGenerationTasksForDeclarationsInFile(file: KtFile, packageFragment: PackageFragmentDescriptor, partType: Type) {
|
||||
val facadeContext = state.rootContext.intoMultifileClass(packageFragment, facadeClassType, partType)
|
||||
val memberCodegen = createCodegenForDelegatesInMultifileFacade(facadeContext)
|
||||
|
||||
@@ -17,17 +17,10 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.context.PackageContext;
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface PackageCodegen {
|
||||
void generate(@NotNull CompilationErrorHandler errorHandler);
|
||||
|
||||
void generateClassOrObject(@NotNull KtClassOrObject classOrObject, @NotNull PackageContext packagePartContext);
|
||||
|
||||
PackageFragmentDescriptor getPackageFragment();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||
import org.jetbrains.kotlin.codegen.context.PackageContext;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
@@ -82,9 +83,39 @@ public class PackageCodegenImpl implements PackageCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateClassesAndObjectsInFile(@NotNull List<KtClassOrObject> classOrObjects, @NotNull PackageContext packagePartContext) {
|
||||
for (KtClassOrObject classOrObject : CodegenUtilKt.sortTopLevelClassesAndPrepareContextForSealedClasses(classOrObjects, packagePartContext, state)) {
|
||||
generateClassOrObject(classOrObject, packagePartContext);
|
||||
public static void generateClassesAndObjectsInFile(
|
||||
@NotNull KtFile file,
|
||||
@NotNull CodegenContext<?> context,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
List<KtClassOrObject> classOrObjects = new ArrayList<>();
|
||||
|
||||
for (KtDeclaration declaration : file.getDeclarations()) {
|
||||
if (declaration instanceof KtClassOrObject) {
|
||||
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration);
|
||||
if (PsiUtilsKt.hasExpectModifier(declaration) &&
|
||||
(descriptor == null || !ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
KtClassOrObject classOrObject = (KtClassOrObject) declaration;
|
||||
if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) {
|
||||
classOrObjects.add(classOrObject);
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof KtScript) {
|
||||
KtScript script = (KtScript) declaration;
|
||||
|
||||
if (state.getGenerateDeclaredClassFilter().shouldGenerateScript(script)) {
|
||||
ScriptCodegen.createScriptCodegen(script, state, context).generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<KtClassOrObject> sortedClasses =
|
||||
CodegenUtilKt.sortTopLevelClassesAndPrepareContextForSealedClasses(classOrObjects, context, state);
|
||||
for (KtClassOrObject classOrObject : sortedClasses) {
|
||||
MemberCodegen.genClassOrObject(context, classOrObject, state, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,31 +134,7 @@ public class PackageCodegenImpl implements PackageCodegen {
|
||||
CodeFragmentCodegen.createCodegen((KtCodeFragment) file, state, packagePartContext).generate();
|
||||
}
|
||||
} else {
|
||||
List<KtClassOrObject> classOrObjects = new ArrayList<>();
|
||||
|
||||
for (KtDeclaration declaration : file.getDeclarations()) {
|
||||
if (declaration instanceof KtClassOrObject) {
|
||||
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration);
|
||||
if (PsiUtilsKt.hasExpectModifier(declaration) &&
|
||||
(descriptor == null || !ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
KtClassOrObject classOrObject = (KtClassOrObject) declaration;
|
||||
if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) {
|
||||
classOrObjects.add(classOrObject);
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof KtScript) {
|
||||
KtScript script = (KtScript) declaration;
|
||||
|
||||
if (state.getGenerateDeclaredClassFilter().shouldGenerateScript(script)) {
|
||||
ScriptCodegen.createScriptCodegen(script, state, packagePartContext).generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateClassesAndObjectsInFile(classOrObjects, packagePartContext);
|
||||
generateClassesAndObjectsInFile(file, packagePartContext, state);
|
||||
}
|
||||
|
||||
if (!state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return;
|
||||
@@ -166,11 +173,6 @@ public class PackageCodegenImpl implements PackageCodegen {
|
||||
return fragments.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateClassOrObject(@NotNull KtClassOrObject classOrObject, @NotNull PackageContext packagePartContext) {
|
||||
MemberCodegen.genClassOrObject(packagePartContext, classOrObject, state, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackageFragmentDescriptor getPackageFragment() {
|
||||
return packageFragment;
|
||||
|
||||
@@ -8,12 +8,11 @@ package org.jetbrains.kotlin.codegen
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||
import org.jetbrains.kotlin.codegen.context.MultifileClassFacadeContext
|
||||
import org.jetbrains.kotlin.codegen.context.PackageContext
|
||||
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
|
||||
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
||||
@@ -169,13 +168,13 @@ fun populateCompanionBackingFieldNamesToOuterContextIfNeeded(
|
||||
// so that we'd generate the necessary accessor for its constructor afterwards
|
||||
fun sortTopLevelClassesAndPrepareContextForSealedClasses(
|
||||
classOrObjects: List<KtClassOrObject>,
|
||||
packagePartContext: PackageContext,
|
||||
context: CodegenContext<*>,
|
||||
state: GenerationState
|
||||
): List<KtClassOrObject> {
|
||||
fun prepareContextIfNeeded(descriptor: ClassDescriptor?) {
|
||||
if (DescriptorUtils.isSealedClass(descriptor)) {
|
||||
// save context for sealed class
|
||||
packagePartContext.intoClass(descriptor!!, OwnerKind.IMPLEMENTATION, state)
|
||||
context.intoClass(descriptor!!, OwnerKind.IMPLEMENTATION, state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,9 @@ package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.context.PackageContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||
|
||||
@@ -45,10 +43,6 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory
|
||||
JvmBackendFacade.doGenerateFiles(files, state, errorHandler, phaseConfig)
|
||||
}
|
||||
|
||||
override fun generateClassOrObject(classOrObject: KtClassOrObject, packagePartContext: PackageContext) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun getPackageFragment(): PackageFragmentDescriptor {
|
||||
return impl.packageFragment
|
||||
}
|
||||
|
||||
+2
-1
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
|
||||
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
|
||||
import org.jetbrains.kotlin.codegen.MemberCodegen
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -48,7 +49,7 @@ class LightClassDataProviderForClassOrObject(
|
||||
val packageCodegen = state.factory.forPackage(packageFqName, files)
|
||||
val packagePartType = Type.getObjectType(JvmFileClassUtil.getFileClassInternalName(file))
|
||||
val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file)
|
||||
packageCodegen.generateClassOrObject(getOutermostClassOrObject(classOrObject), context)
|
||||
MemberCodegen.genClassOrObject(context, getOutermostClassOrObject(classOrObject), state, null)
|
||||
state.factory.done()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("Test")
|
||||
package test
|
||||
|
||||
sealed class Foo(val value: String)
|
||||
|
||||
class Bar : Foo("OK")
|
||||
|
||||
fun box(): String = Bar().value
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: common.kt
|
||||
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("Test")
|
||||
package test
|
||||
|
||||
expect class Foo {
|
||||
val value: String
|
||||
}
|
||||
|
||||
// FILE: jvm.kt
|
||||
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("Test")
|
||||
package test
|
||||
|
||||
actual class Foo(actual val value: String)
|
||||
|
||||
fun box(): String {
|
||||
return Foo("OK").value
|
||||
}
|
||||
+10
@@ -15822,6 +15822,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/samePartNameDifferentFacades.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sealedClassHierarchy.kt")
|
||||
public void testSealedClassHierarchy() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/sealedClassHierarchy.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/multifileClasses/optimized")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -15878,6 +15883,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/multiplatform"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("expectClassInJvmMultifileFacade.kt")
|
||||
public void testExpectClassInJvmMultifileFacade() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/expectClassInJvmMultifileFacade.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noArgActualConstructor.kt")
|
||||
public void testNoArgActualConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt");
|
||||
|
||||
+10
@@ -15822,6 +15822,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/samePartNameDifferentFacades.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sealedClassHierarchy.kt")
|
||||
public void testSealedClassHierarchy() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/sealedClassHierarchy.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/multifileClasses/optimized")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -15878,6 +15883,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/multiplatform"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("expectClassInJvmMultifileFacade.kt")
|
||||
public void testExpectClassInJvmMultifileFacade() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/expectClassInJvmMultifileFacade.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noArgActualConstructor.kt")
|
||||
public void testNoArgActualConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt");
|
||||
|
||||
+10
@@ -15827,6 +15827,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/samePartNameDifferentFacades.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sealedClassHierarchy.kt")
|
||||
public void testSealedClassHierarchy() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multifileClasses/sealedClassHierarchy.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/multifileClasses/optimized")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -15883,6 +15888,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/multiplatform"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("expectClassInJvmMultifileFacade.kt")
|
||||
public void testExpectClassInJvmMultifileFacade() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/expectClassInJvmMultifileFacade.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noArgActualConstructor.kt")
|
||||
public void testNoArgActualConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt");
|
||||
|
||||
Reference in New Issue
Block a user