From 41997769e398c6571578183ee6027159dc9a0c82 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 19 Nov 2018 17:52:12 +0300 Subject: [PATCH] Support @JvmField annotation in light classes --- .../kotlin/asJava/classes/ultraLightPsi.kt | 25 ++++++++++++------- .../asJava/ultraLightClasses/jvmField.kt | 20 +++++++++++++++ .../resolve/IDELightClassGenerationSupport.kt | 4 ++- .../UltraLightClassLoadingTestGenerated.java | 5 ++++ 4 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/asJava/ultraLightClasses/jvmField.kt diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt index 2894f336537..e0649c17cb2 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt @@ -161,16 +161,19 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult ) for (property in companion.declarations.filterIsInstance()) { - if (isInterface && !property.hasModifier(CONST_KEYWORD)) continue - + if (isInterface && !property.isConstOrJvmField()) continue propertyField(property, ::generateUniqueName, true)?.let(result::add) } } - if (!isInterface && - !(this.classOrObject is KtObjectDeclaration && this.classOrObject.isCompanion() && containingClass?.isInterface == false) - ) { + if (!isInterface) { + val isCompanion = this.classOrObject is KtObjectDeclaration && this.classOrObject.isCompanion() for (property in this.classOrObject.declarations.filterIsInstance()) { + // All fields for companion object of classes are generated to the containing class + // For interfaces, only @JvmField-annotated properties are generated to the containing class + // Probably, the same should work for const vals but it doesn't at the moment (see KT-28294) + if (isCompanion && (containingClass?.isInterface == false || property.isJvmField())) continue + propertyField(property, ::generateUniqueName, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add) } } @@ -200,11 +203,10 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult val visibility = when { property.hasModifier(PRIVATE_KEYWORD) -> PsiModifier.PRIVATE - property.hasModifier(LATEINIT_KEYWORD) -> { + property.hasModifier(LATEINIT_KEYWORD) || property.isConstOrJvmField() -> { val declaration = property.setter ?: property simpleVisibility(declaration) } - property.hasModifier(CONST_KEYWORD) -> PsiModifier.PUBLIC else -> PsiModifier.PRIVATE } val modifiers = hashSetOf(visibility) @@ -433,8 +435,8 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult } private fun propertyAccessors(declaration: KtCallableDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List { - val propertyName = declaration.name - if (declaration.hasModifier(CONST_KEYWORD) || propertyName == null) return emptyList() + val propertyName = declaration.name ?: return emptyList() + if (declaration.isConstOrJvmField()) return emptyList() val ktGetter = (declaration as? KtProperty)?.getter val ktSetter = (declaration as? KtProperty)?.setter @@ -484,6 +486,11 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult return result } + private fun KtCallableDeclaration.isConstOrJvmField() = + hasModifier(CONST_KEYWORD) || isJvmField() + + private fun KtCallableDeclaration.isJvmField() = hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME) + private fun isFinal(declaration: KtDeclaration): Boolean { if (declaration.hasModifier(FINAL_KEYWORD)) return true return declaration !is KtPropertyAccessor && diff --git a/compiler/testData/asJava/ultraLightClasses/jvmField.kt b/compiler/testData/asJava/ultraLightClasses/jvmField.kt new file mode 100644 index 00000000000..03c9db5dc2b --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/jvmField.kt @@ -0,0 +1,20 @@ +class A { + @JvmField + val a: Collection<*> = emptyList() + @JvmField + var b: Int = 1 + + companion object { + @JvmField + val c: Collection<*> = emptyList() + @JvmField + var d: Int = 1 + } +} + +interface B { + companion object { + @JvmField + val a: Collection<*> = emptyList() + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index e6d97095d17..46c353dec6c 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -115,6 +115,7 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG if (name == JVM_STATIC_ANNOTATION_FQ_NAME.shortName()) return false if (name == JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME.shortName()) return false if (name == JVM_WILDCARD_ANNOTATION_FQ_NAME.shortName()) return false + if (name == JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME.shortName()) return false return true } @@ -129,7 +130,8 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG declaration.hasModifier(KtTokens.INLINE_KEYWORD) && declaration is KtClassOrObject || declaration.hasModifier(KtTokens.DATA_KEYWORD) || declaration.hasModifier(KtTokens.ENUM_KEYWORD) || - declaration.hasModifier(KtTokens.SUSPEND_KEYWORD)) { + declaration.hasModifier(KtTokens.SUSPEND_KEYWORD) + ) { return declaration } diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java index 256ca924b6b..824d6bb308a 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java @@ -99,6 +99,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass runTest("compiler/testData/asJava/ultraLightClasses/inlineOnly.kt"); } + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/jvmField.kt"); + } + @TestMetadata("jvmName.kt") public void testJvmName() throws Exception { runTest("compiler/testData/asJava/ultraLightClasses/jvmName.kt");