From 2d4d5e2a34287de7757b93df32142858c433acbf Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 9 Jun 2014 15:58:31 +0400 Subject: [PATCH] Java to Kotlin converter: added nullability calculation caching --- .../org/jetbrains/jet/j2k/TypeConverter.kt | 36 ++++++++++++++----- j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 13 +++---- .../jet/j2k/visitors/ExpressionVisitor.kt | 17 ++------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 75c6e6e9945..3b379e08f97 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -20,8 +20,11 @@ import org.jetbrains.jet.j2k.ast.Type import org.jetbrains.jet.j2k.ast.Nullability import com.intellij.psi.* import org.jetbrains.jet.j2k.visitors.TypeVisitor +import java.util.HashMap class TypeConverter(val settings: ConverterSettings) { + private val nullabilityCache = HashMap() + public fun convertType(`type`: PsiType?, nullability: Nullability = Nullability.Default): Type { if (`type` == null) return Type.Empty @@ -33,15 +36,21 @@ class TypeConverter(val settings: ConverterSettings) { } } - public fun convertTypes(types: Array): List { - return types.map { convertType(it) } - } + public fun convertTypes(types: Array): List + = types.map { convertType(it) } - public fun convertVariableType(variable: PsiVariable): Type { - return convertType(variable.getType(), variableNullability(variable)) - } + public fun convertVariableType(variable: PsiVariable): Type + = convertType(variable.getType(), variableNullability(variable)) public fun variableNullability(variable: PsiVariable): Nullability { + val cached = nullabilityCache[variable] + if (cached != null) return cached + val value = variableNullabilityNoCache(variable) + nullabilityCache[variable] = value + return value + } + + private fun variableNullabilityNoCache(variable: PsiVariable): Nullability { if (variable is PsiEnumConstant) return Nullability.NotNull var nullability = variable.nullabilityFromAnnotations() @@ -91,7 +100,18 @@ class TypeConverter(val settings: ConverterSettings) { return nullability } - public fun convertMethodReturnType(method: PsiMethod): Type { + public fun convertMethodReturnType(method: PsiMethod): Type + = convertType(method.getReturnType(), methodNullability(method)) + + public fun methodNullability(method: PsiMethod): Nullability { + val cached = nullabilityCache[method] + if (cached != null) return cached + val value = methodNullabilityNoCache(method) + nullabilityCache[method] = value + return value + } + + private fun methodNullabilityNoCache(method: PsiMethod): Nullability { var nullability = method.nullabilityFromAnnotations() if (nullability == Nullability.Default) { @@ -117,7 +137,7 @@ class TypeConverter(val settings: ConverterSettings) { } } - return convertType(method.getReturnType(), nullability) + return nullability } private fun searchScope(element: PsiElement): PsiElement? { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 04ef39e0ba6..122b3b90e7a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -16,7 +16,6 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.Converter import java.util.ArrayList import org.jetbrains.jet.j2k.ConverterSettings @@ -29,12 +28,14 @@ enum class Nullability { Default } +fun Nullability.isNullable(settings: ConverterSettings) = when(this) { + Nullability.Nullable -> true + Nullability.NotNull -> false + Nullability.Default -> !settings.forceNotNullTypes +} + abstract class MayBeNullableType(nullability: Nullability, val settings: ConverterSettings) : Type { - override val isNullable: Boolean = when (nullability) { - Nullability.Nullable -> true - Nullability.NotNull -> false - Nullability.Default -> !settings.forceNotNullTypes - } + override val isNullable: Boolean = nullability.isNullable(settings) } trait NotNullType : Type { diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 0bc0680800e..7d6e8358dc2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -34,7 +34,6 @@ import org.jetbrains.jet.lang.psi.psiUtil.isExtensionDeclaration import org.jetbrains.jet.lang.psi.JetPropertyAccessor import com.intellij.psi.impl.light.LightField import org.jetbrains.jet.lang.resolve.java.JvmAbi -import org.jetbrains.jet.lang.psi.JetNullableType class ExpressionVisitor(private val converter: Converter, private val typeConverter: TypeConverter, @@ -153,7 +152,7 @@ class ExpressionVisitor(private val converter: Converter, val methodExpr = expression.getMethodExpression() val arguments = expression.getArgumentList().getExpressions() val target = methodExpr.resolve() - val isNullable = if (target is PsiMethod) typeConverter.convertMethodReturnType(target).isNullable else false + val isNullable = if (target is PsiMethod) typeConverter.methodNullability(target).isNullable(converter.settings) else false val typeArguments = typeConverter.convertTypes(expression.getTypeArguments()) if (target is KotlinLightMethod) { @@ -295,7 +294,8 @@ class ExpressionVisitor(private val converter: Converter, } override fun visitReferenceExpression(expression: PsiReferenceExpression) { - val isNullable = typeConverter.convertType(expression.getType(), expression.nullability()).isNullable + val target = expression.getReference()?.resolve() + val isNullable = if (target is PsiVariable) typeConverter.variableNullability(target).isNullable(converter.settings) else false val referencedName = expression.getReferenceName()!! var identifier: Expression = Identifier(referencedName, isNullable) val qualifier = expression.getQualifierExpression() @@ -314,7 +314,6 @@ class ExpressionVisitor(private val converter: Converter, } else if (qualifier != null) { if (referencedName == JvmAbi.CLASS_OBJECT_FIELD || referencedName == JvmAbi.INSTANCE_FIELD) { - val target = expression.getReference()?.resolve() if (target is LightField) { //TODO: should be KotlinLightField with check of origin here, see KT-5188 result = converter.convertExpression(qualifier) return @@ -322,8 +321,6 @@ class ExpressionVisitor(private val converter: Converter, } } else { - val target = expression.getReference()?.resolve() - if (target is PsiClass) { if (PrimitiveType.values() any { it.getTypeName().asString() == target.getName() }) { result = Identifier(target.getQualifiedName()!!, false) @@ -358,14 +355,6 @@ class ExpressionVisitor(private val converter: Converter, result = QualifiedExpression(converter.convertExpression(qualifier), identifier) } - private fun PsiReference.nullability(): Nullability { - val target = resolve() - return when(target) { - is PsiVariable -> typeConverter.variableNullability(target) - else -> Nullability.Default - } - } - override fun visitSuperExpression(expression: PsiSuperExpression) { val qualifier = expression.getQualifier() result = SuperExpression(if (qualifier != null) Identifier(qualifier.getQualifiedName()!!) else Identifier.Empty)