New J2K: Add ParameterModificationInMethodCallsConversion

This commit is contained in:
Ilya Kirillov
2018-12-18 14:37:57 +03:00
committed by Ilya Kirillov
parent aa173783aa
commit be90db7fca
2 changed files with 72 additions and 0 deletions
@@ -0,0 +1,33 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.asAssignmentFromTarget
import org.jetbrains.kotlin.j2k.findUsages
import org.jetbrains.kotlin.j2k.hasWritableUsages
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.*
class ParameterModificationInMethodCallsConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKMethod) return recurse(element)
val newVariables =
element.parameters.mapNotNull { parameter ->
if (parameter.hasWritableUsages(element.block, context)) {
JKLocalVariableImpl(
JKTypeElementImpl(parameter.type.type),
JKNameIdentifierImpl(parameter.name.value),
JKFieldAccessExpressionImpl(context.symbolProvider.provideUniverseSymbol(parameter)),
Mutability.MUTABLE
)
} else null
}
element.block.statements = listOf(JKDeclarationStatementImpl(newVariables)) + element.block.statements
return recurse(element)
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.j2k
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.j2k.conversions.RecursiveApplicableConversionBase
import org.jetbrains.kotlin.j2k.conversions.multiResolveFqName
import org.jetbrains.kotlin.j2k.conversions.resolveFqName
import org.jetbrains.kotlin.j2k.tree.*
@@ -220,3 +221,41 @@ fun throwAnnotation(throws: List<JKType>, symbolProvider: JKSymbolProvider) =
}
)
)
fun JKVariable.findUsages(scope: JKTreeElement, context: ConversionContext): List<JKFieldAccessExpression> {
val symbol = context.symbolProvider.provideUniverseSymbol(this)
val usages = mutableListOf<JKFieldAccessExpression>()
val searcher = object : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element is JKExpression) {
element.unboxFieldReference()?.also {
if (it.identifier == symbol) {
usages += it
}
}
}
return recurse(element)
}
}
searcher.runConversion(scope, context)
return usages
}
fun JKExpression.unboxFieldReference(): JKFieldAccessExpression? = when {
this is JKFieldAccessExpression -> this
this is JKQualifiedExpression && receiver is JKThisExpression -> selector as? JKFieldAccessExpression
else -> null
}
fun JKFieldAccessExpression.asAssignmentFromTarget(): JKKtAssignmentStatement? =
(parent as? JKKtAssignmentStatement)
?.takeIf { it.field == this }
fun JKFieldAccessExpression.isInDecrementOrIncrement(): Boolean =
(parent as? JKUnaryExpression)?.operator?.token?.text in listOf("++", "--")
fun JKVariable.hasWritableUsages(scope: JKTreeElement, context: ConversionContext): Boolean =
findUsages(scope, context).any {
it.asAssignmentFromTarget() != null
|| it.isInDecrementOrIncrement()
}