New J2K: Use returnType instead of methodSymbol in operator expressions

This commit is contained in:
Ilya Kirillov
2019-01-17 14:43:40 +03:00
committed by Ilya Kirillov
parent a92c5ebe61
commit 8aa28c0d50
11 changed files with 208 additions and 95 deletions
@@ -33,6 +33,7 @@ object ConversionsRunner {
+AssignmentStatementOperatorConversion()
+AssignmentStatementSimplifyValConversion()
+AssignmentStatementSimplifyAlsoConversion()
+PolyadicExpressionConversion(context)
+OperatorExpressionConversion(context)
+ThrowStatementConversion()
+EnumClassConversion()
@@ -52,7 +53,6 @@ object ConversionsRunner {
+JavaMethodToKotlinFunctionConversion(context)
+MainFunctionConversion(context)
+AssertStatementConversion(context)
+PolyadicExpressionConversion(context)
+SwitchStatementConversion(context)
+LiteralConversion()
+ForConversion(context)
@@ -23,6 +23,7 @@ import com.intellij.psi.JavaTokenType.THIS_KEYWORD
import com.intellij.psi.impl.source.tree.ChildRole
import com.intellij.psi.impl.source.tree.java.*
import com.intellij.psi.javadoc.PsiDocComment
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.InheritanceUtil
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
@@ -32,6 +33,8 @@ import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.JKLiteralExpression.LiteralType.*
import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
@@ -99,7 +102,7 @@ class JavaToJKTreeBuilder(
)
is PsiPolyadicExpression -> JKJavaPolyadicExpressionImpl(
operands.map { it.toJK() },
Array(operands.lastIndex) { getTokenBeforeOperand(operands[it + 1]) }.map { it?.toJK() ?: TODO() }
Array(operands.lastIndex) { getTokenBeforeOperand(operands[it + 1]) }.map { it?.tokenType?.toJK() ?: TODO() }
)
is PsiArrayInitializerExpression -> toJK()
is PsiLambdaExpression -> toJK()
@@ -132,12 +135,21 @@ class JavaToJKTreeBuilder(
return JKJavaAssignmentExpressionImpl(
lExpression.toJK() as? JKAssignableExpression ?: error("Its possible? ${lExpression.toJK().prettyDebugPrintTree()}"),
rExpression.toJK(),
operationSign.toJK()
operationSign.tokenType.toJK()
)
}
fun PsiBinaryExpression.toJK(): JKExpression {
return JKBinaryExpressionImpl(lOperand.toJK(), rOperand.toJK(), operationSign.toJK())
val token = when (operationSign.tokenType) {
JavaTokenType.EQEQ, JavaTokenType.NE ->
when {
canKeepEqEq(lOperand, rOperand) -> operationSign.tokenType
operationSign.tokenType == JavaTokenType.EQEQ -> KtTokens.EQEQEQ
else -> KtTokens.EXCLEQEQEQ
}
else -> operationSign.tokenType
}
return JKBinaryExpressionImpl(lOperand.toJK(), rOperand.toJK(), token.toJK())
}
fun PsiLiteralExpression.toJK(): JKLiteralExpression {
@@ -157,10 +169,10 @@ class JavaToJKTreeBuilder(
}
}
fun PsiJavaToken.toJK(): JKOperator = JKJavaOperatorImpl.tokenToOperator[tokenType] ?: error("Unsupported token-type: $tokenType")
fun IElementType.toJK(): JKOperator = JKJavaOperatorImpl.tokenToOperator[this] ?: error("Unsupported token-type: $this")
fun PsiPrefixExpression.toJK(): JKExpression {
return JKPrefixExpressionImpl(operand.toJK(), operationSign.toJK()).let {
return JKPrefixExpressionImpl(operand.toJK(), operationSign.tokenType.toJK()).let {
if (it.operator.token.text in listOf("+", "-") && it.expression is JKLiteralExpression) {
JKJavaLiteralExpressionImpl(
it.operator.token.text + (it.expression as JKLiteralExpression).literal,
@@ -171,7 +183,7 @@ class JavaToJKTreeBuilder(
}
fun PsiPostfixExpression.toJK(): JKExpression {
return JKPostfixExpressionImpl(operand.toJK(), operationSign.toJK())
return JKPostfixExpressionImpl(operand.toJK(), operationSign.tokenType.toJK())
}
fun PsiLambdaExpression.toJK(): JKExpression {
@@ -5,13 +5,10 @@
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.kotlinBinaryExpression
import org.jetbrains.kotlin.j2k.kotlinPostfixExpression
import org.jetbrains.kotlin.j2k.kotlinPrefixExpression
import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.JKJavaOperatorImpl
import org.jetbrains.kotlin.j2k.tree.impl.toKtToken
import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.lexer.KtTokens
class OperatorExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
@@ -24,17 +21,37 @@ class OperatorExpressionConversion(private val context: ConversionContext) : Rec
is JKBinaryExpression -> {
val left = applyToElement(element::left.detached()) as JKExpression
val right = applyToElement(element::right.detached()) as JKExpression
kotlinBinaryExpression(left, right, operatorToken, context.symbolProvider)?.let { recurse(it) }
recurse(convertBinaryExpression(left, right, operatorToken))
}
is JKPrefixExpression -> {
val operand = applyToElement(element::expression.detached()) as JKExpression
kotlinPrefixExpression(operand, operatorToken, context.symbolProvider)?.let { recurse(it) }
recurse(kotlinPrefixExpression(operand, operatorToken, context.symbolProvider))
}
is JKPostfixExpression -> {
val operand = applyToElement(element::expression.detached()) as JKExpression
kotlinPostfixExpression(operand, operatorToken, context.symbolProvider)?.let { recurse(it) }
recurse(kotlinPostfixExpression(operand, operatorToken, context.symbolProvider))
}
else -> TODO(element.javaClass.toString())
} ?: recurse(element)
}
private fun convertBinaryExpression(left: JKExpression, right: JKExpression, token: JKKtOperatorToken): JKBinaryExpression =
convertStringImplicitConcatenation(left, right, token)
?: kotlinBinaryExpression(left, right, token, context.symbolProvider)
private fun convertStringImplicitConcatenation(left: JKExpression, right: JKExpression, token: JKKtOperatorToken): JKBinaryExpression? =
if (token is JKKtSingleValueOperatorToken
&& token.psiToken == KtTokens.PLUS
&& right.type(context.symbolProvider)?.isStringType() == true
&& left.type(context.symbolProvider)?.isStringType() == false
) {
val toStringCall =
JKKtCallExpressionImpl(
context.symbolProvider.provideByFqName("kotlin.Any.toString"),
JKExpressionListImpl()
)
val qualifiedCall = JKQualifiedExpressionImpl(left, JKKtQualifierImpl.DOT, toStringCall)
kotlinBinaryExpression(qualifiedCall, right, KtTokens.PLUS, context.symbolProvider)
} else null
}
@@ -7,21 +7,20 @@ package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.kotlinBinaryExpression
import org.jetbrains.kotlin.j2k.tree.JKExpression
import org.jetbrains.kotlin.j2k.tree.JKJavaPolyadicExpression
import org.jetbrains.kotlin.j2k.tree.JKOperator
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.*
class PolyadicExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
return (if (element is JKJavaPolyadicExpression)
convertPolyadic(element.operands.also { element.operands = emptyList() }, element.tokens)
else
element).also {
recurse(it)
}
return recurse(
if (element is JKJavaPolyadicExpression)
convertPolyadic(
element.operands.also { element.operands = emptyList() },
element.tokens
)
else element
)
}
private fun convertPolyadic(operands: List<JKExpression>, operators: List<JKOperator>): JKExpression {
@@ -29,16 +28,15 @@ class PolyadicExpressionConversion(private val context: ConversionContext) : Rec
operands.first()
else {
val operator = operators.maxBy { it.precedence }
val token =
when (operator) {
is JKJavaOperatorImpl -> operator.token.toKtToken()
is JKKtOperatorImpl -> operator.token
else -> error("operator should be either kotlin or java")
}
when (operator) {
is JKJavaOperatorImpl -> operator.token.toKtToken()
is JKKtOperatorImpl -> operator.token
else -> error("operator should be either kotlin or java")
}
val index = operators.indexOf(operator)
val left = convertPolyadic(operands.subList(0, index + 1), operators.subList(0, index))
val right = convertPolyadic(operands.subList(index + 1, operands.size), operators.subList(index + 1, operators.size))
kotlinBinaryExpression(left, right, token, context.symbolProvider)!!
JKBinaryExpressionImpl(left, right, operator)
}
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.j2k
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.j2k.conversions.RecursiveApplicableConversionBase
@@ -14,6 +15,7 @@ import org.jetbrains.kotlin.j2k.conversions.multiResolveFqName
import org.jetbrains.kotlin.j2k.conversions.resolveFqName
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -42,12 +44,12 @@ private fun JKType.classSymbol(symbolProvider: JKSymbolProvider) =
else -> null
}
private fun JKKtOperatorToken.binaryExpressionMethodSymbol(
private fun JKKtOperatorToken.arithmeticMethodType(
leftType: JKType,
rightType: JKType,
symbolProvider: JKSymbolProvider
): JKMethodSymbol {
fun PsiClass.methodSymbol() =
): JKType? {
fun PsiClass.methodReturnType() =
allMethods
.filter { it.name == operatorName }
.firstOrNull {
@@ -56,28 +58,13 @@ private fun JKKtOperatorToken.binaryExpressionMethodSymbol(
if (type !is JKTypeParameterType) rightType.isSubtypeOf(type, symbolProvider)
else true//TODO check for type bounds
} != null
}?.let { symbolProvider.provideDirectSymbol(it) as JKMethodSymbol }
}?.let { it.returnType?.toJK(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
@@ -86,53 +73,112 @@ private fun JKKtOperatorToken.binaryExpressionMethodSymbol(
.filter { it.name == operatorName }
.mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol }
.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
?.returnType
is JKUniverseClassSymbol -> classSymbol.target.psi<PsiClass>()?.methodReturnType()
is JKMultiverseClassSymbol -> classSymbol.target.methodReturnType()
else -> null
}
}
private fun JKKtOperatorToken.unaryExpressionMethodSymbol(
operandType: JKType,
private fun JKKtOperatorToken.unaryExpressionMethodType(
operandType: JKType?,
symbolProvider: JKSymbolProvider
): JKMethodSymbol {
if (this == KtTokens.EXCLEQ) {
return JKExclExclMethod(operandType)
): JKType {
if (operandType is JKNoType) {
return operandType
}
val classSymbol = operandType.classSymbol(symbolProvider)
if (this == KtTokens.EXCLEXCL) {
return operandType!!
}
if (this == KtTokens.EXCL) {
return symbolProvider.provideByFqName<JKClassSymbol>(KotlinBuiltIns.FQ_NAMES._boolean).asType()
}
if (this == KtTokens.MINUS || this == KtTokens.PLUS) {
return operandType!!
}
val classSymbol = operandType!!.classSymbol(symbolProvider)
return when (classSymbol) {
is JKMultiverseKtClassSymbol ->// todo look for extensions
classSymbol.target.declarations.asSequence()
.filterIsInstance<KtNamedFunction>()
.filter { it.name == operatorName }
.mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol }
.firstOrNull()!!
.mapNotNull { it.typeReference?.typeElement?.toJK(symbolProvider) }
.firstOrNull() ?: TODO(classSymbol::class.toString() + this.operatorName)
null -> TODO(" No class symbol")
else -> TODO(classSymbol::class.toString())
}
}
private val booleanOperators = TokenSet.create(
KtTokens.LT,
KtTokens.GT,
KtTokens.LTEQ,
KtTokens.GTEQ,
KtTokens.EQEQEQ,
KtTokens.EXCLEQEQEQ,
KtTokens.EQEQ,
KtTokens.EXCLEQ,
KtTokens.ANDAND,
KtTokens.OROR
)
private val arithmeticOperators = TokenSet.create(
KtTokens.MUL,
KtTokens.PLUS,
KtTokens.MINUS,
KtTokens.DIV,
KtTokens.PERC
)
private fun JKKtOperatorToken.defaultReturnType(leftType: JKType?, rightType: JKType?, symbolProvider: JKSymbolProvider): JKType? {
if (this is JKKtSingleValueOperatorToken && psiToken in arithmeticOperators) return leftType
return null
}
fun kotlinBinaryExpression(
left: JKExpression,
right: JKExpression,
token: JKKtOperatorToken,
symbolProvider: JKSymbolProvider
): JKBinaryExpression? {
val leftType = left.type(symbolProvider) ?: return null
val rightType = right.type(symbolProvider) ?: return null
val methodSymbol = token.binaryExpressionMethodSymbol(leftType, rightType, symbolProvider)
return JKBinaryExpressionImpl(left, right, JKKtOperatorImpl(token, methodSymbol))
): JKBinaryExpression {
val returnType =
when {
token is JKKtSingleValueOperatorToken && token.psiToken in booleanOperators ->
JKClassTypeImpl(symbolProvider.provideByFqName(KotlinBuiltIns.FQ_NAMES._boolean))
else -> {
val leftType = left.type(symbolProvider)
val rightType = right.type(symbolProvider)
leftType?.let { l ->
rightType?.let { r ->
token.arithmeticMethodType(l, r, symbolProvider)
}
} ?: token.defaultReturnType(leftType, rightType, symbolProvider)
?: symbolProvider.provideByFqName<JKClassSymbol>(KotlinBuiltIns.FQ_NAMES.nothing).asType()
}
}
return JKBinaryExpressionImpl(left, right, JKKtOperatorImpl(token, returnType))
}
fun kotlinBinaryExpression(
left: JKExpression,
right: JKExpression,
token: KtSingleValueToken,
symbolProvider: JKSymbolProvider
): JKBinaryExpression =
kotlinBinaryExpression(
left,
right,
JKKtSingleValueOperatorToken(token),
symbolProvider
)
fun kotlinPrefixExpression(
operand: JKExpression,
token: JKKtOperatorToken,
symbolProvider: JKSymbolProvider
): JKPrefixExpression? {
val operandType = operand.type(symbolProvider) ?: return null
val methodSymbol = token.unaryExpressionMethodSymbol(operandType, symbolProvider)
): JKPrefixExpression {
val operandType = operand.type(symbolProvider)
val methodSymbol = token.unaryExpressionMethodType(operandType, symbolProvider)
return JKPrefixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol))
}
@@ -140,9 +186,9 @@ fun kotlinPostfixExpression(
operand: JKExpression,
token: JKKtOperatorToken,
symbolProvider: JKSymbolProvider
): JKPostfixExpression? {
val operandType = operand.type(symbolProvider) ?: return null
val methodSymbol = token.unaryExpressionMethodSymbol(operandType, symbolProvider)
): JKPostfixExpression {
val operandType = operand.type(symbolProvider)
val methodSymbol = token.unaryExpressionMethodType(operandType, symbolProvider)
return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol))
}
@@ -181,10 +227,10 @@ fun rangeExpression(
conversionContext: ConversionContext,
psiContext: PsiElement
): JKExpression {
val symbol = conversionContext.symbolProvider.provideDirectSymbol(
val returnType = (conversionContext.symbolProvider.provideDirectSymbol(
multiResolveFqName(ClassId.fromString("kotlin/ranges/$operatorName"), psiContext).first()
) as JKMethodSymbol
return JKBinaryExpressionImpl(from, to, JKKtOperatorImpl(JKKtWordOperatorToken(operatorName), symbol))
) as JKMethodSymbol).returnType
return JKBinaryExpressionImpl(from, to, JKKtOperatorImpl(JKKtWordOperatorToken(operatorName), returnType!!))
}
fun blockStatement(vararg statements: JKStatement) =
@@ -291,7 +337,7 @@ fun JKFieldAccessExpression.isInDecrementOrIncrement(): Boolean =
fun JKExpression.bangedBangedExpr(symbolProvider: JKSymbolProvider): JKExpression =
JKPostfixExpressionImpl(
this,
JKKtOperatorImpl(KtTokens.EXCLEXCL, JKExclExclMethod(type(symbolProvider)!!))
JKKtOperatorImpl(KtTokens.EXCLEXCL, type(symbolProvider)!!)
)
fun JKVariable.hasWritableUsages(scope: JKTreeElement, context: ConversionContext): Boolean =
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k
import com.intellij.codeInsight.generation.GenerateEqualsHelper.getEqualsSignature
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.MethodSignatureUtil
//copied from old j2k
fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean {
if (left.isNullLiteral() || (right?.isNullLiteral() == true)) return true
val type = left.type
when (type) {
is PsiPrimitiveType, is PsiArrayType -> return true
is PsiClassType -> {
if (right?.type is PsiPrimitiveType) return true
val psiClass = type.resolve() ?: return false
if (!psiClass.hasModifierProperty(PsiModifier.FINAL)) return false
if (psiClass.isEnum) return true
val equalsSignature = getEqualsSignature(left.project, GlobalSearchScope.allScope(left.project))
val equalsMethod = MethodSignatureUtil.findMethodBySignature(psiClass, equalsSignature, true)
if (equalsMethod != null && equalsMethod.containingClass?.qualifiedName != CommonClassNames.JAVA_LANG_OBJECT) return false
return true
}
else -> return false
}
}
@@ -145,6 +145,9 @@ fun JKJavaOperatorToken.toKtToken(): JKKtOperatorToken =
JavaTokenType.MINUSMINUS -> JKKtSingleValueOperatorToken(KtTokens.MINUSMINUS)
JavaTokenType.EXCL -> JKKtSingleValueOperatorToken(KtTokens.EXCL)
KtTokens.EQEQEQ -> JKKtSingleValueOperatorToken(KtTokens.EQEQEQ)
KtTokens.EXCLEQEQEQ -> JKKtSingleValueOperatorToken(KtTokens.EXCLEQEQEQ)
JavaTokenType.AND -> JKKtWordOperatorToken("and")
JavaTokenType.OR -> JKKtWordOperatorToken("or")
JavaTokenType.XOR -> JKKtWordOperatorToken("xor")
@@ -180,9 +183,11 @@ class JKJavaOperatorImpl private constructor(psiToken: IElementType) : JKOperato
}
companion object {
val tokenToOperator = OPERATION_BIT_SET.types.associate {
it to JKJavaOperatorImpl(it)
}
val tokenToOperator =
(OPERATION_BIT_SET.types + arrayOf(KtTokens.EQEQEQ, KtTokens.EXCLEQEQEQ))
.associate {
it to JKJavaOperatorImpl(it)
}
}
}
@@ -102,13 +102,11 @@ class JKBlockImpl(statements: List<JKStatement> = emptyList()) : JKBlock, JKBran
override var statements by children(statements)
}
//todo split to java and kt sbinary expression
class JKBinaryExpressionImpl(
left: JKExpression,
right: JKExpression,
override var operator: JKOperator
) : JKBinaryExpression,
JKBranchElementBase(), PsiOwner by PsiOwnerImpl() {
) : JKBinaryExpression, JKBranchElementBase(), PsiOwner by PsiOwnerImpl() {
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitBinaryExpression(this, data)
override var right by child(right)
override var left by child(left)
@@ -104,10 +104,10 @@ class JKKtWordOperatorToken(override val text: String) : JKKtOperatorToken {
override val operatorName: String = text
}
class JKKtOperatorImpl(override val token: JKKtOperatorToken, val methodSymbol: JKMethodSymbol) : JKOperator, JKElementBase() {
constructor(singleValueToken: KtSingleValueToken, methodSymbol: JKMethodSymbol) : this(
class JKKtOperatorImpl(override val token: JKKtOperatorToken, val returnType: JKType) : JKOperator, JKElementBase() {
constructor(singleValueToken: KtSingleValueToken, returnType: JKType) : this(
JKKtSingleValueOperatorToken(singleValueToken),
methodSymbol
returnType
)
override val precedence: Int
@@ -221,6 +221,7 @@ interface JKOperatorExpression : JKExpression {
var operator: JKOperator
}
//TODO make left & right to be immutable
interface JKBinaryExpression : JKOperatorExpression {
var left: JKExpression
var right: JKExpression
@@ -30,13 +30,9 @@ fun JKExpression.type(symbolProvider: JKSymbolProvider): JKType? =
when (this) {
is JKLiteralExpression -> type.toJkType(symbolProvider)
is JKOperatorExpression -> {
if (operator !is JKKtOperatorImpl) {
error("Cannot get type of ${operator::class}, it should be first converted to KtOperator")
}
val operatorSymbol = (operator as JKKtOperatorImpl).methodSymbol
if (operatorSymbol.name == "compareTo") {
kotlinTypeByName("kotlin.Boolean", symbolProvider)
} else operatorSymbol.returnType
(operator as? JKKtOperatorImpl)?.returnType
?: error("Cannot get type of ${operator::class}, it should be first converted to KtOperator")
}
is JKMethodCallExpression -> identifier.returnType
is JKFieldAccessExpressionImpl -> identifier.fieldType
@@ -118,6 +114,9 @@ fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nu
}
}
fun JKClassSymbol.asType(nullability: Nullability = Nullability.Default): JKClassType =
JKClassTypeImpl(this, emptyList(), nullability)
fun JKType.isSubtypeOf(other: JKType, symbolProvider: JKSymbolProvider): Boolean =
other.toKtType(symbolProvider)
?.let { otherType -> this.toKtType(symbolProvider)?.isSubtypeOf(otherType) } == true