J2K: do not generate super call to abstract property
This commit is contained in:
@@ -348,7 +348,7 @@ class Converter private constructor(
|
|||||||
getter = PropertyAccessor(AccessorKind.GETTER, method.annotations, Modifiers.Empty, method.parameterList, method.body)
|
getter = PropertyAccessor(AccessorKind.GETTER, method.annotations, Modifiers.Empty, method.parameterList, method.body)
|
||||||
getter.assignPrototype(getMethod, CommentsAndSpacesInheritance.NO_SPACES)
|
getter.assignPrototype(getMethod, CommentsAndSpacesInheritance.NO_SPACES)
|
||||||
}
|
}
|
||||||
else if (propertyInfo.modifiers.contains(Modifier.OVERRIDE)) {
|
else if (propertyInfo.modifiers.contains(Modifier.OVERRIDE) && !(propertyInfo.superInfo?.isAbstract() ?: false)) {
|
||||||
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
||||||
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
||||||
val returnStatement = ReturnStatement(superAccess).assignNoPrototype()
|
val returnStatement = ReturnStatement(superAccess).assignNoPrototype()
|
||||||
@@ -357,7 +357,10 @@ class Converter private constructor(
|
|||||||
getter = PropertyAccessor(AccessorKind.GETTER, Annotations.Empty, Modifiers.Empty, parameterList, deferredElement { body })
|
getter = PropertyAccessor(AccessorKind.GETTER, Annotations.Empty, Modifiers.Empty, parameterList, deferredElement { body })
|
||||||
getter.assignNoPrototype()
|
getter.assignNoPrototype()
|
||||||
}
|
}
|
||||||
//TODO: what else?
|
else {
|
||||||
|
//TODO: what else?
|
||||||
|
getter = PropertyAccessor(AccessorKind.GETTER, Annotations.Empty, Modifiers.Empty, null, null).assignNoPrototype()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var setter: PropertyAccessor? = null
|
var setter: PropertyAccessor? = null
|
||||||
@@ -378,7 +381,7 @@ class Converter private constructor(
|
|||||||
setter = PropertyAccessor(AccessorKind.SETTER, method.annotations, accessorModifiers, parameterList, method.body)
|
setter = PropertyAccessor(AccessorKind.SETTER, method.annotations, accessorModifiers, parameterList, method.body)
|
||||||
setter.assignPrototype(setMethod, CommentsAndSpacesInheritance.NO_SPACES)
|
setter.assignPrototype(setMethod, CommentsAndSpacesInheritance.NO_SPACES)
|
||||||
}
|
}
|
||||||
else if (propertyInfo.modifiers.contains(Modifier.OVERRIDE)) {
|
else if (propertyInfo.modifiers.contains(Modifier.OVERRIDE) && !(propertyInfo.superInfo?.isAbstract() ?: false)) {
|
||||||
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
||||||
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
||||||
val valueIdentifier = Identifier("value", false).assignNoPrototype()
|
val valueIdentifier = Identifier("value", false).assignNoPrototype()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.intellij.psi.*
|
|||||||
import com.intellij.psi.util.MethodSignatureUtil
|
import com.intellij.psi.util.MethodSignatureUtil
|
||||||
import org.jetbrains.kotlin.asJava.KtLightMethod
|
import org.jetbrains.kotlin.asJava.KtLightMethod
|
||||||
import org.jetbrains.kotlin.j2k.ast.*
|
import org.jetbrains.kotlin.j2k.ast.*
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
@@ -38,7 +39,8 @@ class PropertyInfo(
|
|||||||
val isGetMethodBodyFieldAccess: Boolean,
|
val isGetMethodBodyFieldAccess: Boolean,
|
||||||
val isSetMethodBodyFieldAccess: Boolean,
|
val isSetMethodBodyFieldAccess: Boolean,
|
||||||
val modifiers: Modifiers,
|
val modifiers: Modifiers,
|
||||||
val specialSetterAccess: Modifier?
|
val specialSetterAccess: Modifier?,
|
||||||
|
val superInfo: SuperInfo?
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
assert(field != null || getMethod != null || setMethod != null)
|
assert(field != null || getMethod != null || setMethod != null)
|
||||||
@@ -73,7 +75,7 @@ class PropertyInfo(
|
|||||||
fun fromFieldWithNoAccessors(field: PsiField, converter: Converter): PropertyInfo {
|
fun fromFieldWithNoAccessors(field: PsiField, converter: Converter): PropertyInfo {
|
||||||
val isVar = field.isVar(converter.referenceSearcher)
|
val isVar = field.isVar(converter.referenceSearcher)
|
||||||
val modifiers = converter.convertModifiers(field, false)
|
val modifiers = converter.convertModifiers(field, false)
|
||||||
return PropertyInfo(field.declarationIdentifier(), isVar, field.type, field, null, null, false, false, modifiers, null)
|
return PropertyInfo(field.declarationIdentifier(), isVar, field.type, field, null, null, false, false, modifiers, null, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,6 +94,21 @@ class PropertyDetectionCache(private val converter: Converter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class SuperInfo {
|
||||||
|
class Property(
|
||||||
|
val isVar: Boolean,
|
||||||
|
val name: String,
|
||||||
|
val hasAbstractModifier: Boolean
|
||||||
|
//TODO: add visibility
|
||||||
|
) : SuperInfo()
|
||||||
|
|
||||||
|
object Function : SuperInfo()
|
||||||
|
|
||||||
|
fun isAbstract(): Boolean {
|
||||||
|
return if (this is Property) hasAbstractModifier else false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class PropertyDetector(
|
private class PropertyDetector(
|
||||||
private val psiClass: PsiClass,
|
private val psiClass: PsiClass,
|
||||||
private val converter: Converter
|
private val converter: Converter
|
||||||
@@ -151,7 +168,8 @@ private class PropertyDetector(
|
|||||||
|
|
||||||
val type = getterInfo?.method?.returnType ?: setterInfo!!.method.parameterList.parameters.single()?.type!!
|
val type = getterInfo?.method?.returnType ?: setterInfo!!.method.parameterList.parameters.single()?.type!!
|
||||||
|
|
||||||
val isOverride = getterInfo?.superProperty != null || setterInfo?.superProperty != null
|
val superProperty = getterInfo?.superProperty ?: setterInfo?.superProperty
|
||||||
|
val isOverride = superProperty != null
|
||||||
|
|
||||||
val modifiers = convertModifiers(field, getterInfo?.method, setterInfo?.method, isOverride)
|
val modifiers = convertModifiers(field, getterInfo?.method, setterInfo?.method, isOverride)
|
||||||
|
|
||||||
@@ -173,7 +191,8 @@ private class PropertyDetector(
|
|||||||
field != null && getterInfo?.field == field,
|
field != null && getterInfo?.field == field,
|
||||||
field != null && setterInfo?.field == field,
|
field != null && setterInfo?.field == field,
|
||||||
modifiers,
|
modifiers,
|
||||||
specialSetterAccess)
|
specialSetterAccess,
|
||||||
|
superProperty)
|
||||||
|
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
memberToPropertyInfo[field] = propertyInfo
|
memberToPropertyInfo[field] = propertyInfo
|
||||||
@@ -329,17 +348,6 @@ private class PropertyDetector(
|
|||||||
val superProperty: SuperInfo.Property?
|
val superProperty: SuperInfo.Property?
|
||||||
)
|
)
|
||||||
|
|
||||||
private sealed class SuperInfo {
|
|
||||||
class Property(
|
|
||||||
val isVar: Boolean,
|
|
||||||
val name: String
|
|
||||||
//TODO: add visibility
|
|
||||||
) : SuperInfo()
|
|
||||||
|
|
||||||
object Function : SuperInfo()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getGetterInfo(method: PsiMethod, superProperty: SuperInfo.Property?): AccessorInfo? {
|
private fun getGetterInfo(method: PsiMethod, superProperty: SuperInfo.Property?): AccessorInfo? {
|
||||||
val propertyName = propertyNameByGetMethod(method) ?: return null
|
val propertyName = propertyNameByGetMethod(method) ?: return null
|
||||||
val field = fieldFromGetterBody(method)
|
val field = fieldFromGetterBody(method)
|
||||||
@@ -364,11 +372,11 @@ private class PropertyDetector(
|
|||||||
val containingClass = superMethod.containingClass!!
|
val containingClass = superMethod.containingClass!!
|
||||||
if (converter.inConversionScope(containingClass)) {
|
if (converter.inConversionScope(containingClass)) {
|
||||||
val propertyInfo = converter.propertyDetectionCache[containingClass][superMethod]
|
val propertyInfo = converter.propertyDetectionCache[containingClass][superMethod]
|
||||||
return if (propertyInfo != null) SuperInfo.Property(propertyInfo.isVar, propertyInfo.name) else SuperInfo.Function
|
return if (propertyInfo != null) SuperInfo.Property(propertyInfo.isVar, propertyInfo.name, propertyInfo.modifiers.contains(Modifier.ABSTRACT)) else SuperInfo.Function
|
||||||
}
|
}
|
||||||
else if (superMethod is KtLightMethod) {
|
else if (superMethod is KtLightMethod) {
|
||||||
val origin = superMethod.kotlinOrigin
|
val origin = superMethod.kotlinOrigin
|
||||||
return if (origin is KtProperty) SuperInfo.Property(origin.isVar, origin.name ?: "") else SuperInfo.Function
|
return if (origin is KtProperty) SuperInfo.Property(origin.isVar, origin.name ?: "", origin.hasModifier(KtTokens.ABSTRACT_KEYWORD)) else SuperInfo.Function
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return SuperInfo.Function
|
return SuperInfo.Function
|
||||||
|
|||||||
Vendored
+4
@@ -70,3 +70,7 @@ public open class KotlinClassWithProperties {
|
|||||||
public open fun getSomething4() { return 1; }
|
public open fun getSomething4() { return 1; }
|
||||||
public open fun setSomething4(value: Int) { }
|
public open fun setSomething4(value: Int) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class KotlinClassAbstractProperty {
|
||||||
|
abstract val isVisible: Boolean
|
||||||
|
}
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package test;
|
||||||
|
|
||||||
|
import kotlinApi.*;
|
||||||
|
|
||||||
|
public class KotlinClassAbstractPropertyImpl extends KotlinClassAbstractProperty {
|
||||||
|
private boolean myIsVisible;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVisible() {
|
||||||
|
return myIsVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void test() {
|
||||||
|
myIsVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import kotlinApi.*
|
||||||
|
|
||||||
|
class KotlinClassAbstractPropertyImpl : KotlinClassAbstractProperty() {
|
||||||
|
override var isVisible: Boolean = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
private fun test() {
|
||||||
|
isVisible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-8
@@ -1,6 +1,6 @@
|
|||||||
// 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: Abstract member cannot be accessed directly
|
// ERROR: Property must be initialized
|
||||||
internal interface I {
|
internal interface I {
|
||||||
val isSomething1: Boolean
|
val isSomething1: Boolean
|
||||||
|
|
||||||
@@ -23,17 +23,15 @@ internal abstract class C : I {
|
|||||||
|
|
||||||
override var isSomething4: Boolean
|
override var isSomething4: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
set(value: Boolean) {
|
set
|
||||||
super.isSomething4 = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override var isSomething5: Boolean
|
override var isSomething5: Boolean
|
||||||
get() = super.isSomething5
|
get
|
||||||
set(value) {
|
set(value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override var something6: Boolean
|
override var something6: Boolean
|
||||||
get() = super.something6
|
get
|
||||||
set(value) {
|
set(value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// ERROR: Abstract member cannot be accessed directly
|
// ERROR: Property must be initialized
|
||||||
// ERROR: Abstract member cannot be accessed directly
|
// ERROR: Property must be initialized
|
||||||
internal interface I {
|
internal interface I {
|
||||||
val something1: Int
|
val something1: Int
|
||||||
|
|
||||||
@@ -56,12 +56,10 @@ internal abstract class C(override val something1: Int) : B(), I {
|
|||||||
|
|
||||||
override var something4: Int
|
override var something4: Int
|
||||||
get() = 0
|
get() = 0
|
||||||
set(value: Int) {
|
set
|
||||||
super.something4 = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override var something5: Int
|
override var something5: Int
|
||||||
get() = super.something5
|
get
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1368,6 +1368,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class DetectProperties extends AbstractJavaToKotlinConverterForWebDemoTest {
|
public static class DetectProperties extends AbstractJavaToKotlinConverterForWebDemoTest {
|
||||||
|
@TestMetadata("AbstractPropertyPrivateSetter.java")
|
||||||
|
public void testAbstractPropertyPrivateSetter() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/detectProperties/AbstractPropertyPrivateSetter.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("AccessInGetterWithThis.java")
|
@TestMetadata("AccessInGetterWithThis.java")
|
||||||
public void testAccessInGetterWithThis() throws Exception {
|
public void testAccessInGetterWithThis() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/detectProperties/AccessInGetterWithThis.java");
|
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/detectProperties/AccessInGetterWithThis.java");
|
||||||
|
|||||||
@@ -1368,6 +1368,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class DetectProperties extends AbstractJavaToKotlinConverterSingleFileTest {
|
public static class DetectProperties extends AbstractJavaToKotlinConverterSingleFileTest {
|
||||||
|
@TestMetadata("AbstractPropertyPrivateSetter.java")
|
||||||
|
public void testAbstractPropertyPrivateSetter() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/detectProperties/AbstractPropertyPrivateSetter.java");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("AccessInGetterWithThis.java")
|
@TestMetadata("AccessInGetterWithThis.java")
|
||||||
public void testAccessInGetterWithThis() throws Exception {
|
public void testAccessInGetterWithThis() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/detectProperties/AccessInGetterWithThis.java");
|
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/detectProperties/AccessInGetterWithThis.java");
|
||||||
|
|||||||
Reference in New Issue
Block a user