From 6850e9180eb1d59770480628705e3a254932ecbf Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 10 Sep 2015 11:31:37 +0300 Subject: [PATCH] Effectively this is a return of "${facadeName}__${partName}" scheme. Suggestions from @udalov: - Make multifile class parts synthetic. - Multifile class parts should have well-formed Java identifiers as names. - Multifile class part names should contain facade name. Add test with clashing part names. Add test with local generic classes used in method signatures (it works with parts names not being well-formed Java identifiers, though). Capitalized annotations. --- .../codegen/MultifileClassPartCodegen.kt | 4 +-- .../kotlin/fileClasses/JvmFileClassUtil.kt | 2 +- .../load/kotlin/PackagePartClassUtils.kt | 30 +++++++++---------- .../samePartNameDifferentFacades/1/part.kt | 5 ++++ .../samePartNameDifferentFacades/2/part.kt | 5 ++++ .../samePartNameDifferentFacades/box.kt | 3 ++ .../multifileClassWithLocalGeneric.kt | 17 +++++++++++ ...BlackBoxMultiFileCodegenTestGenerated.java | 6 ++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 6 ++++ 9 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/1/part.kt create mode 100644 compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/2/part.kt create mode 100644 compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/box.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/platformNames/multifileClassWithLocalGeneric.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt index b1a8bb92145..7087cf43937 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassPartCodegen.kt @@ -44,10 +44,10 @@ public class MultifileClassPartCodegen( private val multifileClassFqName: FqName, partContext: FieldOwnerContext<*>, state: GenerationState -) : MemberCodegen(state, null, partContext, file, v){ +) : MemberCodegen(state, null, partContext, file, v) { override fun generateDeclaration() { v.defineClass(element, Opcodes.V1_6, - Opcodes.ACC_FINAL, + Opcodes.ACC_FINAL or Opcodes.ACC_SYNTHETIC, filePartType.internalName, null, "java/lang/Object", diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt index d5364ff5b35..e4dad593df1 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt @@ -53,7 +53,7 @@ public object JvmFileClassUtil { file.packageFqName.child(Name.identifier(manglePartName(jvmFileClassAnnotations.name, file.name))) public @JvmStatic fun manglePartName(facadeName: String, fileName: String): String = - "1${PackagePartClassUtils.getFilePartShortName(fileName)}" + "${facadeName}__${PackagePartClassUtils.getFilePartShortName(fileName)}" public @JvmStatic fun parseJvmFileClass(jvmName: AnnotationDescriptor, jvmMultifileClass: AnnotationDescriptor?): ParsedJmvFileClassAnnotations? { val jvmNameArgument = jvmName.allValueArguments.values().singleOrNull() ?: return null diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt index 9517875cf17..425654d7e9b 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt @@ -31,21 +31,21 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf import java.util.* public object PackagePartClassUtils { - public @jvmStatic fun getPathHashCode(file: VirtualFile): Int = + public @JvmStatic fun getPathHashCode(file: VirtualFile): Int = file.path.toLowerCase().hashCode() private val PART_CLASS_NAME_SUFFIX = "Kt" - private @jvmStatic fun getPartClassName(str: String): String = + private @JvmStatic fun getPartClassName(str: String): String = if (str.isEmpty()) "_$PART_CLASS_NAME_SUFFIX" else capitalizeAsJavaClassName(sanitizeAsJavaIdentifier(str)) + PART_CLASS_NAME_SUFFIX - private @jvmStatic fun sanitizeAsJavaIdentifier(str: String): String = + private @JvmStatic fun sanitizeAsJavaIdentifier(str: String): String = str.replace("[^\\p{L}\\p{Digit}]".toRegex(), "_") - private @jvmStatic fun capitalizeAsJavaClassName(str: String): String = + private @JvmStatic fun capitalizeAsJavaClassName(str: String): String = // NB use Locale.ENGLISH so that build is locale-independent. // See Javadoc on java.lang.String.toUpperCase() for more details. if (Character.isJavaIdentifierStart(str.charAt(0))) @@ -54,38 +54,38 @@ public object PackagePartClassUtils { "_$str" @TestOnly - public @jvmStatic fun getDefaultPartFqName(facadeClassFqName: FqName, file: VirtualFile): FqName = + public @JvmStatic fun getDefaultPartFqName(facadeClassFqName: FqName, file: VirtualFile): FqName = getPackagePartFqName(facadeClassFqName.parent(), file.name) - public @jvmStatic fun getPackagePartFqName(packageFqName: FqName, fileName: String): FqName { + public @JvmStatic fun getPackagePartFqName(packageFqName: FqName, fileName: String): FqName { val partClassName = getFilePartShortName(fileName) return packageFqName.child(Name.identifier(partClassName)) } - @deprecated("Migrate to JvmFileClassesProvider") - public @jvmStatic fun getPackagePartInternalName(file: JetFile): String = + @Deprecated("Migrate to JvmFileClassesProvider") + public @JvmStatic fun getPackagePartInternalName(file: JetFile): String = JvmClassName.byFqNameWithoutInnerClasses(getPackagePartFqName(file)).internalName - @deprecated("Migrate to JvmFileClassesProvider") - public @jvmStatic fun getPackagePartFqName(file: JetFile): FqName = + @Deprecated("Migrate to JvmFileClassesProvider") + public @JvmStatic fun getPackagePartFqName(file: JetFile): FqName = getPackagePartFqName(file.packageFqName, file.name) - public @jvmStatic fun getPackagePartFqName(callable: DeserializedCallableMemberDescriptor): FqName { + public @JvmStatic fun getPackagePartFqName(callable: DeserializedCallableMemberDescriptor): FqName { val implClassName = callable.nameResolver.getName(callable.proto.getExtension(JvmProtoBuf.implClassName)) val packageFqName = (callable.containingDeclaration as PackageFragmentDescriptor).fqName return packageFqName.child(implClassName) } - public @jvmStatic fun getFilesWithCallables(files: Collection): List = + public @JvmStatic fun getFilesWithCallables(files: Collection): List = files.filter { fileHasTopLevelCallables(it) } - public @jvmStatic fun fileHasTopLevelCallables(file: JetFile): Boolean = + public @JvmStatic fun fileHasTopLevelCallables(file: JetFile): Boolean = file.declarations.any { it is JetProperty || it is JetNamedFunction } - public @jvmStatic fun getFilesForPart(partFqName: FqName, files: Collection): List = + public @JvmStatic fun getFilesForPart(partFqName: FqName, files: Collection): List = getFilesWithCallables(files).filter { getPackagePartFqName(it) == partFqName } - public @jvmStatic fun getFilePartShortName(fileName: String): String = + public @JvmStatic fun getFilePartShortName(fileName: String): String = getPartClassName(FileUtil.getNameWithoutExtension(fileName)) } \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/1/part.kt b/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/1/part.kt new file mode 100644 index 00000000000..bbf345a063f --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/1/part.kt @@ -0,0 +1,5 @@ +@file:JvmName("Foo") +@file:JvmMultifileClass +package test + +fun foo(): String = "O" \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/2/part.kt b/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/2/part.kt new file mode 100644 index 00000000000..a80959a5736 --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/2/part.kt @@ -0,0 +1,5 @@ +@file:JvmName("Bar") +@file:JvmMultifileClass +package test + +fun bar(): String = "K" \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/box.kt b/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/box.kt new file mode 100644 index 00000000000..aaae71300c2 --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/box.kt @@ -0,0 +1,3 @@ +package test + +fun box(): String = foo() + bar() \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/platformNames/multifileClassWithLocalGeneric.kt b/compiler/testData/codegen/boxWithStdlib/platformNames/multifileClassWithLocalGeneric.kt new file mode 100644 index 00000000000..a03b6aa00fc --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/platformNames/multifileClassWithLocalGeneric.kt @@ -0,0 +1,17 @@ +@file:JvmName("TestPackage") +@file:JvmMultifileClass +package test + +fun foo(): String = bar() +fun bar(): String { + open class LocalGeneric(val x: T) + class Derived(x: String) : LocalGeneric(x) + fun LocalGeneric.extFun() = this + fun localFun(x: LocalGeneric) = x + class Local3 { + fun method(x: LocalGeneric) = x.x + } + return Local3().method(localFun(Derived("OK")).extFun()) +} + +fun box(): String = foo() \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java index 8e55d8224af..dc642814a52 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java @@ -101,6 +101,12 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg doTestMultiFile(fileName); } + @TestMetadata("samePartNameDifferentFacades") + public void testSamePartNameDifferentFacades() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/samePartNameDifferentFacades/"); + doTestMultiFile(fileName); + } + @TestMetadata("simple") public void testSimple() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/simple/"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index a6b911c4d0f..e5f1a04583b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2245,6 +2245,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("multifileClassWithLocalGeneric.kt") + public void testMultifileClassWithLocalGeneric() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/platformNames/multifileClassWithLocalGeneric.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("propertyName.kt") public void testPropertyName() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/platformNames/propertyName.kt");