Fix for loop conversion when multiple initializers are present

#KT-35074 fixed
This commit is contained in:
Ilya Kirillov
2019-11-25 14:01:03 +03:00
parent b73625ad9e
commit f368d9761a
12 changed files with 99 additions and 29 deletions
@@ -885,6 +885,14 @@ class JavaToJKTreeBuilder constructor(
} }
} }
fun PsiStatement?.asJKStatementsList() = when (this) {
null -> emptyList()
is PsiExpressionListStatement -> expressionList.expressions.map { expression ->
JKExpressionStatement(with(expressionTreeMapper) { expression.toJK() })
}
else -> listOf(toJK())
}
fun PsiStatement?.toJK(): JKStatement { fun PsiStatement?.toJK(): JKStatement {
return when (this) { return when (this) {
null -> JKExpressionStatement(JKStubExpression()) null -> JKExpressionStatement(JKStubExpression())
@@ -909,15 +917,9 @@ class JavaToJKTreeBuilder constructor(
is PsiForStatement -> JKJavaForLoopStatement( is PsiForStatement -> JKJavaForLoopStatement(
initialization.toJK(), initialization.asJKStatementsList(),
with(expressionTreeMapper) { condition.toJK() }, with(expressionTreeMapper) { condition.toJK() },
when (update) { update.asJKStatementsList(),
is PsiExpressionListStatement ->
(update as PsiExpressionListStatement).expressionList.expressions.map {
JKExpressionStatement(with(expressionTreeMapper) { it.toJK() })
}
else -> listOf(update.toJK())
},
body.toJK() body.toJK()
) )
is PsiForeachStatement -> is PsiForeachStatement ->
@@ -40,11 +40,13 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
else JKLiteralExpression("true", JKLiteralExpression.LiteralType.BOOLEAN) else JKLiteralExpression("true", JKLiteralExpression.LiteralType.BOOLEAN)
val whileStatement = JKWhileStatement(condition, whileBody) val whileStatement = JKWhileStatement(condition, whileBody)
if (loopStatement.initializer is JKEmptyStatement) return whileStatement if (loopStatement.initializers.isEmpty()
|| loopStatement.initializers.singleOrNull() is JKEmptyStatement
) return whileStatement
val convertedFromForLoopSyntheticWhileStatement = val convertedFromForLoopSyntheticWhileStatement =
JKKtConvertedFromForLoopSyntheticWhileStatement( JKKtConvertedFromForLoopSyntheticWhileStatement(
loopStatement::initializer.detached(), loopStatement::initializers.detached(),
whileStatement whileStatement
) )
@@ -81,8 +83,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
val body = continueStatementConverter.applyToElement(loopStatement::body.detached()) val body = continueStatementConverter.applyToElement(loopStatement::body.detached())
if (body is JKBlockStatement) { if (body is JKBlockStatement) {
val initializer = loopStatement.initializer val hasNameConflict = loopStatement.initializers.any { initializer ->
val hasNameConflict =
initializer is JKDeclarationStatement && initializer.declaredStatements.any { loopVar -> initializer is JKDeclarationStatement && initializer.declaredStatements.any { loopVar ->
loopVar is JKLocalVariable && body.statements.any { statement -> loopVar is JKLocalVariable && body.statements.any { statement ->
statement is JKDeclarationStatement && statement.declaredStatements.any { statement is JKDeclarationStatement && statement.declaredStatements.any {
@@ -90,6 +91,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
} }
} }
} }
}
val statements = val statements =
if (hasNameConflict) { if (hasNameConflict) {
@@ -106,8 +108,8 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
} }
private fun convertToForeach(loopStatement: JKJavaForLoopStatement): JKForInStatement? { private fun convertToForeach(loopStatement: JKJavaForLoopStatement): JKForInStatement? {
val loopVar = val initializer = loopStatement.initializers.singleOrNull() ?: return null
(loopStatement.initializer as? JKDeclarationStatement)?.declaredStatements?.singleOrNull() as? JKLocalVariable ?: return null val loopVar = (initializer as? JKDeclarationStatement)?.declaredStatements?.singleOrNull() as? JKLocalVariable ?: return null
val loopVarPsi = loopVar.psi<PsiLocalVariable>() ?: return null val loopVarPsi = loopVar.psi<PsiLocalVariable>() ?: return null
val condition = loopStatement.condition as? JKBinaryExpression ?: return null val condition = loopStatement.condition as? JKBinaryExpression ?: return null
if (!loopVarPsi.hasWriteAccesses(referenceSearcher, loopStatement.body.psi()) if (!loopVarPsi.hasWriteAccesses(referenceSearcher, loopStatement.body.psi())
@@ -276,7 +278,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
} }
private fun JKJavaForLoopStatement.hasNameConflict(): Boolean { private fun JKJavaForLoopStatement.hasNameConflict(): Boolean {
val names = initializer.declaredVariableNames() val names = initializers.flatMap { it.declaredVariableNames() }
if (names.isEmpty()) return false if (names.isEmpty()) return false
val factory = PsiElementFactory.SERVICE.getInstance(context.project) val factory = PsiElementFactory.SERVICE.getInstance(context.project)
@@ -301,7 +303,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
when (this) { when (this) {
is JKDeclarationStatement -> is JKDeclarationStatement ->
declaredStatements.filterIsInstance<JKVariable>().map { it.name.value } declaredStatements.filterIsInstance<JKVariable>().map { it.name.value }
is JKJavaForLoopStatement -> initializer.declaredVariableNames() is JKJavaForLoopStatement -> initializers.flatMap { it.declaredVariableNames() }
else -> emptyList() else -> emptyList()
} }
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.nj2k.tree.*
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class LabeledStatementConversion(context : NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { class LabeledStatementConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) {
override fun applyToElement(element: JKTreeElement): JKTreeElement { override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKExpressionStatement) return recurse(element) if (element !is JKExpressionStatement) return recurse(element)
val labeledStatement = element.expression as? JKLabeledExpression ?: return recurse(element) val labeledStatement = element.expression as? JKLabeledExpression ?: return recurse(element)
@@ -26,13 +26,11 @@ class LabeledStatementConversion(context : NewJ2kConverterContext) : RecursiveAp
return recurse( return recurse(
JKBlockStatementWithoutBrackets( JKBlockStatementWithoutBrackets(
listOf( convertedFromForLoopSyntheticWhileStatement::variableDeclarations.detached() +
convertedFromForLoopSyntheticWhileStatement::variableDeclaration.detached(), JKLabeledExpression(
JKLabeledExpression( convertedFromForLoopSyntheticWhileStatement::whileStatement.detached(),
convertedFromForLoopSyntheticWhileStatement::whileStatement.detached(), labeledStatement::labels.detached()
labeledStatement::labels.detached() ).asStatement()
).asStatement()
)
) )
) )
} }
@@ -548,7 +548,11 @@ internal class JKCodeBuilder(context: NewJ2kConverterContext) {
override fun visitKtConvertedFromForLoopSyntheticWhileStatementRaw( override fun visitKtConvertedFromForLoopSyntheticWhileStatementRaw(
ktConvertedFromForLoopSyntheticWhileStatement: JKKtConvertedFromForLoopSyntheticWhileStatement ktConvertedFromForLoopSyntheticWhileStatement: JKKtConvertedFromForLoopSyntheticWhileStatement
) { ) {
ktConvertedFromForLoopSyntheticWhileStatement.variableDeclaration.accept(this) printer.renderList(
ktConvertedFromForLoopSyntheticWhileStatement.variableDeclarations,
{ printer.println() }) {
it.accept(this)
}
printer.println() printer.println()
ktConvertedFromForLoopSyntheticWhileStatement.whileStatement.accept(this) ktConvertedFromForLoopSyntheticWhileStatement.whileStatement.accept(this)
} }
@@ -83,10 +83,10 @@ class JKKtWhenStatement(
} }
class JKKtConvertedFromForLoopSyntheticWhileStatement( class JKKtConvertedFromForLoopSyntheticWhileStatement(
variableDeclaration: JKStatement, variableDeclarations: List<JKStatement>,
whileStatement: JKWhileStatement whileStatement: JKWhileStatement
) : JKStatement() { ) : JKStatement() {
var variableDeclaration: JKStatement by child(variableDeclaration) var variableDeclarations: List<JKStatement> by children(variableDeclarations)
var whileStatement: JKWhileStatement by child(whileStatement) var whileStatement: JKWhileStatement by child(whileStatement)
override fun accept(visitor: JKVisitor) = visitor.visitKtConvertedFromForLoopSyntheticWhileStatement(this) override fun accept(visitor: JKVisitor) = visitor.visitKtConvertedFromForLoopSyntheticWhileStatement(this)
} }
@@ -154,7 +154,7 @@ class JKJavaAssertStatement(condition: JKExpression, description: JKExpression)
} }
class JKJavaForLoopStatement( class JKJavaForLoopStatement(
initializer: JKStatement, initializers: List<JKStatement>,
condition: JKExpression, condition: JKExpression,
updaters: List<JKStatement>, updaters: List<JKStatement>,
body: JKStatement body: JKStatement
@@ -162,7 +162,7 @@ class JKJavaForLoopStatement(
override var body by child(body) override var body by child(body)
var updaters by children(updaters) var updaters by children(updaters)
var condition by child(condition) var condition by child(condition)
var initializer by child(initializer) var initializers by children(initializers)
override fun accept(visitor: JKVisitor) = visitor.visitJavaForLoopStatement(this) override fun accept(visitor: JKVisitor) = visitor.visitJavaForLoopStatement(this)
} }
+7
View File
@@ -0,0 +1,7 @@
public class SomeClass {
void doSomeFor() {
int i = 0, u = 0;
for (; i < 42; i++) {
}
}
}
+9
View File
@@ -0,0 +1,9 @@
class SomeClass {
fun doSomeFor() {
var i = 0
val u = 0
while (i < 42) {
i++
}
}
}
+7
View File
@@ -0,0 +1,7 @@
public class SomeClass {
void doSomeFor() {
int i, u;
for (i = 0, u = 0; i < 42; i++) {
}
}
}
+11
View File
@@ -0,0 +1,11 @@
class SomeClass {
fun doSomeFor() {
var i: Int
val u: Int
i = 0
u = 0
while (i < 42) {
i++
}
}
}
@@ -0,0 +1,6 @@
public class SomeClass {
void doSomeFor() {
for (int i = 0, u = 0; i < 42; i++) {
}
}
}
@@ -0,0 +1,9 @@
class SomeClass {
fun doSomeFor() {
var i = 0
val u = 0
while (i < 42) {
i++
}
}
}
@@ -2023,6 +2023,11 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
runTest("nj2k/testData/newJ2k/for/downTo4.java"); runTest("nj2k/testData/newJ2k/for/downTo4.java");
} }
@TestMetadata("emptyInitializers.java")
public void testEmptyInitializers() throws Exception {
runTest("nj2k/testData/newJ2k/for/emptyInitializers.java");
}
@TestMetadata("falseArrayIndicesReversed.java") @TestMetadata("falseArrayIndicesReversed.java")
public void testFalseArrayIndicesReversed() throws Exception { public void testFalseArrayIndicesReversed() throws Exception {
runTest("nj2k/testData/newJ2k/for/falseArrayIndicesReversed.java"); runTest("nj2k/testData/newJ2k/for/falseArrayIndicesReversed.java");
@@ -2153,6 +2158,16 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
runTest("nj2k/testData/newJ2k/for/infiniteFor.java"); runTest("nj2k/testData/newJ2k/for/infiniteFor.java");
} }
@TestMetadata("multipleInitializers.java")
public void testMultipleInitializers() throws Exception {
runTest("nj2k/testData/newJ2k/for/multipleInitializers.java");
}
@TestMetadata("multipleInitializersWithvariableDeclarations.java")
public void testMultipleInitializersWithvariableDeclarations() throws Exception {
runTest("nj2k/testData/newJ2k/for/multipleInitializersWithvariableDeclarations.java");
}
@TestMetadata("nameConflict1.java") @TestMetadata("nameConflict1.java")
public void testNameConflict1() throws Exception { public void testNameConflict1() throws Exception {
runTest("nj2k/testData/newJ2k/for/nameConflict1.java"); runTest("nj2k/testData/newJ2k/for/nameConflict1.java");