Java to Kotlin converter: do not produce incorrect "code blocks" which are actually parsed as lambda's in Kotlin

#KT-4670 Fixed
This commit is contained in:
Valentin Kipyatkov
2014-06-20 17:52:10 +04:00
parent 116c27117f
commit 2188af2bf9
15 changed files with 145 additions and 63 deletions
@@ -51,7 +51,8 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
}
override fun visitBlockStatement(statement: PsiBlockStatement) {
result = converter.convertBlock(statement.getCodeBlock())
val block = converter.convertBlock(statement.getCodeBlock())
result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block))
}
override fun visitBreakStatement(statement: PsiBreakStatement) {
@@ -82,7 +83,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
converter.convertExpression(condition, condition.getType())
else
converter.convertExpression(condition)
result = DoWhileStatement(expression, converter.convertStatement(statement.getBody()), statement.isInSingleLine())
result = DoWhileStatement(expression, convertStatementOrBlock(statement.getBody()), statement.isInSingleLine())
}
override fun visitExpressionStatement(statement: PsiExpressionStatement) {
@@ -111,7 +112,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
&& condition != null
&& update != null
&& update.getChildren().size == 1
&& isPlusPlusExpression(update.getChildren().single())
&& update.getChildren().single().isPlusPlusExpression()
&& (operationTokenType == JavaTokenType.LT || operationTokenType == JavaTokenType.LE)
&& loopVar != null
&& loopVar.getNameIdentifier() != null
@@ -121,19 +122,48 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
result = ForeachWithRangeStatement(loopVar.declarationIdentifier(),
converter.convertExpression(loopVar.getInitializer()),
endExpression,
converter.convertStatement(body),
convertStatementOrBlock(body),
statement.isInSingleLine())
}
else {
var forStatements = ArrayList<Statement>()
forStatements.add(converter.convertStatement(initialization))
val bodyAndUpdate = listOf(converter.convertStatement(body),
Block(listOf(converter.convertStatement(update)), LBrace(), RBrace()))
forStatements.add(WhileStatement(
if (condition == null) LiteralExpression("true") else converter.convertExpression(condition),
Block(bodyAndUpdate, LBrace(), RBrace()),
statement.isInSingleLine()))
result = Block(forStatements, LBrace(), RBrace())
val initializationConverted = converter.convertStatement(initialization)
val updateConverted = converter.convertStatement(update)
val whileBody = if (updateConverted.isEmpty) {
converter.convertStatement(body)
}
else if (body is PsiBlockStatement) {
val nameConflict = initialization is PsiDeclarationStatement && initialization.getDeclaredElements().any { loopVar ->
loopVar is PsiNamedElement && body.getCodeBlock().getStatements().any { statement ->
statement is PsiDeclarationStatement && statement.getDeclaredElements().any {
it is PsiNamedElement && it.getName() == loopVar.getName()
}
}
}
if (nameConflict) {
Block(listOf(converter.convertStatement(body), updateConverted), LBrace(), RBrace(), true)
}
else {
val block = converter.convertBlock(body.getCodeBlock(), true)
Block(block.statements + listOf(updateConverted), block.lBrace, block.rBrace, true).assignPrototypesFrom(block)
}
}
else {
Block(listOf(converter.convertStatement(body), updateConverted), LBrace(), RBrace(), true)
}
val whileStatement = WhileStatement(
if (condition != null) converter.convertExpression(condition) else LiteralExpression("true"),
whileBody,
statement.isInSingleLine())
if (initializationConverted.isEmpty) {
result = whileStatement
}
else {
val block = Block(listOf(initializationConverted, whileStatement), LBrace(), RBrace())
result = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block))
}
}
}
@@ -147,7 +177,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
}
result = ForeachStatement(converter.convertParameter(statement.getIterationParameter()),
iterator,
converter.convertStatement(statement.getBody()),
convertStatementOrBlock(statement.getBody()),
statement.isInSingleLine())
}
@@ -155,8 +185,8 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
val condition = statement.getCondition()
val expression = converter.convertExpression(condition, PsiType.BOOLEAN)
result = IfStatement(expression,
converter.convertStatement(statement.getThenBranch()),
converter.convertStatement(statement.getElseBranch()),
convertStatementOrBlock(statement.getThenBranch()),
convertStatementOrBlock(statement.getElseBranch()),
statement.isInSingleLine())
}
@@ -307,7 +337,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
converter.convertExpression(condition, condition!!.getType())
else
converter.convertExpression(condition)
result = WhileStatement(expression, converter.convertStatement(statement.getBody()), statement.isInSingleLine())
result = WhileStatement(expression, convertStatementOrBlock(statement.getBody()), statement.isInSingleLine())
}
override fun visitReturnStatement(statement: PsiReturnStatement) {
@@ -324,9 +354,9 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
result = Statement.Empty
}
private fun isPlusPlusExpression(psiElement: PsiElement): Boolean {
return (psiElement is PsiPostfixExpression && psiElement.getOperationTokenType() == JavaTokenType.PLUSPLUS) ||
(psiElement is PsiPrefixExpression && psiElement.getOperationTokenType() == JavaTokenType.PLUSPLUS)
private fun PsiElement.isPlusPlusExpression(): Boolean {
return (this is PsiPostfixExpression && this.getOperationTokenType() == JavaTokenType.PLUSPLUS) ||
(this is PsiPrefixExpression && this.getOperationTokenType() == JavaTokenType.PLUSPLUS)
}
private fun containsBreak(slice: List<PsiElement?>) = slice.any { it is PsiBreakStatement }
@@ -371,4 +401,11 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito
return cases
}
private fun convertStatementOrBlock(statement: PsiStatement?): Statement {
return if (statement is PsiBlockStatement)
converter.convertBlock(statement.getCodeBlock())
else
converter.convertStatement(statement)
}
}
@@ -31,7 +31,7 @@ import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("j2k/tests/testData/ast")
@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.Comments.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class})
@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.Blocks.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.Comments.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class})
public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInAst() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true);
@@ -441,6 +441,19 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
}
@TestMetadata("j2k/tests/testData/ast/blocks")
public static class Blocks extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInBlocks() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/blocks"), Pattern.compile("^(.+)\\.java$"), true);
}
@TestMetadata("Blocks.java")
public void testBlocks() throws Exception {
doTest("j2k/tests/testData/ast/blocks/Blocks.java");
}
}
@TestMetadata("j2k/tests/testData/ast/boxedType")
public static class BoxedType extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInBoxedType() throws Exception {
@@ -1109,6 +1122,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
doTest("j2k/tests/testData/ast/for/commonCaseForTest.java");
}
@TestMetadata("forRangeWithBlock.java")
public void testForRangeWithBlock() throws Exception {
doTest("j2k/tests/testData/ast/for/forRangeWithBlock.java");
}
@TestMetadata("forRangeWithLE.java")
public void testForRangeWithLE() throws Exception {
doTest("j2k/tests/testData/ast/for/forRangeWithLE.java");
@@ -2809,6 +2827,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
suite.addTestSuite(AssertStatement.class);
suite.addTestSuite(AssignmentExpression.class);
suite.addTestSuite(BinaryExpression.class);
suite.addTestSuite(Blocks.class);
suite.addTestSuite(BoxedType.class);
suite.addTestSuite(BreakStatement.class);
suite.addTestSuite(CallChainExpression.class);
+16
View File
@@ -0,0 +1,16 @@
//method
void foo() {
{
int a = 1;
bar(a);
}
{
int a = 2;
bar(a);
}
{
bar(3);
}
}
+13
View File
@@ -0,0 +1,13 @@
fun foo() {
run {
val a = 1
bar(a)
}
run {
val a = 2
bar(a)
}
run { bar(3) }
}
@@ -1,9 +1,7 @@
{
run {
init()
while (condition()) {
body()
{
update()
}
update()
}
}
@@ -0,0 +1,3 @@
//statement
int[] array = new int[10];
for (int i = 0; i < 10; i++) {array[i] = i;}
@@ -0,0 +1,4 @@
val array = IntArray(10)
for (i in 0..10 - 1) {
array[i] = i
}
+4 -2
View File
@@ -1,3 +1,5 @@
//statement
int[] array = new int[10];
for (int i = 0; i < 10; i++) {array[i] = i;}
for (int i = 0; i < 10; j++, i++) {
System.out.println(i);
System.out.println(j);
}
+8 -3
View File
@@ -1,4 +1,9 @@
val array = IntArray(10)
for (i in 0..10 - 1) {
array[i] = i
run {
val i = 0
while (i < 10) {
System.out.println(i)
System.out.println(j)
j++
i++
}
}
@@ -1,13 +1,11 @@
{
run {
val i = 0
while (i < 0) {
{
run {
val i = 1
i++
}
{
j++
i++
}
j++
i++
}
}
@@ -1,10 +1,7 @@
{
run {
val i = 0
while (i < 0) {
{}
{
j++
i++
}
j++
i++
}
}
@@ -1,9 +1,7 @@
{
run {
init()
while (true) {
body()
{
update()
}
update()
}
}
@@ -1,8 +1,4 @@
{
while (condition()) {
body()
{
update()
}
}
}
while (condition()) {
body()
update()
}
@@ -1,6 +1,4 @@
{
run {
init()
while (condition()) {
body()
}
while (condition()) body()
}
+3 -5
View File
@@ -1,10 +1,8 @@
{
run {
val i = 0
while (i < 0) {
return i
{
j++
i++
}
j++
i++
}
}