diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt index 1f756442c03..8d3c153763b 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticExtensionsScope.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.typeUtil.isBoolean +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeFirstWord @@ -54,8 +55,7 @@ interface SyntheticJavaPropertyDescriptor : PropertyDescriptor { val identifier = name.getIdentifier() if (!identifier.startsWith("get") && !identifier.startsWith("is") && !identifier.startsWith("set")) return null // optimization - val owner = getterOrSetter.getContainingDeclaration() - if (owner !is JavaClassDescriptor) return null + val owner = getterOrSetter.getContainingDeclaration() as? ClassDescriptor ?: return null val originalGetterOrSetter = getterOrSetter.original return resolutionScope.getSyntheticExtensionProperties(listOf(owner.getDefaultType())) @@ -94,50 +94,76 @@ class AdditionalScopesWithJavaSyntheticExtensions(storageManager: StorageManager } class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by JetScope.Empty { - private val syntheticPropertyInClass = storageManager.createMemoizedFunctionWithNullableValues, PropertyDescriptor> { pair -> + private val syntheticPropertyInClass = storageManager.createMemoizedFunctionWithNullableValues, PropertyDescriptor> { pair -> syntheticPropertyInClassNotCached(pair.first, pair.second) } - private fun syntheticPropertyInClassNotCached(javaClass: JavaClassDescriptor, name: Name): PropertyDescriptor? { + private fun syntheticPropertyInClassNotCached(ownerClass: ClassDescriptor, name: Name): PropertyDescriptor? { if (name.isSpecial()) return null val identifier = name.identifier if (identifier.isEmpty()) return null val firstChar = identifier[0] if (!firstChar.isJavaIdentifierStart() || firstChar.isUpperCase()) return null - val memberScope = javaClass.getUnsubstitutedMemberScope() + val memberScope = ownerClass.unsubstitutedMemberScope val getMethod = possibleGetMethodNames(name) .asSequence() .flatMap { memberScope.getFunctions(it).asSequence() } - .singleOrNull { it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && isGoodGetMethod(it) } ?: return null + .singleOrNull { + it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && isGoodGetMethod(it) && it.hasJavaOriginInHierarchy() + } ?: return null // don't accept "uRL" for "getURL" etc if (SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(getMethod.name) != name) return null - val propertyType = getMethod.getReturnType() ?: return null - val setMethod = memberScope.getFunctions(setMethodName(getMethod.getName())) - .singleOrNull { it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && isGoodSetMethod(it, propertyType) } + val setMethod = memberScope.getFunctions(setMethodName(getMethod.name)) + .singleOrNull { isGoodSetMethod(it, getMethod) } - return MyPropertyDescriptor(javaClass, getMethod.original, setMethod?.original, name, propertyType) + val propertyType = getMethod.returnType ?: return null + return MyPropertyDescriptor(ownerClass, getMethod.original, setMethod?.original, name, propertyType) + } + + private fun FunctionDescriptor.hasJavaOriginInHierarchy(): Boolean { + return if (overriddenDescriptors.isEmpty()) + containingDeclaration is JavaClassDescriptor + else + overriddenDescriptors.any { it.hasJavaOriginInHierarchy() } } private fun isGoodGetMethod(descriptor: FunctionDescriptor): Boolean { - val returnType = descriptor.getReturnType() ?: return false + val returnType = descriptor.returnType ?: return false if (returnType.isUnit()) return false - if (descriptor.getName().asString().startsWith("is") && !returnType.isBoolean()) return false + if (descriptor.name.asString().startsWith("is") && !returnType.isBoolean()) return false - return descriptor.getValueParameters().isEmpty() - && descriptor.getTypeParameters().isEmpty() - && descriptor.getVisibility() == Visibilities.PUBLIC //TODO: what about protected and package-local? + return descriptor.valueParameters.isEmpty() + && descriptor.typeParameters.isEmpty() + && descriptor.visibility == Visibilities.PUBLIC //TODO: what about protected and package-local? } - private fun isGoodSetMethod(descriptor: FunctionDescriptor, propertyType: JetType): Boolean { - val parameter = descriptor.getValueParameters().singleOrNull() ?: return false - return parameter.getType() == propertyType - && parameter.getVarargElementType() == null - && descriptor.getTypeParameters().isEmpty() - && descriptor.getReturnType()?.let { it.isUnit() } ?: false - && descriptor.getVisibility() == Visibilities.PUBLIC + private fun isGoodSetMethod(descriptor: FunctionDescriptor, getMethod: FunctionDescriptor): Boolean { + val propertyType = getMethod.returnType ?: return false + val parameter = descriptor.valueParameters.singleOrNull() ?: return false + if (parameter.type != propertyType) { + if (descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) return false // real setter must exactly match getter's type + if (!propertyType.isSubtypeOf(parameter.type)) return false + if (descriptor.findOverridden { + val baseProperty = SyntheticJavaPropertyDescriptor.findByGetterOrSetter(it, this) + baseProperty?.getMethod?.name == getMethod.name + } == null) return false + } + + return parameter.varargElementType == null + && descriptor.typeParameters.isEmpty() + && descriptor.returnType?.let { it.isUnit() } ?: false + && descriptor.visibility == Visibilities.PUBLIC + } + + private fun FunctionDescriptor.findOverridden(condition: (FunctionDescriptor) -> Boolean): FunctionDescriptor? { + for (descriptor in overriddenDescriptors) { + if (condition(descriptor)) return descriptor + descriptor.findOverridden(condition)?.let { return it } + } + return null } override fun getSyntheticExtensionProperties(receiverTypes: Collection, name: Name): Collection { @@ -161,7 +187,7 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by val typeConstructor = type.getConstructor() val classifier = typeConstructor.getDeclarationDescriptor() - if (classifier is JavaClassDescriptor) { + if (classifier is ClassDescriptor) { result = result.add(syntheticPropertyInClass(Pair(classifier, name))) } @@ -184,7 +210,7 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by val typeConstructor = type.getConstructor() val classifier = typeConstructor.getDeclarationDescriptor() - if (classifier is JavaClassDescriptor) { + if (classifier is ClassDescriptor) { for (descriptor in classifier.getUnsubstitutedMemberScope().getDescriptors(DescriptorKindFilter.FUNCTIONS)) { if (descriptor is FunctionDescriptor) { val propertyName = SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(descriptor.getName()) ?: continue @@ -233,13 +259,13 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by } private class MyPropertyDescriptor( - javaClass: JavaClassDescriptor, + ownerClass: ClassDescriptor, override val getMethod: FunctionDescriptor, override val setMethod: FunctionDescriptor?, name: Name, type: JetType ) : SyntheticJavaPropertyDescriptor, PropertyDescriptorImpl( - DescriptorUtils.getContainingModule(javaClass)/* TODO:is it ok? */, + DescriptorUtils.getContainingModule(ownerClass)/* TODO:is it ok? */, null, Annotations.EMPTY, Modality.FINAL, @@ -250,12 +276,12 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by SourceElement.NO_SOURCE/*TODO?*/ ) { init { - val classTypeParams = javaClass.typeConstructor.parameters + val classTypeParams = ownerClass.typeConstructor.parameters val typeParameters = ArrayList(classTypeParams.size()) val typeSubstitutor = DescriptorSubstitutor.substituteTypeParameters(classTypeParams, TypeSubstitutor.EMPTY, this, typeParameters) val propertyType = typeSubstitutor.safeSubstitute(type, Variance.INVARIANT) - val receiverType = typeSubstitutor.safeSubstitute(javaClass.defaultType, Variance.INVARIANT) + val receiverType = typeSubstitutor.safeSubstitute(ownerClass.defaultType, Variance.INVARIANT) setType(propertyType, typeParameters, null, receiverType) val getter = PropertyGetterDescriptorImpl(this, diff --git a/compiler/testData/codegen/boxAgainstJava/syntheticExtensions/overrideOnlyGetter.java b/compiler/testData/codegen/boxAgainstJava/syntheticExtensions/overrideOnlyGetter.java new file mode 100644 index 00000000000..4a7ab421bc5 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/syntheticExtensions/overrideOnlyGetter.java @@ -0,0 +1,10 @@ +class JavaClass1 { + protected Object value = null; + + public Object getSomething() { return null; } + public void setSomething(Object value) { this.value = value; } +} + +class JavaClass2 extends JavaClass1 { + public String getSomething() { return (String)value; } +} diff --git a/compiler/testData/codegen/boxAgainstJava/syntheticExtensions/overrideOnlyGetter.kt b/compiler/testData/codegen/boxAgainstJava/syntheticExtensions/overrideOnlyGetter.kt new file mode 100644 index 00000000000..cd8d6552080 --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/syntheticExtensions/overrideOnlyGetter.kt @@ -0,0 +1,5 @@ +fun box(): String { + val javaClass = JavaClass2() + javaClass.something = "OK" + return javaClass.something +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/JavaOverridesKotlin.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/JavaOverridesKotlin.kt new file mode 100644 index 00000000000..ca18c9b15bc --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/JavaOverridesKotlin.kt @@ -0,0 +1,29 @@ +// FILE: KotlinFile.kt +open class KotlinClass { + public open fun getSomething1(): Int = 1 + + public open fun setSomething2(value: Int) {} +} + +fun foo(javaClass: JavaClass) { + useInt(javaClass.getSomething1()) + useInt(javaClass.something1) + + javaClass.setSomething2(javaClass.getSomething2() + 1) + javaClass.something2 = javaClass.something2 + 1 +} + +fun useInt(i: Int) {} + +// FILE: JavaClass.java +public class JavaClass extends KotlinClass implements JavaInterface { + public int getSomething1() { return 1; } + + public int getSomething2() { return 1; } + public void setSomething2(int value) {} +} + +// FILE: JavaInterface.java +public class JavaInterface { + int getSomething2(); +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/JavaOverridesKotlin.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/JavaOverridesKotlin.txt new file mode 100644 index 00000000000..85484900fc5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/JavaOverridesKotlin.txt @@ -0,0 +1,31 @@ +package + +internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit +internal fun useInt(/*0*/ i: kotlin.Int): kotlin.Unit + +public open class JavaClass : KotlinClass, JavaInterface { + public constructor JavaClass() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun getSomething1(): kotlin.Int + public open override /*1*/ fun getSomething2(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun setSomething2(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class JavaInterface { + public constructor JavaInterface() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getSomething2(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal open class KotlinClass { + public constructor KotlinClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething1(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething2(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava.kt new file mode 100644 index 00000000000..bbebad6f852 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava.kt @@ -0,0 +1,52 @@ +// FILE: KotlinFile.kt +abstract class KotlinClass : JavaClass(), KotlinInterface, JavaInterface { + override fun getSomething1(): Int = 1 + override fun getSomething3(): String = "" + override fun setSomething4(value: String) {} + override fun getSomething5(): String = "" +} + +interface KotlinInterface { + public fun getSomething1(): Int + public fun getSomething4(): String +} + +fun foo(k: KotlinClass) { + useInt(k.getSomething1()) + useInt(k.something1) + + useInt(k.getSomething2()) + useInt(k.something2) + + useString(k.getSomething3()) + useString(k.something3) + + k.setSomething4("") + k.something4 += "" + k.setSomething4(null) + k.something4 = null + + useString(k.getSomething5()) + useString(k.something5) + k.setSomething5(1) + k.something5 = 1 +} + +fun useInt(i: Int) {} +fun useString(i: String) {} + +// FILE: JavaClass.java +public class JavaClass { + public int getSomething1() { return 1; } + public int getSomething2() { return 1; } + public Object getSomething3() { return null; } +} + +// FILE: JavaInterface.java +public interface JavaInterface { + String getSomething4(); + void setSomething4(String value); + + Object getSomething5(); + void setSomething5(Object value); +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava.txt new file mode 100644 index 00000000000..a48f3c46a49 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava.txt @@ -0,0 +1,47 @@ +package + +internal fun foo(/*0*/ k: KotlinClass): kotlin.Unit +internal fun useInt(/*0*/ i: kotlin.Int): kotlin.Unit +internal fun useString(/*0*/ i: kotlin.String): kotlin.Unit + +public open class JavaClass { + public constructor JavaClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething1(): kotlin.Int + public open fun getSomething2(): kotlin.Int + public open fun getSomething3(): kotlin.Any! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething4(): kotlin.String! + public abstract fun getSomething5(): kotlin.Any! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun setSomething4(/*0*/ value: kotlin.String!): kotlin.Unit + public abstract fun setSomething5(/*0*/ value: kotlin.Any!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal abstract class KotlinClass : JavaClass, KotlinInterface, JavaInterface { + public constructor KotlinClass() + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun getSomething1(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun getSomething2(): kotlin.Int + public open override /*1*/ fun getSomething3(): kotlin.String + public abstract override /*2*/ /*fake_override*/ fun getSomething4(): kotlin.String! + public open override /*1*/ fun getSomething5(): kotlin.String + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun setSomething4(/*0*/ value: kotlin.String): kotlin.Unit + public abstract override /*1*/ /*fake_override*/ fun setSomething5(/*0*/ value: kotlin.Any!): kotlin.Unit + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal interface KotlinInterface { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething1(): kotlin.Int + public abstract fun getSomething4(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava2.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava2.kt new file mode 100644 index 00000000000..fadda63cd94 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava2.kt @@ -0,0 +1,25 @@ +// FILE: KotlinFile.kt +abstract class KotlinClass : JavaInterface1, JavaInterface2 { + override fun getSomething(): String = "" +} + +fun foo(k: KotlinClass) { + useString(k.getSomething()) + useString(k.something) + if (k.something == null) return + + k.setSomething(1) + k.something = 1 +} + +fun useString(i: String) {} + +// FILE: JavaInterface1.java +public interface JavaInterface1 { + String getSomething(); +} + +// FILE: JavaInterface2.java +public interface JavaInterface2 { + void setSomething(int value); +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava2.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava2.txt new file mode 100644 index 00000000000..50f76abf47e --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava2.txt @@ -0,0 +1,29 @@ +package + +public /*synthesized*/ fun JavaInterface1(/*0*/ function: () -> kotlin.String!): JavaInterface1 +public /*synthesized*/ fun JavaInterface2(/*0*/ function: (kotlin.Int) -> kotlin.Unit): JavaInterface2 +internal fun foo(/*0*/ k: KotlinClass): kotlin.Unit +internal fun useString(/*0*/ i: kotlin.String): kotlin.Unit + +public interface JavaInterface1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun setSomething(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal abstract class KotlinClass : JavaInterface1, JavaInterface2 { + public constructor KotlinClass() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun getSomething(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun setSomething(/*0*/ value: kotlin.Int): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava3.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava3.kt new file mode 100644 index 00000000000..7af74313db4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava3.kt @@ -0,0 +1,25 @@ +// FILE: KotlinFile.kt +abstract class KotlinClass : JavaInterface1, JavaInterface2 { + override fun getSomething(): String = "" +} + +fun foo(k: KotlinClass) { + useString(k.getSomething()) + useString(k.something) + if (k.something == null) return + + k.setSomething("") + k.something = "" +} + +fun useString(i: String) {} + +// FILE: JavaInterface1.java +public interface JavaInterface1 { + String getSomething(); +} + +// FILE: JavaInterface2.java +public interface JavaInterface2 { + void setSomething(String value); +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava3.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava3.txt new file mode 100644 index 00000000000..dab991a8dcf --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava3.txt @@ -0,0 +1,29 @@ +package + +public /*synthesized*/ fun JavaInterface1(/*0*/ function: () -> kotlin.String!): JavaInterface1 +public /*synthesized*/ fun JavaInterface2(/*0*/ function: (kotlin.String!) -> kotlin.Unit): JavaInterface2 +internal fun foo(/*0*/ k: KotlinClass): kotlin.Unit +internal fun useString(/*0*/ i: kotlin.String): kotlin.Unit + +public interface JavaInterface1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal abstract class KotlinClass : JavaInterface1, JavaInterface2 { + public constructor KotlinClass() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun getSomething(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava4.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava4.kt new file mode 100644 index 00000000000..a53a67f5084 --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava4.kt @@ -0,0 +1,28 @@ +// FILE: KotlinFile.kt +abstract class KotlinClass : JavaInterface3 { + override fun getSomething(): String = "" +} + +fun foo(k: KotlinClass) { + useString(k.getSomething()) + useString(k.something) + if (k.something == null) return + + k.setSomething("") + k.something = "" +} + +fun useString(i: String) {} + +// FILE: JavaInterface1.java +public interface JavaInterface1 { + String getSomething(); +} + +// FILE: JavaInterface2.java +public interface JavaInterface2 { + void setSomething(String value); +} + +// FILE: JavaInterface3.java +public interface JavaInterface3 extends JavaInterface1, JavaInterface2 {} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava4.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava4.txt new file mode 100644 index 00000000000..4d1dff211de --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava4.txt @@ -0,0 +1,37 @@ +package + +public /*synthesized*/ fun JavaInterface1(/*0*/ function: () -> kotlin.String!): JavaInterface1 +public /*synthesized*/ fun JavaInterface2(/*0*/ function: (kotlin.String!) -> kotlin.Unit): JavaInterface2 +internal fun foo(/*0*/ k: KotlinClass): kotlin.Unit +internal fun useString(/*0*/ i: kotlin.String): kotlin.Unit + +public interface JavaInterface1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface3 : JavaInterface1, JavaInterface2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ /*fake_override*/ fun getSomething(): kotlin.String! + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal abstract class KotlinClass : JavaInterface3 { + public constructor KotlinClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun getSomething(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava5.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava5.kt new file mode 100644 index 00000000000..69e516b4abc --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava5.kt @@ -0,0 +1,29 @@ +// FILE: KotlinFile.kt +abstract class KotlinClass : JavaInterface3 { + override fun getSomething(): String = "" +} + +fun foo(k: KotlinClass) { + useString(k.getSomething()) + useString(k.something) + if (k.something == null) return + + k.setSomething("") + k.something = "" +} + +fun useString(i: String) {} + +// FILE: JavaInterface1.java +public interface JavaInterface1 { + String getSomething(); +} + +// FILE: JavaInterface2.java +public interface JavaInterface2 { + String getSomething(); + void setSomething(String value); +} + +// FILE: JavaInterface3.java +public interface JavaInterface3 extends JavaInterface1, JavaInterface2 {} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava5.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava5.txt new file mode 100644 index 00000000000..7f113511b9c --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava5.txt @@ -0,0 +1,37 @@ +package + +public /*synthesized*/ fun JavaInterface1(/*0*/ function: () -> kotlin.String!): JavaInterface1 +internal fun foo(/*0*/ k: KotlinClass): kotlin.Unit +internal fun useString(/*0*/ i: kotlin.String): kotlin.Unit + +public interface JavaInterface1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun getSomething(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface JavaInterface3 : JavaInterface1, JavaInterface2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun getSomething(): kotlin.String! + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal abstract class KotlinClass : JavaInterface3 { + public constructor KotlinClass() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun getSomething(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun setSomething(/*0*/ value: kotlin.String!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/OverrideGetterOnly.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/OverrideGetterOnly.kt new file mode 100644 index 00000000000..c8e14d5333b --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/OverrideGetterOnly.kt @@ -0,0 +1,22 @@ +// FILE: KotlinFile.kt + +fun foo(o: JavaClass2) { + useString(o.something) + o.something = "" + o.setSomething(1) + o.something = 1 // we generate extension property for JavaClass2 with more specific type + o.something += "1" +} + +fun useString(i: String) {} + +// FILE: JavaClass1.java +public class JavaClass1 { + public Object getSomething() { return null; } + public void setSomething(Object value) { } +} + +// FILE: JavaClass2.java +public class JavaClass2 extends JavaClass1 { + public String getSomething() { return ""; } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/OverrideGetterOnly.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/OverrideGetterOnly.txt new file mode 100644 index 00000000000..d49adc526da --- /dev/null +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/OverrideGetterOnly.txt @@ -0,0 +1,22 @@ +package + +internal fun foo(/*0*/ o: JavaClass2): kotlin.Unit +internal fun useString(/*0*/ i: kotlin.String): kotlin.Unit + +public open class JavaClass1 { + public constructor JavaClass1() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getSomething(): kotlin.Any! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun setSomething(/*0*/ value: kotlin.Any!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class JavaClass2 : JavaClass1 { + public constructor JavaClass2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun getSomething(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun setSomething(/*0*/ value: kotlin.Any!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 4de00ef2cf9..9609029d56a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -14082,12 +14082,54 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("JavaOverridesKotlin.kt") + public void testJavaOverridesKotlin() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/JavaOverridesKotlin.kt"); + doTest(fileName); + } + + @TestMetadata("KotlinOverridesJava.kt") + public void testKotlinOverridesJava() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava.kt"); + doTest(fileName); + } + + @TestMetadata("KotlinOverridesJava2.kt") + public void testKotlinOverridesJava2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava2.kt"); + doTest(fileName); + } + + @TestMetadata("KotlinOverridesJava3.kt") + public void testKotlinOverridesJava3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava3.kt"); + doTest(fileName); + } + + @TestMetadata("KotlinOverridesJava4.kt") + public void testKotlinOverridesJava4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava4.kt"); + doTest(fileName); + } + + @TestMetadata("KotlinOverridesJava5.kt") + public void testKotlinOverridesJava5() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/KotlinOverridesJava5.kt"); + doTest(fileName); + } + @TestMetadata("OnlyPublic.kt") public void testOnlyPublic() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.kt"); doTest(fileName); } + @TestMetadata("OverrideGetterOnly.kt") + public void testOverrideGetterOnly() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/OverrideGetterOnly.kt"); + doTest(fileName); + } + @TestMetadata("SetterOnly.kt") public void testSetterOnly() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/SetterOnly.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java index 040a22f3ef9..86f18641a95 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxAgainstJavaCodegenTestGenerated.java @@ -847,6 +847,12 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod doTestAgainstJava(fileName); } + @TestMetadata("overrideOnlyGetter.kt") + public void testOverrideOnlyGetter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/syntheticExtensions/overrideOnlyGetter.kt"); + doTestAgainstJava(fileName); + } + @TestMetadata("plusPlus.kt") public void testPlusPlus() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/syntheticExtensions/plusPlus.kt");