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() +AssignmentStatementOperatorConversion()
+AssignmentStatementSimplifyValConversion() +AssignmentStatementSimplifyValConversion()
+AssignmentStatementSimplifyAlsoConversion() +AssignmentStatementSimplifyAlsoConversion()
+PolyadicExpressionConversion(context)
+OperatorExpressionConversion(context) +OperatorExpressionConversion(context)
+ThrowStatementConversion() +ThrowStatementConversion()
+EnumClassConversion() +EnumClassConversion()
@@ -52,7 +53,6 @@ object ConversionsRunner {
+JavaMethodToKotlinFunctionConversion(context) +JavaMethodToKotlinFunctionConversion(context)
+MainFunctionConversion(context) +MainFunctionConversion(context)
+AssertStatementConversion(context) +AssertStatementConversion(context)
+PolyadicExpressionConversion(context)
+SwitchStatementConversion(context) +SwitchStatementConversion(context)
+LiteralConversion() +LiteralConversion()
+ForConversion(context) +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.ChildRole
import com.intellij.psi.impl.source.tree.java.* import com.intellij.psi.impl.source.tree.java.*
import com.intellij.psi.javadoc.PsiDocComment import com.intellij.psi.javadoc.PsiDocComment
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.InheritanceUtil
import com.intellij.psi.util.PsiUtil import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade 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.*
import org.jetbrains.kotlin.j2k.tree.JKLiteralExpression.LiteralType.* import org.jetbrains.kotlin.j2k.tree.JKLiteralExpression.LiteralType.*
import org.jetbrains.kotlin.j2k.tree.impl.* 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.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
@@ -99,7 +102,7 @@ class JavaToJKTreeBuilder(
) )
is PsiPolyadicExpression -> JKJavaPolyadicExpressionImpl( is PsiPolyadicExpression -> JKJavaPolyadicExpressionImpl(
operands.map { it.toJK() }, 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 PsiArrayInitializerExpression -> toJK()
is PsiLambdaExpression -> toJK() is PsiLambdaExpression -> toJK()
@@ -132,12 +135,21 @@ class JavaToJKTreeBuilder(
return JKJavaAssignmentExpressionImpl( return JKJavaAssignmentExpressionImpl(
lExpression.toJK() as? JKAssignableExpression ?: error("Its possible? ${lExpression.toJK().prettyDebugPrintTree()}"), lExpression.toJK() as? JKAssignableExpression ?: error("Its possible? ${lExpression.toJK().prettyDebugPrintTree()}"),
rExpression.toJK(), rExpression.toJK(),
operationSign.toJK() operationSign.tokenType.toJK()
) )
} }
fun PsiBinaryExpression.toJK(): JKExpression { 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 { 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 { 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) { if (it.operator.token.text in listOf("+", "-") && it.expression is JKLiteralExpression) {
JKJavaLiteralExpressionImpl( JKJavaLiteralExpressionImpl(
it.operator.token.text + (it.expression as JKLiteralExpression).literal, it.operator.token.text + (it.expression as JKLiteralExpression).literal,
@@ -171,7 +183,7 @@ class JavaToJKTreeBuilder(
} }
fun PsiPostfixExpression.toJK(): JKExpression { fun PsiPostfixExpression.toJK(): JKExpression {
return JKPostfixExpressionImpl(operand.toJK(), operationSign.toJK()) return JKPostfixExpressionImpl(operand.toJK(), operationSign.tokenType.toJK())
} }
fun PsiLambdaExpression.toJK(): JKExpression { fun PsiLambdaExpression.toJK(): JKExpression {
@@ -5,13 +5,10 @@
package org.jetbrains.kotlin.j2k.conversions package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.j2k.kotlinBinaryExpression
import org.jetbrains.kotlin.j2k.kotlinPostfixExpression
import org.jetbrains.kotlin.j2k.kotlinPrefixExpression
import org.jetbrains.kotlin.j2k.tree.* import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.JKJavaOperatorImpl import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.j2k.tree.impl.toKtToken import org.jetbrains.kotlin.lexer.KtTokens
class OperatorExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() { class OperatorExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
@@ -24,17 +21,37 @@ class OperatorExpressionConversion(private val context: ConversionContext) : Rec
is JKBinaryExpression -> { is JKBinaryExpression -> {
val left = applyToElement(element::left.detached()) as JKExpression val left = applyToElement(element::left.detached()) as JKExpression
val right = applyToElement(element::right.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 -> { is JKPrefixExpression -> {
val operand = applyToElement(element::expression.detached()) as JKExpression val operand = applyToElement(element::expression.detached()) as JKExpression
kotlinPrefixExpression(operand, operatorToken, context.symbolProvider)?.let { recurse(it) } recurse(kotlinPrefixExpression(operand, operatorToken, context.symbolProvider))
} }
is JKPostfixExpression -> { is JKPostfixExpression -> {
val operand = applyToElement(element::expression.detached()) as JKExpression 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()) else -> TODO(element.javaClass.toString())
} ?: recurse(element) } ?: 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.ConversionContext
import org.jetbrains.kotlin.j2k.kotlinBinaryExpression import org.jetbrains.kotlin.j2k.kotlinBinaryExpression
import org.jetbrains.kotlin.j2k.tree.JKExpression import org.jetbrains.kotlin.j2k.tree.*
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.impl.* import org.jetbrains.kotlin.j2k.tree.impl.*
class PolyadicExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() { class PolyadicExpressionConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement { override fun applyToElement(element: JKTreeElement): JKTreeElement {
return (if (element is JKJavaPolyadicExpression) return recurse(
convertPolyadic(element.operands.also { element.operands = emptyList() }, element.tokens) if (element is JKJavaPolyadicExpression)
else convertPolyadic(
element).also { element.operands.also { element.operands = emptyList() },
recurse(it) element.tokens
} )
else element
)
} }
private fun convertPolyadic(operands: List<JKExpression>, operators: List<JKOperator>): JKExpression { private fun convertPolyadic(operands: List<JKExpression>, operators: List<JKOperator>): JKExpression {
@@ -29,16 +28,15 @@ class PolyadicExpressionConversion(private val context: ConversionContext) : Rec
operands.first() operands.first()
else { else {
val operator = operators.maxBy { it.precedence } val operator = operators.maxBy { it.precedence }
val token = when (operator) {
when (operator) { is JKJavaOperatorImpl -> operator.token.toKtToken()
is JKJavaOperatorImpl -> operator.token.toKtToken() is JKKtOperatorImpl -> operator.token
is JKKtOperatorImpl -> operator.token else -> error("operator should be either kotlin or java")
else -> error("operator should be either kotlin or java") }
}
val index = operators.indexOf(operator) val index = operators.indexOf(operator)
val left = convertPolyadic(operands.subList(0, index + 1), operators.subList(0, index)) 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)) 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.PsiClass
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.tree.TokenSet
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
import org.jetbrains.kotlin.j2k.conversions.RecursiveApplicableConversionBase 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.conversions.resolveFqName
import org.jetbrains.kotlin.j2k.tree.* import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.* import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -42,12 +44,12 @@ private fun JKType.classSymbol(symbolProvider: JKSymbolProvider) =
else -> null else -> null
} }
private fun JKKtOperatorToken.binaryExpressionMethodSymbol( private fun JKKtOperatorToken.arithmeticMethodType(
leftType: JKType, leftType: JKType,
rightType: JKType, rightType: JKType,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKMethodSymbol { ): JKType? {
fun PsiClass.methodSymbol() = fun PsiClass.methodReturnType() =
allMethods allMethods
.filter { it.name == operatorName } .filter { it.name == operatorName }
.firstOrNull { .firstOrNull {
@@ -56,28 +58,13 @@ private fun JKKtOperatorToken.binaryExpressionMethodSymbol(
if (type !is JKTypeParameterType) rightType.isSubtypeOf(type, symbolProvider) if (type !is JKTypeParameterType) rightType.isSubtypeOf(type, symbolProvider)
else true//TODO check for type bounds else true//TODO check for type bounds
} != null } != null
}?.let { symbolProvider.provideDirectSymbol(it) as JKMethodSymbol } }?.let { it.returnType?.toJK(symbolProvider) }
val classSymbol = val classSymbol =
if (leftType.isStringType()) symbolProvider.provideByFqName(KotlinBuiltIns.FQ_NAMES.string.toSafe()) if (leftType.isStringType()) symbolProvider.provideByFqName(KotlinBuiltIns.FQ_NAMES.string.toSafe())
else leftType.classSymbol(symbolProvider) 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
@@ -86,53 +73,112 @@ private fun JKKtOperatorToken.binaryExpressionMethodSymbol(
.filter { it.name == operatorName } .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 }
?: defaultClassSymbol ?.returnType
is JKUniverseClassSymbol -> classSymbol.target.psi<PsiClass>()?.methodSymbol() ?: defaultClassSymbol is JKUniverseClassSymbol -> classSymbol.target.psi<PsiClass>()?.methodReturnType()
is JKMultiverseClassSymbol -> classSymbol.target.methodSymbol() ?: defaultClassSymbol is JKMultiverseClassSymbol -> classSymbol.target.methodReturnType()
else -> defaultClassSymbol else -> null
} }
} }
private fun JKKtOperatorToken.unaryExpressionMethodSymbol( private fun JKKtOperatorToken.unaryExpressionMethodType(
operandType: JKType, operandType: JKType?,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKMethodSymbol { ): JKType {
if (this == KtTokens.EXCLEQ) { if (operandType is JKNoType) {
return JKExclExclMethod(operandType) 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) { return when (classSymbol) {
is JKMultiverseKtClassSymbol ->// todo look for extensions is JKMultiverseKtClassSymbol ->// todo look for extensions
classSymbol.target.declarations.asSequence() classSymbol.target.declarations.asSequence()
.filterIsInstance<KtNamedFunction>() .filterIsInstance<KtNamedFunction>()
.filter { it.name == operatorName } .filter { it.name == operatorName }
.mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol } .mapNotNull { it.typeReference?.typeElement?.toJK(symbolProvider) }
.firstOrNull()!! .firstOrNull() ?: TODO(classSymbol::class.toString() + this.operatorName)
null -> TODO(" No class symbol") null -> TODO(" No class symbol")
else -> TODO(classSymbol::class.toString()) 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( fun kotlinBinaryExpression(
left: JKExpression, left: JKExpression,
right: JKExpression, right: JKExpression,
token: JKKtOperatorToken, token: JKKtOperatorToken,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKBinaryExpression? { ): JKBinaryExpression {
val leftType = left.type(symbolProvider) ?: return null val returnType =
val rightType = right.type(symbolProvider) ?: return null when {
val methodSymbol = token.binaryExpressionMethodSymbol(leftType, rightType, symbolProvider) token is JKKtSingleValueOperatorToken && token.psiToken in booleanOperators ->
return JKBinaryExpressionImpl(left, right, JKKtOperatorImpl(token, methodSymbol)) 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( fun kotlinPrefixExpression(
operand: JKExpression, operand: JKExpression,
token: JKKtOperatorToken, token: JKKtOperatorToken,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKPrefixExpression? { ): JKPrefixExpression {
val operandType = operand.type(symbolProvider) ?: return null val operandType = operand.type(symbolProvider)
val methodSymbol = token.unaryExpressionMethodSymbol(operandType, symbolProvider) val methodSymbol = token.unaryExpressionMethodType(operandType, symbolProvider)
return JKPrefixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol)) return JKPrefixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol))
} }
@@ -140,9 +186,9 @@ fun kotlinPostfixExpression(
operand: JKExpression, operand: JKExpression,
token: JKKtOperatorToken, token: JKKtOperatorToken,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKPostfixExpression? { ): JKPostfixExpression {
val operandType = operand.type(symbolProvider) ?: return null val operandType = operand.type(symbolProvider)
val methodSymbol = token.unaryExpressionMethodSymbol(operandType, symbolProvider) val methodSymbol = token.unaryExpressionMethodType(operandType, symbolProvider)
return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol)) return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, methodSymbol))
} }
@@ -181,10 +227,10 @@ fun rangeExpression(
conversionContext: ConversionContext, conversionContext: ConversionContext,
psiContext: PsiElement psiContext: PsiElement
): JKExpression { ): JKExpression {
val symbol = conversionContext.symbolProvider.provideDirectSymbol( val returnType = (conversionContext.symbolProvider.provideDirectSymbol(
multiResolveFqName(ClassId.fromString("kotlin/ranges/$operatorName"), psiContext).first() multiResolveFqName(ClassId.fromString("kotlin/ranges/$operatorName"), psiContext).first()
) as JKMethodSymbol ) as JKMethodSymbol).returnType
return JKBinaryExpressionImpl(from, to, JKKtOperatorImpl(JKKtWordOperatorToken(operatorName), symbol)) return JKBinaryExpressionImpl(from, to, JKKtOperatorImpl(JKKtWordOperatorToken(operatorName), returnType!!))
} }
fun blockStatement(vararg statements: JKStatement) = fun blockStatement(vararg statements: JKStatement) =
@@ -291,7 +337,7 @@ fun JKFieldAccessExpression.isInDecrementOrIncrement(): Boolean =
fun JKExpression.bangedBangedExpr(symbolProvider: JKSymbolProvider): JKExpression = fun JKExpression.bangedBangedExpr(symbolProvider: JKSymbolProvider): JKExpression =
JKPostfixExpressionImpl( JKPostfixExpressionImpl(
this, this,
JKKtOperatorImpl(KtTokens.EXCLEXCL, JKExclExclMethod(type(symbolProvider)!!)) JKKtOperatorImpl(KtTokens.EXCLEXCL, type(symbolProvider)!!)
) )
fun JKVariable.hasWritableUsages(scope: JKTreeElement, context: ConversionContext): Boolean = 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.MINUSMINUS -> JKKtSingleValueOperatorToken(KtTokens.MINUSMINUS)
JavaTokenType.EXCL -> JKKtSingleValueOperatorToken(KtTokens.EXCL) JavaTokenType.EXCL -> JKKtSingleValueOperatorToken(KtTokens.EXCL)
KtTokens.EQEQEQ -> JKKtSingleValueOperatorToken(KtTokens.EQEQEQ)
KtTokens.EXCLEQEQEQ -> JKKtSingleValueOperatorToken(KtTokens.EXCLEQEQEQ)
JavaTokenType.AND -> JKKtWordOperatorToken("and") JavaTokenType.AND -> JKKtWordOperatorToken("and")
JavaTokenType.OR -> JKKtWordOperatorToken("or") JavaTokenType.OR -> JKKtWordOperatorToken("or")
JavaTokenType.XOR -> JKKtWordOperatorToken("xor") JavaTokenType.XOR -> JKKtWordOperatorToken("xor")
@@ -180,9 +183,11 @@ class JKJavaOperatorImpl private constructor(psiToken: IElementType) : JKOperato
} }
companion object { companion object {
val tokenToOperator = OPERATION_BIT_SET.types.associate { val tokenToOperator =
it to JKJavaOperatorImpl(it) (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) override var statements by children(statements)
} }
//todo split to java and kt sbinary expression
class JKBinaryExpressionImpl( class JKBinaryExpressionImpl(
left: JKExpression, left: JKExpression,
right: JKExpression, right: JKExpression,
override var operator: JKOperator override var operator: JKOperator
) : JKBinaryExpression, ) : JKBinaryExpression, JKBranchElementBase(), PsiOwner by PsiOwnerImpl() {
JKBranchElementBase(), PsiOwner by PsiOwnerImpl() {
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitBinaryExpression(this, data) override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitBinaryExpression(this, data)
override var right by child(right) override var right by child(right)
override var left by child(left) override var left by child(left)
@@ -104,10 +104,10 @@ class JKKtWordOperatorToken(override val text: String) : JKKtOperatorToken {
override val operatorName: String = text override val operatorName: String = text
} }
class JKKtOperatorImpl(override val token: JKKtOperatorToken, val methodSymbol: JKMethodSymbol) : JKOperator, JKElementBase() { class JKKtOperatorImpl(override val token: JKKtOperatorToken, val returnType: JKType) : JKOperator, JKElementBase() {
constructor(singleValueToken: KtSingleValueToken, methodSymbol: JKMethodSymbol) : this( constructor(singleValueToken: KtSingleValueToken, returnType: JKType) : this(
JKKtSingleValueOperatorToken(singleValueToken), JKKtSingleValueOperatorToken(singleValueToken),
methodSymbol returnType
) )
override val precedence: Int override val precedence: Int
@@ -221,6 +221,7 @@ interface JKOperatorExpression : JKExpression {
var operator: JKOperator var operator: JKOperator
} }
//TODO make left & right to be immutable
interface JKBinaryExpression : JKOperatorExpression { interface JKBinaryExpression : JKOperatorExpression {
var left: JKExpression var left: JKExpression
var right: JKExpression var right: JKExpression
@@ -30,13 +30,9 @@ fun JKExpression.type(symbolProvider: JKSymbolProvider): JKType? =
when (this) { when (this) {
is JKLiteralExpression -> type.toJkType(symbolProvider) is JKLiteralExpression -> type.toJkType(symbolProvider)
is JKOperatorExpression -> { is JKOperatorExpression -> {
if (operator !is JKKtOperatorImpl) { (operator as? JKKtOperatorImpl)?.returnType
error("Cannot get type of ${operator::class}, it should be first converted to KtOperator") ?: 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
} }
is JKMethodCallExpression -> identifier.returnType is JKMethodCallExpression -> identifier.returnType
is JKFieldAccessExpressionImpl -> identifier.fieldType 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 = fun JKType.isSubtypeOf(other: JKType, symbolProvider: JKSymbolProvider): Boolean =
other.toKtType(symbolProvider) other.toKtType(symbolProvider)
?.let { otherType -> this.toKtType(symbolProvider)?.isSubtypeOf(otherType) } == true ?.let { otherType -> this.toKtType(symbolProvider)?.isSubtypeOf(otherType) } == true