New J2K: Fix NPE in a case of unresolved symbols

This commit is contained in:
Ilya Kirillov
2018-12-19 15:48:57 +03:00
committed by Ilya Kirillov
parent 410000f94c
commit db8beab499
2 changed files with 46 additions and 27 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.j2k package org.jetbrains.kotlin.j2k
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.j2k.ast.Nullability import org.jetbrains.kotlin.j2k.ast.Nullability
@@ -42,36 +43,50 @@ private fun JKKtOperatorToken.binaryExpressionMethodSymbol(
rightType: JKType, rightType: JKType,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKMethodSymbol { ): JKMethodSymbol {
val operatorNames =
if (operatorName == "equals") listOf("equals", "compareTo")
else listOf(operatorName)
fun PsiClass.methodSymbol() = fun PsiClass.methodSymbol() =
allMethods allMethods
.filter { it.name in operatorNames } .filter { it.name == operatorName }
.firstOrNull { .firstOrNull {
it.parameterList.parameters.singleOrNull()?.takeIf { it.parameterList.parameters.singleOrNull()?.takeIf { parameter ->
rightType.isSubtypeOf( val type = parameter.type.toJK(symbolProvider)
it.type.toJK(symbolProvider), if (type !is JKTypeParameterType) rightType.isSubtypeOf(type, symbolProvider)
symbolProvider else true//TODO check for type bounds
)
} != null } != null
}?.let { symbolProvider.provideDirectSymbol(it) as JKMethodSymbol } }?.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) { return when (classSymbol) {
is JKMultiverseKtClassSymbol -> is JKMultiverseKtClassSymbol ->
classSymbol.target.declarations classSymbol.target.declarations
.asSequence() .asSequence()
.filterIsInstance<KtNamedFunction>() .filterIsInstance<KtNamedFunction>()
.filter { it.name in operatorNames } .filter { it.name == operatorName }
.mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol } .mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol }
.firstOrNull { it.parameterTypes.singleOrNull()?.takeIf { rightType.isSubtypeOf(it, symbolProvider) } != null }!! .firstOrNull { it.parameterTypes.singleOrNull()?.takeIf { rightType.isSubtypeOf(it, symbolProvider) } != null }
is JKUniverseClassSymbol -> classSymbol.target.psi<PsiClass>()?.methodSymbol()!! ?: defaultClassSymbol
is JKMultiverseClassSymbol -> classSymbol.target.methodSymbol()!! is JKUniverseClassSymbol -> classSymbol.target.psi<PsiClass>()?.methodSymbol() ?: defaultClassSymbol
is JKMultiverseClassSymbol -> classSymbol.target.methodSymbol() ?: defaultClassSymbol
else -> TODO(classSymbol::class.toString()) else -> defaultClassSymbol
} }
} }
@@ -124,8 +139,6 @@ fun kotlinPostfixExpression(
return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol)) return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol))
} }
fun untilToExpression( fun untilToExpression(
from: JKExpression, from: JKExpression,
to: JKExpression, to: JKExpression,
@@ -207,6 +220,7 @@ fun kotlinAssert(assertion: JKExpression, message: JKExpression?, symbolProvider
), ),
JKExpressionListImpl(listOfNotNull(assertion, message)) JKExpressionListImpl(listOfNotNull(assertion, message))
) )
fun jvmAnnotation(name: String, symbolProvider: JKSymbolProvider) = fun jvmAnnotation(name: String, symbolProvider: JKSymbolProvider) =
JKAnnotationImpl( JKAnnotationImpl(
symbolProvider.provideByFqName("kotlin.annotation.AnnotationTarget.$name") symbolProvider.provideByFqName("kotlin.annotation.AnnotationTarget.$name")
@@ -46,6 +46,8 @@ fun JKExpression.type(context: ConversionContext): JKType? =
is JKJavaInstanceOfExpression -> kotlinTypeByName(KotlinBuiltIns.FQ_NAMES._boolean.asString(), context.symbolProvider) is JKJavaInstanceOfExpression -> kotlinTypeByName(KotlinBuiltIns.FQ_NAMES._boolean.asString(), context.symbolProvider)
is JKParenthesizedExpression -> expression.type(context) is JKParenthesizedExpression -> expression.type(context)
is JKTypeCastExpression -> type.type is JKTypeCastExpression -> type.type
is JKThisExpression -> null// TODO return actual type
is JKSuperExpression -> null// TODO return actual type
else -> TODO(this::class.java.toString()) 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 = 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 = fun KtTypeElement.toJK(symbolProvider: JKSymbolProvider): JKType =
when (this) { when (this) {
@@ -119,31 +123,32 @@ fun KtTypeElement.toJK(symbolProvider: JKSymbolProvider): JKType =
else -> TODO(this::class.java.toString()) else -> TODO(this::class.java.toString())
} }
fun JKType.toKtType(symbolProvider: JKSymbolProvider): KotlinType = fun JKType.toKtType(symbolProvider: JKSymbolProvider): KotlinType? =
when (this) { when (this) {
is JKClassType -> classReference!!.toKtType(symbolProvider) is JKClassType -> classReference.toKtType()
is JKJavaPrimitiveType -> is JKJavaPrimitiveType ->
kotlinTypeByName( kotlinTypeByName(
jvmPrimitiveType.primitiveType.typeFqName.asString(), jvmPrimitiveType.primitiveType.typeFqName.asString(),
symbolProvider symbolProvider
).toKtType(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) { val classDescriptor = when (this) {
is JKMultiverseKtClassSymbol -> { is JKMultiverseKtClassSymbol -> {
val bindingContext = target.analyze() val bindingContext = target.analyze()
bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, target] as ClassDescriptor bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, target] as ClassDescriptor
} }
is JKMultiverseClassSymbol -> is JKMultiverseClassSymbol ->
target.getJavaClassDescriptor()!! target.getJavaClassDescriptor()
is JKUniverseClassSymbol -> is JKUniverseClassSymbol ->
target.psi<PsiClass>()?.getJavaClassDescriptor()!! target.psi<PsiClass>()?.getJavaClassDescriptor()//TODO null in case of a fake package
else -> TODO(this::class.java.toString()) else -> TODO(this::class.java.toString())
} }
return classDescriptor.defaultType return classDescriptor?.defaultType
} }
inline fun <reified T : JKType> T.updateNullability(newNullability: Nullability): T = inline fun <reified T : JKType> T.updateNullability(newNullability: Nullability): T =