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.
This commit is contained in:
Dmitry Petrov
2015-09-10 11:31:37 +03:00
parent 9b11b5300c
commit 6850e9180e
9 changed files with 60 additions and 18 deletions
@@ -44,10 +44,10 @@ public class MultifileClassPartCodegen(
private val multifileClassFqName: FqName,
partContext: FieldOwnerContext<*>,
state: GenerationState
) : MemberCodegen<JetFile>(state, null, partContext, file, v){
) : MemberCodegen<JetFile>(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",
@@ -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
@@ -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<JetFile>): List<JetFile> =
public @JvmStatic fun getFilesWithCallables(files: Collection<JetFile>): List<JetFile> =
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<JetFile>): List<JetFile> =
public @JvmStatic fun getFilesForPart(partFqName: FqName, files: Collection<JetFile>): List<JetFile> =
getFilesWithCallables(files).filter { getPackagePartFqName(it) == partFqName }
public @jvmStatic fun getFilePartShortName(fileName: String): String =
public @JvmStatic fun getFilePartShortName(fileName: String): String =
getPartClassName(FileUtil.getNameWithoutExtension(fileName))
}
@@ -0,0 +1,5 @@
@file:JvmName("Foo")
@file:JvmMultifileClass
package test
fun foo(): String = "O"
@@ -0,0 +1,5 @@
@file:JvmName("Bar")
@file:JvmMultifileClass
package test
fun bar(): String = "K"
@@ -0,0 +1,3 @@
package test
fun box(): String = foo() + bar()
@@ -0,0 +1,17 @@
@file:JvmName("TestPackage")
@file:JvmMultifileClass
package test
fun foo(): String = bar()
fun bar(): String {
open class LocalGeneric<T>(val x: T)
class Derived(x: String) : LocalGeneric<String>(x)
fun <T> LocalGeneric<T>.extFun() = this
fun <T> localFun(x: LocalGeneric<T>) = x
class Local3 {
fun <T> method(x: LocalGeneric<T>) = x.x
}
return Local3().method(localFun(Derived("OK")).extFun())
}
fun box(): String = foo()
@@ -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/");
@@ -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");