New J2K: Fix NPE in a case of unresolved symbols
This commit is contained in:
committed by
Ilya Kirillov
parent
410000f94c
commit
db8beab499
@@ -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 =
|
||||||
|
|||||||
Reference in New Issue
Block a user