Synthetic extensions for non-public get/set java methods

This commit is contained in:
Valentin Kipyatkov
2015-07-29 18:15:27 +03:00
parent d5f95cf126
commit c3064e2b0f
8 changed files with 84 additions and 35 deletions
@@ -116,7 +116,7 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : JetScopeImp
return descriptor.valueParameters.isEmpty()
&& descriptor.typeParameters.isEmpty()
&& descriptor.visibility == Visibilities.PUBLIC //TODO: what about protected and package-local?
&& descriptor.visibility.isVisibleOutside()
}
private fun isGoodSetMethod(descriptor: FunctionDescriptor, getMethod: FunctionDescriptor): Boolean {
@@ -133,7 +133,7 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : JetScopeImp
return parameter.varargElementType == null
&& descriptor.typeParameters.isEmpty()
&& descriptor.returnType?.let { it.isUnit() } ?: false
&& descriptor.visibility == Visibilities.PUBLIC
&& descriptor.visibility.isVisibleOutside()
}
private fun FunctionDescriptor.findOverridden(condition: (FunctionDescriptor) -> Boolean): FunctionDescriptor? {
@@ -251,15 +251,15 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : JetScopeImp
name: Name,
type: JetType
) : SyntheticJavaPropertyDescriptor, PropertyDescriptorImpl(
DescriptorUtils.getContainingModule(ownerClass)/* TODO:is it ok? */,
DescriptorUtils.getContainingModule(ownerClass),
null,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PUBLIC,
syntheticExtensionVisibility(getMethod),
setMethod != null,
name,
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE/*TODO?*/
SourceElement.NO_SOURCE
) {
init {
val classTypeParams = ownerClass.typeConstructor.parameters
@@ -273,24 +273,24 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : JetScopeImp
val getter = PropertyGetterDescriptorImpl(this,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PUBLIC,
visibility,
false,
false,
CallableMemberDescriptor.Kind.SYNTHESIZED,
null,
SourceElement.NO_SOURCE/*TODO*/)
SourceElement.NO_SOURCE)
getter.initialize(null)
val setter = if (setMethod != null)
PropertySetterDescriptorImpl(this,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PUBLIC,
syntheticExtensionVisibility(setMethod),
false,
false,
CallableMemberDescriptor.Kind.SYNTHESIZED,
null,
SourceElement.NO_SOURCE/*TODO*/)
SourceElement.NO_SOURCE)
else
null
setter?.initializeDefault()
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.DescriptorSubstitutor
import org.jetbrains.kotlin.types.JetType
@@ -46,7 +45,7 @@ class SamAdapterFunctionsScope(storageManager: StorageManager) : JetScope by Jet
}
private fun extensionForFunctionNotCached(function: FunctionDescriptor): FunctionDescriptor? {
if (function.visibility == Visibilities.PRIVATE || function.visibility == Visibilities.PRIVATE_TO_THIS || function.visibility == Visibilities.INVISIBLE_FAKE) return null
if (!function.visibility.isVisibleOutside()) return null
if (!function.hasJavaOriginInHierarchy()) return null //TODO: should we go into base at all?
if (!SingleAbstractMethodUtils.isSamAdapterNecessary(function)) return null
if (function.returnType == null) return null
@@ -111,24 +110,7 @@ class SamAdapterFunctionsScope(storageManager: StorageManager) : JetScope by Jet
val receiverType = typeSubstitutor.safeSubstitute(ownerClass.defaultType, Variance.INVARIANT)
val valueParameters = SingleAbstractMethodUtils.createValueParametersForSamAdapter(originalFunction, this, typeSubstitutor)
val originalVisibility = originalFunction.visibility
val visibility = when (originalVisibility) {
Visibilities.PUBLIC -> Visibilities.PUBLIC
else -> object : Visibility(originalVisibility.name, originalVisibility.isPublicAPI) {
override fun isVisible(receiver: ReceiverValue, what: DeclarationDescriptorWithVisibility, from: DeclarationDescriptor)
= originalVisibility.isVisible(receiver, originalFunction, from)
override fun mustCheckInImports()
= throw UnsupportedOperationException("Should never be called for this visibility")
override fun normalize()
= originalVisibility.normalize()
override val displayName: String
get() = originalVisibility.displayName + " for synthetic extension"
}
}
val visibility = syntheticExtensionVisibility(originalFunction)
initialize(receiverType, null, typeParameters, valueParameters, returnType, Modality.FINAL, visibility)
}
@@ -16,8 +16,9 @@
package org.jetbrains.kotlin.synthetic
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
fun FunctionDescriptor.hasJavaOriginInHierarchy(): Boolean {
return if (overriddenDescriptors.isEmpty())
@@ -25,3 +26,27 @@ fun FunctionDescriptor.hasJavaOriginInHierarchy(): Boolean {
else
overriddenDescriptors.any { it.hasJavaOriginInHierarchy() }
}
fun Visibility.isVisibleOutside() = this != Visibilities.PRIVATE && this != Visibilities.PRIVATE_TO_THIS && this != Visibilities.INVISIBLE_FAKE
fun syntheticExtensionVisibility(originalDescriptor: DeclarationDescriptorWithVisibility): Visibility {
val originalVisibility = originalDescriptor.visibility
return when (originalVisibility) {
Visibilities.PUBLIC -> Visibilities.PUBLIC
else -> object : Visibility(originalVisibility.name, originalVisibility.isPublicAPI) {
override fun isVisible(receiver: ReceiverValue, what: DeclarationDescriptorWithVisibility, from: DeclarationDescriptor)
= originalVisibility.isVisible(receiver, originalDescriptor, from)
override fun mustCheckInImports()
= throw UnsupportedOperationException("Should never be called for this visibility")
override fun normalize()
= originalVisibility.normalize()
override val displayName: String
get() = originalVisibility.displayName + " for synthetic extension"
}
}
}
@@ -1,10 +1,14 @@
// FILE: KotlinFile.kt
package k
import JavaClass
fun foo(javaClass: JavaClass) {
javaClass.somethingPublic
javaClass.<!UNRESOLVED_REFERENCE!>somethingProtected<!>
javaClass.<!INVISIBLE_MEMBER!>somethingProtected<!>
javaClass.<!UNRESOLVED_REFERENCE!>somethingPrivate<!>
javaClass.<!UNRESOLVED_REFERENCE!>somethingPackage<!>
<!VAL_REASSIGNMENT!>javaClass.somethingPublic<!> = 1
javaClass.<!INVISIBLE_MEMBER!>somethingPackage<!>
<!INVISIBLE_SETTER!>javaClass.somethingPublic<!> = 1
}
// FILE: JavaClass.java
@@ -1,7 +1,5 @@
package
internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit
public open class JavaClass {
public constructor JavaClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -13,3 +11,7 @@ public open class JavaClass {
protected/*protected and package*/ open fun setSomethingPublic(/*0*/ value: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package k {
internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit
}
@@ -0,0 +1,16 @@
// FILE: KotlinFile.kt
package k
import JavaClass
fun foo(javaClass: JavaClass) {
val <!UNUSED_VARIABLE!>v<!> = javaClass.<!INVISIBLE_MEMBER!>something<!>
javaClass.<!INVISIBLE_MEMBER!>something<!> = 1
javaClass.<!INVISIBLE_MEMBER!>something<!>++
}
// FILE: JavaClass.java
public class JavaClass {
protected int getSomething() { return 1; }
public void setSomething(int value) {}
}
@@ -0,0 +1,14 @@
package
public open class JavaClass {
public constructor JavaClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ open fun getSomething(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open fun setSomething(/*0*/ value: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package k {
internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit
}
@@ -14366,6 +14366,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("SetterHasHigherAccess.kt")
public void testSetterHasHigherAccess() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/SetterHasHigherAccess.kt");
doTest(fileName);
}
@TestMetadata("SetterOnly.kt")
public void testSetterOnly() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/SetterOnly.kt");