Java to Kotlin converter: converting usages of Kotlin properties from Java

This commit is contained in:
Valentin Kipyatkov
2014-06-04 20:33:00 +04:00
parent 81caaaf579
commit f343b89501
12 changed files with 113 additions and 18 deletions
+1
View File
@@ -11,6 +11,7 @@
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="descriptor.loader.java" />
<orderEntry type="library" name="idea-full" level="project" />
<orderEntry type="module" module-name="frontend.java" />
</component>
</module>
+3 -3
View File
@@ -160,7 +160,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
var keepStatement = true
if (statement is AssignmentExpression) {
val assignee = statement.left
if (assignee is CallChainExpression) {
if (assignee is QualifiedExpression) {
for (field in finalOrWithEmptyInitializerFields) {
val id = field.identifier.toKotlin()
if (assignee.identifier.toKotlin().endsWith("." + id)) {
@@ -600,8 +600,8 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
private fun convertToNotNullableTypes(types: Array<out PsiType?>): List<Type>
= types.map { convertType(it, Nullability.NotNull) }
public fun convertParameterList(parameters: PsiParameterList): ParameterList
= ParameterList(parameters.getParameters().map { convertParameter(it) })
public fun convertParameterList(parameterList: PsiParameterList): ParameterList
= ParameterList(parameterList.getParameters().map { convertParameter(it) })
public fun convertParameter(parameter: PsiParameter,
nullability: Nullability = Nullability.Default,
@@ -36,7 +36,7 @@ open class MethodCallExpression(
class object {
fun build(receiver: Expression, methodName: String, arguments: List<Expression> = ArrayList()): MethodCallExpression {
return MethodCallExpression(CallChainExpression(receiver, Identifier(methodName, false)),
return MethodCallExpression(QualifiedExpression(receiver, Identifier(methodName, false)),
arguments,
ArrayList(), false)
}
@@ -16,7 +16,7 @@
package org.jetbrains.jet.j2k.ast
class CallChainExpression(val expression: Expression, val identifier: Expression) : Expression() {
class QualifiedExpression(val expression: Expression, val identifier: Expression) : Expression() {
override val isNullable: Boolean
get() {
if (!expression.isEmpty && expression.isNullable) return true
@@ -25,6 +25,8 @@ import com.intellij.psi.CommonClassNames.*
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.jet.lang.types.lang.PrimitiveType
import org.jetbrains.jet.j2k.*
import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod
import org.jetbrains.jet.lang.psi.JetProperty
open class ExpressionVisitor(protected val converter: Converter,
private val usageReplacementMap: Map<PsiVariable, String> = mapOf()) : JavaElementVisitor() {
@@ -75,8 +77,7 @@ open class ExpressionVisitor(protected val converter: Converter,
result = MethodCallExpression.build(lhs, "ushr", listOf(rhs))
}
else {
result = BinaryExpression(lhs, rhs,
getOperatorString(expression.getOperationSign().getTokenType()))
result = BinaryExpression(lhs, rhs, getOperatorString(expression.getOperationSign().getTokenType()))
}
}
@@ -137,15 +138,38 @@ open class ExpressionVisitor(protected val converter: Converter,
}
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
convertMethodCallExpression(expression)
}
val methodExpr = expression.getMethodExpression()
val target = methodExpr.resolve()
if (target is KotlinLightMethod) {
val property = target.origin as? JetProperty
if (property != null) {
val parameterCount = target.getParameterList().getParameters().size
val argCount = expression.getArgumentList().getExpressions().size
if (parameterCount == argCount) {
val qualifier = converter.convertExpression(methodExpr.getQualifierExpression())
val propertyName = Identifier(property.getName()!!, false)
val propertyAccess = QualifiedExpression(qualifier, propertyName)
when(parameterCount) {
0 /* getter */ -> {
result = propertyAccess
return
}
1 /* setter */ -> {
val argument = converter.convertExpression(expression.getArgumentList().getExpressions().single())
result = AssignmentExpression(propertyAccess, argument, "=")
return
}
}
}
}
}
protected fun convertMethodCallExpression(expression: PsiMethodCallExpression) {
if (!expression.isSuperConstructorCall() || !expression.isInsidePrimaryConstructor()) {
result = MethodCallExpression(converter.convertExpression(expression.getMethodExpression()),
converter.convertArguments(expression),
converter.convertTypes(expression.getTypeArguments()),
converter.convertType(expression.getType()).isNullable)
result = MethodCallExpression(converter.convertExpression(methodExpr),
converter.convertArguments(expression),
converter.convertTypes(expression.getTypeArguments()),
converter.convertType(expression.getType()).isNullable)
}
}
@@ -177,7 +201,7 @@ open class ExpressionVisitor(protected val converter: Converter,
val reference = expression.getClassReference()
val typeParameters = if (reference != null) converter.convertTypes(reference.getTypeParameters()) else listOf()
return CallChainExpression(Identifier(constructor.getName(), false),
return QualifiedExpression(Identifier(constructor.getName(), false),
MethodCallExpression(Identifier("init"), converter.convertExpressions(arguments), typeParameters, false))
}
@@ -222,7 +246,7 @@ open class ExpressionVisitor(protected val converter: Converter,
val qualifier = expression.getQualifierExpression()
if (addReceiver) {
identifier = CallChainExpression(Identifier("__", false), Identifier(referencedName, isNullable))
identifier = QualifiedExpression(Identifier("__", false), Identifier(referencedName, isNullable))
}
else if (insideSecondaryConstructor && expression.isThisConstructorCall()) {
identifier = Identifier("val __ = " + (containingConstructor?.getContainingClass()?.getNameIdentifier()?.getText() ?: ""))
@@ -263,7 +287,7 @@ open class ExpressionVisitor(protected val converter: Converter,
}
}
result = CallChainExpression(converter.convertExpression(qualifier), identifier)
result = QualifiedExpression(converter.convertExpression(qualifier), identifier)
}
private fun PsiReference.nullability(): Nullability {
@@ -32,10 +32,22 @@ import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.jet.JetTestUtils
import com.intellij.openapi.project.Project
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.application.ApplicationManager
abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() {
val testHeaderPattern = Pattern.compile("//(element|expression|statement|method|class|file|comp)\n")
override fun setUp() {
super.setUp()
ApplicationManager.getApplication()!!.runWriteAction{
val kotlinApiFileName = "KotlinApi.kt"
val kotlinCode = FileUtil.loadFile(File("j2k/tests/testData/$kotlinApiFileName"), true)
val kotlinFile = LightPlatformTestCase.getSourceRoot()!!.createChildData(null, kotlinApiFileName)!!
kotlinFile.getOutputStream(null)!!.writer().use { it.write(kotlinCode) }
}
}
public fun doTest(javaPath: String) {
val project = LightPlatformTestCase.getProject()!!
val javaFile = File(javaPath)
@@ -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.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.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.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})
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);
@@ -1550,6 +1550,24 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
}
@TestMetadata("j2k/tests/testData/ast/kotlinApiAccess")
public static class KotlinApiAccess extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInKotlinApiAccess() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/kotlinApiAccess"), Pattern.compile("^(.+)\\.java$"), true);
}
@TestMetadata("InheritedProperty.java")
public void testInheritedProperty() throws Exception {
doTest("j2k/tests/testData/ast/kotlinApiAccess/InheritedProperty.java");
}
@TestMetadata("Property.java")
public void testProperty() throws Exception {
doTest("j2k/tests/testData/ast/kotlinApiAccess/Property.java");
}
}
@TestMetadata("j2k/tests/testData/ast/kotlinExclusion")
public static class KotlinExclusion extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInKotlinExclusion() throws Exception {
@@ -2497,6 +2515,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
suite.addTestSuite(Inheritance.class);
suite.addTestSuite(IsOperator.class);
suite.addTestSuite(Issues.class);
suite.addTestSuite(KotlinApiAccess.class);
suite.addTestSuite(KotlinExclusion.class);
suite.addTestSuite(LabelStatement.class);
suite.addTestSuite(List.class);
+5
View File
@@ -0,0 +1,5 @@
package kotlinApi
public open class KotlinClass {
public var property: String
}
@@ -0,0 +1,9 @@
//file
import kotlinApi.*
class C extends KotlinClass {
void foo() {
System.out.println(getProperty());
setProperty("a")
}
}
@@ -0,0 +1,8 @@
import kotlinApi.*
class C() : KotlinClass() {
fun foo() {
System.out.println(property)
property = "a"
}
}
@@ -0,0 +1,9 @@
//file
import kotlinApi.*
class C {
void foo(KotlinClass k) {
System.out.println(k.getProperty());
k.setProperty("a")
}
}
@@ -0,0 +1,8 @@
import kotlinApi.*
class C() {
fun foo(k: KotlinClass) {
System.out.println(k.property)
k.property = "a"
}
}