Fix conversion of assignment as expression in J2K

Blockless if's and so with assignment as expression inside
should turn into blockful
 #KT-16816 fixed
This commit is contained in:
Simon Ogorodnik
2017-03-31 14:16:10 +03:00
parent 86137e1f65
commit 57c1d8eda4
13 changed files with 136 additions and 5 deletions
@@ -33,6 +33,8 @@ class ArrayAccessExpression(val expression: Expression, val index: Expression, v
open class AssignmentExpression(val left: Expression, val right: Expression, val op: Operator) : Expression() { open class AssignmentExpression(val left: Expression, val right: Expression, val op: Operator) : Expression() {
fun isMultiAssignment() = right is AssignmentExpression
fun appendAssignment(builder: CodeBuilder, left: Expression, right: Expression) { fun appendAssignment(builder: CodeBuilder, left: Expression, right: Expression) {
builder.appendOperand(this, left).append(" ").append(op).append(" ").appendOperand(this, right) builder.appendOperand(this, left).append(" ").append(op).append(" ").appendOperand(this, right)
} }
@@ -65,9 +65,9 @@ class IfStatement(
private val brAfterElse = if (singleLine || elseStatement is IfStatement) " " else "\n" private val brAfterElse = if (singleLine || elseStatement is IfStatement) " " else "\n"
override fun generateCode(builder: CodeBuilder) { override fun generateCode(builder: CodeBuilder) {
builder append "if (" append condition append ")" append br append thenStatement builder append "if (" append condition append ")" append br append thenStatement.wrapToBlockIfRequired()
if (!elseStatement.isEmpty) { if (!elseStatement.isEmpty) {
builder append br append "else" append brAfterElse append elseStatement builder append br append "else" append brAfterElse append elseStatement.wrapToBlockIfRequired()
} }
} }
} }
@@ -78,7 +78,7 @@ class WhileStatement(val condition: Expression, val body: Element, singleLine: B
private val br = if (singleLine) " " else "\n" private val br = if (singleLine) " " else "\n"
override fun generateCode(builder: CodeBuilder) { override fun generateCode(builder: CodeBuilder) {
builder append "while (" append condition append ")" append br append body builder append "while (" append condition append ")" append br append body.wrapToBlockIfRequired()
} }
} }
@@ -86,7 +86,7 @@ class DoWhileStatement(val condition: Expression, val body: Element, singleLine:
private val br = if (singleLine) " " else "\n" private val br = if (singleLine) " " else "\n"
override fun generateCode(builder: CodeBuilder) { override fun generateCode(builder: CodeBuilder) {
builder append "do" append br append body append br append "while (" append condition append ")" builder append "do" append br append body.wrapToBlockIfRequired() append br append "while (" append condition append ")"
} }
} }
@@ -105,7 +105,7 @@ class ForeachStatement(
if (explicitVariableType != null) { if (explicitVariableType != null) {
builder append ":" append explicitVariableType builder append ":" append explicitVariableType
} }
builder append " in " append collection append ")" append br append body builder append " in " append collection append ")" append br append body.wrapToBlockIfRequired()
} }
} }
@@ -32,6 +32,12 @@ fun CodeBuilder.appendOperand(expression: Expression, operand: Expression, paren
return this return this
} }
fun Element.wrapToBlockIfRequired(): Element = when (this) {
is AssignmentExpression -> if (isMultiAssignment()) Block.of(this).assignNoPrototype() else this
else -> this
}
private fun Expression.precedence(): Int? { private fun Expression.precedence(): Int? {
return when (this) { return when (this) {
is QualifiedExpression, is MethodCallExpression, is ArrayAccessExpression, is PostfixExpression, is BangBangExpression, is StarExpression -> 0 is QualifiedExpression, is MethodCallExpression, is ArrayAccessExpression, is PostfixExpression, is BangBangExpression, is StarExpression -> 0
@@ -0,0 +1,7 @@
public class SomeClass {
int a;
int b;
void doSomeWhile(int i) {
do a = b = i; while (i < 0)
}
}
@@ -0,0 +1,10 @@
class SomeClass {
internal var a: Int = 0
internal var b: Int = 0
internal fun doSomeWhile(i: Int) {
do {
b = i
a = b
} while (i < 0)
}
}
@@ -0,0 +1,7 @@
public class SomeClass {
void doSomeFor() {
int a,b;
for (int i = 0; i < 10; i++)
a = b = i;
}
}
@@ -0,0 +1,10 @@
class SomeClass {
internal fun doSomeFor() {
var a: Int
var b: Int
for (i in 0..9) {
b = i
a = b
}
}
}
@@ -0,0 +1,9 @@
public class SomeClass {
void doSomeIf(int i) {
int a,b,c
if (i < 0)
a = b = i;
else
b = c = i;
}
}
@@ -0,0 +1,14 @@
class SomeClass {
internal fun doSomeIf(i: Int) {
val a: Int
val b: Int
val c: Int
if (i < 0) {
b = i
a = b
} else {
c = i
b = c
}
}
}
@@ -0,0 +1,8 @@
public class SomeClass {
int a;
int b;
void doSomeWhile(int i) {
while (i < 0)
a = b = i;
}
}
@@ -0,0 +1,10 @@
class SomeClass {
internal var a: Int = 0
internal var b: Int = 0
internal fun doSomeWhile(i: Int) {
while (i < 0) {
b = i
a = b
}
}
}
@@ -1733,6 +1733,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/doWhileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/doWhileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true);
} }
@TestMetadata("whileWithAssignmentAsExpression.java")
public void testWhileWithAssignmentAsExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/doWhileStatement/whileWithAssignmentAsExpression.java");
doTest(fileName);
}
@TestMetadata("whileWithBlock.java") @TestMetadata("whileWithBlock.java")
public void testWhileWithBlock() throws Exception { public void testWhileWithBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/doWhileStatement/whileWithBlock.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/doWhileStatement/whileWithBlock.java");
@@ -2108,6 +2114,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
doTest(fileName); doTest(fileName);
} }
@TestMetadata("assignmentAsExpressionInBody.java")
public void testAssignmentAsExpressionInBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/assignmentAsExpressionInBody.java");
doTest(fileName);
}
@TestMetadata("commonCaseForTest.java") @TestMetadata("commonCaseForTest.java")
public void testCommonCaseForTest() throws Exception { public void testCommonCaseForTest() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/commonCaseForTest.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/commonCaseForTest.java");
@@ -2699,6 +2711,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/ifStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/ifStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true);
} }
@TestMetadata("assignmentAsExpressionInIf.java")
public void testAssignmentAsExpressionInIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/ifStatement/assignmentAsExpressionInIf.java");
doTest(fileName);
}
@TestMetadata("elseIf.java") @TestMetadata("elseIf.java")
public void testElseIf() throws Exception { public void testElseIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/ifStatement/elseIf.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/ifStatement/elseIf.java");
@@ -5018,6 +5036,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/whileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/whileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true);
} }
@TestMetadata("whileWithAssignmentAsExpression.java")
public void testWhileWithAssignmentAsExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/whileStatement/whileWithAssignmentAsExpression.java");
doTest(fileName);
}
@TestMetadata("whileWithBlock.java") @TestMetadata("whileWithBlock.java")
public void testWhileWithBlock() throws Exception { public void testWhileWithBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/whileStatement/whileWithBlock.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/whileStatement/whileWithBlock.java");
@@ -1733,6 +1733,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/doWhileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/doWhileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true);
} }
@TestMetadata("whileWithAssignmentAsExpression.java")
public void testWhileWithAssignmentAsExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/doWhileStatement/whileWithAssignmentAsExpression.java");
doTest(fileName);
}
@TestMetadata("whileWithBlock.java") @TestMetadata("whileWithBlock.java")
public void testWhileWithBlock() throws Exception { public void testWhileWithBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/doWhileStatement/whileWithBlock.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/doWhileStatement/whileWithBlock.java");
@@ -2108,6 +2114,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
doTest(fileName); doTest(fileName);
} }
@TestMetadata("assignmentAsExpressionInBody.java")
public void testAssignmentAsExpressionInBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/assignmentAsExpressionInBody.java");
doTest(fileName);
}
@TestMetadata("commonCaseForTest.java") @TestMetadata("commonCaseForTest.java")
public void testCommonCaseForTest() throws Exception { public void testCommonCaseForTest() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/commonCaseForTest.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/commonCaseForTest.java");
@@ -2699,6 +2711,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/ifStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/ifStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true);
} }
@TestMetadata("assignmentAsExpressionInIf.java")
public void testAssignmentAsExpressionInIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/ifStatement/assignmentAsExpressionInIf.java");
doTest(fileName);
}
@TestMetadata("elseIf.java") @TestMetadata("elseIf.java")
public void testElseIf() throws Exception { public void testElseIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/ifStatement/elseIf.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/ifStatement/elseIf.java");
@@ -5018,6 +5036,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/whileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/whileStatement"), Pattern.compile("^(.+)\\.java$"), TargetBackend.ANY, true);
} }
@TestMetadata("whileWithAssignmentAsExpression.java")
public void testWhileWithAssignmentAsExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/whileStatement/whileWithAssignmentAsExpression.java");
doTest(fileName);
}
@TestMetadata("whileWithBlock.java") @TestMetadata("whileWithBlock.java")
public void testWhileWithBlock() throws Exception { public void testWhileWithBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/whileStatement/whileWithBlock.java"); String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/whileStatement/whileWithBlock.java");