From db8beab4996d520bf8219ce0a31965dbec21db9e Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 19 Dec 2018 15:48:57 +0300 Subject: [PATCH] New J2K: Fix NPE in a case of unresolved symbols --- .../org/jetbrains/kotlin/j2k/expressions.kt | 52 ++++++++++++------- .../org/jetbrains/kotlin/j2k/tree/types.kt | 21 +++++--- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt index fcf5709202d..ffe5c6d1902 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.j2k +import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.j2k.ast.Nullability @@ -42,36 +43,50 @@ private fun JKKtOperatorToken.binaryExpressionMethodSymbol( rightType: JKType, symbolProvider: JKSymbolProvider ): JKMethodSymbol { - val operatorNames = - if (operatorName == "equals") listOf("equals", "compareTo") - else listOf(operatorName) - fun PsiClass.methodSymbol() = allMethods - .filter { it.name in operatorNames } + .filter { it.name == operatorName } .firstOrNull { - it.parameterList.parameters.singleOrNull()?.takeIf { - rightType.isSubtypeOf( - it.type.toJK(symbolProvider), - symbolProvider - ) + it.parameterList.parameters.singleOrNull()?.takeIf { parameter -> + val type = parameter.type.toJK(symbolProvider) + if (type !is JKTypeParameterType) rightType.isSubtypeOf(type, symbolProvider) + else true//TODO check for type bounds } != null }?.let { symbolProvider.provideDirectSymbol(it) as JKMethodSymbol } - val classSymbol = leftType.classSymbol(symbolProvider) + val classSymbol = + if (leftType.isStringType()) symbolProvider.provideByFqName(KotlinBuiltIns.FQ_NAMES.string.toSafe()) + else leftType.classSymbol(symbolProvider) + + + val defaultClassSymbol by lazy { + when (text) { + "<", ">", "<=", ">=", "==", "!=", "&&", "||" -> + JKUnresolvedMethod( + text, + kotlinTypeByName( + KotlinBuiltIns.FQ_NAMES._boolean.toSafe().asString(), + symbolProvider, + Nullability.NotNull + ) + ) + "+", "-", "*", "/" -> JKUnresolvedMethod(text, leftType)//TODO fix that + else -> TODO() + } + } return when (classSymbol) { is JKMultiverseKtClassSymbol -> classSymbol.target.declarations .asSequence() .filterIsInstance() - .filter { it.name in operatorNames } + .filter { it.name == operatorName } .mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol } - .firstOrNull { it.parameterTypes.singleOrNull()?.takeIf { rightType.isSubtypeOf(it, symbolProvider) } != null }!! - is JKUniverseClassSymbol -> classSymbol.target.psi()?.methodSymbol()!! - is JKMultiverseClassSymbol -> classSymbol.target.methodSymbol()!! - - else -> TODO(classSymbol::class.toString()) + .firstOrNull { it.parameterTypes.singleOrNull()?.takeIf { rightType.isSubtypeOf(it, symbolProvider) } != null } + ?: defaultClassSymbol + is JKUniverseClassSymbol -> classSymbol.target.psi()?.methodSymbol() ?: defaultClassSymbol + is JKMultiverseClassSymbol -> classSymbol.target.methodSymbol() ?: defaultClassSymbol + else -> defaultClassSymbol } } @@ -124,8 +139,6 @@ fun kotlinPostfixExpression( return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol)) } - - fun untilToExpression( from: JKExpression, to: JKExpression, @@ -207,6 +220,7 @@ fun kotlinAssert(assertion: JKExpression, message: JKExpression?, symbolProvider ), JKExpressionListImpl(listOfNotNull(assertion, message)) ) + fun jvmAnnotation(name: String, symbolProvider: JKSymbolProvider) = JKAnnotationImpl( symbolProvider.provideByFqName("kotlin.annotation.AnnotationTarget.$name") diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt index 9052255e075..87bdea3c131 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt @@ -46,6 +46,8 @@ fun JKExpression.type(context: ConversionContext): JKType? = is JKJavaInstanceOfExpression -> kotlinTypeByName(KotlinBuiltIns.FQ_NAMES._boolean.asString(), context.symbolProvider) is JKParenthesizedExpression -> expression.type(context) is JKTypeCastExpression -> type.type + is JKThisExpression -> null// TODO return actual type + is JKSuperExpression -> null// TODO return actual type else -> TODO(this::class.java.toString()) } @@ -101,7 +103,9 @@ fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nu } fun JKType.isSubtypeOf(other: JKType, symbolProvider: JKSymbolProvider): Boolean = - toKtType(symbolProvider).isSubtypeOf(other.toKtType(symbolProvider)) + other.toKtType(symbolProvider) + ?.let { otherType -> this.toKtType(symbolProvider)?.isSubtypeOf(otherType) } == true + fun KtTypeElement.toJK(symbolProvider: JKSymbolProvider): JKType = when (this) { @@ -119,31 +123,32 @@ fun KtTypeElement.toJK(symbolProvider: JKSymbolProvider): JKType = else -> TODO(this::class.java.toString()) } -fun JKType.toKtType(symbolProvider: JKSymbolProvider): KotlinType = +fun JKType.toKtType(symbolProvider: JKSymbolProvider): KotlinType? = when (this) { - is JKClassType -> classReference!!.toKtType(symbolProvider) + is JKClassType -> classReference.toKtType() is JKJavaPrimitiveType -> kotlinTypeByName( jvmPrimitiveType.primitiveType.typeFqName.asString(), symbolProvider ).toKtType(symbolProvider) - else -> TODO(this::class.java.toString()) + else -> null +// else -> TODO(this::class.java.toString()) } -fun JKClassSymbol.toKtType(symbolProvider: JKSymbolProvider): KotlinType { +fun JKClassSymbol.toKtType(): KotlinType? { val classDescriptor = when (this) { is JKMultiverseKtClassSymbol -> { val bindingContext = target.analyze() bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, target] as ClassDescriptor } is JKMultiverseClassSymbol -> - target.getJavaClassDescriptor()!! + target.getJavaClassDescriptor() is JKUniverseClassSymbol -> - target.psi()?.getJavaClassDescriptor()!! + target.psi()?.getJavaClassDescriptor()//TODO null in case of a fake package else -> TODO(this::class.java.toString()) } - return classDescriptor.defaultType + return classDescriptor?.defaultType } inline fun T.updateNullability(newNullability: Nullability): T =