Generate accessor with delegation to super when it's necessary
This commit is contained in:
@@ -340,24 +340,52 @@ class Converter private constructor(
|
|||||||
|
|
||||||
//TODO: doc-comments
|
//TODO: doc-comments
|
||||||
|
|
||||||
val getter = getMethod
|
var getter: PropertyAccessor? = null
|
||||||
?.check { propertyInfo.needExplicitGetter } //TODO: what if annotations are not empty?
|
if (propertyInfo.needExplicitGetter) {
|
||||||
?.let {
|
if (getMethod != null) {
|
||||||
val method = convertMethod(it, null, null, null, classKind)!!
|
val method = convertMethod(getMethod, null, null, null, classKind)!!
|
||||||
PropertyAccessor(AccessorKind.GETTER, method.annotations, Modifiers.Empty, method.parameterList, method.body)
|
getter = PropertyAccessor(AccessorKind.GETTER, method.annotations, Modifiers.Empty, method.parameterList, method.body)
|
||||||
.assignPrototype(it, CommentsAndSpacesInheritance.NO_SPACES)
|
getter.assignPrototype(getMethod, CommentsAndSpacesInheritance.NO_SPACES)
|
||||||
}
|
}
|
||||||
|
else if (propertyInfo.isOverride) { //TODO: expression body!
|
||||||
|
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
||||||
|
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
||||||
|
val returnStatement = ReturnStatement(superAccess).assignNoPrototype()
|
||||||
|
val body = Block(listOf(returnStatement), LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
|
||||||
|
val parameterList = ParameterList(emptyList()).assignNoPrototype()
|
||||||
|
getter = PropertyAccessor(AccessorKind.GETTER, Annotations.Empty, Modifiers.Empty, parameterList, deferredElement { body })
|
||||||
|
getter.assignNoPrototype()
|
||||||
|
}
|
||||||
|
//TODO: what else?
|
||||||
|
}
|
||||||
|
|
||||||
var setter: PropertyAccessor? = null
|
var setter: PropertyAccessor? = null
|
||||||
if (propertyInfo.needExplicitSetter) {
|
if (propertyInfo.needExplicitSetter) {
|
||||||
val method = setMethod?.let { convertMethod(it, null, null, null, classKind)!! }
|
|
||||||
val accessorModifiers = Modifiers(propertyInfo.specialSetterAccess.singletonOrEmptyList()).assignNoPrototype()
|
val accessorModifiers = Modifiers(propertyInfo.specialSetterAccess.singletonOrEmptyList()).assignNoPrototype()
|
||||||
setter = PropertyAccessor(
|
if (setMethod != null) {
|
||||||
AccessorKind.SETTER,
|
val method = setMethod.let { convertMethod(it, null, null, null, classKind)!! }
|
||||||
method?.annotations ?: Annotations.Empty,
|
setter = PropertyAccessor(
|
||||||
accessorModifiers,
|
AccessorKind.SETTER,
|
||||||
method?.parameterList?.check { propertyInfo.needSetterBody },
|
method.annotations,
|
||||||
method?.body?.check { propertyInfo.needSetterBody }).assignPrototype(setMethod, CommentsAndSpacesInheritance.NO_SPACES)
|
accessorModifiers,
|
||||||
|
method.parameterList?.check { method.body != null },
|
||||||
|
method.body)
|
||||||
|
setter.assignPrototype(setMethod, CommentsAndSpacesInheritance.NO_SPACES)
|
||||||
|
}
|
||||||
|
else if (propertyInfo.isOverride) { //TODO: expression body!
|
||||||
|
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
||||||
|
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
||||||
|
val valueIdentifier = Identifier("value", false).assignNoPrototype()
|
||||||
|
val assignment = AssignmentExpression(superAccess, valueIdentifier, "=").assignNoPrototype()
|
||||||
|
val body = Block(listOf(assignment), LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
|
||||||
|
val parameter = FunctionParameter(valueIdentifier, propertyType, FunctionParameter.VarValModifier.None, Annotations.Empty, Modifiers.Empty).assignNoPrototype()
|
||||||
|
val parameterList = ParameterList(listOf(parameter)).assignNoPrototype()
|
||||||
|
setter = PropertyAccessor(AccessorKind.SETTER, Annotations.Empty, accessorModifiers, parameterList, deferredElement { body })
|
||||||
|
setter.assignNoPrototype()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setter = PropertyAccessor(AccessorKind.SETTER, Annotations.Empty, accessorModifiers, null, null).assignNoPrototype()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val needInitializer = field != null && shouldGenerateDefaultInitializer(referenceSearcher, field)
|
val needInitializer = field != null && shouldGenerateDefaultInitializer(referenceSearcher, field)
|
||||||
@@ -648,8 +676,7 @@ class Converter private constructor(
|
|||||||
|
|
||||||
val modifiers = ArrayList<Modifier>()
|
val modifiers = ArrayList<Modifier>()
|
||||||
|
|
||||||
//TODO: what if one is abstract and another is not?
|
if (propertyInfo.isAbstract) {
|
||||||
if (getterModifiers.contains(Modifier.ABSTRACT) || setterModifiers.contains(Modifier.ABSTRACT)) {
|
|
||||||
modifiers.add(Modifier.ABSTRACT)
|
modifiers.add(Modifier.ABSTRACT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,30 +36,44 @@ class PropertyInfo(
|
|||||||
val field: PsiField?,
|
val field: PsiField?,
|
||||||
val getMethod: PsiMethod?,
|
val getMethod: PsiMethod?,
|
||||||
val setMethod: PsiMethod?,
|
val setMethod: PsiMethod?,
|
||||||
val needGetterBody: Boolean,
|
val isGetMethodBodyFieldAccess: Boolean,
|
||||||
val needSetterBody: Boolean,
|
val isSetMethodBodyFieldAccess: Boolean,
|
||||||
val specialSetterAccess: Modifier?,
|
val specialSetterAccess: Modifier?,
|
||||||
val isOverride: Boolean
|
val isOverride: Boolean,
|
||||||
|
val isAbstract: Boolean //TODO: modifiers here
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
assert(field != null || getMethod != null || setMethod != null)
|
assert(field != null || getMethod != null || setMethod != null)
|
||||||
if (needGetterBody) {
|
if (isGetMethodBodyFieldAccess) {
|
||||||
assert(getMethod != null && getMethod.body != null)
|
assert(field != null && getMethod != null)
|
||||||
}
|
}
|
||||||
if (needSetterBody) {
|
if (isSetMethodBodyFieldAccess) {
|
||||||
assert(setMethod != null && setMethod.body != null)
|
assert(field != null && setMethod != null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val name: String
|
val name: String
|
||||||
get() = identifier.name
|
get() = identifier.name
|
||||||
|
|
||||||
val needExplicitGetter: Boolean get() = needGetterBody
|
//TODO: what if annotations are not empty?
|
||||||
val needExplicitSetter: Boolean get() = needSetterBody || specialSetterAccess != null
|
val needExplicitGetter: Boolean
|
||||||
|
get() {
|
||||||
|
if (getMethod != null && getMethod.body != null && !isGetMethodBodyFieldAccess) return true
|
||||||
|
return isOverride && this.field == null && !isAbstract
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: what if annotations are not empty?
|
||||||
|
val needExplicitSetter: Boolean
|
||||||
|
get() {
|
||||||
|
if (!isVar) return false
|
||||||
|
if (specialSetterAccess != null) return true
|
||||||
|
if (setMethod != null && setMethod.body != null && !isSetMethodBodyFieldAccess) return true
|
||||||
|
return isOverride && this.field == null && !isAbstract
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromFieldWithNoAccessors(field: PsiField, isVar: Boolean)
|
fun fromFieldWithNoAccessors(field: PsiField, isVar: Boolean)
|
||||||
= PropertyInfo(field.declarationIdentifier(), isVar, field.type, field, null, null, false, false, null, false)
|
= PropertyInfo(field.declarationIdentifier(), isVar, field.type, field, null, null, false, false, null, false, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,16 +162,24 @@ private class PropertyDetector(
|
|||||||
|
|
||||||
val type = field?.type ?: getterInfo?.method?.returnType ?: setterInfo!!.method.parameterList.parameters.single()?.type!!
|
val type = field?.type ?: getterInfo?.method?.returnType ?: setterInfo!!.method.parameterList.parameters.single()?.type!!
|
||||||
|
|
||||||
|
val isOverride = getterInfo?.superProperty != null || setterInfo?.superProperty != null
|
||||||
|
|
||||||
|
//TODO: what if one is abstract and another is not?
|
||||||
|
val isGetterAbstract = getterInfo?.method?.hasModifierProperty(PsiModifier.ABSTRACT) ?: true
|
||||||
|
val isSetterAbstract = setterInfo?.method?.hasModifierProperty(PsiModifier.ABSTRACT) ?: true
|
||||||
|
val isAbstract = field == null && isGetterAbstract && isSetterAbstract
|
||||||
|
|
||||||
val propertyInfo = PropertyInfo(Identifier(propertyName).assignNoPrototype(),
|
val propertyInfo = PropertyInfo(Identifier(propertyName).assignNoPrototype(),
|
||||||
isVar,
|
isVar,
|
||||||
type,
|
type,
|
||||||
field,
|
field,
|
||||||
getterInfo?.method,
|
getterInfo?.method,
|
||||||
setterInfo?.method,
|
setterInfo?.method,
|
||||||
getterInfo != null && getterInfo.method.body != null && (field == null || getterInfo.field != field),
|
field != null && getterInfo?.field == field,
|
||||||
setterInfo != null && setterInfo.method.body != null && (field == null || setterInfo.field != field),
|
field != null && setterInfo?.field == field,
|
||||||
specialSetterAccess,
|
specialSetterAccess,
|
||||||
getterInfo?.superProperty != null || setterInfo?.superProperty != null)
|
isOverride,
|
||||||
|
isAbstract)
|
||||||
|
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
memberToPropertyInfo[field] = propertyInfo
|
memberToPropertyInfo[field] = propertyInfo
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ interface I {
|
|||||||
void setSomething6(int value);
|
void setSomething6(int value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface I1 extends I {
|
||||||
|
void setSomething1(int value);
|
||||||
|
|
||||||
|
int getSomething6();
|
||||||
|
}
|
||||||
|
|
||||||
class B {
|
class B {
|
||||||
public String getFromB1() {
|
public String getFromB1() {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
+20
-4
@@ -1,7 +1,5 @@
|
|||||||
// ERROR: Property must be initialized
|
// ERROR: Abstract member cannot be accessed directly
|
||||||
// ERROR: Property must be initialized
|
// ERROR: Abstract member cannot be accessed directly
|
||||||
// ERROR: Property must be initialized
|
|
||||||
// ERROR: Property must be initialized
|
|
||||||
internal interface I {
|
internal interface I {
|
||||||
val something1: Int
|
val something1: Int
|
||||||
|
|
||||||
@@ -16,6 +14,12 @@ internal interface I {
|
|||||||
fun setSomething6(value: Int)
|
fun setSomething6(value: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal interface I1 : I {
|
||||||
|
fun setSomething1(value: Int)
|
||||||
|
|
||||||
|
val something6: Int
|
||||||
|
}
|
||||||
|
|
||||||
internal open class B {
|
internal open class B {
|
||||||
open val fromB1: String
|
open val fromB1: String
|
||||||
get() {
|
get() {
|
||||||
@@ -66,8 +70,14 @@ internal abstract class C(override val something1: Int) : B(), I {
|
|||||||
get() {
|
get() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
set(value: Int) {
|
||||||
|
super.something4 = value
|
||||||
|
}
|
||||||
|
|
||||||
override var something5: Int
|
override var something5: Int
|
||||||
|
get() {
|
||||||
|
return super.something5
|
||||||
|
}
|
||||||
set(value: Int) {
|
set(value: Int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -97,8 +107,14 @@ internal abstract class C(override val something1: Int) : B(), I {
|
|||||||
get() {
|
get() {
|
||||||
return super.fromB3
|
return super.fromB3
|
||||||
}
|
}
|
||||||
|
set(value: String) {
|
||||||
|
super.fromB3 = value
|
||||||
|
}
|
||||||
|
|
||||||
override var fromB4: String
|
override var fromB4: String
|
||||||
|
get() {
|
||||||
|
return super.fromB4
|
||||||
|
}
|
||||||
set(value: String) {
|
set(value: String) {
|
||||||
super.fromB4 = value
|
super.fromB4 = value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
// ERROR: Property must be initialized
|
|
||||||
// ERROR: Property must be initialized
|
|
||||||
// ERROR: Property must be initialized
|
|
||||||
// ERROR: Property must be initialized
|
|
||||||
// ERROR: Property must be initialized
|
|
||||||
// ERROR: Property must be initialized
|
|
||||||
import kotlinApi.KotlinClassWithProperties
|
import kotlinApi.KotlinClassWithProperties
|
||||||
import javaApi.JavaClassWithProperties
|
import javaApi.JavaClassWithProperties
|
||||||
import javaApi.JavaClassDerivedFromKotlinClassWithProperties
|
import javaApi.JavaClassDerivedFromKotlinClassWithProperties
|
||||||
@@ -21,8 +15,14 @@ internal open class A : KotlinClassWithProperties() {
|
|||||||
get() {
|
get() {
|
||||||
return super.someVar2
|
return super.someVar2
|
||||||
}
|
}
|
||||||
|
set(value: String) {
|
||||||
|
super.someVar2 = value
|
||||||
|
}
|
||||||
|
|
||||||
override var someVar3: String
|
override var someVar3: String
|
||||||
|
get() {
|
||||||
|
return super.someVar3
|
||||||
|
}
|
||||||
set(s: String) {
|
set(s: String) {
|
||||||
super.someVar3 = s
|
super.someVar3 = s
|
||||||
}
|
}
|
||||||
@@ -31,6 +31,9 @@ internal open class A : KotlinClassWithProperties() {
|
|||||||
get() {
|
get() {
|
||||||
return super.someVar4
|
return super.someVar4
|
||||||
}
|
}
|
||||||
|
set(value: String) {
|
||||||
|
super.someVar4 = value
|
||||||
|
}
|
||||||
|
|
||||||
override val someVal: String
|
override val someVal: String
|
||||||
get() {
|
get() {
|
||||||
@@ -85,6 +88,9 @@ internal class C : A() {
|
|||||||
get() {
|
get() {
|
||||||
return super.someVar1
|
return super.someVar1
|
||||||
}
|
}
|
||||||
|
set(value: String) {
|
||||||
|
super.someVar1 = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class D : JavaClassDerivedFromKotlinClassWithProperties() {
|
internal class D : JavaClassDerivedFromKotlinClassWithProperties() {
|
||||||
@@ -92,8 +98,14 @@ internal class D : JavaClassDerivedFromKotlinClassWithProperties() {
|
|||||||
get() {
|
get() {
|
||||||
return "a"
|
return "a"
|
||||||
}
|
}
|
||||||
|
set(value: String) {
|
||||||
|
super.someVar1 = value
|
||||||
|
}
|
||||||
|
|
||||||
override var someVar2: String
|
override var someVar2: String
|
||||||
|
get() {
|
||||||
|
return super.someVar2
|
||||||
|
}
|
||||||
set(value: String) {
|
set(value: String) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user