提交 ad683788 编写于 作者: D Denis Zharkov

Support loading methods from Java as common properties overrides

上级 396f38e9
......@@ -62,28 +62,10 @@ interface SyntheticJavaPropertyDescriptor : PropertyDescriptor {
}
fun propertyNameByGetMethodName(methodName: Name): Name?
= propertyNameFromAccessorMethodName(methodName, "get") ?: propertyNameFromAccessorMethodName(methodName, "is", removePrefix = false)
= org.jetbrains.kotlin.load.java.propertyNameByGetMethodName(methodName)
fun propertyNameBySetMethodName(methodName: Name, withIsPrefix: Boolean): Name?
= propertyNameFromAccessorMethodName(methodName, "set", addPrefix = if (withIsPrefix) "is" else null)
private fun propertyNameFromAccessorMethodName(methodName: Name, prefix: String, removePrefix: Boolean = true, addPrefix: String? = null): Name? {
if (methodName.isSpecial()) return null
val identifier = methodName.getIdentifier()
if (!identifier.startsWith(prefix)) return null
if (identifier.length() == prefix.length()) return null
if (identifier[prefix.length()] in 'a'..'z') return null
if (addPrefix != null) {
assert(removePrefix)
return Name.identifier(addPrefix + identifier.removePrefix(prefix))
}
if (!removePrefix) return methodName
val name = identifier.removePrefix(prefix).decapitalizeSmart(asciiOnly = true)
if (!Name.isValidIdentifier(name)) return null
return Name.identifier(name)
}
= org.jetbrains.kotlin.load.java.propertyNameBySetMethodName(methodName, withIsPrefix)
}
}
......
public class J extends A {
public boolean okField = false;
public int getValProp() {
return 123;
}
public int getVarProp() {
return 456;
}
public void setVarProp(int x) {
okField = true;
}
public int isProp() {
return 789;
}
public void setProp(int x) {
okField = true;
}
}
open class A {
open val valProp: Int = -1
open var varProp: Int = -1
open var isProp: Int = -1
}
fun box(): String {
val j = J()
val a: A = j
if (j.valProp != 123) return "fail 1"
if (a.valProp != 123) return "fail 2"
j.varProp = -1
if (!j.okField) return "fail 3"
j.okField = false
a.varProp = -1
if (!j.okField) return "fail 4"
j.okField = false
if (j.varProp != 456) return "fail 5"
if (a.varProp != 456) return "fail 6"
j.isProp = -1
if (!j.okField) return "fail 7"
j.okField = false
a.isProp = -1
if (!j.okField) return "fail 8"
j.okField = false
if (j.isProp != 789) return "fail 9"
if (a.isProp != 789) return "fail 10"
return "OK"
}
// FILE: A.java
public interface A extends B {
public int getFoo();
public void setFoo(int x);
}
// FILE: BImpl.java
public class BImpl implements B {
public int getFoo() {}
public void setFoo(int x) {}
}
// FILE: main.kt
interface B {
var foo: Int
}
interface C1 : A {
override var foo: Int
}
class D : C1, BImpl()
fun foo() {
BImpl().foo = BImpl().foo + 1
D().foo = D().foo + 2
}
package
public fun foo(): kotlin.Unit
public interface A : B {
public abstract override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface B {
public abstract var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class BImpl : B {
public constructor BImpl()
public open override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface C1 : A {
public abstract override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class D : C1, BImpl {
public constructor D()
public open override /*2*/ /*fake_override*/ var foo: kotlin.Int
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
// FILE: A.java
public class A extends B {
public int isFoo() { return 0; }
public void setFoo(int x) {}
}
// FILE: F.java
public class F extends B {
public final int isFoo() { return 0; }
public final void setFoo(int x) {}
}
// FILE: main.kt
open class B {
open var isFoo: Int = 1
}
class C1 : A() {
override var isFoo: Int = 2
}
class C2 : F() {
<!OVERRIDING_FINAL_MEMBER!>override<!> var isFoo: Int = 3
}
package
public open class A : B {
public constructor A()
public open override /*1*/ var isFoo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class B {
public constructor B()
public open var isFoo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class C1 : A {
public constructor C1()
public open override /*1*/ var isFoo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class C2 : F {
public constructor C2()
public open override /*1*/ var isFoo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class F : B {
public constructor F()
public final override /*1*/ var isFoo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
// FILE: A.java
public class A extends B {
public int getFoo() { return 0; }
}
// FILE: F.java
public class F extends B {
public final int getFoo() { return 0; }
}
// FILE: main.kt
open class B {
open val foo: Int = 1
}
class C1 : A() {
override val foo: Int = 2
}
class C2 : F() {
<!OVERRIDING_FINAL_MEMBER!>override<!> val foo: Int = 3
}
package
public open class A : B {
public constructor A()
public open override /*1*/ val foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class B {
public constructor B()
public open val foo: kotlin.Int = 1
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class C1 : A {
public constructor C1()
public open override /*1*/ val foo: kotlin.Int = 2
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class C2 : F {
public constructor C2()
public open override /*1*/ val foo: kotlin.Int = 3
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class F : B {
public constructor F()
public final override /*1*/ val foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
// FILE: A.java
public class A extends B {
public int getFoo() { return 0; }
public void setFoo(int x) {}
}
// FILE: F.java
public class F extends B {
public final int getFoo() { return 0; }
public final void setFoo(int x) {}
}
// FILE: ConflictingModality.java
public class ConflictingModality extends B {
public final int getFoo() { return 0; }
public abstract void setFoo(int x) {}
}
// FILE: ConflictingVisibility.java
public class ConflictingVisibility extends B {
public int getFoo() { return 0; }
protected void setFoo(int x) {}
}
// FILE: main.kt
open class B {
// check that final is not overridden
open protected var foo: Int = 1
}
class C1 : A() {
override var foo: Int = 2
}
class C2 : F() {
<!OVERRIDING_FINAL_MEMBER!>override<!> var foo: Int = 3
}
package
public open class A : B {
public constructor A()
public open override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class B {
public constructor B()
protected open var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class C1 : A {
public constructor C1()
public open override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class C2 : F {
public constructor C2()
public open override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class ConflictingModality : B {
public constructor ConflictingModality()
protected open override /*1*/ /*fake_override*/ var foo: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun getFoo(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun setFoo(/*0*/ x: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class ConflictingVisibility : B {
public constructor ConflictingVisibility()
public open override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class F : B {
public constructor F()
public final override /*1*/ var foo: kotlin.Int
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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
......@@ -5,7 +5,7 @@ public fun foo(): kotlin.Unit
@kotlin.jvm.PurelyImplements(value = "kotlin.MutableCollection") public/*package*/ open class A</*0*/ T : kotlin.Any!> : java.util.AbstractCollection<T!>, kotlin.MutableCollection<T> {
public/*package*/ constructor A</*0*/ T : kotlin.Any!>()
@java.lang.Override() public open override /*2*/ val size: kotlin.Int
public open override /*2*/ val size: kotlin.Int
public open override /*2*/ /*fake_override*/ fun add(/*0*/ e: T): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun addAll(/*0*/ c: kotlin.Collection<T>): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun clear(): kotlin.Unit
......
......@@ -6,7 +6,7 @@ public fun foo(): kotlin.Unit
@kotlin.jvm.PurelyImplements(value = "kotlin.MutableList") public/*package*/ open class A</*0*/ T : kotlin.Any!> : java.util.AbstractList<T!>, kotlin.MutableList<T> {
public/*package*/ constructor A</*0*/ T : kotlin.Any!>()
protected/*protected and package*/ final override /*1*/ /*fake_override*/ var modCount: kotlin.Int
@java.lang.Override() public open override /*2*/ val size: kotlin.Int
public open override /*2*/ val size: kotlin.Int
public open override /*2*/ /*fake_override*/ fun add(/*0*/ e: T): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun add(/*0*/ index: kotlin.Int, /*1*/ element: T): kotlin.Unit
public open override /*2*/ /*fake_override*/ fun addAll(/*0*/ c: kotlin.Collection<T>): kotlin.Boolean
......
......@@ -6,7 +6,7 @@ public val y: B<kotlin.String>
@kotlin.jvm.PurelyImplements(value = "") public open class A</*0*/ T : kotlin.Any!> : java.util.AbstractList<T!> {
public constructor A</*0*/ T : kotlin.Any!>()
protected/*protected and package*/ final override /*1*/ /*fake_override*/ var modCount: kotlin.Int
@java.lang.Override() public open override /*1*/ val size: kotlin.Int
public open override /*1*/ val size: kotlin.Int
public open override /*1*/ /*fake_override*/ fun add(/*0*/ e: T!): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun add(/*0*/ index: kotlin.Int, /*1*/ element: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun addAll(/*0*/ c: kotlin.Collection<T!>): kotlin.Boolean
......
......@@ -6,7 +6,7 @@ public fun foo(): kotlin.Unit
@kotlin.jvm.PurelyImplements(value = "kotlin.MutableList") public/*package*/ open class A</*0*/ T : kotlin.Any!, /*1*/ V : kotlin.Any!> : java.util.AbstractList<T!> {
public/*package*/ constructor A</*0*/ T : kotlin.Any!, /*1*/ V : kotlin.Any!>()
protected/*protected and package*/ final override /*1*/ /*fake_override*/ var modCount: kotlin.Int
@java.lang.Override() public open override /*1*/ val size: kotlin.Int
public open override /*1*/ val size: kotlin.Int
public open override /*1*/ /*fake_override*/ fun add(/*0*/ e: T!): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun add(/*0*/ index: kotlin.Int, /*1*/ element: T!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun addAll(/*0*/ c: kotlin.Collection<T!>): kotlin.Boolean
......
......@@ -9087,6 +9087,39 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
}
}
@TestMetadata("compiler/testData/diagnostics/tests/j+k/properties")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Properties extends AbstractJetDiagnosticsTest {
public void testAllFilesPresentInProperties() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/properties"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("interface.kt")
public void testInterface() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/properties/interface.kt");
doTest(fileName);
}
@TestMetadata("isName.kt")
public void testIsName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/properties/isName.kt");
doTest(fileName);
}
@TestMetadata("val.kt")
public void testVal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/properties/val.kt");
doTest(fileName);
}
@TestMetadata("var.kt")
public void testVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/properties/var.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/j+k/types")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
......
......@@ -359,6 +359,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName);
}
@TestMetadata("commonProperties")
public void testCommonProperties() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/properties/commonProperties/");
doTestWithJava(fileName);
}
@TestMetadata("substituteJavaSuperField")
public void testSubstituteJavaSuperField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/properties/substituteJavaSuperField/");
......
......@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
class FieldOverridabilityCondition : ExternalOverridabilityCondition {
......@@ -26,8 +27,4 @@ class FieldOverridabilityCondition : ExternalOverridabilityCondition {
return subDescriptor.isJavaField == superDescriptor.isJavaField
}
// Currently getter is null iff it's loaded from Java field
private val PropertyDescriptor.isJavaField: Boolean
get() = getter == null
}
......@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.addToStdlib.check
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
private val BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES = setOf(FqName("kotlin.Collection.size"), FqName("kotlin.Map.size"))
private val BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES = BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES.map { it.shortName() }.toSet()
......@@ -61,35 +60,26 @@ private fun CallableDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.check { it
val Name.isBuiltinSpecialPropertyName: Boolean get() = this in BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES
private val CallableDescriptor.builtinSpecialPropertyAccessorName: String?
get() = when(this) {
is PropertyAccessorDescriptor -> correspondingProperty.check { it.hasBuiltinSpecialPropertyFqName() }?.name?.asString()
else -> null
}
public val CallableMemberDescriptor.builtinSpecialPropertyAccessorName: String?
get() = propertyIfAccessor.check { it.hasBuiltinSpecialPropertyFqName() }?.name?.asString()
@Suppress("UNCHECKED_CAST")
val <T : CallableDescriptor> T.builtinSpecialOverridden: T? get() {
return when (this) {
is PropertyAccessorDescriptor -> check { correspondingProperty.hasBuiltinSpecialPropertyFqName() }
?: overriddenDescriptors.firstNotNullResult { it.builtinSpecialOverridden } as T?
is PropertyDescriptor -> check { hasBuiltinSpecialPropertyFqName() }
?: overriddenDescriptors.firstNotNullResult { it.builtinSpecialOverridden } as T?
else -> null
}
val <T : CallableMemberDescriptor> T.builtinSpecialOverridden: T? get() {
return firstOverridden { it.propertyIfAccessor.hasBuiltinSpecialPropertyFqName() } as T?
}
fun CallableDescriptor.overridesBuiltinSpecialDeclaration(): Boolean = builtinSpecialOverridden != null
fun CallableMemberDescriptor.overridesBuiltinSpecialDeclaration(): Boolean = builtinSpecialOverridden != null
public val CallableDescriptor.jvmMethodNameIfSpecial: String?
public val CallableMemberDescriptor.jvmMethodNameIfSpecial: String?
get() = builtinOverriddenThatAffectsJvmName?.builtinSpecialPropertyAccessorName
public val CallableDescriptor.builtinOverriddenThatAffectsJvmName: CallableDescriptor?
get() = if (hasBuiltinSpecialPropertyFqName() || isFromJava) builtinSpecialOverridden else null
private val CallableMemberDescriptor.builtinOverriddenThatAffectsJvmName: CallableMemberDescriptor?
get() = if (hasBuiltinSpecialPropertyFqName() || original.isFromJava) builtinSpecialOverridden else null
private val CallableDescriptor.isFromJava: Boolean
private val CallableMemberDescriptor.isFromJava: Boolean
get() = propertyIfAccessor is JavaCallableMemberDescriptor
private val CallableDescriptor.propertyIfAccessor: CallableDescriptor
private val CallableMemberDescriptor.propertyIfAccessor: CallableDescriptor
get() = if (this is PropertyAccessorDescriptor) correspondingProperty else this
val CallableMemberDescriptor.hasErasedValueParametersInJava: Boolean
......
......@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.types.JetType;
......@@ -79,8 +80,16 @@ public class JavaPropertyDescriptor extends PropertyDescriptorImpl implements Ja
newGetter.initialize(enhancedReturnType);
}
assert getSetter() == null : "Field must not have a setter: " + this;
enhanced.initialize(newGetter, null);
PropertySetterDescriptorImpl newSetter = null;
PropertySetterDescriptor setter = getSetter();
if (setter != null) {
newSetter = new PropertySetterDescriptorImpl(
enhanced, setter.getAnnotations(), setter.getModality(), setter.getVisibility(),
setter.hasBody(), setter.isDefault(), getKind(), setter, SourceElement.NO_SOURCE);
newSetter.initialize(setter.getValueParameters().get(0));
}
enhanced.initialize(newGetter, newSetter);
enhanced.setSetterProjectedOut(isSetterProjectedOut());
if (compileTimeInitializer != null) {
enhanced.setCompileTimeInitializer(compileTimeInitializer);
......
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.load.java.lazy.descriptors
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
// Currently getter is null iff it's loaded from Java field
public val PropertyDescriptor.isJavaField: Boolean
get() = getter == null
\ No newline at end of file
......@@ -16,10 +16,12 @@
package org.jetbrains.kotlin.load.java.lazy.descriptors
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
......@@ -34,10 +36,7 @@ import org.jetbrains.kotlin.load.java.lazy.child
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
import org.jetbrains.kotlin.load.java.lazy.types.RawSubstitution
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.typeEnhacement.enhanceSignatures
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
......@@ -80,30 +79,65 @@ public class LazyJavaClassMemberScope(
}
override fun JavaMethodDescriptor.isVisibleAsFunction(): Boolean {
if (!canOverrideProperty) return true
return !doesOverrideAnySpecialProperty(getPropertiesFromSupertypes(name))
}
val nameAsString = name.asString()
if (JvmAbi.isGetterName(nameAsString)) {
val propertyName = propertyNameByGetMethodName(name) ?: return true
return !doesClassOverrideAnyProperty(getPropertiesFromSupertypes(propertyName))
}
if (JvmAbi.isSetterName(nameAsString)) {
return propertyNamesBySetMethodName(name).none {
propertyName ->
getPropertiesFromSupertypes(propertyName).any {
property -> property.isVar && doesClassOverridesProperty(property)
}
}
}
if (name.isBuiltinSpecialPropertyName) {
return !doesClassOverrideAnyProperty(getPropertiesFromSupertypes(name))
}
private val JavaMethodDescriptor.canOverrideProperty: Boolean
get() = valueParameters.isEmpty() && name.isBuiltinSpecialPropertyName
return true
}
private fun JavaMethodDescriptor.doesOverridesSpecialBuiltinProperty(property: PropertyDescriptor): Boolean {
if (valueParameters.isNotEmpty()) return false
private fun doesClassOverrideAnyProperty(properties: Collection<PropertyDescriptor>)
= properties.any { property -> doesClassOverridesProperty(property) }
// TODO: is it always false?
if (name != property.name) return false
private fun PropertyDescriptor.findGetterOverride(): JavaMethodDescriptor? {
val getterName = getter?.builtinSpecialOverridden?.builtinSpecialPropertyAccessorName ?: JvmAbi.getterName(name.asString())
return memberIndex().findMethodsByName(Name.identifier(getterName)).firstNotNullResult factory@{
javaMethod ->
val descriptor = resolveMethodToFunctionDescriptor(javaMethod)
if (descriptor.valueParameters.size != 0) return@factory null
return JetTypeChecker.DEFAULT.isSubtypeOf(returnType ?: return false, property.type)
descriptor.check { JetTypeChecker.DEFAULT.isSubtypeOf(descriptor.returnType ?: return@check false, type) }
}
}
private fun JavaMethodDescriptor.doesOverrideAnySpecialProperty(properties: Collection<PropertyDescriptor>): Boolean {
return properties.any overridesProperty@{
property ->
val specialOverridden = property.builtinSpecialOverridden ?: return@overridesProperty false
doesOverridesSpecialBuiltinProperty(specialOverridden)
private fun PropertyDescriptor.findSetterOverride(): JavaMethodDescriptor? {
return memberIndex().findMethodsByName(Name.identifier(JvmAbi.setterName(name.asString()))).firstNotNullResult factory@{
javaMethod ->
val descriptor = resolveMethodToFunctionDescriptor(javaMethod)
if (descriptor.valueParameters.size != 1) return@factory null
if (!KotlinBuiltIns.isUnit(descriptor.returnType ?: return@factory null)) return@factory null
descriptor.check { JetTypeChecker.DEFAULT.equalTypes(descriptor.valueParameters.single().type, type) }
}
}
private fun doesClassOverridesProperty(property: PropertyDescriptor): Boolean {
if (property.isJavaField) return false
val getter = property.findGetterOverride()
val setter = property.findSetterOverride()
if (getter == null) return false
if (!property.isVar) return true
return setter != null && setter.modality == getter.modality
}
override fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {
val functionsFromSupertypes = getFunctionsFromSupertypes(name)
......@@ -122,27 +156,22 @@ public class LazyJavaClassMemberScope(
}
val propertiesFromSupertypes = getPropertiesFromSupertypes(name)
addPropertyOverrideByMethod(name, propertiesFromSupertypes, result)
addPropertyOverrideByMethod(propertiesFromSupertypes, result)
result.addAll(DescriptorResolverUtils.resolveOverrides(name, propertiesFromSupertypes, result, getContainingDeclaration(),
c.components.errorReporter))
}
private fun addPropertyOverrideByMethod(
name: Name,
propertiesFromSupertypes: Set<PropertyDescriptor>,
result: MutableCollection<PropertyDescriptor>
) {
val javaMethod = memberIndex()
.findMethodsByName(name)
.firstOrNull { it.valueParameters.isEmpty() && it.typeParameters.isEmpty() && it.visibility.isPublicAPI }
?: return
val methodDescriptor = resolveMethodToFunctionDescriptor(javaMethod)
if (methodDescriptor.doesOverrideAnySpecialProperty(propertiesFromSupertypes)) {
result.add(createPropertyDescriptorWithDefaultGetter(javaMethod, methodDescriptor.returnType, methodDescriptor.modality))
for (property in propertiesFromSupertypes) {
val newProperty = createPropertyDescriptorByMethods(property)
if (newProperty != null) {
result.add(newProperty)
break
}
}
}
......@@ -172,6 +201,40 @@ public class LazyJavaClassMemberScope(
return propertyDescriptor
}
private fun createPropertyDescriptorByMethods(
overriddenProperty: PropertyDescriptor
): JavaPropertyDescriptor? {
if (!doesClassOverridesProperty(overriddenProperty)) return null
val getterMethod = overriddenProperty.findGetterOverride()!!
val setterMethod =
if (overriddenProperty.isVar)
overriddenProperty.findSetterOverride()!!
else
null
val propertyDescriptor = JavaPropertyDescriptor(
getContainingDeclaration(), Annotations.EMPTY, getterMethod.modality, getterMethod.visibility,
/* isVar = */ setterMethod != null, overriddenProperty.name, getterMethod.source,
/* original */ null,
/* isStaticFinal = */ false
)
propertyDescriptor.setType(getterMethod.returnType!!, listOf(), getDispatchReceiverParameter(), null as JetType?)
val getter = DescriptorFactory.createGetter(
propertyDescriptor, getterMethod.annotations, /* isDefault = */false, getterMethod.source
).apply {
initialize(propertyDescriptor.type)
}
val setter = setterMethod?.let { setterMethod ->
DescriptorFactory.createSetter(propertyDescriptor, setterMethod.annotations, /* isDefault = */false, setterMethod.visibility)
}
return propertyDescriptor.apply { initialize(getter, setter) }
}
private fun getPropertiesFromSupertypes(name: Name): Set<PropertyDescriptor> {
return getContainingDeclaration().typeConstructor.supertypes.flatMap {
it.memberScope.getProperties(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS).map { p -> p as PropertyDescriptor }
......
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
fun propertyNameByGetMethodName(methodName: Name): Name?
= propertyNameFromAccessorMethodName(methodName, "get") ?: propertyNameFromAccessorMethodName(methodName, "is", removePrefix = false)
fun propertyNameBySetMethodName(methodName: Name, withIsPrefix: Boolean): Name?
= propertyNameFromAccessorMethodName(methodName, "set", addPrefix = if (withIsPrefix) "is" else null)
fun propertyNamesBySetMethodName(methodName: Name)
= listOf(propertyNameBySetMethodName(methodName, false), propertyNameBySetMethodName(methodName, true)).filterNotNull()
private fun propertyNameFromAccessorMethodName(methodName: Name, prefix: String, removePrefix: Boolean = true, addPrefix: String? = null): Name? {
if (methodName.isSpecial()) return null
val identifier = methodName.getIdentifier()
if (!identifier.startsWith(prefix)) return null
if (identifier.length() == prefix.length()) return null
if (identifier[prefix.length()] in 'a'..'z') return null
if (addPrefix != null) {
assert(removePrefix)
return Name.identifier(addPrefix + identifier.removePrefix(prefix))
}
if (!removePrefix) return methodName
val name = identifier.removePrefix(prefix).decapitalizeSmart(asciiOnly = true)
if (!Name.isValidIdentifier(name)) return null
return Name.identifier(name)
}
......@@ -56,10 +56,20 @@ public class DescriptorFactory {
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations,
boolean isDefault
) {
return createSetter(propertyDescriptor, annotations, isDefault, propertyDescriptor.getVisibility());
}
@NotNull
public static PropertySetterDescriptorImpl createSetter(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations,
boolean isDefault,
@NotNull Visibility visibility
) {
PropertySetterDescriptorImpl setterDescriptor =
new PropertySetterDescriptorImpl(propertyDescriptor, annotations, propertyDescriptor.getModality(),
propertyDescriptor.getVisibility(), !isDefault, isDefault,
visibility, !isDefault, isDefault,
CallableMemberDescriptor.Kind.DECLARATION, null, propertyDescriptor.getSource());
setterDescriptor.initializeDefault();
return setterDescriptor;
......@@ -78,9 +88,18 @@ public class DescriptorFactory {
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations,
boolean isDefault) {
return createGetter(propertyDescriptor, annotations, isDefault, propertyDescriptor.getSource());
}
@NotNull
public static PropertyGetterDescriptorImpl createGetter(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations,
boolean isDefault,
@NotNull SourceElement sourceElement) {
return new PropertyGetterDescriptorImpl(propertyDescriptor, annotations, propertyDescriptor.getModality(),
propertyDescriptor.getVisibility(), !isDefault, isDefault,
CallableMemberDescriptor.Kind.DECLARATION, null, propertyDescriptor.getSource());
CallableMemberDescriptor.Kind.DECLARATION, null, sourceElement);
}
@NotNull
......
......@@ -28,12 +28,12 @@ internal class KFunctionFromReferenceImpl(
val reference: FunctionReference
): KFunctionImpl(
reference.getOwner() as? KDeclarationContainerImpl ?: EmptyContainerForLocal,
reference.getName(),
reference.name,
reference.getSignature()
) {
override fun getArity() = reference.getArity()
override val name = reference.getName()
override val name = reference.name
// The rest of the class is auto-generated. Use the following script:
// (0..22).forEach { n -> println("override fun invoke(" + (1..n).joinToString { "p$it: Any?" } + "): Any? = reference(" + (1..n).joinToString { "p$it" } + ")") }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册