Skip to content

Commit 6dbb13c

Browse files
committed
KT-6798 J2K: Needless use of run {} function after converting for-loop
#KT-6798 Fixed
1 parent 46193f3 commit 6dbb13c

28 files changed

+373
-113
lines changed

j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ package org.jetbrains.kotlin.j2k
1818

1919
import com.intellij.psi.*
2020
import com.intellij.psi.tree.IElementType
21+
import com.intellij.util.IncorrectOperationException
2122
import org.jetbrains.kotlin.j2k.ast.*
23+
import org.jetbrains.kotlin.psi.psiUtil.parents
24+
import org.jetbrains.kotlin.psi.psiUtil.siblings
2225

2326
class ForConverter(
2427
private val statement: PsiForStatement,
@@ -101,23 +104,44 @@ class ForConverter(
101104
statement.isInSingleLine()).assignNoPrototype()
102105
if (initializationConverted.isEmpty) return whileStatement
103106

104-
//TODO: we could omit "run { ... }" when it won't cause any name conflicts
105-
return RunBlockWithLoopStatement(initializationConverted, whileStatement)
107+
val kind = if (statement.parents(withItself = false).filter { it !is PsiLabeledStatement }.first() !is PsiCodeBlock) {
108+
WhileWithInitializationPseudoStatement.Kind.WITH_BLOCK
109+
}
110+
else if (hasNameConflict())
111+
WhileWithInitializationPseudoStatement.Kind.WITH_RUN_BLOCK
112+
else
113+
WhileWithInitializationPseudoStatement.Kind.SIMPLE
114+
return WhileWithInitializationPseudoStatement(initializationConverted, whileStatement, kind)
106115
}
107116

108-
public class RunBlockWithLoopStatement(
117+
public class WhileWithInitializationPseudoStatement(
109118
public val initialization: Statement,
110-
public val loop: Statement
119+
public val loop: Statement,
120+
public val kind: WhileWithInitializationPseudoStatement.Kind
111121
) : Statement() {
112122

113-
private val methodCall = run {
114-
val statements = listOf(initialization, loop)
115-
val block = Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
116-
MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block))
123+
public enum class Kind {
124+
SIMPLE
125+
WITH_BLOCK
126+
WITH_RUN_BLOCK
117127
}
118128

129+
private val statements = listOf(initialization, loop)
130+
119131
override fun generateCode(builder: CodeBuilder) {
120-
methodCall.generateCode(builder)
132+
if (kind == Kind.SIMPLE) {
133+
builder.append(statements, "\n")
134+
}
135+
else {
136+
val block = Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
137+
if (kind == Kind.WITH_BLOCK) {
138+
block.generateCode(builder)
139+
}
140+
else {
141+
val call = MethodCallExpression.build(null, "run", listOf(), listOf(), false, LambdaExpression(null, block))
142+
call.generateCode(builder)
143+
}
144+
}
121145
}
122146
}
123147

@@ -260,4 +284,42 @@ class ForConverter(
260284
else -> null
261285
}
262286
}
287+
288+
private fun hasNameConflict(): Boolean {
289+
val names = statement.getInitialization()?.declaredVariableNames() ?: return false
290+
if (names.isEmpty()) return false
291+
292+
val factory = PsiElementFactory.SERVICE.getInstance(project)
293+
for (name in names) {
294+
val refExpr = try {
295+
factory.createExpressionFromText(name, statement) as? PsiReferenceExpression ?: return true
296+
}
297+
catch(e: IncorrectOperationException) {
298+
return true
299+
}
300+
if (refExpr.resolve() != null) return true
301+
}
302+
303+
var hasConflict = false
304+
for (laterStatement in statement.siblings(forward = true, withItself = false)) {
305+
laterStatement.accept(object: JavaRecursiveElementVisitor() {
306+
override fun visitDeclarationStatement(statement: PsiDeclarationStatement) {
307+
super.visitDeclarationStatement(statement)
308+
309+
if (statement.declaredVariableNames().any { it in names }) {
310+
hasConflict = true
311+
}
312+
}
313+
})
314+
}
315+
316+
return hasConflict
317+
}
318+
319+
private fun PsiStatement.declaredVariableNames(): Collection<String> {
320+
val declarationStatement = this as? PsiDeclarationStatement ?: return listOf()
321+
return declarationStatement.getDeclaredElements()
322+
.filterIsInstance<PsiVariable>()
323+
.map { it.getName() }
324+
}
263325
}

j2k/src/org/jetbrains/kotlin/j2k/StatementConverter.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,11 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
144144
}
145145

