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 {
return when (this) {
null -> JKExpressionStatement(JKStubExpression())
@@ -909,15 +917,9 @@ class JavaToJKTreeBuilder constructor(
is PsiForStatement -> JKJavaForLoopStatement(
initialization.toJK(),
initialization.asJKStatementsList(),
with(expressionTreeMapper) { condition.toJK() },
when (update) {
is PsiExpressionListStatement ->
(update as PsiExpressionListStatement).expressionList.expressions.map {
JKExpressionStatement(with(expressionTreeMapper) { it.toJK() })
}
else -> listOf(update.toJK())
},
update.asJKStatementsList(),
body.toJK()
)
is PsiForeachStatement ->
@@ -40,11 +40,13 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
else JKLiteralExpression("true", JKLiteralExpression.LiteralType.BOOLEAN)
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 =
JKKtConvertedFromForLoopSyntheticWhileStatement(
loopStatement::initializer.detached(),
loopStatement::initializers.detached(),
whileStatement
)
@@ -81,8 +83,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
val body = continueStatementConverter.applyToElement(loopStatement::body.detached())
if (body is JKBlockStatement) {
val initializer = loopStatement.initializer
val hasNameConflict =
val hasNameConflict = loopStatement.initializers.any { initializer ->
initializer is JKDeclarationStatement && initializer.declaredStatements.any { loopVar ->
loopVar is JKLocalVariable && body.statements.any { statement ->
statement is JKDeclarationStatement && statement.declaredStatements.any {
@@ -90,6 +91,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
}
}
}
}
val statements =
if (hasNameConflict) {
@@ -106,8 +108,8 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
}
private fun convertToForeach(loopStatement: JKJavaForLoopStatement): JKForInStatement? {
val loopVar =
(loopStatement.initializer as? JKDeclarationStatement)?.declaredStatements?.singleOrNull() as? JKLocalVariable ?: return null
val initializer = loopStatement.initializers.singleOrNull() ?: return null
val loopVar = (initializer as? JKDeclarationStatement)?.declaredStatements?.singleOrNull() as? JKLocalVariable ?: return null
val loopVarPsi = loopVar.psi<PsiLocalVariable>() ?: return null
val condition = loopStatement.condition as? JKBinaryExpression ?: return null
if (!loopVarPsi.hasWriteAccesses(referenceSearcher, loopStatement.body.psi())
@@ -276,7 +278,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
}
private fun JKJavaForLoopStatement.hasNameConflict(): Boolean {
val names = initializer.declaredVariableNames()
val names = initializers.flatMap { it.declaredVariableNames() }
if (names.isEmpty()) return false
val factory = PsiElementFactory.SERVICE.getInstance(context.project)
@@ -301,7 +303,7 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
when (this) {
is JKDeclarationStatement ->
declaredStatements.filterIsInstance<JKVariable>().map { it.name.value }
is JKJavaForLoopStatement -> initializer.declaredVariableNames()
is JKJavaForLoopStatement -> initializers.flatMap { it.declaredVariableNames() }
else -> emptyList()
}
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.nj2k.tree.*
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 {
if (element !is JKExpressionStatement) return recurse(element)
val labeledStatement = element.expression as? JKLabeledExpression ?: return recurse(element)
@@ -26,13 +26,11 @@ class LabeledStatementConversion(context : NewJ2kConverterContext) : RecursiveAp
return recurse(
JKBlockStatementWithoutBrackets(
listOf(
convertedFromForLoopSyntheticWhileStatement::variableDeclaration.detached(),
JKLabeledExpression(
convertedFromForLoopSyntheticWhileStatement::whileStatement.detached(),
labeledStatement::labels.detached()
).asStatement()
)
convertedFromForLoopSyntheticWhileStatement::variableDeclarations.detached() +
JKLabeledExpression(
convertedFromForLoopSyntheticWhileStatement::whileStatement.detached(),
labeledStatement::labels.detached()
).asStatement()
)
)
}
@@ -548,7 +548,11 @@ internal class JKCodeBuilder(context: NewJ2kConverterContext) {
override fun visitKtConvertedFromForLoopSyntheticWhileStatementRaw(
ktConvertedFromForLoopSyntheticWhileStatement: JKKtConvertedFromForLoopSyntheticWhileStatement
) {
ktConvertedFromForLoopSyntheticWhileStatement.variableDeclaration.accept(this)
printer.renderList(
ktConvertedFromForLoopSyntheticWhileStatement.variableDeclarations,
{ printer.println() }) {
it.accept(this)
}
printer.println()
ktConvertedFromForLoopSyntheticWhileStatement.whileStatement.accept(this)
}
@@ -83,10 +83,10 @@ class JKKtWhenStatement(
}
class JKKtConvertedFromForLoopSyntheticWhileStatement(
variableDeclaration: JKStatement,
variableDeclarations: List<JKStatement>,
whileStatement: JKWhileStatement
) : JKStatement() {
var variableDeclaration: JKStatement by child(variableDeclaration)
var variableDeclarations: List<JKStatement> by children(variableDeclarations)
var whileStatement: JKWhileStatement by child(whileStatement)
override fun accept(visitor: JKVisitor) = visitor.visitKtConvertedFromForLoopSyntheticWhileStatement(this)
}
@@ -154,7 +154,7 @@ class JKJavaAssertStatement(condition: JKExpression, description: JKExpression)
}
class JKJavaForLoopStatement(
initializer: JKStatement,
initializers: List<JKStatement>,
condition: JKExpression,
updaters: List<JKStatement>,
body: JKStatement
@@ -162,7 +162,7 @@ class JKJavaForLoopStatement(
override var body by child(body)
var updaters by children(updaters)
var condition by child(condition)
var initializer by child(initializer)
var initializers by children(initializers)
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");
}
@TestMetadata("emptyInitializers.java")
public void testEmptyInitializers() throws Exception {
runTest("nj2k/testData/newJ2k/for/emptyInitializers.java");
}
@TestMetadata("falseArrayIndicesReversed.java")
public void testFalseArrayIndicesReversed() throws Exception {
runTest("nj2k/testData/newJ2k/for/falseArrayIndicesReversed.java");
@@ -2153,6 +2158,16 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
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")
public void testNameConflict1() throws Exception {
runTest("nj2k/testData/newJ2k/for/nameConflict1.java");