From af1e3fb10d5b54c4d1eaf77483d4334501ac1cf2 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Mon, 16 Mar 2020 14:50:17 +0300 Subject: [PATCH] UL properties supports JvmSynthetic annotation for get: and set: modifiers (+small refactoring) Fixed #KT-34973 --- .../classes/ultraLightMembersCreator.kt | 90 ++++++++++--------- .../jvmSyntheticForAccessors.java | 9 ++ .../jvmSyntheticForAccessors.kt | 9 ++ .../UltraLightClassLoadingTestGenerated.java | 5 ++ 4 files changed, 69 insertions(+), 44 deletions(-) create mode 100644 compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.java create mode 100644 compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.kt diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt index 3d51ce71e2c..db172d49b9a 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.asJava.elements.convertToLightAnnotationMemberValue import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotated -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.kotlin.TypeMappingMode @@ -32,12 +31,8 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi import org.jetbrains.kotlin.resolve.inline.isInlineOnly -import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_OVERLOADS_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.annotations.STRICTFP_ANNOTATION_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.resolve.jvm.annotations.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind -import org.jetbrains.kotlin.util.isOrdinaryClass internal class UltraLightMembersCreator( private val containingClass: KtLightClass, @@ -72,8 +67,8 @@ internal class UltraLightMembersCreator( val fieldName = generateUniqueFieldName((variable.name ?: "") + (if (hasDelegate) "\$delegate" else ""), usedPropertyNames) val visibility = when { - variable.hasModifier(KtTokens.PRIVATE_KEYWORD) -> PsiModifier.PRIVATE - variable.hasModifier(KtTokens.LATEINIT_KEYWORD) || variable.isConstOrJvmField() -> { + variable.hasModifier(PRIVATE_KEYWORD) -> PsiModifier.PRIVATE + variable.hasModifier(LATEINIT_KEYWORD) || variable.isConstOrJvmField() -> { val declaration = property?.setter ?: variable declaration.simpleVisibility() } @@ -87,7 +82,7 @@ internal class UltraLightMembersCreator( else -> error("Unexpected type of variable: ${variable::class.java}") } - if (!isMutable || variable.hasModifier(KtTokens.CONST_KEYWORD) || hasDelegate) { + if (!isMutable || variable.hasModifier(CONST_KEYWORD) || hasDelegate) { modifiers.add(PsiModifier.FINAL) } @@ -99,8 +94,8 @@ internal class UltraLightMembersCreator( } private fun hasBackingField(property: KtProperty): Boolean { - if (property.hasModifier(KtTokens.ABSTRACT_KEYWORD)) return false - if (property.hasModifier(KtTokens.LATEINIT_KEYWORD) || property.accessors.isEmpty()) return true + if (property.hasModifier(ABSTRACT_KEYWORD)) return false + if (property.hasModifier(LATEINIT_KEYWORD) || property.accessors.isEmpty()) return true val context = LightClassGenerationSupport.getInstance(containingClass.project).analyze(property) val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property) @@ -282,13 +277,13 @@ internal class UltraLightMembersCreator( if (forcePrivate || declaration.isPrivate() || accessedProperty?.isPrivate() == true) { return name == PsiModifier.PRIVATE } - if (declaration.hasModifier(KtTokens.PROTECTED_KEYWORD) || accessedProperty - ?.hasModifier(KtTokens.PROTECTED_KEYWORD) == true + if (declaration.hasModifier(PROTECTED_KEYWORD) || accessedProperty + ?.hasModifier(PROTECTED_KEYWORD) == true ) { return name == PsiModifier.PROTECTED } - if (outerDeclaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) { + if (outerDeclaration.hasModifier(OVERRIDE_KEYWORD)) { when ((outerDeclaration.resolve() as? CallableDescriptor)?.visibility) { Visibilities.PUBLIC -> return name == PsiModifier.PUBLIC Visibilities.PRIVATE -> return name == PsiModifier.PRIVATE @@ -301,7 +296,7 @@ internal class UltraLightMembersCreator( return when (name) { PsiModifier.FINAL -> !containingClass.isInterface && outerDeclaration !is KtConstructor<*> && isFinal(outerDeclaration) - PsiModifier.ABSTRACT -> containingClass.isInterface || outerDeclaration.hasModifier(KtTokens.ABSTRACT_KEYWORD) + PsiModifier.ABSTRACT -> containingClass.isInterface || outerDeclaration.hasModifier(ABSTRACT_KEYWORD) PsiModifier.STATIC -> forceStatic || containingClassIsNamedObject && (outerDeclaration.isJvmStatic(support) || declaration .isJvmStatic(support)) PsiModifier.STRICTFP -> declaration is KtFunction && declaration.hasAnnotation(STRICTFP_ANNOTATION_FQ_NAME) @@ -312,10 +307,10 @@ internal class UltraLightMembersCreator( } private fun KtDeclaration.isPrivate() = - hasModifier(KtTokens.PRIVATE_KEYWORD) || this is KtConstructor<*> && containingClassIsSealed || isInlineOnly() + hasModifier(PRIVATE_KEYWORD) || this is KtConstructor<*> && containingClassIsSealed || isInlineOnly() private fun KtDeclaration.isInlineOnly(): Boolean { - if (this !is KtCallableDeclaration || !hasModifier(KtTokens.INLINE_KEYWORD)) return false + if (this !is KtCallableDeclaration || !hasModifier(INLINE_KEYWORD)) return false if (annotationEntries.isEmpty()) return false val descriptor = resolve() as? CallableMemberDescriptor ?: return false @@ -378,9 +373,9 @@ internal class UltraLightMembersCreator( } private tailrec fun isInternalNonPublishedApi(declaration: KtDeclaration): Boolean { - if (declaration.hasModifier(KtTokens.PRIVATE_KEYWORD) || - declaration.hasModifier(KtTokens.PROTECTED_KEYWORD) || - declaration.hasModifier(KtTokens.PUBLIC_KEYWORD) + if (declaration.hasModifier(PRIVATE_KEYWORD) || + declaration.hasModifier(PROTECTED_KEYWORD) || + declaration.hasModifier(PUBLIC_KEYWORD) ) { return false } @@ -394,12 +389,12 @@ internal class UltraLightMembersCreator( private fun KtAnnotated.hasAnnotation(name: FqName) = support.findAnnotation(this, name) != null private fun isInternal(f: KtDeclaration): Boolean { - if (f.hasModifier(KtTokens.OVERRIDE_KEYWORD)) { + if (f.hasModifier(OVERRIDE_KEYWORD)) { val desc = f.resolve() return desc is CallableDescriptor && desc.visibility.effectiveVisibility(desc, false) == EffectiveVisibility.Internal } - return f.hasModifier(KtTokens.INTERNAL_KEYWORD) + return f.hasModifier(INTERNAL_KEYWORD) } fun propertyAccessors( @@ -419,29 +414,36 @@ internal class UltraLightMembersCreator( val ktGetter = (declaration as? KtProperty)?.getter val ktSetter = (declaration as? KtProperty)?.setter - val isPrivate = !forceStatic && declaration.hasModifier(KtTokens.PRIVATE_KEYWORD) + val isPrivate = !forceStatic && declaration.hasModifier(PRIVATE_KEYWORD) if (isPrivate && declaration !is KtProperty) return emptyList() - fun needsAccessor(accessor: KtPropertyAccessor?): Boolean { - if (!onlyJvmStatic || declaration.isJvmStatic(support) || accessor != null && accessor.isJvmStatic(support)) { - if (declaration is KtProperty && declaration.hasDelegate()) { - return true - } - if (accessor?.hasModifier(KtTokens.PRIVATE_KEYWORD) == true || accessor - ?.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) == true - ) { - return false - } - if (!isPrivate || accessor?.hasBody() == true) { - return true - } + fun needsAccessor(accessor: KtPropertyAccessor?, type: MethodType): Boolean { + + if (onlyJvmStatic && !declaration.isJvmStatic(support) && !(accessor != null && accessor.isJvmStatic(support))) + return false + + if (declaration is KtProperty && declaration.hasDelegate()) + return true + + if (accessor?.hasModifier(PRIVATE_KEYWORD) == true || accessor?.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) == true) + return false + + if (isPrivate && accessor?.hasBody() != true) return false + + if (!declaration.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME)) return true + + val annotated = (declaration.resolve() as? PropertyDescriptor) ?: return false + val propertyAnnotated = when (type) { + MethodType.GETTER -> annotated.getter + MethodType.SETTER -> annotated.setter + else -> throw NotImplementedError() } - return false + return propertyAnnotated?.hasJvmSyntheticAnnotation() != true } val result = arrayListOf() - if (needsAccessor(ktGetter)) { + if (needsAccessor(ktGetter, MethodType.GETTER)) { val auxiliaryOrigin = ktGetter ?: declaration val lightMemberOrigin = LightMemberOriginForDeclaration( originalElement = declaration, @@ -473,7 +475,7 @@ internal class UltraLightMembersCreator( result.add(getterMethodResult) } - if (!createAsAnnotationMethod && mutable && needsAccessor(ktSetter)) { + if (!createAsAnnotationMethod && mutable && needsAccessor(ktSetter, MethodType.SETTER)) { val auxiliaryOrigin = ktSetter ?: declaration val lightMemberOrigin = LightMemberOriginForDeclaration( originalElement = declaration, @@ -521,15 +523,15 @@ internal class UltraLightMembersCreator( typeParameters.any { it.hasModifier(REIFIED_KEYWORD) } private fun KtCallableDeclaration.isConstOrJvmField() = - hasModifier(KtTokens.CONST_KEYWORD) || isJvmField() + hasModifier(CONST_KEYWORD) || isJvmField() private fun KtCallableDeclaration.isJvmField() = hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME) private fun isFinal(declaration: KtDeclaration): Boolean { - if (declaration.hasModifier(KtTokens.FINAL_KEYWORD)) return true + if (declaration.hasModifier(FINAL_KEYWORD)) return true return declaration !is KtPropertyAccessor && - !declaration.hasModifier(KtTokens.OPEN_KEYWORD) && - !declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD) && - !declaration.hasModifier(KtTokens.ABSTRACT_KEYWORD) + !declaration.hasModifier(OPEN_KEYWORD) && + !declaration.hasModifier(OVERRIDE_KEYWORD) && + !declaration.hasModifier(ABSTRACT_KEYWORD) } } diff --git a/compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.java b/compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.java new file mode 100644 index 00000000000..9e8df1fdd97 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.java @@ -0,0 +1,9 @@ +public final class X /* X*/ { + @null() + public X(); + + public final int getW(); + + public final void setV(int); + +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.kt b/compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.kt new file mode 100644 index 00000000000..f122ffdbf0e --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.kt @@ -0,0 +1,9 @@ + + +class X { + @get:JvmSynthetic + var v = 1 + + @set:JvmSynthetic + var w = 1 +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java index 6e67a35f8f7..eca278af474 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java @@ -138,6 +138,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass runTest("compiler/testData/asJava/ultraLightClasses/jvmSynthetic.kt"); } + @TestMetadata("jvmSyntheticForAccessors.kt") + public void testJvmSyntheticForAccessors() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/jvmSyntheticForAccessors.kt"); + } + @TestMetadata("jvmWildcardAnnotations.kt") public void testJvmWildcardAnnotations() throws Exception { runTest("compiler/testData/asJava/ultraLightClasses/jvmWildcardAnnotations.kt");