Support JvmPackageName annotation in JVM back-end
This annotation is currently internal because we only commit to its support for our own libraries. It will be used to change JVM package names of declarations in JDK-specific stdlib additions (now called kotlin-stdlib-jre7/8), both to preserve source compatibility of the old Kotlin code and to solve the split package problem (KT-19258)
This commit is contained in:
@@ -34,6 +34,9 @@ object JvmFileClassUtil {
|
|||||||
val JVM_MULTIFILE_CLASS: FqName = FqName("kotlin.jvm.JvmMultifileClass")
|
val JVM_MULTIFILE_CLASS: FqName = FqName("kotlin.jvm.JvmMultifileClass")
|
||||||
val JVM_MULTIFILE_CLASS_SHORT = JVM_MULTIFILE_CLASS.shortName().asString()
|
val JVM_MULTIFILE_CLASS_SHORT = JVM_MULTIFILE_CLASS.shortName().asString()
|
||||||
|
|
||||||
|
private val JVM_PACKAGE_NAME: FqName = FqName("kotlin.jvm.JvmPackageName")
|
||||||
|
private val JVM_PACKAGE_NAME_SHORT = JVM_PACKAGE_NAME.shortName().asString()
|
||||||
|
|
||||||
private const val MULTIFILE_PART_NAME_DELIMITER = "__"
|
private const val MULTIFILE_PART_NAME_DELIMITER = "__"
|
||||||
|
|
||||||
fun getPartFqNameForDeserialized(descriptor: DeserializedMemberDescriptor): FqName {
|
fun getPartFqNameForDeserialized(descriptor: DeserializedMemberDescriptor): FqName {
|
||||||
@@ -55,13 +58,14 @@ object JvmFileClassUtil {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getFileClassInfoNoResolve(file: KtFile): JvmFileClassInfo {
|
fun getFileClassInfoNoResolve(file: KtFile): JvmFileClassInfo {
|
||||||
val parsedAnnotations = parseJvmNameOnFileNoResolve(file)
|
val parsedAnnotations = parseJvmNameOnFileNoResolve(file)
|
||||||
val packageFqName = file.packageFqName
|
val packageFqName = parsedAnnotations?.jvmPackageName ?: file.packageFqName
|
||||||
return when {
|
return when {
|
||||||
parsedAnnotations != null -> {
|
parsedAnnotations != null -> {
|
||||||
val facadeClassFqName = packageFqName.child(Name.identifier(parsedAnnotations.jvmName))
|
val simpleName = parsedAnnotations.jvmName ?: PackagePartClassUtils.getFilePartShortName(file.name)
|
||||||
|
val facadeClassFqName = packageFqName.child(Name.identifier(simpleName))
|
||||||
when {
|
when {
|
||||||
parsedAnnotations.isMultifileClass -> JvmMultifileClassPartInfo(
|
parsedAnnotations.isMultifileClass -> JvmMultifileClassPartInfo(
|
||||||
fileClassFqName = packageFqName.child(Name.identifier(manglePartName(parsedAnnotations.jvmName, file.name))),
|
fileClassFqName = packageFqName.child(Name.identifier(manglePartName(simpleName, file.name))),
|
||||||
facadeClassFqName = facadeClassFqName
|
facadeClassFqName = facadeClassFqName
|
||||||
)
|
)
|
||||||
else -> JvmSimpleFileClassInfo(facadeClassFqName, true)
|
else -> JvmSimpleFileClassInfo(facadeClassFqName, true)
|
||||||
@@ -72,12 +76,17 @@ object JvmFileClassUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseJvmNameOnFileNoResolve(file: KtFile): ParsedJvmFileClassAnnotations? {
|
private fun parseJvmNameOnFileNoResolve(file: KtFile): ParsedJvmFileClassAnnotations? {
|
||||||
val jvmName = findAnnotationEntryOnFileNoResolve(file, JVM_NAME_SHORT) ?: return null
|
val jvmNameAnnotation = findAnnotationEntryOnFileNoResolve(file, JVM_NAME_SHORT)
|
||||||
val nameExpr = jvmName.valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
|
val jvmName = jvmNameAnnotation?.let(this::getLiteralStringFromAnnotation)?.takeIf(Name::isValidIdentifier)
|
||||||
val name = getLiteralStringFromRestrictedConstExpression(nameExpr) ?: return null
|
|
||||||
if (!Name.isValidIdentifier(name)) return null
|
val jvmPackageNameAnnotation = findAnnotationEntryOnFileNoResolve(file, JVM_PACKAGE_NAME_SHORT)
|
||||||
val isMultifileClassPart = findAnnotationEntryOnFileNoResolve(file, JVM_MULTIFILE_CLASS_SHORT) != null
|
val jvmPackageName = jvmPackageNameAnnotation?.let(this::getLiteralStringFromAnnotation)?.let(::FqName)
|
||||||
return ParsedJvmFileClassAnnotations(name, isMultifileClassPart)
|
|
||||||
|
if (jvmName == null && jvmPackageName == null) return null
|
||||||
|
|
||||||
|
val isMultifileClass = findAnnotationEntryOnFileNoResolve(file, JVM_MULTIFILE_CLASS_SHORT) != null
|
||||||
|
|
||||||
|
return ParsedJvmFileClassAnnotations(jvmName, jvmPackageName, isMultifileClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@@ -86,14 +95,15 @@ object JvmFileClassUtil {
|
|||||||
it.calleeExpression?.constructorReferenceExpression?.getReferencedName() == shortName
|
it.calleeExpression?.constructorReferenceExpression?.getReferencedName() == shortName
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLiteralStringFromRestrictedConstExpression(argumentExpression: KtExpression?): String? {
|
private fun getLiteralStringFromAnnotation(annotation: KtAnnotationEntry): String? {
|
||||||
|
val argumentExpression = annotation.valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
|
||||||
val stringTemplate = argumentExpression as? KtStringTemplateExpression ?: return null
|
val stringTemplate = argumentExpression as? KtStringTemplateExpression ?: return null
|
||||||
val singleEntry = stringTemplate.entries.singleOrNull() as? KtLiteralStringTemplateEntry ?: return null
|
val singleEntry = stringTemplate.entries.singleOrNull() as? KtLiteralStringTemplateEntry ?: return null
|
||||||
return singleEntry.text
|
return singleEntry.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ParsedJvmFileClassAnnotations(val jvmName: String, val isMultifileClass: Boolean)
|
internal class ParsedJvmFileClassAnnotations(val jvmName: String?, val jvmPackageName: FqName?, val isMultifileClass: Boolean)
|
||||||
|
|
||||||
val KtFile.javaFileFacadeFqName: FqName
|
val KtFile.javaFileFacadeFqName: FqName
|
||||||
get() {
|
get() {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// LANGUAGE_VERSION: 1.2
|
||||||
|
|
||||||
|
// FILE: foo.kt
|
||||||
|
|
||||||
|
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
|
@file:JvmPackageName("baz.foo.quux.bar")
|
||||||
|
package foo.bar
|
||||||
|
|
||||||
|
fun f(): String = "O"
|
||||||
|
|
||||||
|
val g: String? get() = "K"
|
||||||
|
|
||||||
|
inline fun <T> i(block: () -> T): T = block()
|
||||||
|
|
||||||
|
// FILE: bar.kt
|
||||||
|
|
||||||
|
import foo.bar.*
|
||||||
|
|
||||||
|
fun box(): String = i { f() + g }
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// LANGUAGE_VERSION: 1.2
|
||||||
|
|
||||||
|
// FILE: 1.kt
|
||||||
|
|
||||||
|
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
|
@file:JvmPackageName("baz.foo.quux.bar")
|
||||||
|
package foo.bar
|
||||||
|
|
||||||
|
fun f(): String = "O"
|
||||||
|
|
||||||
|
val g: String? get() = "K"
|
||||||
|
|
||||||
|
inline fun <T> i(block: () -> T): T = block()
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import foo.bar.*
|
||||||
|
|
||||||
|
fun box(): String = i { f() + g }
|
||||||
+15
@@ -10401,6 +10401,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractIrBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/jvmPackageName/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+15
@@ -1572,6 +1572,21 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractIrBlackBoxInlineCodegenTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/jvmPackageName/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+15
@@ -1572,6 +1572,21 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractIrCompileKotlinAgainstInlineKotlinTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/jvmPackageName/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -10401,6 +10401,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/jvmPackageName/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -1572,6 +1572,21 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractBlackBoxInlineCodegenTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/jvmPackageName/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+15
@@ -1572,6 +1572,21 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractCompileKotlinAgainstInlineKotlinTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/jvmPackageName/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
@TestMetadata("compiler/testData/codegen/boxInline/lambdaClassClash")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -10401,6 +10401,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractLightAnalysisModeTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/jvmPackageName/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -62,6 +62,18 @@ public annotation class JvmName(val name: String)
|
|||||||
@MustBeDocumented
|
@MustBeDocumented
|
||||||
public annotation class JvmMultifileClass
|
public annotation class JvmMultifileClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the fully qualified name of the JVM package of the .class file generated from this file.
|
||||||
|
* This does not affect the way Kotlin clients will see the declarations in this file, but Java clients and other JVM language clients
|
||||||
|
* will see the class file as if it was declared in the specified package.
|
||||||
|
* If a file is annotated with this annotation, it can only have function, property and typealias declarations, but no classes.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FILE)
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
|
@MustBeDocumented
|
||||||
|
@SinceKotlin("1.2")
|
||||||
|
internal annotation class JvmPackageName(val name: String)
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FIELD)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.FIELD)
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
public annotation class JvmSynthetic
|
public annotation class JvmSynthetic
|
||||||
|
|||||||
@@ -11733,6 +11733,15 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/jvmPackageName")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class JvmPackageName extends AbstractJsCodegenBoxTest {
|
||||||
|
public void testAllFilesPresentInJvmPackageName() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/jvmPackageName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
@TestMetadata("compiler/testData/codegen/box/jvmStatic")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user