J2K breaks code if applied to a java class with static field which is accessed from another java class
#KT-11587 Fixed
This commit is contained in:
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.j2k
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
import org.jetbrains.kotlin.j2k.usageProcessing.AccessorToPropertyProcessing
|
||||
import org.jetbrains.kotlin.j2k.usageProcessing.MethodIntoObjectProcessing
|
||||
import org.jetbrains.kotlin.j2k.usageProcessing.MemberIntoObjectProcessing
|
||||
import org.jetbrains.kotlin.j2k.usageProcessing.ToObjectWithOnlyMethodsProcessing
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
@@ -100,9 +100,8 @@ class ClassBodyConverter(private val psiClass: PsiClass,
|
||||
}
|
||||
else {
|
||||
for (psiMember in psiMembers) {
|
||||
if (psiMember is PsiMethod /* fields in object can be accessed as fields from java */
|
||||
&& !psiMember.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
converter.addUsageProcessing(MethodIntoObjectProcessing(psiMember, JvmAbi.INSTANCE_FIELD))
|
||||
if (!psiMember.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
converter.addUsageProcessing(MemberIntoObjectProcessing(psiMember, JvmAbi.INSTANCE_FIELD))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,9 +122,8 @@ class ClassBodyConverter(private val psiClass: PsiClass,
|
||||
}
|
||||
else if (useCompanionObject && member !is Class && psiMember !is PsiEnumConstant && psiMember.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
companionObjectMembers.add(member)
|
||||
if (psiMember is PsiMethod /* fields in companion object can be accessed as fields from java */
|
||||
&& !psiMember.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
converter.addUsageProcessing(MethodIntoObjectProcessing(psiMember, SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT.identifier))
|
||||
if (!psiMember.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
converter.addUsageProcessing(MemberIntoObjectProcessing(psiMember, SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT.identifier))
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -152,7 +152,7 @@ class JavaToKotlinConverter(
|
||||
|
||||
val map: Map<PsiElement, Collection<UsageProcessing>> = usageProcessings.values
|
||||
.flatMap { it }
|
||||
.filter { it.javaCodeProcessor != null || it.kotlinCodeProcessor != null }
|
||||
.filter { it.javaCodeProcessors != null || it.kotlinCodeProcessors != null }
|
||||
.groupBy { it.targetElement }
|
||||
if (map.isEmpty()) return null
|
||||
|
||||
@@ -171,8 +171,8 @@ class JavaToKotlinConverter(
|
||||
|
||||
ProgressManager.getInstance().runProcess(
|
||||
{
|
||||
val searchJava = processings.any { it.javaCodeProcessor != null }
|
||||
val searchKotlin = processings.any { it.kotlinCodeProcessor != null }
|
||||
val searchJava = processings.any { it.javaCodeProcessors != null }
|
||||
val searchKotlin = processings.any { it.kotlinCodeProcessors != null }
|
||||
services.referenceSearcher.findUsagesForExternalCodeProcessing(psiElement, searchJava, searchKotlin)
|
||||
.filterNot { inConversionScope(it.element) }
|
||||
.mapTo(refs) { ReferenceInfo(it, psiElement, it.element.containingFile, processings) }
|
||||
@@ -191,8 +191,8 @@ class JavaToKotlinConverter(
|
||||
ReferenceLoop@
|
||||
for ((reference, target, file, processings) in fileRefs.sortedWith(ReferenceComparator)) {
|
||||
val processors = when (reference.element.language) {
|
||||
JavaLanguage.INSTANCE -> processings.mapNotNull { it.javaCodeProcessor }
|
||||
KotlinLanguage.INSTANCE -> processings.mapNotNull { it.kotlinCodeProcessor }
|
||||
JavaLanguage.INSTANCE -> processings.flatMap { it.javaCodeProcessors }
|
||||
KotlinLanguage.INSTANCE -> processings.flatMap { it.kotlinCodeProcessors }
|
||||
else -> continue@ReferenceLoop
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,12 @@ import org.jetbrains.kotlin.j2k.AccessorKind
|
||||
import org.jetbrains.kotlin.j2k.CodeConverter
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
class AccessorToPropertyProcessing(val accessorMethod: PsiMethod, val accessorKind: AccessorKind, val propertyName: String) : UsageProcessing {
|
||||
override val targetElement: PsiElement get() = accessorMethod
|
||||
|
||||
override val convertedCodeProcessor = object: ConvertedCodeProcessor {
|
||||
override val convertedCodeProcessor = object : ConvertedCodeProcessor {
|
||||
override fun convertMethodUsage(methodCall: PsiMethodCallExpression, codeConverter: CodeConverter): Expression? {
|
||||
val isNullable = codeConverter.typeConverter.methodNullability(accessorMethod).isNullable(codeConverter.settings)
|
||||
|
||||
@@ -47,44 +48,47 @@ class AccessorToPropertyProcessing(val accessorMethod: PsiMethod, val accessorKi
|
||||
}
|
||||
}
|
||||
|
||||
override val javaCodeProcessor: ExternalCodeProcessor? = null
|
||||
override val javaCodeProcessors = emptyList<ExternalCodeProcessor>()
|
||||
|
||||
override val kotlinCodeProcessor: ExternalCodeProcessor? = if (accessorMethod.hasModifierProperty(PsiModifier.PRIVATE))
|
||||
null
|
||||
else
|
||||
object : ExternalCodeProcessor {
|
||||
override fun processUsage(reference: PsiReference): Array<PsiReference>? {
|
||||
val nameExpr = reference.element as? KtSimpleNameExpression ?: return null
|
||||
val callExpr = nameExpr.parent as? KtCallExpression ?: return null
|
||||
override val kotlinCodeProcessors =
|
||||
if (accessorMethod.hasModifierProperty(PsiModifier.PRIVATE))
|
||||
emptyList()
|
||||
else
|
||||
AccessorToPropertyProcessor().singletonList()
|
||||
|
||||
val arguments = callExpr.valueArguments
|
||||
inner class AccessorToPropertyProcessor: ExternalCodeProcessor {
|
||||
override fun processUsage(reference: PsiReference): Array<PsiReference>? {
|
||||
val nameExpr = reference.element as? KtSimpleNameExpression ?: return null
|
||||
val callExpr = nameExpr.parent as? KtCallExpression ?: return null
|
||||
|
||||
val factory = KtPsiFactory(nameExpr.project)
|
||||
var propertyNameExpr = factory.createSimpleName(propertyName)
|
||||
if (accessorKind == AccessorKind.GETTER) {
|
||||
if (arguments.size != 0) return null // incorrect call
|
||||
propertyNameExpr = callExpr.replace(propertyNameExpr) as KtSimpleNameExpression
|
||||
return propertyNameExpr.references
|
||||
val arguments = callExpr.valueArguments
|
||||
|
||||
val factory = KtPsiFactory(nameExpr.project)
|
||||
var propertyNameExpr = factory.createSimpleName(propertyName)
|
||||
if (accessorKind == AccessorKind.GETTER) {
|
||||
if (arguments.size != 0) return null // incorrect call
|
||||
propertyNameExpr = callExpr.replace(propertyNameExpr) as KtSimpleNameExpression
|
||||
return propertyNameExpr.references
|
||||
}
|
||||
else {
|
||||
val value = arguments.singleOrNull()?.getArgumentExpression() ?: return null
|
||||
var assignment = factory.createExpression("a = b") as KtBinaryExpression
|
||||
assignment.right!!.replace(value)
|
||||
|
||||
val qualifiedExpression = callExpr.parent as? KtQualifiedExpression
|
||||
if (qualifiedExpression != null && qualifiedExpression.selectorExpression == callExpr) {
|
||||
callExpr.replace(propertyNameExpr)
|
||||
assignment.left!!.replace(qualifiedExpression)
|
||||
assignment = qualifiedExpression.replace(assignment) as KtBinaryExpression
|
||||
return (assignment.left as KtQualifiedExpression).selectorExpression!!.references
|
||||
}
|
||||
else {
|
||||
val value = arguments.singleOrNull()?.getArgumentExpression() ?: return null
|
||||
var assignment = factory.createExpression("a = b") as KtBinaryExpression
|
||||
assignment.right!!.replace(value)
|
||||
|
||||
val qualifiedExpression = callExpr.parent as? KtQualifiedExpression
|
||||
if (qualifiedExpression != null && qualifiedExpression.selectorExpression == callExpr) {
|
||||
callExpr.replace(propertyNameExpr)
|
||||
assignment.left!!.replace(qualifiedExpression)
|
||||
assignment = qualifiedExpression.replace(assignment) as KtBinaryExpression
|
||||
return (assignment.left as KtQualifiedExpression).selectorExpression!!.references
|
||||
}
|
||||
else {
|
||||
assignment.left!!.replace(propertyNameExpr)
|
||||
assignment = callExpr.replace(assignment) as KtBinaryExpression
|
||||
return assignment.left!!.references
|
||||
}
|
||||
assignment.left!!.replace(propertyNameExpr)
|
||||
assignment = callExpr.replace(assignment) as KtBinaryExpression
|
||||
return assignment.left!!.references
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.kotlin.j2k.AccessorKind
|
||||
import org.jetbrains.kotlin.j2k.CodeConverter
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
class FieldToPropertyProcessing(val field: PsiField, val propertyName: String, val isNullable: Boolean) : UsageProcessing {
|
||||
override val targetElement: PsiElement get() = this.field
|
||||
@@ -28,16 +29,19 @@ class FieldToPropertyProcessing(val field: PsiField, val propertyName: String, v
|
||||
override val convertedCodeProcessor: ConvertedCodeProcessor? =
|
||||
if (field.name != propertyName) MyConvertedCodeProcessor() else null
|
||||
|
||||
override var javaCodeProcessor = if (field.hasModifierProperty(PsiModifier.PRIVATE))
|
||||
null
|
||||
else if (!field.hasModifierProperty(PsiModifier.STATIC))
|
||||
UseAccessorsJavaCodeProcessor()
|
||||
else if (field.name != propertyName)
|
||||
ElementRenamedCodeProcessor(propertyName)
|
||||
else
|
||||
null
|
||||
override var javaCodeProcessors =
|
||||
if (field.hasModifierProperty(PsiModifier.PRIVATE))
|
||||
emptyList()
|
||||
else if (field.name != propertyName)
|
||||
listOf(ElementRenamedCodeProcessor(propertyName), UseAccessorsJavaCodeProcessor())
|
||||
else
|
||||
UseAccessorsJavaCodeProcessor().singletonList()
|
||||
|
||||
override val kotlinCodeProcessor = if (field.name != propertyName) ElementRenamedCodeProcessor(propertyName) else null
|
||||
override val kotlinCodeProcessors =
|
||||
if (field.name != propertyName)
|
||||
ElementRenamedCodeProcessor(propertyName).singletonList()
|
||||
else
|
||||
emptyList()
|
||||
|
||||
private inner class MyConvertedCodeProcessor : ConvertedCodeProcessor {
|
||||
override fun convertVariableUsage(expression: PsiReferenceExpression, codeConverter: CodeConverter): Expression? {
|
||||
|
||||
+9
-6
@@ -17,17 +17,22 @@
|
||||
package org.jetbrains.kotlin.j2k.usageProcessing
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
class MethodIntoObjectProcessing(private val method: PsiMethod, private val objectName: String) : UsageProcessing {
|
||||
override val targetElement: PsiElement get() = method
|
||||
class MemberIntoObjectProcessing(private val member: PsiMember, private val objectName: String) : UsageProcessing {
|
||||
override val targetElement: PsiElement get() = member
|
||||
|
||||
override val convertedCodeProcessor: ConvertedCodeProcessor? get() = null
|
||||
|
||||
override val javaCodeProcessor = object: ExternalCodeProcessor {
|
||||
override val javaCodeProcessors = AppendObjectNameProcessor().singletonList()
|
||||
|
||||
override val kotlinCodeProcessors = emptyList<ExternalCodeProcessor>()
|
||||
|
||||
inner class AppendObjectNameProcessor : ExternalCodeProcessor {
|
||||
override fun processUsage(reference: PsiReference): Array<PsiReference>? {
|
||||
val refExpr = reference.element as? PsiReferenceExpression ?: return null
|
||||
val qualifier = refExpr.qualifierExpression
|
||||
val factory = PsiElementFactory.SERVICE.getInstance(method.project)
|
||||
val factory = PsiElementFactory.SERVICE.getInstance(member.project)
|
||||
if (qualifier != null) {
|
||||
val newQualifier = factory.createExpressionFromText(qualifier.text + "." + objectName, null)
|
||||
qualifier.replace(newQualifier)
|
||||
@@ -40,6 +45,4 @@ class MethodIntoObjectProcessing(private val method: PsiMethod, private val obje
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val kotlinCodeProcessor: ExternalCodeProcessor? get() = null
|
||||
}
|
||||
+6
-3
@@ -18,13 +18,18 @@ package org.jetbrains.kotlin.j2k.usageProcessing
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
class ToObjectWithOnlyMethodsProcessing(private val psiClass: PsiClass) : UsageProcessing {
|
||||
override val targetElement: PsiElement get() = psiClass
|
||||
|
||||
override val convertedCodeProcessor: ConvertedCodeProcessor? get() = null
|
||||
|
||||
override val javaCodeProcessor = object: ExternalCodeProcessor {
|
||||
override val javaCodeProcessors = ToObjectWithOnlyMethodsProcessor().singletonList()
|
||||
|
||||
override val kotlinCodeProcessors = emptyList<ExternalCodeProcessor>()
|
||||
|
||||
inner class ToObjectWithOnlyMethodsProcessor: ExternalCodeProcessor {
|
||||
override fun processUsage(reference: PsiReference): Array<PsiReference>? {
|
||||
val refExpr = reference.element as? PsiReferenceExpression ?: return null
|
||||
val factory = PsiElementFactory.SERVICE.getInstance(psiClass.project)
|
||||
@@ -33,6 +38,4 @@ class ToObjectWithOnlyMethodsProcessing(private val psiClass: PsiClass) : UsageP
|
||||
return arrayOf(qualifiedExpr)
|
||||
}
|
||||
}
|
||||
|
||||
override val kotlinCodeProcessor: ExternalCodeProcessor? get() = null
|
||||
}
|
||||
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.j2k.ast.Expression
|
||||
interface UsageProcessing {
|
||||
val targetElement: PsiElement
|
||||
val convertedCodeProcessor: ConvertedCodeProcessor?
|
||||
val javaCodeProcessor: ExternalCodeProcessor?
|
||||
val kotlinCodeProcessor: ExternalCodeProcessor?
|
||||
val javaCodeProcessors: List<ExternalCodeProcessor>
|
||||
val kotlinCodeProcessors: List<ExternalCodeProcessor>
|
||||
}
|
||||
|
||||
interface ConvertedCodeProcessor {
|
||||
|
||||
@@ -8,4 +8,6 @@ public class JavaClass {
|
||||
public int getProperty() {
|
||||
return myProperty;
|
||||
}
|
||||
|
||||
public static final String NAME = "Bar";
|
||||
}
|
||||
@@ -5,4 +5,9 @@ open class JavaClass {
|
||||
|
||||
var property = 0
|
||||
protected set
|
||||
|
||||
companion object {
|
||||
|
||||
val NAME = "Bar"
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,7 @@ public class C extends JavaClass {
|
||||
field = myProperty;
|
||||
field *= 2;
|
||||
field = field * 2;
|
||||
|
||||
String s = JavaClass.NAME;
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,7 @@ public class C extends JavaClass {
|
||||
setField(getProperty());
|
||||
setField(getField() * 2);
|
||||
setField(getField() * 2);
|
||||
|
||||
String s = JavaClass.Companion.getNAME();
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ class ClassWithStatics {
|
||||
public static void staticMethod(int p) {}
|
||||
|
||||
public static final int staticField = 1;
|
||||
public static int staticNonFinalField = 1;
|
||||
|
||||
protected static int ourValue = 0;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ internal open class ClassWithStatics {
|
||||
}
|
||||
|
||||
val staticField = 1
|
||||
var staticNonFinalField = 1
|
||||
|
||||
var value = 0
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ class C {
|
||||
void foo(ClassWithStatics c) {
|
||||
ClassWithStatics.staticMethod(ClassWithStatics.staticField);
|
||||
c.instanceMethod();
|
||||
ClassWithStatics.staticField += 2;
|
||||
ClassWithStatics.staticNonFinalField += 2;
|
||||
}
|
||||
|
||||
void methodReferences() {
|
||||
|
||||
@@ -2,9 +2,9 @@ package test;
|
||||
|
||||
class C {
|
||||
void foo(ClassWithStatics c) {
|
||||
ClassWithStatics.Companion.staticMethod(ClassWithStatics.staticField);
|
||||
ClassWithStatics.Companion.staticMethod(ClassWithStatics.Companion.getStaticField());
|
||||
c.instanceMethod();
|
||||
ClassWithStatics.staticField += 2;
|
||||
ClassWithStatics.Companion.setStaticNonFinalField(ClassWithStatics.Companion.getStaticNonFinalField() + 2);
|
||||
}
|
||||
|
||||
void methodReferences() {
|
||||
@@ -15,7 +15,7 @@ class C {
|
||||
|
||||
class D extends ClassWithStatics {
|
||||
void foo() {
|
||||
Companion.staticMethod(staticField);
|
||||
value *= 2;
|
||||
Companion.staticMethod(Companion.getStaticField());
|
||||
Companion.setValue(Companion.getValue() * 2);
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package test;
|
||||
|
||||
class C {
|
||||
void foo() {
|
||||
Utils.INSTANCE.foo1(Utils.staticField);
|
||||
Utils.staticField += Utils.INSTANCE.foo2();
|
||||
Utils.INSTANCE.foo1(Utils.INSTANCE.getStaticField());
|
||||
Utils.INSTANCE.setStaticField(Utils.INSTANCE.getStaticField() + Utils.INSTANCE.foo2());
|
||||
PureUtils.INSTANCE.foo1(PureUtils.INSTANCE.foo2())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user