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
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<KtNamedFunction>()
.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<PsiClass>()?.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<PsiClass>()?.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")
@@ -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<PsiClass>()?.getJavaClassDescriptor()!!
target.psi<PsiClass>()?.getJavaClassDescriptor()//TODO null in case of a fake package
else -> TODO(this::class.java.toString())
}
return classDescriptor.defaultType
return classDescriptor?.defaultType
}
inline fun <reified T : JKType> T.updateNullability(newNullability: Nullability): T =