146146
override fun visitLabeledStatement(statement: PsiLabeledStatement) {
147-
//TODO: multiple labels
148147
val statementConverted = codeConverter.convertStatement(statement.getStatement())
149148
val identifier = converter.convertIdentifier(statement.getLabelIdentifier())
150-
if (statementConverted is ForConverter.RunBlockWithLoopStatement) { // special case - if our loop gets converted to run { ... } we should move label inside
149+
if (statementConverted is ForConverter.WhileWithInitializationPseudoStatement) { // special case - if our loop gets converted to while with initialization we should move the label to the loop
151150
val labeledLoop = LabeledStatement(identifier, statementConverted.loop).assignPrototype(statement)
152-
result = ForConverter.RunBlockWithLoopStatement(statementConverted.initialization, labeledLoop)
151+
result = ForConverter.WhileWithInitializationPseudoStatement(statementConverted.initialization, labeledLoop, statementConverted.kind)
153152
}
154153
else {
155154
result = LabeledStatement(identifier, statementConverted)
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
run {
2-
init()
3-
while (condition()) {
4-
body()
5-
update()
6-
}
1+
init()
2+
while (condition()) {
3+
body()
4+
update()
75
}
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
run {
2-
var i = 0
3-
while (i * 2 <= 10) {
4-
foo(i)
5-
i++
6-
}
1+
var i = 0
2+
while (i * 2 <= 10) {
3+
foo(i)
4+
i++
75
}
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
run {
2-
var i = 0
3-
while (i < 10) {
4-
System.out.println(i)
5-
System.out.println(j)
6-
j++
7-
i++
8-
}
1+
var i = 0
2+
while (i < 10) {
3+
System.out.println(i)
4+
System.out.println(j)
5+
j++
6+
i++
97
}
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
run {
2-
var i = 0
3-
while (i < 0) {
4-
run {
5-
var i = 1
6-
i++
7-
}
8-
j++
1+
var i = 0
2+
while (i < 0) {
3+
run {
4+
var i = 1
95
i++
106
}
7+
j++
8+
i++
119
}
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
run {
2-
var i = 0
3-
while (i < 0) {
4-
j++
5-
i++
6-
}
1+
var i = 0
2+
while (i < 0) {
3+
j++
4+
i++
75
}
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
run {
2-
init()
3-
while (true) {
4-
body()
5-
update()
6-
}
1+
init()
2+
while (true) {
3+
body()
4+
update()
75
}
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
run {
2-
init()
3-
while (condition()) body()
4-
}
1+
init()
2+
while (condition()) body()
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
run {
2-
var i = 0
3-
while (i < 0) {
4-
return i
5-
j++
6-
i++
7-
}
1+
var i = 0
2+
while (i < 0) {
3+
return i
4+
j++
5+
i++
86
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class A {
2+
void foo() {
3+
for (int i = 1; i < 1000; i *= 2) {
4+
System.out.println(i);
5+
}
6+
7+
for (int i = 1; i < 2000; i *= 2) {
8+
System.out.println(i);
9+
}
10+
}
11+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class A {
2+
fun foo() {
3+
run {
4+
var i = 1
5+
while (i < 1000) {
6+
System.out.println(i)
7+
i *= 2
8+
}
9+
}
10+
11+
var i = 1
12+
while (i < 2000) {
13+
System.out.println(i)
14+
i *= 2
15+
}
16+
}
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class A {
2+
void foo() {
3+
for (int i = 1, j = 0; i < 1000; i *= 2, j++) {
4+
System.out.println(i);
5+
}
6+
7+
for (int j = 1; j < 2000; j *= 2) {
8+
System.out.println(j);
9+
}
10+
}
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class A {
2+
fun foo() {
3+
run {
4+
var i = 1
5+
var j = 0
6+
while (i < 1000) {
7+
System.out.println(i)
8+
i *= 2
9+
j++
10+
}
11+
}
12+
13+
var j = 1
14+
while (j < 2000) {
15+
System.out.println(j)
16+
j *= 2
17+
}
18+
}
19+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class A {
2+
int i = 1;
3+
4+
void foo() {
5+
for (int i = 1; i < 1000; i *= 2) {
6+
System.out.println(i);
7+
}
8+
9+
i = 10;
10+
}
11+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class A {
2+
var i = 1
3+
4+
fun foo() {
5+
run {
6+
var i = 1
7+
while (i < 1000) {
8+
System.out.println(i)
9+
i *= 2
10+
}
11+
}
12+
13+
i = 10
14+
}
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class A {
2+
void foo(boolean p) {
3+
for (int i = 1; i < 1000; i *= 2) {
4+
System.out.println(i);
5+
}
6+
7+
if (p) {
8+
int i = 10
9+
}
10+
}
11+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class A {
2+
fun foo(p: Boolean) {
3+
run {
4+
var i = 1
5+
while (i < 1000) {
6+
System.out.println(i)
7+
i *= 2
8+
}
9+
}
10+
11+
if (p) {
12+
val i = 10
13+
}
14+
}
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class A {
2+
void foo(boolean p) {
3+
if (p) {
4+
int i = 10
5+
}
6+
7+
for (int i = 1; i < 1000; i *= 2) {
8+
System.out.println(i);
9+
}
10+
}
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class A {
2+
fun foo(p: Boolean) {
3+
if (p) {
4+
val i = 10
5+
}
6+
7+
var i = 1
8+
while (i < 1000) {
9+
System.out.println(i)
10+
i *= 2
11+
}
12+
}
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class A {
2+
void foo(boolean p) {
3+
if (p)
4+
for (int i = 1; i < 1000; i *= 2) {
5+
System.out.println(i);
6+
}
7+
}
8+
}

0 commit comments

Comments
 (0)