From 149ea16f5cc84157adea1c7bcacc2562821070ff Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 11 Jun 2014 13:07:13 +0400 Subject: [PATCH] Java to Kotlin converter: supported try-with-resource construct, fixed anonymous class generation + fixed a bug with method return type #KT-4488 Fixed --- .../plugin/actions/JavaToKotlinAction.java | 2 +- .../copy/ConvertJavaCopyPastePostProcessor.kt | 2 +- j2k/src/org/jetbrains/jet/j2k/Converter.kt | 56 ++++++------ .../jet/j2k/JavaToKotlinTranslator.kt | 2 +- ...nonymousClass.kt => AnonymousClassBody.kt} | 6 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 13 +++ .../jet/j2k/ast/MethodCallExpression.kt | 44 +++++---- .../jet/j2k/ast/NewClassExpression.kt | 17 ++-- .../jetbrains/jet/j2k/visitors/Dispatcher.kt | 24 ----- .../jet/j2k/visitors/ElementVisitor.kt | 4 +- .../jet/j2k/visitors/ExpressionVisitor.kt | 5 +- .../jet/j2k/visitors/StatementVisitor.kt | 89 ++++++++++++++++--- .../test/AbstractJavaToKotlinConverterTest.kt | 4 +- .../JavaToKotlinConverterTestGenerated.java | 86 ++++++++++++++++-- j2k/tests/testData/KotlinApi.kt | 2 + ...ymousScope.java => newAnonymousClass.java} | 0 ...AnonymousScope.kt => newAnonymousClass.kt} | 2 +- .../newAnonymousClass2.java | 13 +++ .../newClassExpression/newAnonymousClass2.kt | 11 +++ .../newAnonymousClass3.java | 27 ++++++ .../newClassExpression/newAnonymousClass3.kt | 19 ++++ .../MethodReturnsNullInAnonymousClass.kt | 2 +- .../ast/returnStatement/CurrentMethodBug.java | 22 +++++ .../ast/returnStatement/currentMethodBug.kt | 19 ++++ .../ast/tryWithResource/Multiline.java | 12 +++ .../testData/ast/tryWithResource/Multiline.kt | 11 +++ .../tryWithResource/MultipleResources.java | 12 +++ .../ast/tryWithResource/MultipleResources.kt | 12 +++ .../testData/ast/tryWithResource/Simple.java | 10 +++ .../testData/ast/tryWithResource/Simple.kt | 7 ++ .../ast/tryWithResource/WithCatch.java | 15 ++++ .../testData/ast/tryWithResource/WithCatch.kt | 16 ++++ .../tryWithResource/WithCatchAndFinally.java | 18 ++++ .../tryWithResource/WithCatchAndFinally.kt | 17 ++++ .../ast/tryWithResource/WithCatches.java | 18 ++++ .../ast/tryWithResource/WithCatches.kt | 18 ++++ .../ast/tryWithResource/WithFinally.java | 15 ++++ .../ast/tryWithResource/WithFinally.kt | 15 ++++ .../ast/tryWithResource/WithReturn.java.todo | 17 ++++ .../ast/tryWithResource/WithReturnAtEnd.java | 16 ++++ .../ast/tryWithResource/WithReturnAtEnd.kt | 17 ++++ .../WithReturnInAnonymousClass.java | 23 +++++ .../WithReturnInAnonymousClass.kt | 21 +++++ .../WithReturnInAnonymousClass2.java | 23 +++++ .../WithReturnInAnonymousClass2.kt | 21 +++++ .../WithReturnInAnonymousClass3.java.todo | 26 ++++++ 46 files changed, 724 insertions(+), 107 deletions(-) rename j2k/src/org/jetbrains/jet/j2k/ast/{AnonymousClass.kt => AnonymousClassBody.kt} (86%) delete mode 100644 j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt rename j2k/tests/testData/ast/newClassExpression/{newClassWithAnonymousScope.java => newAnonymousClass.java} (100%) rename j2k/tests/testData/ast/newClassExpression/{newClassWithAnonymousScope.kt => newAnonymousClass.kt} (75%) create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java create mode 100644 j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt create mode 100644 j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java create mode 100644 j2k/tests/testData/ast/returnStatement/currentMethodBug.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/Multiline.java create mode 100644 j2k/tests/testData/ast/tryWithResource/Multiline.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/MultipleResources.java create mode 100644 j2k/tests/testData/ast/tryWithResource/MultipleResources.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/Simple.java create mode 100644 j2k/tests/testData/ast/tryWithResource/Simple.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatch.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatch.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatches.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithCatches.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithFinally.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithFinally.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt create mode 100644 j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java index 8404703307d..a8250c61b51 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JavaToKotlinAction.java @@ -52,7 +52,7 @@ public class JavaToKotlinAction extends AnAction { return; } - final Converter converter = new Converter(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); + final Converter converter = Converter.object$.create(project, ConverterSettings.defaultSettings, new FilesConversionScope(selectedJavaFiles)); CommandProcessor.getInstance().executeCommand( project, new Runnable() { diff --git a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt index 143f9b75d50..ebeefcdcb73 100644 --- a/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt @@ -79,7 +79,7 @@ public class ConvertJavaCopyPastePostProcessor() : CopyPastePostProcessor) : Conversi override fun contains(element: PsiElement) = files.any { element.getContainingFile() == it } } -public class Converter(val project: Project, val settings: ConverterSettings, val conversionScope: ConversionScope) { +public class Converter private(val project: Project, val settings: ConverterSettings, val conversionScope: ConversionScope, val state: Converter.State) { + private class State(val typeConverter: TypeConverter, + val methodReturnType: PsiType?, + val expressionVisitorFactory: (Converter) -> ExpressionVisitor, + val statementVisitorFactory: (Converter) -> StatementVisitor) - private val typeConverter = TypeConverter(settings, conversionScope) + val typeConverter: TypeConverter get() = state.typeConverter + val methodReturnType: PsiType? get() = state.methodReturnType - private val dispatcher: Dispatcher = Dispatcher(this, typeConverter) + class object { + public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope): Converter + = Converter(project, settings, conversionScope, State(TypeConverter(settings, conversionScope), null, { ExpressionVisitor(it) }, { StatementVisitor(it) })) + } - public var methodReturnType: PsiType? = null - private set + fun withMethodReturnType(methodReturnType: PsiType?): Converter + = Converter(project, settings, conversionScope, State(typeConverter, methodReturnType, state.expressionVisitorFactory, state.statementVisitorFactory)) + + fun withExpressionVisitor(factory: (Converter) -> ExpressionVisitor): Converter + = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, factory, state.statementVisitorFactory)) + + fun withStatementVisitor(factory: (Converter) -> StatementVisitor): Converter + = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, state.expressionVisitorFactory, factory)) public fun elementToKotlin(element: PsiElement): String = convertTopElement(element)?.toKotlin() ?: "" @@ -65,8 +79,8 @@ public class Converter(val project: Project, val settings: ConverterSettings, va return File(fileMembers, createMainFunction(javaFile)) } - public fun convertAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass { - return AnonymousClass(this, convertClassBody(anonymousClass)) + public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { + return AnonymousClassBody(this, convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) } private fun convertClassBody(psiClass: PsiClass): List { @@ -216,7 +230,10 @@ public class Converter(val project: Project, val settings: ConverterSettings, va } private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { - methodReturnType = method.getReturnType() + return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove) + } + + private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { val returnType = typeConverter.convertMethodReturnType(method) val modifiers = convertModifiers(method) @@ -340,13 +357,8 @@ public class Converter(val project: Project, val settings: ConverterSettings, va usageReplacementMap.put(parameter, field.getName()!!) } } - dispatcher.expressionVisitor = ExpressionVisitor(this, typeConverter, usageReplacementMap) - try { - convertBlock(body, false, { !statementsToRemove.contains(it) }) - } - finally { - dispatcher.expressionVisitor = ExpressionVisitor(this, typeConverter, mapOf()) - } + + withExpressionVisitor { ExpressionVisitor(it, usageReplacementMap) }.convertBlock(body, false, { !statementsToRemove.contains(it) }) } else { Block.Empty @@ -409,7 +421,7 @@ public class Converter(val project: Project, val settings: ConverterSettings, va public fun convertStatement(statement: PsiStatement?): Statement { if (statement == null) return Statement.Empty - val statementVisitor: StatementVisitor = StatementVisitor(this) + val statementVisitor = state.statementVisitorFactory(this) statement.accept(statementVisitor) return statementVisitor.result } @@ -420,7 +432,7 @@ public class Converter(val project: Project, val settings: ConverterSettings, va public fun convertExpression(expression: PsiExpression?): Expression { if (expression == null) return Expression.Empty - val expressionVisitor = dispatcher.expressionVisitor + val expressionVisitor = state.expressionVisitorFactory(this) expression.accept(expressionVisitor) return expressionVisitor.result } @@ -428,19 +440,11 @@ public class Converter(val project: Project, val settings: ConverterSettings, va public fun convertElement(element: PsiElement?): Element { if (element == null) return Element.Empty - val elementVisitor = ElementVisitor(this, typeConverter) + val elementVisitor = ElementVisitor(this) element.accept(elementVisitor) return elementVisitor.result } - fun convertElements(elements: Array): List { - val result = ArrayList() - for (element in elements) { - result.add(convertElement(element)) - } - return result - } - public fun convertTypeElement(element: PsiTypeElement?): TypeElement = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())) diff --git a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt index 88f488124c0..355a5d846c5 100644 --- a/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt +++ b/j2k/src/org/jetbrains/jet/j2k/JavaToKotlinTranslator.kt @@ -89,7 +89,7 @@ public object JavaToKotlinTranslator { fun generateKotlinCode(javaCode: String): String { val file = createFile(javaCode) if (file is PsiJavaFile) { - val converter = Converter(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) + val converter = Converter.create(file.getProject(), ConverterSettings.defaultSettings, FilesConversionScope(listOf(file))) return prettify(converter.convertFile(file).toKotlin()) } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt similarity index 86% rename from j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt rename to j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index ac6dc1a4c88..0b464a4778a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -19,11 +19,11 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.Collections -class AnonymousClass(converter: Converter, bodyElements: List) +class AnonymousClassBody(converter: Converter, bodyElements: List, val extendsTrait: Boolean) : Class(converter, - Identifier("anonClass"), + Identifier(""), MemberComments.Empty, - Collections.emptySet(), + setOf(), TypeParameterList.Empty, listOf(), listOf(), diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 2ff597097af..4082fa010b3 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -91,6 +91,19 @@ class PolyadicExpression(val expressions: List, val token: String) : } } +class LambdaExpression(val arguments: String?, val statementList: StatementList) : Expression() { + override fun toKotlin(): String { + val statementsText = statementList.toKotlin().trim() + if (arguments != null) { + val br = if (statementsText.indexOf('\n') < 0 && statementsText.indexOf('\r') < 0) " " else "\n" + return "{ $arguments ->$br$statementsText }" + } + else { + return "{ $statementsText }" + } + } +} + fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List) : MethodCallExpression { val elementType = arrayType.elementType val createArrayFunction = if (elementType.isPrimitive()) { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 6f2c13cb2d2..aefcd1c5cc2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -16,46 +16,54 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList - class MethodCallExpression( val methodExpression: Expression, val arguments: List, val typeArguments: List, - override val isNullable: Boolean + override val isNullable: Boolean, + val lambdaArgument: LambdaExpression? = null ) : Expression() { override fun toKotlin(): String { - return operandToKotlin(methodExpression) + - typeArguments.toKotlin(", ", "<", ">") + - "(" + - arguments.map { it.toKotlin() }.makeString(", ") + - ")" + val builder = StringBuilder() + builder.append(operandToKotlin(methodExpression)) + builder.append(typeArguments.toKotlin(", ", "<", ">")) + if (arguments.isNotEmpty() || lambdaArgument == null) { + builder.append("(").append(arguments.map { it.toKotlin() }.makeString(", ")).append(")") + } + if (lambdaArgument != null) { + builder.append(lambdaArgument.toKotlin()) + } + return builder.toString() } class object { public fun buildNotNull(receiver: Expression?, - methodName: String, - arguments: List = listOf(), - typeArguments: List = listOf()): MethodCallExpression - = build(receiver, methodName, arguments, typeArguments, false) + methodName: String, + arguments: List = listOf(), + typeArguments: List = listOf(), + lambdaArgument: LambdaExpression? = null): MethodCallExpression + = build(receiver, methodName, arguments, typeArguments, false, lambdaArgument) public fun buildNullable(receiver: Expression?, - methodName: String, - arguments: List = listOf(), - typeArguments: List = listOf()): MethodCallExpression - = build(receiver, methodName, arguments, typeArguments, true) + methodName: String, + arguments: List = listOf(), + typeArguments: List = listOf(), + lambdaArgument: LambdaExpression? = null): MethodCallExpression + = build(receiver, methodName, arguments, typeArguments, true, lambdaArgument) public fun build(receiver: Expression?, methodName: String, arguments: List, typeArguments: List, - isNullable: Boolean): MethodCallExpression { + isNullable: Boolean, + lambdaArgument: LambdaExpression? = null): MethodCallExpression { val identifier = Identifier(methodName, false) return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier) else identifier, arguments, typeArguments, - isNullable) + isNullable, + lambdaArgument) } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt index 45fff2a8fde..77e4427e170 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt @@ -16,20 +16,25 @@ package org.jetbrains.jet.j2k.ast -open class NewClassExpression( +class NewClassExpression( val name: Element, val arguments: List, val qualifier: Expression = Expression.Empty, - val anonymousClass: AnonymousClass? = null + val anonymousClass: AnonymousClassBody? = null ) : Expression() { override fun toKotlin(): String { - val callOperator = if (qualifier.isNullable) "?." else "." + val callOperator = if (qualifier.isNullable) "!!." else "." val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin() + callOperator val appliedArguments = arguments.toKotlin(", ") - return if (anonymousClass != null) - "object : " + qualifier + name.toKotlin() + "(" + appliedArguments + ")" + anonymousClass.toKotlin() - else + return if (anonymousClass != null) { + if (anonymousClass.extendsTrait) + "object : " + qualifier + name.toKotlin() + anonymousClass.toKotlin() + else + "object : " + qualifier + name.toKotlin() + "(" + appliedArguments + ")" + anonymousClass.toKotlin() + } + else{ qualifier + name.toKotlin() + "(" + appliedArguments + ")" + } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt deleted file mode 100644 index 0941f08a9af..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/Dispatcher.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.j2k.visitors - -import org.jetbrains.jet.j2k.Converter -import org.jetbrains.jet.j2k.TypeConverter - -class Dispatcher(converter: Converter, typeConverter: TypeConverter) { - var expressionVisitor: ExpressionVisitor = ExpressionVisitor(converter, typeConverter) -} diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt index 68410680a48..5323567154e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt @@ -20,7 +20,9 @@ import com.intellij.psi.* import org.jetbrains.jet.j2k.* import org.jetbrains.jet.j2k.ast.* -class ElementVisitor(private val converter: Converter, private val typeConverter: TypeConverter) : JavaElementVisitor() { +class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { + private val typeConverter = converter.typeConverter + public var result: Element = Element.Empty protected set diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index e1ff68221f4..35e234b3e6a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -36,8 +36,9 @@ import com.intellij.psi.impl.light.LightField import org.jetbrains.jet.lang.resolve.java.JvmAbi class ExpressionVisitor(private val converter: Converter, - private val typeConverter: TypeConverter, private val usageReplacementMap: Map = mapOf()) : JavaElementVisitor() { + private val typeConverter = converter.typeConverter + public var result: Expression = Expression.Empty protected set @@ -263,7 +264,7 @@ class ExpressionVisitor(private val converter: Converter, return NewClassExpression(converter.convertElement(classReference), convertArguments(expression), converter.convertExpression(expression.getQualifier()), - if (anonymousClass != null) converter.convertAnonymousClass(anonymousClass) else null) + if (anonymousClass != null) converter.convertAnonymousClassBody(anonymousClass) else null) } override fun visitParenthesizedExpression(expression: PsiParenthesizedExpression) { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index a0e5e85d440..6518a05bc97 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -23,10 +23,11 @@ import org.jetbrains.jet.j2k.countWriteAccesses import java.util.ArrayList import org.jetbrains.jet.j2k.hasWriteAccesses import org.jetbrains.jet.j2k.isInSingleLine +import org.jetbrains.jet.j2k.getContainingMethod -class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { +open class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { public var result: Statement = Statement.Empty - private set + protected set override fun visitAssertStatement(statement: PsiAssertStatement) { result = AssertStatement(converter.convertExpression(statement.getAssertCondition()), @@ -56,7 +57,7 @@ class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { } override fun visitDeclarationStatement(statement: PsiDeclarationStatement) { - result = DeclarationStatement(converter.convertElements(statement.getDeclaredElements())) + result = DeclarationStatement(statement.getDeclaredElements().map { converter.convertElement(it) }) } override fun visitDoWhileStatement(statement: PsiDoWhileStatement) { @@ -217,16 +218,76 @@ class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { result = ThrowStatement(converter.convertExpression(statement.getException())) } - override fun visitTryStatement(statement: PsiTryStatement) { - val catches = ArrayList() - val catchBlocks = statement.getCatchBlocks() - val catchBlockParameters = statement.getCatchBlockParameters() - for (i in 0..catchBlocks.size - 1) { - catches.add(CatchStatement(converter.convertParameter(catchBlockParameters[i], Nullability.NotNull), - converter.convertBlock(catchBlocks[i]))) + override fun visitTryStatement(tryStatement: PsiTryStatement) { + val tryBlock = tryStatement.getTryBlock() + val catchesConverted = run { + val catchBlocks = tryStatement.getCatchBlocks() + val catchBlockParameters = tryStatement.getCatchBlockParameters() + catchBlocks.indices.map { + CatchStatement(converter.convertParameter(catchBlockParameters[it], Nullability.NotNull), + converter.convertBlock(catchBlocks[it])) + } } - result = TryStatement(converter.convertBlock(statement.getTryBlock()), - catches, converter.convertBlock(statement.getFinallyBlock())) + val finallyConverted = converter.convertBlock(tryStatement.getFinallyBlock()) + + val resourceList = tryStatement.getResourceList() + if (resourceList != null) { + val variables = resourceList.getResourceVariables() + if (variables.isNotEmpty()) { + var wrapResultStatement: (Expression) -> Statement = { it } + var converterForBody = converter + + val returns = collectReturns(tryBlock) + //TODO: support other returns when non-local returns supported by Kotlin + if (returns.size == 1 && returns.single() == tryBlock!!.getStatements().last()) { + wrapResultStatement = { ReturnStatement(it) } + converterForBody = converter.withStatementVisitor { object : StatementVisitor(it) { + override fun visitReturnStatement(statement: PsiReturnStatement) { + if (statement == returns.single()) { + result = converter.convertExpression(statement.getReturnValue(), tryStatement.getContainingMethod()?.getReturnType()) + } + else { + super.visitReturnStatement(statement) + } + } + }} + } + + var bodyConverted = converterForBody.convertBlock(tryBlock) + var statementList = bodyConverted.statementList + var expression: Expression = Expression.Empty + for (variable in variables.reverse()) { + val lambda = LambdaExpression(Identifier(variable.getName()!!).toKotlin(), statementList) + expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda) + statementList = StatementList(listOf(expression)) + } + + if (catchesConverted.isEmpty() && finallyConverted.isEmpty) { + result = wrapResultStatement(expression) + return + } + + bodyConverted = Block(StatementList(listOf(wrapResultStatement(expression))), true) + result = TryStatement(bodyConverted, catchesConverted, finallyConverted) + return + } + } + + result = TryStatement(converter.convertBlock(tryBlock), catchesConverted, finallyConverted) + } + + private fun collectReturns(block: PsiCodeBlock?): Collection { + val returns = ArrayList() + block?.accept(object: JavaRecursiveElementVisitor() { + override fun visitReturnStatement(statement: PsiReturnStatement) { + returns.add(statement) + } + + override fun visitMethod(method: PsiMethod) { + // do not go inside any other method (e.g. in anonymous class) + } + }) + return returns } override fun visitWhileStatement(statement: PsiWhileStatement) { @@ -241,10 +302,10 @@ class StatementVisitor(public val converter: Converter) : JavaElementVisitor() { override fun visitReturnStatement(statement: PsiReturnStatement) { val returnValue = statement.getReturnValue() val methodReturnType = converter.methodReturnType - val expression = (if (returnValue != null && methodReturnType != null) + val expression = if (returnValue != null && methodReturnType != null) converter.convertExpression(returnValue, methodReturnType) else - converter.convertExpression(returnValue)) + converter.convertExpression(returnValue) result = ReturnStatement(expression) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt index c5e68d2fa7f..d1d2e21ea08 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/AbstractJavaToKotlinConverterTest.kt @@ -116,14 +116,14 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() { private fun elementToKotlin(text: String, settings: ConverterSettings, project: Project): String { val fileWithText = JavaToKotlinTranslator.createFile(project, text) - val converter = Converter(project, settings, FilesConversionScope(listOf(fileWithText))) + val converter = Converter.create(project, settings, FilesConversionScope(listOf(fileWithText))) val element = fileWithText.getFirstChild()!! return converter.elementToKotlin(element) } private fun fileToKotlin(text: String, settings: ConverterSettings, project: Project): String { val file = JavaToKotlinTranslator.createFile(project, text) - val converter = Converter(project, settings, FilesConversionScope(listOf(file))) + val converter = Converter.create(project, settings, FilesConversionScope(listOf(file))) return converter.elementToKotlin(file) } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index ad6d08d33fd..97953f10520 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -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.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.KotlinExclusion.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.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.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.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.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.KotlinExclusion.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.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.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); @@ -1863,16 +1863,26 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/newClassExpression/genericClassInvocation.java"); } + @TestMetadata("newAnonymousClass.java") + public void testNewAnonymousClass() throws Exception { + doTest("j2k/tests/testData/ast/newClassExpression/newAnonymousClass.java"); + } + + @TestMetadata("newAnonymousClass2.java") + public void testNewAnonymousClass2() throws Exception { + doTest("j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java"); + } + + @TestMetadata("newAnonymousClass3.java") + public void testNewAnonymousClass3() throws Exception { + doTest("j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java"); + } + @TestMetadata("newClassByFullName.java") public void testNewClassByFullName() throws Exception { doTest("j2k/tests/testData/ast/newClassExpression/newClassByFullName.java"); } - @TestMetadata("newClassWithAnonymousScope.java") - public void testNewClassWithAnonymousScope() throws Exception { - doTest("j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.java"); - } - @TestMetadata("newInnerClass.java") public void testNewInnerClass() throws Exception { doTest("j2k/tests/testData/ast/newClassExpression/newInnerClass.java"); @@ -2203,6 +2213,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/returnStatement"), Pattern.compile("^(.+)\\.java$"), true); } + @TestMetadata("currentMethodBug.java") + public void testCurrentMethodBug() throws Exception { + doTest("j2k/tests/testData/ast/returnStatement/currentMethodBug.java"); + } + @TestMetadata("returnChar.java") public void testReturnChar() throws Exception { doTest("j2k/tests/testData/ast/returnStatement/returnChar.java"); @@ -2452,6 +2467,64 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } + @TestMetadata("j2k/tests/testData/ast/tryWithResource") + public static class TryWithResource extends AbstractJavaToKotlinConverterTest { + public void testAllFilesPresentInTryWithResource() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/tryWithResource"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("Multiline.java") + public void testMultiline() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/Multiline.java"); + } + + @TestMetadata("MultipleResources.java") + public void testMultipleResources() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/MultipleResources.java"); + } + + @TestMetadata("Simple.java") + public void testSimple() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/Simple.java"); + } + + @TestMetadata("WithCatch.java") + public void testWithCatch() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithCatch.java"); + } + + @TestMetadata("WithCatchAndFinally.java") + public void testWithCatchAndFinally() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java"); + } + + @TestMetadata("WithCatches.java") + public void testWithCatches() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithCatches.java"); + } + + @TestMetadata("WithFinally.java") + public void testWithFinally() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithFinally.java"); + } + + @TestMetadata("WithReturnAtEnd.java") + public void testWithReturnAtEnd() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java"); + } + + @TestMetadata("WithReturnInAnonymousClass.java") + public void testWithReturnInAnonymousClass() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java"); + } + + @TestMetadata("WithReturnInAnonymousClass2.java") + public void testWithReturnInAnonymousClass2() throws Exception { + doTest("j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java"); + } + + } + @TestMetadata("j2k/tests/testData/ast/typeCastExpression") public static class TypeCastExpression extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInTypeCastExpression() throws Exception { @@ -2677,6 +2750,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(ThrowStatement.class); suite.addTestSuite(Trait.class); suite.addTestSuite(TryStatement.class); + suite.addTestSuite(TryWithResource.class); suite.addTestSuite(TypeCastExpression.class); suite.addTestSuite(TypeParameters.class); suite.addTestSuite(VarArg.class); diff --git a/j2k/tests/testData/KotlinApi.kt b/j2k/tests/testData/KotlinApi.kt index 344233b6959..21eb3270a7e 100644 --- a/j2k/tests/testData/KotlinApi.kt +++ b/j2k/tests/testData/KotlinApi.kt @@ -19,6 +19,8 @@ public open class KotlinClass { public trait KotlinTrait { public fun nullableFun(): String? public fun notNullableFun(): String + + public fun nonAbstractFun(): Int = 1 } public fun globalFunction(s: String): String = s diff --git a/j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.java b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass.java similarity index 100% rename from j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.java rename to j2k/tests/testData/ast/newClassExpression/newAnonymousClass.java diff --git a/j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.kt b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass.kt similarity index 75% rename from j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.kt rename to j2k/tests/testData/ast/newClassExpression/newAnonymousClass.kt index 7c22181b2aa..da09fb6ea84 100644 --- a/j2k/tests/testData/ast/newClassExpression/newClassWithAnonymousScope.kt +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass.kt @@ -1,4 +1,4 @@ -object : Runnable() { +object : Runnable { override fun run() { System.out.println("Run") } diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java new file mode 100644 index 00000000000..dc732c71ca6 --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.java @@ -0,0 +1,13 @@ +//file +abstract class A {} + +class C { + void foo() { + A a = new A() { + @Override + public String toString() { + return "a"; + } + }; + } +} diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt new file mode 100644 index 00000000000..e8d2763a65a --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass2.kt @@ -0,0 +1,11 @@ +abstract class A() + +class C() { + fun foo() { + val a = object : A() { + override fun toString(): String { + return "a" + } + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java new file mode 100644 index 00000000000..34283df60aa --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.java @@ -0,0 +1,27 @@ +//file +import kotlinApi.KotlinTrait; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class C { + void foo() { + KotlinTrait t = new KotlinTrait() { + @Nullable + @Override + public String nullableFun() { + return null; + } + + @NotNull + @Override + public String notNullableFun() { + return ""; + } + + @Override + public int nonAbstractFun() { + return 0; + } + }; + } +} diff --git a/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt new file mode 100644 index 00000000000..bd3ffc22d48 --- /dev/null +++ b/j2k/tests/testData/ast/newClassExpression/newAnonymousClass3.kt @@ -0,0 +1,19 @@ +import kotlinApi.KotlinTrait + +class C() { + fun foo() { + val t = object : KotlinTrait { + override fun nullableFun(): String? { + return null + } + + override fun notNullableFun(): String { + return "" + } + + override fun nonAbstractFun(): Int { + return 0 + } + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt b/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt index 9dd3ed82b41..b3b27e608e2 100644 --- a/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt +++ b/j2k/tests/testData/ast/nullability/MethodReturnsNullInAnonymousClass.kt @@ -4,7 +4,7 @@ trait Getter { class C() { fun foo(b: Boolean): String { - val getter = object : Getter() { + val getter = object : Getter { override fun get(): String? { return null } diff --git a/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java b/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java new file mode 100644 index 00000000000..688643d3a5d --- /dev/null +++ b/j2k/tests/testData/ast/returnStatement/CurrentMethodBug.java @@ -0,0 +1,22 @@ +//file +import org.jetbrains.annotations.Nullable; + +interface I { + int getInt(); +} + +class C { + @Nullable Object getObject() { + foo(new I() { + @Override + public int getInt() { + return 0; + } + }); + return string; + } + + void foo(I i) {} + + @Nullable String string; +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/returnStatement/currentMethodBug.kt b/j2k/tests/testData/ast/returnStatement/currentMethodBug.kt new file mode 100644 index 00000000000..1b5e724938a --- /dev/null +++ b/j2k/tests/testData/ast/returnStatement/currentMethodBug.kt @@ -0,0 +1,19 @@ +trait I { + public fun getInt(): Int +} + +class C() { + fun getObject(): Any? { + foo(object : I { + override fun getInt(): Int { + return 0 + } + }) + return string + } + + fun foo(i: I) { + } + + var string: String? = null +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/Multiline.java b/j2k/tests/testData/ast/tryWithResource/Multiline.java new file mode 100644 index 00000000000..4bc2473a748 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Multiline.java @@ -0,0 +1,12 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/Multiline.kt b/j2k/tests/testData/ast/tryWithResource/Multiline.kt new file mode 100644 index 00000000000..4319e413066 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Multiline.kt @@ -0,0 +1,11 @@ +import java.io.* + +public class C() { + fun foo() { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/MultipleResources.java b/j2k/tests/testData/ast/tryWithResource/MultipleResources.java new file mode 100644 index 00000000000..f3dc33b5a36 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/MultipleResources.java @@ -0,0 +1,12 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream input = new FileInputStream("foo"); + OutputStream output = new FileOutputStream("bar")) { + output.write(input.read()); + output.write(0); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt b/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt new file mode 100644 index 00000000000..544c6137ecf --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/MultipleResources.kt @@ -0,0 +1,12 @@ +import java.io.* + +public class C() { + fun foo() { + FileInputStream("foo").use { input -> + FileOutputStream("bar").use { output -> + output.write(input.read()) + output.write(0) + } + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/Simple.java b/j2k/tests/testData/ast/tryWithResource/Simple.java new file mode 100644 index 00000000000..c07eaf8b42e --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Simple.java @@ -0,0 +1,10 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + System.out.println(stream.read()); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/Simple.kt b/j2k/tests/testData/ast/tryWithResource/Simple.kt new file mode 100644 index 00000000000..6d5d5cfacc2 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/Simple.kt @@ -0,0 +1,7 @@ +import java.io.* + +public class C() { + fun foo() { + FileInputStream("foo").use { stream -> System.out.println(stream.read()) } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatch.java b/j2k/tests/testData/ast/tryWithResource/WithCatch.java new file mode 100644 index 00000000000..50e2bb22b68 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatch.java @@ -0,0 +1,15 @@ +//file +import java.io.*; + +public class C { + void foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + catch (IOException e) { + System.out.println(e); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatch.kt b/j2k/tests/testData/ast/tryWithResource/WithCatch.kt new file mode 100644 index 00000000000..dbce19f57cf --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatch.kt @@ -0,0 +1,16 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } catch (e: IOException) { + System.out.println(e) + } + + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java new file mode 100644 index 00000000000..76821717110 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.java @@ -0,0 +1,18 @@ +//file +import java.io.*; + +public class C { + void foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + catch (IOException e) { + System.out.println(e); + } + finally { + System.out.println("Finally!"); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt new file mode 100644 index 00000000000..0f2747e0540 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatchAndFinally.kt @@ -0,0 +1,17 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } catch (e: IOException) { + System.out.println(e) + } finally { + System.out.println("Finally!") + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatches.java b/j2k/tests/testData/ast/tryWithResource/WithCatches.java new file mode 100644 index 00000000000..91317aa109a --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatches.java @@ -0,0 +1,18 @@ +//file +import java.io.*; + +public class C { + void foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + catch (IOException e) { + System.out.println(e); + } + catch (Exception e) { + System.err.println(e); + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithCatches.kt b/j2k/tests/testData/ast/tryWithResource/WithCatches.kt new file mode 100644 index 00000000000..87634a2cf45 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithCatches.kt @@ -0,0 +1,18 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } catch (e: IOException) { + System.out.println(e) + } catch (e: Exception) { + System.err.println(e) + } + + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithFinally.java b/j2k/tests/testData/ast/tryWithResource/WithFinally.java new file mode 100644 index 00000000000..e6d40d475e1 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithFinally.java @@ -0,0 +1,15 @@ +//file +import java.io.*; + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + System.out.println(c); + } + finally { + // dispose something else + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithFinally.kt b/j2k/tests/testData/ast/tryWithResource/WithFinally.kt new file mode 100644 index 00000000000..f127ac2ee0f --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithFinally.kt @@ -0,0 +1,15 @@ +import java.io.* + +public class C() { + fun foo() { + try { + FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + System.out.println(c) + } + } finally { + // dispose something else + } + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo b/j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo new file mode 100644 index 00000000000..27183fa29bc --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturn.java.todo @@ -0,0 +1,17 @@ +//file +import java.io.*; + +public class C { + int foo() { + try(InputStream stream = new FileInputStream("foo")) { + while(true) { + int c = stream.read(); + if (c < 0 || c > 127) return c; + } + } + catch (IOException e) { + System.out.println(e); + return -1; + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java new file mode 100644 index 00000000000..7a9be09c5ea --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.java @@ -0,0 +1,16 @@ +//file +import java.io.*; + +public class C { + int foo() { + try(InputStream stream = new FileInputStream("foo")) { + // reading something + int c = stream.read(); + return c; + } + catch (IOException e) { + System.out.println(e); + return -1; + } + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt new file mode 100644 index 00000000000..f9fdc00d481 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnAtEnd.kt @@ -0,0 +1,17 @@ +import java.io.* + +public class C() { + fun foo(): Int { + try { + return FileInputStream("foo").use { stream -> + // reading something + val c = stream.read() + c + } + } catch (e: IOException) { + System.out.println(e) + return -1 + } + + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java new file mode 100644 index 00000000000..9bc3f676075 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.java @@ -0,0 +1,23 @@ +//file +import java.io.*; + +interface I { + int doIt(InputStream stream) throws IOException; +} + +public class C { + void foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + bar(new I() { + @Override + public int doIt(InputStream stream) throws IOException { + return stream.available(); + } + }, stream); + } + } + + int bar(I i, InputStream stream) throws IOException { + return i.doIt(stream); + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt new file mode 100644 index 00000000000..326bf6b2abf --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass.kt @@ -0,0 +1,21 @@ +import java.io.* + +trait I { + public fun doIt(stream: InputStream): Int +} + +public class C() { + fun foo() { + FileInputStream("foo").use { stream -> + bar(object : I { + override fun doIt(stream: InputStream): Int { + return stream.available() + } + }, stream) + } + } + + fun bar(i: I, stream: InputStream): Int { + return i.doIt(stream) + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java new file mode 100644 index 00000000000..4f1e06a7f2a --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.java @@ -0,0 +1,23 @@ +//file +import java.io.*; + +interface I { + int doIt(InputStream stream) throws IOException; +} + +public class C { + int foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + return bar(new I() { + @Override + public int doIt(InputStream stream) throws IOException { + return stream.available(); + } + }, stream); + } + } + + int bar(I i, InputStream stream) throws IOException { + return i.doIt(stream); + } +} diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt new file mode 100644 index 00000000000..cbaf5dfeb4c --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass2.kt @@ -0,0 +1,21 @@ +import java.io.* + +trait I { + public fun doIt(stream: InputStream): Int +} + +public class C() { + fun foo(): Int { + return FileInputStream("foo").use { stream -> + bar(object : I { + override fun doIt(stream: InputStream): Int { + return stream.available() + } + }, stream) + } + } + + fun bar(i: I, stream: InputStream): Int { + return i.doIt(stream) + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo new file mode 100644 index 00000000000..1872fdbede8 --- /dev/null +++ b/j2k/tests/testData/ast/tryWithResource/WithReturnInAnonymousClass3.java.todo @@ -0,0 +1,26 @@ +//file +import java.io.*; + +interface I { + int doIt(InputStream stream) throws IOException; +} + +public class C { + int foo() throws IOException { + try(InputStream stream = new FileInputStream("foo")) { + if (stream.read() >= 0) { + return bar(new I() { + @Override + public int doIt(InputStream stream) throws IOException { + return stream.available(); + } + }, stream); + } + } + return -1; + } + + int bar(I i, InputStream stream) throws IOException { + return i.doIt(stream); + } +}