New J2K: Add conflicts handling in for conversion

This commit is contained in:
Ilya Kirillov
2019-01-17 19:17:10 +03:00
committed by Ilya Kirillov
parent e43eb4da03
commit 962b971f07
2 changed files with 58 additions and 7 deletions
@@ -6,8 +6,8 @@
package org.jetbrains.kotlin.j2k.conversions
import com.intellij.psi.*
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.j2k.ast.Mutability
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.lexer.KtTokens
@@ -42,10 +42,21 @@ class ForConversion(private val context: ConversionContext) : RecursiveApplicabl
loopStatement::initializer.detached(),
whileStatement
)
val notNeedParentBlock = loopStatement.parent is JKBlock
|| loopStatement.parent is JKLabeledStatement && loopStatement.parent?.parent is JKBlock
return if (notNeedParentBlock) convertedFromForLoopSyntheticWhileStatement
else blockStatement(convertedFromForLoopSyntheticWhileStatement)
return when {
loopStatement.hasNameConflict() ->
JKExpressionStatementImpl(
runExpression(
convertedFromForLoopSyntheticWhileStatement,
context.symbolProvider
)
)
!notNeedParentBlock -> blockStatement(convertedFromForLoopSyntheticWhileStatement)
else -> convertedFromForLoopSyntheticWhileStatement
}
}
private fun createWhileBody(loopStatement: JKJavaForLoopStatement): JKStatement {
@@ -70,15 +81,14 @@ class ForConversion(private val context: ConversionContext) : RecursiveApplicabl
initializer is JKDeclarationStatement && initializer.declaredStatements.any { loopVar ->
loopVar is JKLocalVariable && body.statements.any { statement ->
statement is JKDeclarationStatement && statement.declaredStatements.any {
it is JKLocalVariable && it.name == loopVar.name
it is JKLocalVariable && it.name.value == loopVar.name.value
}
}
}
val statements =
if (hasNameConflict) {
listOf(body) + loopStatement::updaters.detached()
listOf(JKExpressionStatementImpl(runExpression(body, context.symbolProvider))) + loopStatement::updaters.detached()
} else {
body.block::statements.detached() + loopStatement::updaters.detached()
}
@@ -262,6 +272,36 @@ class ForConversion(private val context: ConversionContext) : RecursiveApplicabl
return JKQualifiedExpressionImpl(javaSizeCall::receiver.detached(), javaSizeCall.operator, selector)
}
private fun JKJavaForLoopStatement.hasNameConflict(): Boolean {
val names = initializer.declaredVariableNames()
if (names.isEmpty()) return false
val factory = PsiElementFactory.SERVICE.getInstance(context.project)
for (name in names) {
val refExpr = try {
factory.createExpressionFromText(name, psi) as? PsiReferenceExpression ?: return true
} catch (e: IncorrectOperationException) {
return true
}
if (refExpr.resolve() != null) return true
}
return (parent as? JKBlock)
?.statements
?.takeLastWhile { it != this }
?.any {
it.declaredVariableNames().any { it in names }
} == true
}
private fun JKStatement.declaredVariableNames(): Collection<String> =
when (this) {
is JKDeclarationStatement ->
declaredStatements.filterIsInstance<JKVariable>().map { it.name.value }
is JKJavaForLoopStatement -> initializer.declaredVariableNames()
else -> emptyList()
}
private fun JKExpression.isVariableIncrementOrDecrement(variable: JKLocalVariable): JKOperator? {
val pair = when (this) {
@@ -462,4 +462,15 @@ fun JKClass.getOrCreateCompainonObject(): JKClass =
emptyList(),
Visibility.PUBLIC,
Modality.FINAL
).also { classBody.declarations += it }
).also { classBody.declarations += it }
fun runExpression(body: JKStatement, symbolProvider: JKSymbolProvider): JKExpression {
val lambda = JKLambdaExpressionImpl(
body,
emptyList()
)
return JKKtCallExpressionImpl(
symbolProvider.provideByFqNameMulti("kotlin.run"),
JKExpressionListImpl(listOf(lambda))
)
}