diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt index 4ea6b14b32c..a27ae94ff0b 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt @@ -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) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt index 86b12b49e89..1d688c43bbd 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt @@ -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 { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt index 8ae6135dc80..8945c7b7d4b 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/OperatorExpressionConversion.kt @@ -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 } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/PolyadicExpressionConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/PolyadicExpressionConversion.kt index 5cf0db9dae6..fb14ce6a7b7 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/PolyadicExpressionConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/PolyadicExpressionConversion.kt @@ -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, operators: List): 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) } } } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt index 53529e4f67c..5390dcef5e6 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/expressions.kt @@ -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()?.methodSymbol() ?: defaultClassSymbol - is JKMultiverseClassSymbol -> classSymbol.target.methodSymbol() ?: defaultClassSymbol - else -> defaultClassSymbol + ?.returnType + is JKUniverseClassSymbol -> classSymbol.target.psi()?.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(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() .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(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 = diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/psiUtils.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/psiUtils.kt new file mode 100644 index 00000000000..1ea144b09c9 --- /dev/null +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/psiUtils.kt @@ -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 + } + +} \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt index 68b01d95713..950006c207b 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt @@ -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) + } } } diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt index 182575f72cd..c780cee8db1 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt @@ -102,13 +102,11 @@ class JKBlockImpl(statements: List = 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 accept(visitor: JKVisitor, data: D): R = visitor.visitBinaryExpression(this, data) override var right by child(right) override var left by child(left) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt index 7b7aed58e16..10fa53213e7 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt @@ -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 diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt index f1da0927709..fbe260f36cf 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/jk.kt @@ -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 diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt index 0826c92d749..da1f7b2bd31 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/types.kt @@ -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