From d5326031c4ee0fb4e5e42243fb1d78ee32f3890e Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 31 Mar 2015 13:16:39 +0300 Subject: [PATCH] J2k: for through range with != comparison is also recognized --- .../org/jetbrains/kotlin/j2k/ForConverter.kt | 91 +++++++++---------- j2k/testData/fileOrElement/for/downTo4.java | 7 ++ j2k/testData/fileOrElement/for/downTo4.kt | 7 ++ .../fileOrElement/for/forRangeWithNE.java | 3 + .../fileOrElement/for/forRangeWithNE.kt | 4 + .../for/forThroughListIndicesNE.java | 10 ++ .../for/forThroughListIndicesNE.kt | 9 ++ ...otlinConverterForWebDemoTestGenerated.java | 18 ++++ ...otlinConverterSingleFileTestGenerated.java | 18 ++++ 9 files changed, 120 insertions(+), 47 deletions(-) create mode 100644 j2k/testData/fileOrElement/for/downTo4.java create mode 100644 j2k/testData/fileOrElement/for/downTo4.kt create mode 100644 j2k/testData/fileOrElement/for/forRangeWithNE.java create mode 100644 j2k/testData/fileOrElement/for/forRangeWithNE.kt create mode 100644 j2k/testData/fileOrElement/for/forThroughListIndicesNE.java create mode 100644 j2k/testData/fileOrElement/for/forThroughListIndicesNE.kt diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt index 3f1e7268d2c..1f240bbe409 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt @@ -152,81 +152,78 @@ class ForConverter( && !loopVar.hasWriteAccesses(referenceSearcher, condition) && condition is PsiBinaryExpression) { - val operationTokenType = condition.getOperationTokenType() - val reversed = when (operationTokenType) { - JavaTokenType.LT, JavaTokenType.LE -> false - JavaTokenType.GT, JavaTokenType.GE -> true - else -> return null - } - val left = condition.getLOperand() as? PsiReferenceExpression ?: return null val right = condition.getROperand() ?: return null if (left.resolve() == loopVar) { val start = loopVar.getInitializer() ?: return null - val operationType = if (reversed) JavaTokenType.MINUSMINUS else JavaTokenType.PLUSPLUS - if ((update as? PsiExpressionStatement)?.getExpression()?.isVariableIncrementOrDecrement(loopVar, operationType) ?: false) { - val range = forIterationRange(start, right, operationTokenType).assignNoPrototype() - val explicitType = if (settings.specifyLocalVariableTypeByDefault) - PrimitiveType(Identifier("Int").assignNoPrototype()).assignNoPrototype() - else - null - return ForeachStatement(loopVar.declarationIdentifier(), explicitType, range, codeConverter.convertStatementOrBlock(body), statement.isInSingleLine()) + val operationType = (update as? PsiExpressionStatement)?.getExpression()?.isVariableIncrementOrDecrement(loopVar) + val reversed = when (operationType) { + JavaTokenType.PLUSPLUS -> false + JavaTokenType.MINUSMINUS -> true + else -> return null } + + val inclusive = when (condition.getOperationTokenType()) { + JavaTokenType.LT -> if (reversed) return null else false + JavaTokenType.LE -> if (reversed) return null else true + JavaTokenType.GT -> if (reversed) false else return null + JavaTokenType.GE -> if (reversed) true else return null + JavaTokenType.NE -> false + else -> return null + } + + val range = forIterationRange(start, right, reversed, inclusive).assignNoPrototype() + val explicitType = if (settings.specifyLocalVariableTypeByDefault) + PrimitiveType(Identifier("Int").assignNoPrototype()).assignNoPrototype() + else + null + return ForeachStatement(loopVar.declarationIdentifier(), explicitType, range, codeConverter.convertStatementOrBlock(body), statement.isInSingleLine()) } } } return null } - private fun PsiElement.isVariableIncrementOrDecrement(variable: PsiVariable, operationTokenType: IElementType): Boolean { + private fun PsiElement.isVariableIncrementOrDecrement(variable: PsiVariable): IElementType? { //TODO: simplify code when KT-5453 fixed val pair = when (this) { is PsiPostfixExpression -> getOperationTokenType() to getOperand() is PsiPrefixExpression -> getOperationTokenType() to getOperand() - else -> return false + else -> return null } - return pair.first == operationTokenType && (pair.second as? PsiReferenceExpression)?.resolve() == variable + if ((pair.second as? PsiReferenceExpression)?.resolve() != variable) return null + return pair.first } - private fun forIterationRange(start: PsiExpression, bound: PsiExpression, comparisonTokenType: IElementType): Expression { - val indicesRange = indicesIterationRange(start, bound, comparisonTokenType) + private fun forIterationRange(start: PsiExpression, bound: PsiExpression, reversed: Boolean, inclusiveComparison: Boolean): Expression { + val indicesRange = indicesIterationRange(start, bound, reversed, inclusiveComparison) if (indicesRange != null) return indicesRange val startConverted = codeConverter.convertExpression(start) - return when (comparisonTokenType) { - JavaTokenType.LT, JavaTokenType.LE -> - RangeExpression(startConverted, convertBound(bound, if (comparisonTokenType == JavaTokenType.LT) -1 else 0)) - - JavaTokenType.GT, JavaTokenType.GE -> - DownToExpression(startConverted, convertBound(bound, if (comparisonTokenType == JavaTokenType.GT) +1 else 0)) - - else -> - throw IllegalAccessException() - } + return if (reversed) + DownToExpression(startConverted, convertBound(bound, if (inclusiveComparison) 0 else +1)) + else + RangeExpression(startConverted, convertBound(bound, if (inclusiveComparison) 0 else -1)) } - private fun indicesIterationRange(start: PsiExpression, bound: PsiExpression, comparisonTokenType: IElementType): Expression? { - val reversed = when (comparisonTokenType) { - JavaTokenType.LT -> false - JavaTokenType.GE -> true - else -> return null - } - - val lower = if (reversed) bound else start - val upper = if (reversed) start else bound - - if ((lower as? PsiLiteralExpression)?.getValue() != 0) return null - + private fun indicesIterationRange(start: PsiExpression, bound: PsiExpression, reversed: Boolean, inclusiveComparison: Boolean): Expression? { val collectionSize = if (reversed) { - if (upper !is PsiBinaryExpression) return null - if (upper.getOperationTokenType() != JavaTokenType.MINUS) return null - if ((upper.getROperand() as? PsiLiteralExpression)?.getValue() != 1) return null - upper.getLOperand() + if (!inclusiveComparison) return null + + if ((bound as? PsiLiteralExpression)?.getValue() != 0) return null + + if (start !is PsiBinaryExpression) return null + if (start.getOperationTokenType() != JavaTokenType.MINUS) return null + if ((start.getROperand() as? PsiLiteralExpression)?.getValue() != 1) return null + start.getLOperand() } else { - upper + if (inclusiveComparison) return null + if ((start as? PsiLiteralExpression)?.getValue() != 0) return null + bound } + var indices: Expression? = null // check if it's iteration through list indices diff --git a/j2k/testData/fileOrElement/for/downTo4.java b/j2k/testData/fileOrElement/for/downTo4.java new file mode 100644 index 00000000000..fb554e74991 --- /dev/null +++ b/j2k/testData/fileOrElement/for/downTo4.java @@ -0,0 +1,7 @@ +public class A { + void foo(int min) { + for(int i = 10; i != min; i--) { + System.out.println(i); + } + } +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/for/downTo4.kt b/j2k/testData/fileOrElement/for/downTo4.kt new file mode 100644 index 00000000000..26f4ace7aee --- /dev/null +++ b/j2k/testData/fileOrElement/for/downTo4.kt @@ -0,0 +1,7 @@ +public class A { + fun foo(min: Int) { + for (i in 10 downTo min + 1) { + println(i) + } + } +} diff --git a/j2k/testData/fileOrElement/for/forRangeWithNE.java b/j2k/testData/fileOrElement/for/forRangeWithNE.java new file mode 100644 index 00000000000..8f4f1e5ed22 --- /dev/null +++ b/j2k/testData/fileOrElement/for/forRangeWithNE.java @@ -0,0 +1,3 @@ +//statement +int[] array = new int[10]; +for (int i = 0; i != 10; i++) {array[i] = i;} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/for/forRangeWithNE.kt b/j2k/testData/fileOrElement/for/forRangeWithNE.kt new file mode 100644 index 00000000000..86a56d28afb --- /dev/null +++ b/j2k/testData/fileOrElement/for/forRangeWithNE.kt @@ -0,0 +1,4 @@ +val array = IntArray(10) +for (i in 0..9) { + array[i] = i +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/for/forThroughListIndicesNE.java b/j2k/testData/fileOrElement/for/forThroughListIndicesNE.java new file mode 100644 index 00000000000..d49c8fe0fb7 --- /dev/null +++ b/j2k/testData/fileOrElement/for/forThroughListIndicesNE.java @@ -0,0 +1,10 @@ +import java.util.List; +import java.util.ArrayList; + +class C{ + void foo(List list) { + for (int i = 0; i != list.size(); i++) { + list.set(i, "a"); + } + } +} diff --git a/j2k/testData/fileOrElement/for/forThroughListIndicesNE.kt b/j2k/testData/fileOrElement/for/forThroughListIndicesNE.kt new file mode 100644 index 00000000000..2772d545c26 --- /dev/null +++ b/j2k/testData/fileOrElement/for/forThroughListIndicesNE.kt @@ -0,0 +1,9 @@ +import java.util.ArrayList + +class C { + fun foo(list: MutableList) { + for (i in list.indices) { + list.set(i, "a") + } + } +} diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java index d81d5b649ba..4aad7e91764 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -1892,6 +1892,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("downTo4.java") + public void testDownTo4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/downTo4.java"); + doTest(fileName); + } + @TestMetadata("falseArrayIndicesReversed.java") public void testFalseArrayIndicesReversed() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/falseArrayIndicesReversed.java"); @@ -1940,6 +1946,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("forRangeWithNE.java") + public void testForRangeWithNE() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forRangeWithNE.java"); + doTest(fileName); + } + @TestMetadata("forThroughArrayIndices.java") public void testForThroughArrayIndices() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forThroughArrayIndices.java"); @@ -1958,6 +1970,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("forThroughListIndicesNE.java") + public void testForThroughListIndicesNE() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forThroughListIndicesNE.java"); + doTest(fileName); + } + @TestMetadata("forThroughNonArrayIndices.java") public void testForThroughNonArrayIndices() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forThroughNonArrayIndices.java"); diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index c25d15a19be..166c31f849b 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -1892,6 +1892,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("downTo4.java") + public void testDownTo4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/downTo4.java"); + doTest(fileName); + } + @TestMetadata("falseArrayIndicesReversed.java") public void testFalseArrayIndicesReversed() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/falseArrayIndicesReversed.java"); @@ -1940,6 +1946,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("forRangeWithNE.java") + public void testForRangeWithNE() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forRangeWithNE.java"); + doTest(fileName); + } + @TestMetadata("forThroughArrayIndices.java") public void testForThroughArrayIndices() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forThroughArrayIndices.java"); @@ -1958,6 +1970,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("forThroughListIndicesNE.java") + public void testForThroughListIndicesNE() throws Exception { + String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forThroughListIndicesNE.java"); + doTest(fileName); + } + @TestMetadata("forThroughNonArrayIndices.java") public void testForThroughNonArrayIndices() throws Exception { String fileName = JetTestUtils.navigationMetadata("j2k/testData/fileOrElement/for/forThroughNonArrayIndices.java");