diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt index 5e6834410b5..79c8234a460 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt @@ -31,14 +31,8 @@ object ConversionsRunner { FunctionAsAnonymousObjectToLambdaConversion(context), ReturnStatementInLambdaExpressionConversion(context), BoxedTypeOperationsConversion(context), - AssignmentAsExpressionToAlsoConversion(context), - AssignmentStatementValCreationConversion(context), - AssignmentStatementOperatorConversion(context), - AssignmentStatementSimplifyValConversion(context), - AssignmentStatementSimplifyAlsoConversion(context), - AssignmentStatementSplitAlsoConversion(context), - PolyadicExpressionConversion(context), - OperatorExpressionConversion(context), + AnyWithStringConcatenationConversion(context), + AssignmentExpressionUnfoldingConversion(context), AddParenthesisForLineBreaksInBinaryExpression(context), ThrowStatementConversion(context), ArrayInitializerConversion(context), diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt index 84bf03679c9..9fa56db5453 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt @@ -22,6 +22,7 @@ import com.intellij.psi.JavaTokenType.SUPER_KEYWORD import com.intellij.psi.JavaTokenType.THIS_KEYWORD import com.intellij.psi.impl.source.tree.ChildRole import com.intellij.psi.impl.source.tree.CompositeElement +import com.intellij.psi.impl.source.tree.ElementType import com.intellij.psi.impl.source.tree.java.PsiClassObjectAccessExpressionImpl import com.intellij.psi.impl.source.tree.java.PsiLabeledStatementImpl import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl @@ -138,14 +139,17 @@ class JavaToJKTreeBuilder constructor( is PsiConditionalExpression -> JKIfElseExpressionImpl( condition.toJK(), thenExpression.toJK(), elseExpression.toJK() ) - is PsiPolyadicExpression -> JKJavaPolyadicExpressionImpl( - operands.map { it.toJK() }, - Array(operands.lastIndex) { index -> - getTokenBeforeOperand(operands[index + 1]) - }.map { - it?.tokenType?.toJK() ?: throwCanNotConvertError() + is PsiPolyadicExpression -> { + val token = JKOperatorToken.fromElementType(operationTokenType) + val type = type?.toJK() ?: typeFactory.types.nullableAny + val jkOperands = operands.map { it.toJK().parenthesizeIfBinaryExpression() } + jkOperands.reduce { acc, operand -> + JKBinaryExpressionImpl(acc, operand, JKKtOperatorImpl(token, type)) + }.let { folded -> + if (jkOperands.any { it.containsNewLine() }) folded.parenthesize() + else folded } - ) + } is PsiArrayInitializerExpression -> toJK() is PsiLambdaExpression -> toJK() is PsiClassObjectAccessExpressionImpl -> toJK() @@ -180,9 +184,9 @@ class JavaToJKTreeBuilder constructor( fun PsiAssignmentExpression.toJK(): JKJavaAssignmentExpression { return JKJavaAssignmentExpressionImpl( - lExpression.toJK() as JKAssignableExpression, + lExpression.toJK(), rExpression.toJK(), - operationSign.tokenType.toJK() + createOperator(operationSign.tokenType, type) ).also { it.assignNonCodeElements(this) } @@ -192,16 +196,22 @@ class JavaToJKTreeBuilder constructor( val token = when (operationSign.tokenType) { JavaTokenType.EQEQ, JavaTokenType.NE -> when { - canKeepEqEq(lOperand, rOperand) -> operationSign.tokenType - operationSign.tokenType == JavaTokenType.EQEQ -> KtTokens.EQEQEQ - else -> KtTokens.EXCLEQEQEQ + canKeepEqEq(lOperand, rOperand) -> JKOperatorToken.fromElementType(operationSign.tokenType) + operationSign.tokenType == JavaTokenType.EQEQ -> JKOperatorToken.fromElementType(KtTokens.EQEQEQ) + else -> JKOperatorToken.fromElementType(KtTokens.EXCLEQEQEQ) } - else -> operationSign.tokenType + else -> JKOperatorToken.fromElementType(operationSign.tokenType) + } + return JKBinaryExpressionImpl( + lOperand.toJK(), + rOperand.toJK(), + JKKtOperatorImpl( + token, + type?.toJK() ?: typeFactory.types.nullableAny + ) + ).also { + it.assignNonCodeElements(this) } - return JKBinaryExpressionImpl(lOperand.toJK(), rOperand.toJK(), token.toJK()) - .also { - it.assignNonCodeElements(this) - } } fun PsiLiteralExpression.toJK(): JKLiteralExpression { @@ -223,19 +233,23 @@ class JavaToJKTreeBuilder constructor( } } - fun IElementType.toJK(): JKOperator = JKJavaOperatorImpl.tokenToOperator[this] ?: error("Unsupported token-type: $this") + private fun createOperator(elementType: IElementType, type: PsiType?) = + JKKtOperatorImpl( + JKOperatorToken.fromElementType(elementType), + type?.toJK() ?: typeFactory.types.nullableAny + ) - fun PsiPrefixExpression.toJK(): JKExpression { - return JKPrefixExpressionImpl(operand.toJK(), operationSign.tokenType.toJK()).also { - it.assignNonCodeElements(this) - } + fun PsiPrefixExpression.toJK(): JKExpression = when (operationSign.tokenType) { + JavaTokenType.TILDE -> operand.toJK().callOn(symbolProvider.provideMethodSymbol("kotlin.Int.inv")) + else -> JKPrefixExpressionImpl(operand.toJK(), createOperator(operationSign.tokenType, type)) + }.also { + it.assignNonCodeElements(this) } - fun PsiPostfixExpression.toJK(): JKExpression { - return JKPostfixExpressionImpl(operand.toJK(), operationSign.tokenType.toJK()).also { + fun PsiPostfixExpression.toJK(): JKExpression = + JKPostfixExpressionImpl(operand.toJK(), createOperator(operationSign.tokenType, type)).also { it.assignNonCodeElements(this) } - } fun PsiLambdaExpression.toJK(): JKExpression { return JKLambdaExpressionImpl( @@ -326,7 +340,7 @@ class JavaToJKTreeBuilder constructor( propertyAccessExpression ) else propertyAccessExpression - } else propertyAccessExpression.qualified(qualifier) as JKAssignableExpression + } else propertyAccessExpression.qualified(qualifier) as JKExpression when (if (isExtension) parameterCount - 1 else parameterCount) { 0 /* getter */ -> @@ -337,7 +351,7 @@ class JavaToJKTreeBuilder constructor( JKJavaAssignmentExpressionImpl( propertyAccess, argument, - JKJavaOperatorImpl.tokenToOperator[JavaTokenType.EQ]!! + createOperator(JavaTokenType.EQ, type)//TODO correct type ) } else -> throwCanNotConvertError("expected getter or setter call") @@ -513,14 +527,15 @@ class JavaToJKTreeBuilder constructor( val jkExpressions = expressions.map { it.toJK() } return ((parent as? PsiCall)?.resolveMethod() ?.let { method -> + val lastExpressionType = expressions.lastOrNull()?.type if (jkExpressions.size == method.parameterList.parameters.size && method.parameterList.parameters.getOrNull(jkExpressions.lastIndex)?.isVarArgs == true - && expressions.lastOrNull()?.type is PsiArrayType + && lastExpressionType is PsiArrayType ) { val staredExpression = JKPrefixExpressionImpl( jkExpressions.last(), - JKKtSpreadOperator + JKKtSpreadOperator(lastExpressionType.toJK()) ).withNonCodeElementsFrom(jkExpressions.last()) jkExpressions.dropLast(1) + staredExpression } else jkExpressions diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt index d24ff1b6373..3f4be3f36f4 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt @@ -659,6 +659,9 @@ class NewCodeBuilder(context: NewJ2kConverterContext) { } } + override fun visitKtItExpressionRaw(ktItExpression: JKKtItExpression) { + printer.printWithNoIndent("it") + } override fun visitClassBodyRaw(classBody: JKClassBody) { val declarationsToPrint = classBody.declarations.filterNot { it is JKKtPrimaryConstructor } @@ -818,11 +821,27 @@ class NewCodeBuilder(context: NewJ2kConverterContext) { override fun visitKtAssignmentStatementRaw(ktAssignmentStatement: JKKtAssignmentStatement) { ktAssignmentStatement.field.accept(this) printer.printWithNoIndent(" ") - printer.printWithNoIndent(ktAssignmentStatement.operator.token.text) + printer.printWithNoIndent(ktAssignmentStatement.token.text) printer.printWithNoIndent(" ") ktAssignmentStatement.expression.accept(this) } + override fun visitAssignmentChainAlsoLinkRaw(assignmentChainAlsoLink: JKAssignmentChainAlsoLink) { + assignmentChainAlsoLink.receiver.accept(this) + printer.printWithNoIndent(".also({ ") + assignmentChainAlsoLink.assignmentStatement.accept(this) + printer.printWithNoIndent(" })") + } + + override fun visitAssignmentChainLetLinkRaw(assignmentChainLetLink: JKAssignmentChainLetLink) { + assignmentChainLetLink.receiver.accept(this) + printer.printWithNoIndent(".let({ ") + assignmentChainLetLink.assignmentStatement.accept(this) + printer.printWithNoIndent("; ") + assignmentChainLetLink.field.accept(this) + printer.printWithNoIndent(" })") + } + override fun visitKtWhenStatementRaw(ktWhenStatement: JKKtWhenStatement) { printer.printWithNoIndent("when(") ktWhenStatement.expression.accept(this) diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentAsExpressionToAlsoConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentAsExpressionToAlsoConversion.kt deleted file mode 100644 index 373b8f0e451..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentAsExpressionToAlsoConversion.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.nj2k.conversions - -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.tree.JKBlockStatement -import org.jetbrains.kotlin.nj2k.tree.JKJavaAssignmentExpression -import org.jetbrains.kotlin.nj2k.tree.JKKtAssignmentStatement -import org.jetbrains.kotlin.nj2k.tree.JKTreeElement -import org.jetbrains.kotlin.nj2k.tree.impl.* -import org.jetbrains.kotlin.utils.addToStdlib.cast - -class AssignmentAsExpressionToAlsoConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKJavaAssignmentExpression) return recurse(element) - element.invalidate() - - val alsoExpression = JKKtAlsoCallExpressionImpl( - JKBlockStatementImpl( - JKBlockImpl(listOf(JKKtAssignmentStatementImpl(element.field, JKStubExpressionImpl(), element.operator))) - ), symbolProvider.provideMethodSymbol("kotlin.also") - ).also { - it.statement.cast().block.statements.first().cast().expression = - JKFieldAccessExpressionImpl( - symbolProvider.provideUniverseSymbol( - JKParameterImpl(JKTypeElementImpl(JKContextType), JKNameIdentifierImpl("it")) - ) - )//TODO introduce symbol - } - - return recurse( - JKQualifiedExpressionImpl( - element.expression, - JKKtQualifierImpl.DOT, - alsoExpression - ) - ) - } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentExpressionUnfoldingConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentExpressionUnfoldingConversion.kt new file mode 100644 index 00000000000..18cce5ee909 --- /dev/null +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentExpressionUnfoldingConversion.kt @@ -0,0 +1,178 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.nj2k.conversions + +import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext +import org.jetbrains.kotlin.nj2k.copyTreeAndDetach +import org.jetbrains.kotlin.nj2k.tree.* +import org.jetbrains.kotlin.nj2k.tree.impl.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +class AssignmentExpressionUnfoldingConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { + override fun applyToElement(element: JKTreeElement): JKTreeElement { + val unfolded = when (element) { + is JKBlock -> element.convertAssignments() + is JKExpressionStatement -> element.convertAssignments() + is JKJavaAssignmentExpression -> element.convertAssignments() + else -> null + } ?: return recurse(element) + + return recurse(unfolded) + } + + + private fun JKBlock.convertAssignments(): JKBlock? { + val hasAssignments = statements.any { it.containsAssignment() } + if (!hasAssignments) return null + + val newStatements = mutableListOf() + for (statement in statements) { + when { + statement is JKExpressionStatement && statement.expression is JKJavaAssignmentExpression -> { + val assignment = statement.expression as JKJavaAssignmentExpression + newStatements += assignment + .unfoldToStatementsList(assignmentTarget = null) + .withNonCodeElementsFrom(statement) + } + statement is JKDeclarationStatement && statement.containsAssignment() -> { + val variable = statement.declaredStatements.single() as JKVariable + val assignment = variable.initializer as JKJavaAssignmentExpression + newStatements += assignment + .unfoldToStatementsList(variable.detached(statement)) + .withNonCodeElementsFrom(statement) + } + else -> { + newStatements += statement + } + } + } + statements = newStatements + return this + } + + private fun JKExpressionStatement.convertAssignments(): JKStatement? { + val assignment = expression as? JKJavaAssignmentExpression ?: return null + return when { + canBeConvertedToBlock() && assignment.expression is JKJavaAssignmentExpression -> + JKBlockStatementImpl(JKBlockImpl(assignment.unfoldToStatementsList(assignmentTarget = null))) + else -> createKtAssignmentStatement( + assignment::field.detached(), + assignment::expression.detached(), + assignment.operator + ) + }.withNonCodeElementsFrom(this) + } + + private fun JKExpressionStatement.canBeConvertedToBlock() = when (val parent = parent) { + is JKLoopStatement -> parent.body == this + is JKIfElseStatement -> parent.thenBranch == this || parent.elseBranch == this + is JKIfStatement -> parent.thenBranch == this + is JKJavaSwitchCase -> true + else -> false + } + + private fun JKJavaAssignmentExpression.convertAssignments() = + unfoldToExpressionsChain().withNonCodeElementsFrom(this) + + private fun JKDeclarationStatement.containsAssignment() = + declaredStatements.singleOrNull()?.safeAs()?.initializer is JKJavaAssignmentExpression + + private fun JKStatement.containsAssignment() = when (this) { + is JKExpressionStatement -> expression is JKJavaAssignmentExpression + is JKDeclarationStatement -> containsAssignment() + else -> false + } + + private fun JKJavaAssignmentExpression.unfold() = generateSequence(this) { assignment -> + assignment.expression as? JKJavaAssignmentExpression + }.toList().asReversed() + + private fun JKJavaAssignmentExpression.unfoldToExpressionsChain(): JKExpression { + val links = unfold() + val first = links.first() + return links.subList(1, links.size) + .fold(first.toExpressionChainLink(first::expression.detached())) { state, assignment -> + assignment.toExpressionChainLink(state) + } + } + + private fun JKJavaAssignmentExpression.unfoldToStatementsList(assignmentTarget: JKVariable?): List { + val links = unfold() + val first = links.first() + val statements = links.subList(1, links.size) + .foldIndexed(listOf(first.toDeclarationChainLink(first::expression.detached()))) { index, list, assignment -> + list + assignment.toDeclarationChainLink(links[index].field.copyTreeAndDetach()) + } + return when (assignmentTarget) { + null -> statements + else -> { + assignmentTarget.initializer = statements.last().field.copyTreeAndDetach() + statements + JKDeclarationStatementImpl(listOf(assignmentTarget)) + } + } + } + + private fun JKJavaAssignmentExpression.toExpressionChainLink(receiver: JKExpression): JKExpression { + val assignment = createKtAssignmentStatement( + this::field.detached(), + JKKtItExpressionImpl(operator.returnType), + operator + ).withNonCodeElementsFrom(this) + return when { + operator.isSimpleToken() -> + JKAssignmentChainAlsoLinkImpl(receiver, assignment, field.copyTreeAndDetach()) + else -> + JKAssignmentChainLetLinkImpl(receiver, assignment, field.copyTreeAndDetach()) + } + } + + private fun JKJavaAssignmentExpression.toDeclarationChainLink(expression: JKExpression) = + createKtAssignmentStatement(this::field.detached(), expression, this.operator) + .withNonCodeElementsFrom(this) + + private fun createKtAssignmentStatement( + field: JKExpression, + expression: JKExpression, + operator: JKOperator + ) = when { + operator.isOnlyJavaToken() -> + JKKtAssignmentStatementImpl( + field, + JKBinaryExpressionImpl( + field.copyTreeAndDetach(), + expression, + JKKtOperatorImpl( + onlyJavaAssignTokensToKotlinOnes[operator.token]!!, + operator.returnType + ) + ), + JKOperatorToken.EQ + ) + else -> JKKtAssignmentStatementImpl(field, expression, operator.token) + } + + private fun JKOperator.isSimpleToken() = when { + isOnlyJavaToken() -> false + token == JKOperatorToken.PLUSEQ + || token == JKOperatorToken.MINUSEQ + || token == JKOperatorToken.MULTEQ + || token == JKOperatorToken.DIVEQ -> false + else -> true + } + + private fun JKOperator.isOnlyJavaToken() = token in onlyJavaAssignTokensToKotlinOnes + + companion object { + private val onlyJavaAssignTokensToKotlinOnes = mapOf( + JKOperatorToken.ANDEQ to JKOperatorToken.AND, + JKOperatorToken.OREQ to JKOperatorToken.OR, + JKOperatorToken.XOREQ to JKOperatorToken.XOR, + JKOperatorToken.LTLTEQ to JKOperatorToken.SHL, + JKOperatorToken.GTGTEQ to JKOperatorToken.SHR, + JKOperatorToken.GTGTGTEQ to JKOperatorToken.USHR + ) + } +} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementOperatorConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementOperatorConversion.kt deleted file mode 100644 index 21292b108f5..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementOperatorConversion.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.nj2k.conversions - -import com.intellij.psi.JavaTokenType -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.copyTreeAndDetach -import org.jetbrains.kotlin.nj2k.tree.JKKtAssignmentStatement -import org.jetbrains.kotlin.nj2k.tree.JKTreeElement -import org.jetbrains.kotlin.nj2k.tree.impl.JKBinaryExpressionImpl -import org.jetbrains.kotlin.nj2k.tree.impl.JKJavaOperatorImpl -import org.jetbrains.kotlin.nj2k.tree.impl.JKJavaOperatorToken - -class AssignmentStatementOperatorConversion(context : NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKKtAssignmentStatement) return recurse(element) - val operator = element.operator as? JKJavaOperatorImpl ?: return recurse(element) - operator.token.correspondingBinaryOperation() - ?.apply { - val expression = element.expression.copyTreeAndDetach() - element.expression = - JKBinaryExpressionImpl( - element.field.copyTreeAndDetach(), - expression, - this - ) - element.operator = JKJavaOperatorImpl.tokenToOperator[JavaTokenType.EQ]!! - } - return recurse(element) - } - - private fun JKJavaOperatorToken.correspondingBinaryOperation() = - when (psiToken) { - JavaTokenType.OREQ -> JavaTokenType.OR - JavaTokenType.ANDEQ -> JavaTokenType.AND - JavaTokenType.LTLTEQ -> JavaTokenType.LTLT - JavaTokenType.GTGTEQ -> JavaTokenType.GTGT - JavaTokenType.GTGTGTEQ -> JavaTokenType.GTGTGT - JavaTokenType.XOREQ -> JavaTokenType.XOR - else -> null - }?.let { JKJavaOperatorImpl.tokenToOperator[it] } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSimplifyAlsoConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSimplifyAlsoConversion.kt deleted file mode 100644 index 78bc436c987..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSimplifyAlsoConversion.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.nj2k.conversions - -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.tree.* -import org.jetbrains.kotlin.nj2k.tree.impl.JKExpressionStatementImpl -import org.jetbrains.kotlin.nj2k.tree.impl.JKStubExpressionImpl - -class AssignmentStatementSimplifyAlsoConversion(context : NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKExpressionStatement) return recurse(element) - val qualifiedExpression = element.expression as? JKQualifiedExpression ?: return recurse(element) - val alsoCall = qualifiedExpression.selector as? JKKtAlsoCallExpression ?: return recurse(element) - return recurse(if (alsoCall.statement !is JKBlockStatement) alsoCall.statement.also { - alsoCall.statement = JKExpressionStatementImpl(JKStubExpressionImpl()) - inlineVal(it, qualifiedExpression.receiver.also { qualifiedExpression.receiver = JKStubExpressionImpl() }) - } else element) - } - - private fun inlineVal(statement: JKStatement, expression: JKExpression) { - if (statement is JKKtAssignmentStatement) { - (statement.expression as? JKBinaryExpression)?.right = expression - if (statement.expression !is JKBinaryExpression) statement.expression = expression - } - } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSimplifyValConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSimplifyValConversion.kt deleted file mode 100644 index 896016c33c6..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSimplifyValConversion.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.nj2k.conversions - -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.tree.* -import org.jetbrains.kotlin.nj2k.tree.impl.JKStubExpressionImpl - -class AssignmentStatementSimplifyValConversion(context : NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKKtAlsoCallExpression) return recurse(element) - val codeBlock = (element.statement as? JKBlockStatement)?.block ?: return recurse(element) - if (codeBlock.statements.size > 1) { - val assignment = codeBlock.statements[1] as? JKKtAssignmentStatement ?: return recurse(element) - val declaration = codeBlock.statements[0] as? JKDeclarationStatement ?: return recurse(element) - when (declaration.declaredStatements.size) { - 1 -> if (assignment.expression !is JKBinaryExpression) { - codeBlock.statements = listOf(assignment) - (assignment.field as JKQualifiedExpression).receiver = declaration.extractInitializerByIndex(0) - } else { - - } - 2 -> if (assignment.expression !is JKBinaryExpression) { - codeBlock.statements = listOf(assignment) - val arrayAccess = assignment.field as JKArrayAccessExpression - arrayAccess.expression = declaration.extractInitializerByIndex(0) - arrayAccess.indexExpression = declaration.extractInitializerByIndex(1) - } else { - - } - } - } - if (codeBlock.statements.size == 1) { - element.statement = codeBlock.statements.first().also { codeBlock.statements = emptyList() } - } - return recurse(element) - } - - private fun JKDeclarationStatement.extractInitializerByIndex(i: Int): JKExpression { - val variable = (declaredStatements[i] as JKLocalVariable) - return variable.initializer.also { variable.initializer = JKStubExpressionImpl() } - } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSplitAlsoConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSplitAlsoConversion.kt deleted file mode 100644 index e6284bb61fa..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementSplitAlsoConversion.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.nj2k.conversions - -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.copyTreeAndDetach -import org.jetbrains.kotlin.nj2k.tree.* -import org.jetbrains.kotlin.nj2k.tree.impl.* - -class AssignmentStatementSplitAlsoConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - return recurse( - when (element) { - is JKBlock -> element.splitAssignmentExpressions() - is JKStatement -> - element.splitAsAssignmentExpressions()?.let { JKBlockStatementImpl(JKBlockImpl(it)) } - else -> null - } ?: element) - } - - private fun JKBlock.splitAssignmentExpressions(): JKBlock? { - val newStatements = statements.map { it.splitAsAssignmentExpressions() ?: listOf(it) } - return if (newStatements.any { it.size > 1 }) { - JKBlockImpl( - newStatements.flatMap { statements -> - if (statements.size == 1) statements.map { it.detached(this) } - else statements - } - ).withNonCodeElementsFrom(this) - } else null - } - - private fun JKStatement.splitAsAssignmentExpressions(): List? { - val expression = when (this) { - is JKKtAssignmentStatement -> expression - is JKDeclarationStatementImpl -> (declaredStatements.singleOrNull() as? JKLocalVariableImpl)?.initializer - else -> null - } ?: return null - - val qualifiedExpression = expression as? JKQualifiedExpression ?: return null - val alsoCall = qualifiedExpression.selector as? JKKtAlsoCallExpression ?: return null - val innerAssignmentStatement = alsoCall.statement as? JKKtAssignmentStatement ?: return null - - val secondAssignment = when (this) { - is JKKtAssignmentStatement -> - JKKtAssignmentStatementImpl( - ::field.detached(), - innerAssignmentStatement.field.copyTreeAndDetach(), - operator - ) - is JKDeclarationStatement -> { - val variable = declaredStatements.single() as JKLocalVariableImpl - JKDeclarationStatementImpl( - listOf( - JKLocalVariableImpl( - variable::type.detached(), - variable::name.detached(), - innerAssignmentStatement.field.copyTreeAndDetach(), - variable::mutabilityElement.detached() - ).withNonCodeElementsFrom(variable) - ) - ) - } - else -> error("expression should be either JKKtAssignmentStatement or JKDeclarationStatementImpl") - } - - return listOf( - JKKtAssignmentStatementImpl( - innerAssignmentStatement::field.detached(), - qualifiedExpression::receiver.detached(), - innerAssignmentStatement.operator - ), - secondAssignment.withNonCodeElementsFrom(this) - ) - } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementValCreationConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementValCreationConversion.kt deleted file mode 100644 index 7162b12b940..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AssignmentStatementValCreationConversion.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.nj2k.conversions - -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.tree.* -import org.jetbrains.kotlin.nj2k.tree.impl.* - -class AssignmentStatementValCreationConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKKtAlsoCallExpression) return recurse(element) - val codeBlock = (element.statement as? JKBlockStatement)?.block ?: return recurse(element) - val assignableExpr = (codeBlock.statements.first() as? JKKtAssignmentStatement)?.field ?: return recurse(element) - when (assignableExpr) { - is JKArrayAccessExpression -> { - val ex1 = assignableExpr.expression - val ex2 = assignableExpr.indexExpression - assignableExpr.expression = JKStubExpressionImpl() - assignableExpr.indexExpression = JKStubExpressionImpl() - codeBlock.statements = listOf( - JKDeclarationStatementImpl( - listOf( - JKLocalVariableImpl( - JKTypeElementImpl(JKJavaVoidType/*TODO*/), - JKNameIdentifierImpl("arr"), - ex1, - JKMutabilityModifierElementImpl(Mutability.IMMUTABLE) - ).also { - assignableExpr.expression = JKFieldAccessExpressionImpl(symbolProvider.provideUniverseSymbol(it)) - }, JKLocalVariableImpl( - JKTypeElementImpl(JKJavaVoidType/*TODO*/), - JKNameIdentifierImpl("i"), - ex2, - JKMutabilityModifierElementImpl(Mutability.UNKNOWN) - ).also { - assignableExpr.indexExpression = - JKFieldAccessExpressionImpl(symbolProvider.provideUniverseSymbol(it)) - } - ) - ) - ) + codeBlock.statements - } - is JKQualifiedExpression -> { - val ex = assignableExpr.receiver - assignableExpr.receiver = JKStubExpressionImpl() - codeBlock.statements = listOf( - JKDeclarationStatementImpl( - listOf( - JKLocalVariableImpl( - JKTypeElementImpl(JKJavaVoidType/*TODO*/), - JKNameIdentifierImpl("arg"), - ex, - JKMutabilityModifierElementImpl(Mutability.UNKNOWN) - ).also { - assignableExpr.receiver = JKFieldAccessExpressionImpl(symbolProvider.provideUniverseSymbol(it)) - } - ) - ) - ) + codeBlock.statements - } - } - return recurse(element) - } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt index 2e43588c0ad..3850f6a18c4 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/BuiltinMembersConversion.kt @@ -366,11 +366,10 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli if (expression !is JKMethodCallExpression) error("Expression should be JKMethodCallExpression") val firstArgument = expression.parent.cast()::receiver.detached() val secondArgument = expression.arguments.arguments.first()::value.detached() - kotlinBinaryExpression( + JKBinaryExpressionImpl( firstArgument, secondArgument, - KtTokens.PLUS, - typeFactory + JKKtOperatorImpl(JKOperatorToken.PLUS, typeFactory.types.possiblyNullString) ) } withReplaceType ReplaceType.REPLACE_WITH_QUALIFIER, @@ -390,27 +389,26 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli else expression .also { arguments.arguments = arguments.arguments.dropLast(1) - }.let { - it.callOn( - symbolProvider.provideMethodSymbol("kotlin.collections.dropLastWhile"), + }.callOn( + symbolProvider.provideMethodSymbol("kotlin.collections.dropLastWhile"), + listOf( JKLambdaExpressionImpl( JKFieldAccessExpressionImpl( JKUnresolvedField(//TODO replace with `it` parameter "it", typeFactory ) - ).callOn(symbolProvider.provideMethodSymbol("kotlin.text.isEmpty")) - .asStatement(), + ).callOn(symbolProvider.provideMethodSymbol("kotlin.text.isEmpty")).asStatement(), emptyList() ) ) - } + ) } else -> expression.also { val lastArgument = arguments.arguments.last().value.copyTreeAndDetach() .callOn( symbolProvider.provideMethodSymbol("kotlin.ranges.coerceAtLeast"), - JKKtLiteralExpressionImpl("0", JKLiteralExpression.LiteralType.INT) + listOf(JKKtLiteralExpressionImpl("0", JKLiteralExpression.LiteralType.INT)) ) arguments.arguments = arguments.arguments.dropLast(1) + JKArgumentImpl(lastArgument) } @@ -428,7 +426,7 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli JKArgumentListImpl( JKLambdaExpressionImpl( JKExpressionStatementImpl( - kotlinBinaryExpression( + JKBinaryExpressionImpl( JKFieldAccessExpressionImpl( JKUnresolvedField(//TODO replace with `it` parameter "it", @@ -436,8 +434,10 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli ) ), JKKtLiteralExpressionImpl("' '", JKLiteralExpression.LiteralType.CHAR), - KtTokens.LTEQ, - typeFactory + JKKtOperatorImpl( + JKOperatorToken.LTEQ, + typeFactory.types.boolean + ) ) ), emptyList() @@ -469,7 +469,7 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli ).groupBy { it.from.fqName } - private fun JKExpression.callOn(symbol: JKMethodSymbol, arguments: List = emptyList()) = + private fun JKExpression. callOn(symbol: JKMethodSymbol, arguments: List = emptyList()) = JKQualifiedExpressionImpl( this, JKKtQualifierImpl.DOT, @@ -480,12 +480,6 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli ) ) - private fun JKExpression.callOn(symbol: JKMethodSymbol, vararg arguments: JKArgument) = - callOn(symbol, arguments.toList()) - - private fun JKExpression.callOn(symbol: JKMethodSymbol, vararg arguments: JKExpression) = - callOn(symbol, arguments.map { JKArgumentImpl(it) }) - private fun isSystemOutCall(expression: JKExpression): Boolean = expression.parent ?.safeAs() diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ForConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ForConversion.kt index 2b4d5e2c6bd..7742408d723 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ForConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ForConversion.kt @@ -182,11 +182,13 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver convertBound(bound, 0), context ) - else -> kotlinBinaryExpression( + else -> JKBinaryExpressionImpl( start, convertBound(bound, if (inclusiveComparison) 0 else -1), - JKKtSingleValueOperatorToken(KtTokens.RANGE), - typeFactory + JKKtOperatorImpl( + JKOperatorToken.RANGE, + typeFactory.types.nullableAny //todo range type + ) ) } } @@ -199,12 +201,14 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver return JKKtLiteralExpressionImpl((value + correction).toString(), bound.type) } - val sign = if (correction > 0) KtTokens.PLUS else KtTokens.MINUS - return kotlinBinaryExpression( + val sign = if (correction > 0) JKOperatorToken.PLUS else JKOperatorToken.MINUS + return JKBinaryExpressionImpl( bound, JKKtLiteralExpressionImpl(abs(correction).toString(), JKLiteralExpression.LiteralType.INT), - JKKtSingleValueOperatorToken(sign), - typeFactory + JKKtOperatorImpl( + sign, + typeFactory.types.int + ) ) } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/OperatorExpressionConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/OperatorExpressionConversion.kt index e4748b99ecf..b386383cbae 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/OperatorExpressionConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/OperatorExpressionConversion.kt @@ -5,77 +5,27 @@ package org.jetbrains.kotlin.nj2k.conversions -import com.intellij.psi.JavaTokenType -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.kotlinBinaryExpression -import org.jetbrains.kotlin.nj2k.kotlinPostfixExpression -import org.jetbrains.kotlin.nj2k.kotlinPrefixExpression +import org.jetbrains.kotlin.nj2k.callOn import org.jetbrains.kotlin.nj2k.tree.* -import org.jetbrains.kotlin.nj2k.tree.impl.* +import org.jetbrains.kotlin.nj2k.tree.impl.JKBinaryExpressionImpl -class OperatorExpressionConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { +class AnyWithStringConcatenationConversion(context: NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKOperatorExpression) return recurse(element) - val operator = element.operator as? JKJavaOperatorImpl ?: return recurse(element) - - return when (element) { - is JKBinaryExpression -> { - val operatorToken = operator.token.toKtToken() - val left = applyToElement(element::left.detached()) as JKExpression - val right = applyToElement(element::right.detached()) as JKExpression - recurse(convertBinaryExpression(left, right, operatorToken).withNonCodeElementsFrom(element)) - } - is JKPrefixExpression -> { - val operand = applyToElement(element::expression.detached()) as JKExpression - recurse(convertPrefixExpression(operand, operator)) - } - is JKPostfixExpression -> { - val operatorToken = operator.token.toKtToken() - val operand = applyToElement(element::expression.detached()) as JKExpression - recurse(kotlinPostfixExpression(operand, operatorToken, typeFactory)) - } - else -> TODO(element.javaClass.toString()) - }.withNonCodeElementsFrom(element) - } - - - private fun convertPrefixExpression(operand: JKExpression, javaOperator: JKJavaOperatorImpl) = - convertTildeExpression(operand, javaOperator) - ?: kotlinPrefixExpression(operand, javaOperator.token.toKtToken(), typeFactory) - - private fun convertTildeExpression(operand: JKExpression, javaOperator: JKJavaOperatorImpl): JKExpression? = - if (javaOperator.token.psiToken == JavaTokenType.TILDE) { - val invCall = - JKKtCallExpressionImpl( - symbolProvider.provideMethodSymbol("kotlin.Int.inv"),//TODO check if Long - JKArgumentListImpl() - ) - JKQualifiedExpressionImpl( - JKParenthesizedExpressionImpl(operand), - JKKtQualifierImpl.DOT, - invCall - ) - } else null - - private fun convertBinaryExpression(left: JKExpression, right: JKExpression, token: JKKtOperatorToken): JKBinaryExpression = - convertStringImplicitConcatenation(left, right, token) - ?: kotlinBinaryExpression(left, right, token, typeFactory) - - - private fun convertStringImplicitConcatenation(left: JKExpression, right: JKExpression, token: JKKtOperatorToken): JKBinaryExpression? = - if (token is JKKtSingleValueOperatorToken - && token.psiToken == KtTokens.PLUS - && right.type(typeFactory)?.isStringType() == true - && left.type(typeFactory)?.isStringType() == false + if (element !is JKBinaryExpression) return recurse(element) + if (element.operator.token == JKOperatorToken.PLUS + && element.right.type(typeFactory)?.isStringType() == true + && element.left.type(typeFactory)?.isStringType() == false ) { - val toStringCall = - JKKtCallExpressionImpl( - symbolProvider.provideMethodSymbol("kotlin.Any.toString"), - JKArgumentListImpl() + return recurse( + JKBinaryExpressionImpl( + element::left.detached().callOn(symbolProvider.provideMethodSymbol("kotlin.Any.toString")), + element::right.detached(), + element.operator ) - val qualifiedCall = JKQualifiedExpressionImpl(left, JKKtQualifierImpl.DOT, toStringCall) - kotlinBinaryExpression(qualifiedCall, right, KtTokens.PLUS, typeFactory) - } else null + ) + } + return recurse(element) + } } \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/PolyadicExpressionConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/PolyadicExpressionConversion.kt deleted file mode 100644 index b8f750f4f19..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/PolyadicExpressionConversion.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * 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.nj2k.conversions - -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.nj2k.parenthesizeIfBinaryExpression -import org.jetbrains.kotlin.nj2k.tree.* -import org.jetbrains.kotlin.nj2k.tree.impl.JKBinaryExpressionImpl -import org.jetbrains.kotlin.nj2k.tree.impl.JKParenthesizedExpressionImpl - - -class PolyadicExpressionConversion(context : NewJ2kConverterContext) : RecursiveApplicableConversionBase(context) { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKJavaPolyadicExpression) return recurse(element) - val needParenthesis = element.operands.any { it.containsNewLine() } - val parenthesisedOperands = element::operands.detached().map { it.parenthesizeIfBinaryExpression() } - val polyadic = convertPolyadic(parenthesisedOperands, element.tokens) - - return recurse( - if (needParenthesis) JKParenthesizedExpressionImpl(polyadic) - else polyadic - ) - } - - private fun convertPolyadic(operands: List, operators: List): JKExpression { - return if (operators.isEmpty()) - operands.first() - else { - val operator = operators.maxBy { it.precedence }!! - 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)) - JKBinaryExpressionImpl(left, right, operator) - } - } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt index 245e8e862b5..4e36f4cb5b0 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/TypeMappingConversion.kt @@ -25,7 +25,7 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab element.type = element.type.mapType(element) } is JKJavaNewExpression -> { - val newClassSymbol = element.classSymbol.mapClassSymbol(null) + val newClassSymbol = element.classSymbol.mapClassSymbol() return recurse( JKJavaNewExpressionImpl( newClassSymbol, @@ -55,7 +55,6 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab } } - private fun JKType.fixRawType(typeElement: JKTypeElement?) = when (typeElement?.parent) { is JKClassLiteralExpression -> this @@ -71,7 +70,7 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab private fun JKType.mapType(typeElement: JKTypeElement?): JKType = when (this) { is JKJavaPrimitiveType -> mapPrimitiveType() - is JKClassType -> mapClassType(typeElement) + is JKClassType -> mapClassType() is JKJavaVoidType -> typeFactory.types.unit is JKJavaArrayType -> @@ -94,18 +93,17 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab else -> this }.fixRawType(typeElement) - private fun JKClassSymbol.mapClassSymbol(typeElement: JKTypeElement?): JKClassSymbol { + private fun JKClassSymbol.mapClassSymbol(): JKClassSymbol { if (this is JKUniverseClassSymbol) return this - if (typeElement?.parentOfType() != null) return this val newFqName = kotlinCollectionClassName() ?: kotlinStandardType() ?: fqName return symbolProvider.provideClassSymbol(newFqName) } - private fun JKClassType.mapClassType(typeElement: JKTypeElement?): JKClassType = + private fun JKClassType.mapClassType(): JKClassType = JKClassTypeImpl( - classReference.mapClassSymbol(typeElement), + classReference.mapClassSymbol(), parameters.map { it.mapType(null) }, nullability ) @@ -118,13 +116,8 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab return JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqName))?.asString() } - private fun JKJavaPrimitiveType.mapPrimitiveType(): JKClassType { - val fqName = jvmPrimitiveType.primitiveType.typeFqName - return JKClassTypeImpl( - symbolProvider.provideClassSymbol(fqName), - nullability = Nullability.NotNull - ) - } + private fun JKJavaPrimitiveType.mapPrimitiveType(): JKClassType = + typeFactory.fromPrimitiveType(this) private inline fun T.addTypeParametersToRawProjectionType(typeParameter: JKType): T = if (this is JKClassType && parameters.isEmpty()) { @@ -147,7 +140,6 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab companion object { private val ktFunctionRegex = "kotlin\\.jvm\\.functions\\.Function\\d+".toRegex() - private fun isKtFunction(fqName: String) = - ktFunctionRegex.matches(fqName) + private fun isKtFunction(fqName: String) = ktFunctionRegex.matches(fqName) } } \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt index d758bda6285..c52f6493330 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt @@ -5,67 +5,18 @@ package org.jetbrains.kotlin.nj2k -import com.intellij.psi.PsiClass import com.intellij.psi.tree.TokenSet -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.lexer.KtSingleValueToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.nj2k.conversions.RecursiveApplicableConversionBase -import org.jetbrains.kotlin.nj2k.symbols.* +import org.jetbrains.kotlin.nj2k.symbols.JKMethodSymbol +import org.jetbrains.kotlin.nj2k.symbols.JKUnresolvedMethod import org.jetbrains.kotlin.nj2k.tree.* import org.jetbrains.kotlin.nj2k.tree.impl.* -import org.jetbrains.kotlin.nj2k.types.JKClassType -import org.jetbrains.kotlin.nj2k.types.JKJavaPrimitiveType import org.jetbrains.kotlin.nj2k.types.JKTypeFactory -import org.jetbrains.kotlin.nj2k.types.JKTypeParameterType -import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs -private fun JKType.classSymbol(typeFactory: JKTypeFactory) = when (this) { - is JKClassType -> classReference - is JKJavaPrimitiveType -> typeFactory.fromPrimitiveType(this).classReference - else -> null -} - -private fun JKKtOperatorToken.arithmeticMethodType( - leftType: JKType, - rightType: JKType, - typeFactory: JKTypeFactory -): JKType? { - val symbolProvider = typeFactory.symbolProvider - - fun PsiClass.methodReturnType() = - allMethods - .filter { it.name == operatorName } - .firstOrNull { - it.parameterList.parameters.singleOrNull()?.takeIf { parameter -> - val type = typeFactory.fromPsiType(parameter.type) - if (type !is JKTypeParameterType) rightType.isSubtypeOf(type, typeFactory) - else true//TODO check for type bounds - } != null - }?.returnType?.let { typeFactory.fromPsiType(it) } - - val classSymbol = - if (leftType.isStringType()) symbolProvider.provideClassSymbol(KotlinBuiltIns.FQ_NAMES.string.toSafe()) - else leftType.classSymbol(typeFactory) - - return when (classSymbol) { - is JKMultiverseKtClassSymbol -> - classSymbol.target.declarations - .asSequence() - .filterIsInstance() - .filter { it.name == operatorName } - .mapNotNull { symbolProvider.provideDirectSymbol(it) as? JKMethodSymbol } - .firstOrNull { it.parameterTypes?.singleOrNull()?.takeIf { rightType.isSubtypeOf(it, typeFactory) } != null } - ?.returnType - is JKUniverseClassSymbol -> classSymbol.target.psi()?.methodReturnType() - is JKMultiverseClassSymbol -> classSymbol.target.methodReturnType() - else -> null - } -} - fun JKOperator.isEquals() = (token as? JKKtSingleValueOperatorToken)?.psiToken in equalsOperators @@ -77,98 +28,6 @@ private val equalsOperators = KtTokens.EXCLEQ ) -private val lessGreaterOperators = - TokenSet.create( - KtTokens.LT, - KtTokens.GT, - KtTokens.LTEQ, - KtTokens.GTEQ - ) - -private val comparisonOperators = - TokenSet.orSet( - lessGreaterOperators, - equalsOperators - ) - -private val booleanOperators = - TokenSet.orSet( - comparisonOperators, - TokenSet.create( - 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?): JKType? { - if (this is JKKtSingleValueOperatorToken && psiToken in arithmeticOperators) return leftType - return null -} - -fun kotlinBinaryExpression( - left: JKExpression, - right: JKExpression, - token: JKKtOperatorToken, - typeFactory: JKTypeFactory -): JKBinaryExpression { - val symbolProvider = typeFactory.symbolProvider - val returnType = - when { - token is JKKtSingleValueOperatorToken && token.psiToken in booleanOperators -> - JKClassTypeImpl(symbolProvider.provideClassSymbol(KotlinBuiltIns.FQ_NAMES._boolean.toSafe())) - else -> { - val leftType = left.type(typeFactory) - val rightType = right.type(typeFactory) - leftType?.let { l -> - rightType?.let { r -> - token.arithmeticMethodType(l, r, typeFactory) - } - } ?: token.defaultReturnType(leftType) - ?: typeFactory.types.nothing - } - } - return JKBinaryExpressionImpl(left, right, JKKtOperatorImpl(token, returnType)) -} - -fun kotlinBinaryExpression( - left: JKExpression, - right: JKExpression, - token: KtSingleValueToken, - typeFactory: JKTypeFactory -): JKBinaryExpression = - kotlinBinaryExpression( - left, - right, - JKKtSingleValueOperatorToken(token), - typeFactory - ) - -fun kotlinPrefixExpression( - operand: JKExpression, - token: JKKtOperatorToken, - typeFactory: JKTypeFactory -): JKPrefixExpression { - val operandType = operand.type(typeFactory) ?: JKNoTypeImpl - return JKPrefixExpressionImpl(operand, JKKtOperatorImpl(token, operandType)) -} - -fun kotlinPostfixExpression( - operand: JKExpression, - token: JKKtOperatorToken, - typeFactory: JKTypeFactory -): JKPostfixExpression { - val operandType = operand.type(typeFactory) ?: JKNoTypeImpl - return JKPostfixExpressionImpl(operand, JKKtOperatorImpl(token, operandType)) -} - fun untilToExpression( from: JKExpression, to: JKExpression, @@ -199,6 +58,8 @@ fun JKExpression.parenthesizeIfBinaryExpression() = else -> this } +fun JKExpression.parenthesize() = JKParenthesizedExpressionImpl(this) + fun rangeExpression( from: JKExpression, to: JKExpression, @@ -277,7 +138,7 @@ fun stringLiteral(content: String, typeFactory: JKTypeFactory): JKExpression { val newlineSeparator = if (i == lines.size - 1) "" else "\\n" JKKtLiteralExpressionImpl("\"$line$newlineSeparator\"", JKLiteralExpression.LiteralType.STRING) }.reduce { acc: JKExpression, literalExpression: JKKtLiteralExpression -> - kotlinBinaryExpression(acc, literalExpression, JKKtSingleValueOperatorToken(KtTokens.PLUS), typeFactory) + JKBinaryExpressionImpl(acc, literalExpression, JKKtOperatorImpl(JKOperatorToken.PLUS, typeFactory.types.string)) } } @@ -320,11 +181,13 @@ fun JKVariable.hasWritableUsages(scope: JKTreeElement, context: NewJ2kConverterC } fun equalsExpression(left: JKExpression, right: JKExpression, typeFactory: JKTypeFactory) = - kotlinBinaryExpression( + JKBinaryExpressionImpl( left, right, - KtTokens.EQEQ, - typeFactory + JKKtOperatorImpl( + JKOperatorToken.EQEQ, + typeFactory.types.boolean + ) ) fun createCompanion(declarations: List): JKClass = @@ -438,4 +301,19 @@ fun T.nullIfStubExpression(): T? = fun JKExpression.qualified(qualifier: JKExpression?) = if (qualifier != null && qualifier !is JKStubExpression) { JKQualifiedExpressionImpl(qualifier, JKJavaQualifierImpl.DOT, this) - } else this \ No newline at end of file + } else this + +fun JKExpression.callOn( + symbol: JKMethodSymbol, + arguments: List = emptyList(), + typeArguments: List = emptyList() +) = JKQualifiedExpressionImpl( + this, + JKKtQualifierImpl.DOT, + JKKtCallExpressionImpl( + symbol, + JKArgumentListImpl(arguments.map { JKArgumentImpl(it) }), + JKTypeArgumentListImpl(typeArguments) + ) +) + diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/base.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/base.kt index 86b2f8b6d2b..b302979ed90 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/base.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/base.kt @@ -5,21 +5,119 @@ package org.jetbrains.kotlin.nj2k.tree +import com.intellij.psi.JavaTokenType +import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.j2k.ast.Nullability +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.nj2k.tree.impl.JKJavaOperatorToken +import org.jetbrains.kotlin.nj2k.tree.impl.JKKtSingleValueOperatorToken +import org.jetbrains.kotlin.nj2k.tree.impl.JKKtWordOperatorToken interface JKOperator { val token: JKOperatorToken - val precedence: Int + val returnType: JKType } interface JKOperatorToken { val text: String + + @Suppress("MemberVisibilityCanBePrivate", "SpellCheckingInspection") + companion object { + fun fromElementType(elementType: IElementType) = elementTypeToToken.getValue(elementType) + + val RANGE = JKKtSingleValueOperatorToken(KtTokens.RANGE) + + val DIV = JKKtSingleValueOperatorToken(KtTokens.DIV) + val MINUS = JKKtSingleValueOperatorToken(KtTokens.MINUS) + val ANDAND = JKKtSingleValueOperatorToken(KtTokens.ANDAND) + val OROR = JKKtSingleValueOperatorToken(KtTokens.OROR) + val PLUS = JKKtSingleValueOperatorToken(KtTokens.PLUS) + val MUL = JKKtSingleValueOperatorToken(KtTokens.MUL) + val GT = JKKtSingleValueOperatorToken(KtTokens.GT) + val GTEQ = JKKtSingleValueOperatorToken(KtTokens.GTEQ) + val LT = JKKtSingleValueOperatorToken(KtTokens.LT) + val LTEQ = JKKtSingleValueOperatorToken(KtTokens.LTEQ) + val PERC = JKKtSingleValueOperatorToken(KtTokens.PERC) + val EQ = JKKtSingleValueOperatorToken(KtTokens.EQ) + val EQEQ = JKKtSingleValueOperatorToken(KtTokens.EQEQ) + val EXCLEQ = JKKtSingleValueOperatorToken(KtTokens.EXCLEQ) + + val PLUSEQ = JKKtSingleValueOperatorToken(KtTokens.PLUSEQ) + val MINUSEQ = JKKtSingleValueOperatorToken(KtTokens.MINUSEQ) + val DIVEQ = JKKtSingleValueOperatorToken(KtTokens.DIVEQ) + val MULTEQ = JKKtSingleValueOperatorToken(KtTokens.MULTEQ) + val PERCEQ = JKKtSingleValueOperatorToken(KtTokens.PERCEQ) + + + val PLUSPLUS = JKKtSingleValueOperatorToken(KtTokens.PLUSPLUS) + val MINUSMINUS = JKKtSingleValueOperatorToken(KtTokens.MINUSMINUS) + val EXCL = JKKtSingleValueOperatorToken(KtTokens.EXCL) + val EQEQEQ = JKKtSingleValueOperatorToken(KtTokens.EQEQEQ) + val EXCLEQEQEQ = JKKtSingleValueOperatorToken(KtTokens.EXCLEQEQEQ) + + val AND = JKKtWordOperatorToken("and") + val OR = JKKtWordOperatorToken("or") + val XOR = JKKtWordOperatorToken("xor") + val USHR = JKKtWordOperatorToken("ushr") + val SHR = JKKtWordOperatorToken("shr") + val SHL = JKKtWordOperatorToken("shl") + + val ANDEQ = JKJavaOperatorToken(JavaTokenType.ANDEQ) + val OREQ = JKJavaOperatorToken(JavaTokenType.OREQ) + val XOREQ = JKJavaOperatorToken(JavaTokenType.XOREQ) + val LTLTEQ = JKJavaOperatorToken(JavaTokenType.LTLTEQ) + val GTGTEQ = JKJavaOperatorToken(JavaTokenType.GTGTEQ) + val GTGTGTEQ = JKJavaOperatorToken(JavaTokenType.GTGTGTEQ) + + + private val elementTypeToToken: Map = mapOf( + JavaTokenType.DIV to DIV, + JavaTokenType.MINUS to MINUS, + JavaTokenType.ANDAND to ANDAND, + JavaTokenType.OROR to OROR, + JavaTokenType.PLUS to PLUS, + JavaTokenType.ASTERISK to MUL, + JavaTokenType.GT to GT, + JavaTokenType.GE to GTEQ, + JavaTokenType.LT to LT, + JavaTokenType.LE to LTEQ, + JavaTokenType.PERC to PERC, + + JavaTokenType.EQ to EQ, + JavaTokenType.EQEQ to EQEQ, + JavaTokenType.NE to EXCLEQ, + + JavaTokenType.PLUSEQ to PLUSEQ, + JavaTokenType.MINUSEQ to MINUSEQ, + JavaTokenType.DIVEQ to DIVEQ, + JavaTokenType.ASTERISKEQ to MULTEQ, + + JavaTokenType.PLUSPLUS to PLUSPLUS, + JavaTokenType.MINUSMINUS to MINUSMINUS, + JavaTokenType.EXCL to EXCL, + + KtTokens.EQEQEQ to EQEQEQ, + KtTokens.EXCLEQEQEQ to EXCLEQEQEQ, + + JavaTokenType.AND to AND, + JavaTokenType.OR to OR, + JavaTokenType.XOR to XOR, + JavaTokenType.GTGTGT to USHR, + JavaTokenType.GTGT to SHR, + JavaTokenType.LTLT to SHL, + + JavaTokenType.ANDEQ to ANDEQ, + JavaTokenType.OREQ to OREQ, + JavaTokenType.XOREQ to XOREQ, + JavaTokenType.PERCEQ to PERCEQ, + JavaTokenType.LTLTEQ to LTLTEQ, + JavaTokenType.GTGTEQ to GTGTEQ, + JavaTokenType.GTGTGTEQ to GTGTGTEQ + ) + } } -interface JKKtOperatorToken : JKOperatorToken { - val operatorName: String -} - +interface JKKtOperatorToken : JKOperatorToken interface JKQualifier interface JKElement { diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaAndKotlinElements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaAndKotlinElements.kt index a5cea6eaa8b..099e810deb9 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaAndKotlinElements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaAndKotlinElements.kt @@ -159,7 +159,7 @@ class JKQualifiedExpressionImpl( class JKExpressionStatementImpl(expression: JKExpression) : JKExpressionStatement(), PsiOwner by PsiOwnerImpl() { override fun accept(visitor: JKVisitor) = visitor.visitExpressionStatement(this) - override val expression: JKExpression by child(expression) + override var expression: JKExpression by child(expression) } class JKDeclarationStatementImpl(declaredStatements: List) : JKDeclarationStatement(), diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaElements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaElements.kt index 3e3d9ed3549..614da0db960 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaElements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/javaElements.kt @@ -92,125 +92,9 @@ class JKJavaLiteralExpressionImpl( } } - class JKJavaOperatorToken(val psiToken: IElementType) : JKOperatorToken { override val text: String - get() = when (psiToken) { - JavaTokenType.EQ -> "=" - JavaTokenType.EQEQ -> "==" - JavaTokenType.NE -> "!=" - JavaTokenType.ANDAND -> "&&" - JavaTokenType.OROR -> "||" - JavaTokenType.GT -> ">" - JavaTokenType.LT -> "<" - JavaTokenType.GE -> ">=" - JavaTokenType.LE -> "<=" - JavaTokenType.EXCL -> "!" - JavaTokenType.PLUS -> "+" - JavaTokenType.MINUS -> "-" - JavaTokenType.ASTERISK -> "*" - JavaTokenType.DIV -> "/" - JavaTokenType.PERC -> "%" - JavaTokenType.PLUSEQ -> "+=" - JavaTokenType.MINUSEQ -> "-=" - JavaTokenType.ASTERISKEQ -> "*=" - JavaTokenType.DIVEQ -> "/=" - JavaTokenType.PERCEQ -> "%=" - JavaTokenType.GTGT -> "shr" - JavaTokenType.LTLT -> "shl" - JavaTokenType.XOR -> "xor" - JavaTokenType.AND -> "and" - JavaTokenType.OR -> "or" - JavaTokenType.GTGTGT -> "ushr" - JavaTokenType.GTGTEQ -> "shr" - JavaTokenType.LTLTEQ -> "shl" - JavaTokenType.XOREQ -> "xor" - JavaTokenType.ANDEQ -> "and" - JavaTokenType.OREQ -> "or" - JavaTokenType.GTGTGTEQ -> "ushr" - JavaTokenType.PLUSPLUS -> "++" - JavaTokenType.MINUSMINUS -> "--" - JavaTokenType.TILDE -> "~" - else -> TODO(psiToken.toString()) - } -} - -fun JKJavaOperatorToken.toKtToken(): JKKtOperatorToken = - when (this.psiToken) { - JavaTokenType.DIV -> JKKtSingleValueOperatorToken(KtTokens.DIV) - JavaTokenType.MINUS -> JKKtSingleValueOperatorToken(KtTokens.MINUS) - JavaTokenType.ANDAND -> JKKtSingleValueOperatorToken(KtTokens.ANDAND) - JavaTokenType.OROR -> JKKtSingleValueOperatorToken(KtTokens.OROR) - JavaTokenType.PLUS -> JKKtSingleValueOperatorToken(KtTokens.PLUS) - JavaTokenType.ASTERISK -> JKKtSingleValueOperatorToken(KtTokens.MUL) - JavaTokenType.GT -> JKKtSingleValueOperatorToken(KtTokens.GT) - JavaTokenType.GE -> JKKtSingleValueOperatorToken(KtTokens.GTEQ) - JavaTokenType.LT -> JKKtSingleValueOperatorToken(KtTokens.LT) - JavaTokenType.LE -> JKKtSingleValueOperatorToken(KtTokens.LTEQ) - JavaTokenType.PERC -> JKKtSingleValueOperatorToken(KtTokens.PERC) - - JavaTokenType.EQ -> JKKtSingleValueOperatorToken(KtTokens.EQ) - JavaTokenType.EQEQ -> JKKtSingleValueOperatorToken(KtTokens.EQEQ) - JavaTokenType.NE -> JKKtSingleValueOperatorToken(KtTokens.EXCLEQ) - JavaTokenType.PLUSEQ -> JKKtSingleValueOperatorToken(KtTokens.PLUSEQ) - JavaTokenType.MINUSEQ -> JKKtSingleValueOperatorToken(KtTokens.MINUSEQ) - JavaTokenType.PLUSPLUS -> JKKtSingleValueOperatorToken(KtTokens.PLUSPLUS) - 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") - JavaTokenType.GTGTGT -> JKKtWordOperatorToken("ushr") - JavaTokenType.GTGT -> JKKtWordOperatorToken("shr") - JavaTokenType.LTLT -> JKKtWordOperatorToken("shl") - - JavaTokenType.OREQ -> JKKtWordOperatorToken("or") - JavaTokenType.ANDEQ -> JKKtWordOperatorToken("and") - JavaTokenType.LTLTEQ -> JKKtWordOperatorToken("shl") - JavaTokenType.GTGTEQ -> JKKtWordOperatorToken("shr") - JavaTokenType.GTGTGTEQ -> JKKtWordOperatorToken("ushr") - JavaTokenType.XOREQ -> JKKtWordOperatorToken("xor") - - else -> TODO(this.psiToken.toString()) - } - - -class JKJavaOperatorImpl private constructor(psiToken: IElementType) : JKOperator { - override val token: JKJavaOperatorToken = JKJavaOperatorToken(psiToken) - - override val precedence: Int - get() = when (token.psiToken) { - JavaTokenType.ASTERISK, JavaTokenType.DIV, JavaTokenType.PERC -> 3 - JavaTokenType.PLUS, JavaTokenType.MINUS -> 4 - KtTokens.ELVIS -> 7 - JavaTokenType.GT, JavaTokenType.LT, JavaTokenType.GE, JavaTokenType.LE -> 9 - JavaTokenType.EQEQ, JavaTokenType.NE, KtTokens.EQEQEQ, KtTokens.EXCLEQEQEQ -> 10 - JavaTokenType.ANDAND -> 11 - JavaTokenType.OROR -> 12 - JavaTokenType.GTGTGT, JavaTokenType.GTGT, JavaTokenType.LTLT -> 7 - else -> 6 /* simple name */ - } - -// override val priority: Int -// get() = when (token.psiToken) { -// JavaTokenType.ASTERISK, JavaTokenType.DIV, JavaTokenType.PERC -> 12 -// JavaTokenType.PLUS, JavaTokenType.MINUS -> 11 -// JavaTokenType.GTGTGT, JavaTokenType.GTGT, JavaTokenType.LTLT -> 10 -// JavaTokenType.GT, JavaTokenType.LT, JavaTokenType.GE, JavaTokenType.LE -> 9 -// JavaTokenType.EQEQ, JavaTokenType.NE, KtTokens.EQEQEQ, KtTokens.EXCLEQEQEQ -> -// } - - companion object { - val tokenToOperator = - (OPERATION_BIT_SET.types + arrayOf(KtTokens.EQEQEQ, KtTokens.EXCLEQEQEQ)) - .associate { - it to JKJavaOperatorImpl(it) - } - } + get() = error("Java token should not be printed, it should be replaces with corresponding Kotlin one") } sealed class JKJavaQualifierImpl : JKQualifier { @@ -342,13 +226,13 @@ class JKJavaPolyadicExpressionImpl(operands: List, override var to } class JKJavaAssignmentExpressionImpl( - field: JKAssignableExpression, + field: JKExpression, expression: JKExpression, override var operator: JKOperator ) : JKBranchElementBase(), JKJavaAssignmentExpression, PsiOwner by PsiOwnerImpl() { override fun accept(visitor: JKVisitor) = visitor.visitJavaAssignmentExpression(this) - override var field: JKAssignableExpression by child(field) - override var expression: JKExpression by child(expression) + override var field by child(field) + override var expression by child(expression) } class JKJavaSwitchStatementImpl( diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/kotlinElements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/kotlinElements.kt index 7f205521b9c..841741a341f 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/kotlinElements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/impl/kotlinElements.kt @@ -104,64 +104,51 @@ class JKKtLiteralExpressionImpl( } class JKKtSingleValueOperatorToken(val psiToken: KtSingleValueToken) : JKKtOperatorToken { - override val operatorName: String - get() = OperatorConventions.getNameForOperationSymbol(psiToken, true, true)?.identifier - ?: OperatorConventions.BOOLEAN_OPERATIONS[psiToken]?.identifier - ?: TODO(psiToken.value) override val text: String = psiToken.value } object JKKtSpreadOperatorToken : JKKtOperatorToken { override val text: String = "*" - override val operatorName: String = "*" } -object JKKtSpreadOperator : JKOperator { +class JKKtSpreadOperator(override val returnType: JKType) : JKOperator { override val token: JKOperatorToken = JKKtSpreadOperatorToken - override val precedence: Int - get() = TODO() } -class JKKtWordOperatorToken(override val text: String) : JKKtOperatorToken { - override val operatorName: String = text +class JKKtWordOperatorToken(override val text: String) : JKKtOperatorToken + +class JKKtOperatorImpl(override val token: JKOperatorToken, override val returnType: JKType) : JKOperator + +class JKAssignmentChainAlsoLinkImpl( + receiver: JKExpression, + assignmentStatement: JKKtAssignmentStatement, + field: JKExpression +) : JKAssignmentChainAlsoLink, JKBranchElementBase() { + override val receiver by child(receiver) + override val assignmentStatement by child(assignmentStatement) + override val field by child(field) + + override fun accept(visitor: JKVisitor) = visitor.visitAssignmentChainAlsoLink(this) } -class JKKtOperatorImpl(override val token: JKKtOperatorToken, val returnType: JKType) : JKOperator, JKElementBase() { - constructor(singleValueToken: KtSingleValueToken, returnType: JKType) : this( - JKKtSingleValueOperatorToken(singleValueToken), - returnType - ) +class JKAssignmentChainLetLinkImpl( + receiver: JKExpression, + assignmentStatement: JKKtAssignmentStatement, + field: JKExpression +) : JKAssignmentChainLetLink, JKBranchElementBase() { + override val receiver by child(receiver) + override val assignmentStatement by child(assignmentStatement) + override val field by child(field) - override val precedence: Int - get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. -} - - -class JKKtAlsoCallExpressionImpl( - statement: JKStatement, - override val identifier: JKMethodSymbol, - typeArgumentList: JKTypeArgumentList = JKTypeArgumentListImpl() -) : JKKtAlsoCallExpression, JKBranchElementBase() { - override fun accept(visitor: JKVisitor) = visitor.visitKtAlsoCallExpression(this) - override var statement - get() = arguments.arguments.first().value.cast().statement - set(it) { - arguments.arguments.first().value.cast().statement = it - } - override var arguments: JKArgumentList by child( - JKArgumentListImpl( - JKLambdaExpressionImpl(statement, emptyList()) - ) - ) - override var typeArgumentList: JKTypeArgumentList by child(typeArgumentList) + override fun accept(visitor: JKVisitor) = visitor.visitAssignmentChainLetLink(this) } class JKKtAssignmentStatementImpl( - field: JKAssignableExpression, + field: JKExpression, expression: JKExpression, - override var operator: JKOperator + override var token: JKOperatorToken ) : JKKtAssignmentStatement() { - override var field: JKAssignableExpression by child(field) + override var field: JKExpression by child(field) override var expression by child(expression) override fun accept(visitor: JKVisitor) = visitor.visitKtAssignmentStatement(this) @@ -320,4 +307,8 @@ class JKKtEmptyGetterOrSetterImpl : JKKtEmptyGetterOrSetter, JKBranchElementBase override var visibilityElement by child(JKVisibilityModifierElementImpl(Visibility.PUBLIC)) override fun accept(visitor: JKVisitor) = visitor.visitKtEmptyGetterOrSetter(this) +} + +class JKKtItExpressionImpl(override val type: JKType) : JKKtItExpression, JKBranchElementBase() { + override fun accept(visitor: JKVisitor) = visitor.visitKtItExpression(this) } \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaAndKotlinElements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaAndKotlinElements.kt index 76bcf510e4c..bbcd2d8f366 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaAndKotlinElements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaAndKotlinElements.kt @@ -290,7 +290,7 @@ interface JKMethodReferenceExpression : JKExpression, PsiOwner { } abstract class JKExpressionStatement : JKStatement() { - abstract val expression: JKExpression + abstract var expression: JKExpression } abstract class JKDeclarationStatement : JKStatement() { @@ -315,7 +315,7 @@ interface JKPrefixExpression : JKUnaryExpression interface JKPostfixExpression : JKUnaryExpression -interface JKQualifiedExpression : JKExpression, JKAssignableExpression { +interface JKQualifiedExpression : JKExpression { var receiver: JKExpression var operator: JKQualifier var selector: JKExpression @@ -334,11 +334,11 @@ interface JKMethodCallExpression : JKExpression, JKTypeArgumentListOwner, JKBran var arguments: JKArgumentList } -interface JKFieldAccessExpression : JKAssignableExpression { +interface JKFieldAccessExpression : JKExpression { val identifier: JKFieldSymbol } -interface JKPackageAccessExpression : JKAssignableExpression { +interface JKPackageAccessExpression : JKExpression { val identifier: JKPackageSymbol } @@ -346,7 +346,7 @@ interface JKClassAccessExpression : JKExpression { val identifier: JKClassSymbol } -interface JKArrayAccessExpression : JKAssignableExpression { +interface JKArrayAccessExpression : JKExpression { var expression: JKExpression var indexExpression: JKExpression } @@ -447,8 +447,6 @@ interface JKIfElseExpression : JKExpression { var elseBranch: JKExpression } -interface JKAssignableExpression : JKExpression - interface JKLambdaExpression : JKExpression { var parameters: List val returnType: JKTypeElement diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaElements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaElements.kt index ab5f15456ed..b6927db7122 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaElements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/javaElements.kt @@ -95,7 +95,7 @@ interface JKJavaPolyadicExpression : JKExpression { } interface JKJavaAssignmentExpression : JKExpression, JKBranchElement { - var field: JKAssignableExpression + var field: JKExpression var expression: JKExpression var operator: JKOperator } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/kotlinElements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/kotlinElements.kt index c2d8f7c2215..b1a94178430 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/kotlinElements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/kotlinElements.kt @@ -42,19 +42,24 @@ abstract class JKKtConstructor : JKMethod(), JKOtherModifiersOwner { abstract class JKKtPrimaryConstructor : JKKtConstructor() abstract class JKKtAssignmentStatement : JKStatement() { - abstract var field: JKAssignableExpression + abstract var field: JKExpression abstract var expression: JKExpression - abstract var operator: JKOperator + abstract var token: JKOperatorToken } interface JKKtCall : JKMethodCallExpression interface JKKtMethodCallExpression : JKMethodCallExpression -interface JKKtAlsoCallExpression : JKKtMethodCallExpression { - var statement: JKStatement +interface JKKtAssignmentChainLink : JKExpression { + val receiver: JKExpression + val assignmentStatement: JKKtAssignmentStatement + val field: JKExpression } +interface JKAssignmentChainAlsoLink : JKKtAssignmentChainLink +interface JKAssignmentChainLetLink : JKKtAssignmentChainLink + interface JKKtLiteralExpression : JKLiteralExpression abstract class JKKtWhenStatement : JKStatement() { @@ -108,4 +113,8 @@ interface JKKtTryCatchSection : JKTreeElement { interface JKKtAnnotationArrayInitializerExpression : JKExpression, JKBranchElement { val initializers: List +} + +interface JKKtItExpression : JKExpression { + val type: JKType } \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/tokensElements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/tokensElements.kt index ea802ef361f..99eb2091dab 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/tokensElements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/tokensElements.kt @@ -53,6 +53,14 @@ fun JKTreeElement.commentsFromInside(): List { inline fun T.withNonCodeElementsFrom(other: JKNonCodeElementsListOwner): T = also { it.takeNonCodeElementsFrom(other) } +inline fun List.withNonCodeElementsFrom(other: JKNonCodeElementsListOwner): List = + also { + if (isNotEmpty()) { + it.first().leftNonCodeElements += other.leftNonCodeElements + it.last().rightNonCodeElements += other.rightNonCodeElements + } + } + fun JKNonCodeElementsListOwner.clearNonCodeElements() { leftNonCodeElements = emptyList() rightNonCodeElements = emptyList() diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/typesUtils.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/typesUtils.kt index f7a20c67494..ffd565c9058 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/typesUtils.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/typesUtils.kt @@ -11,16 +11,11 @@ import com.intellij.psi.PsiClassType import com.intellij.psi.PsiType import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.j2k.ast.Nullability import org.jetbrains.kotlin.nj2k.JKSymbolProvider import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol -import org.jetbrains.kotlin.nj2k.symbols.JKMultiverseClassSymbol -import org.jetbrains.kotlin.nj2k.symbols.JKMultiverseKtClassSymbol -import org.jetbrains.kotlin.nj2k.symbols.JKUniverseClassSymbol import org.jetbrains.kotlin.nj2k.tree.impl.* import org.jetbrains.kotlin.nj2k.types.* import org.jetbrains.kotlin.psi.KtClass @@ -28,8 +23,6 @@ import org.jetbrains.kotlin.psi.KtTypeReference import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.utils.addToStdlib.safeAs fun JKExpression.type(typeFactory: JKTypeFactory): JKType? = @@ -73,6 +66,10 @@ fun JKExpression.type(typeFactory: JKTypeFactory): JKType? = is JKLabeledStatement -> statement.safeAs()?.expression?.type(typeFactory) is JKMethodReferenceExpression -> JKNoTypeImpl //TODO + is JKAssignmentChainAlsoLink -> receiver.type(typeFactory) + is JKAssignmentChainLetLink -> field.type(typeFactory) + is JKKtAssignmentStatement -> typeFactory.types.unit + is JKKtItExpression -> type else -> TODO(this::class.java.toString()) } @@ -82,33 +79,20 @@ fun JKType.asTypeElement() = fun JKClassSymbol.asType(nullability: Nullability = Nullability.Default): JKClassType = JKClassTypeImpl(this, emptyList(), nullability) -fun JKType.isSubtypeOf(other: JKType, typeFactory: JKTypeFactory): Boolean = - other.toKtType(typeFactory) - ?.let { otherType -> this.toKtType(typeFactory)?.isSubtypeOf(otherType) } == true - - val PsiType.isKotlinFunctionalType: Boolean get() { val fqName = safeAs()?.resolve()?.getKotlinFqName() ?: return false return functionalTypeRegex.matches(fqName.asString()) } - private val functionalTypeRegex = """(kotlin\.jvm\.functions|kotlin)\.Function[\d+]""".toRegex() - fun KtTypeReference.toJK(typeFactory: JKTypeFactory): JKType? = analyze(BodyResolveMode.PARTIAL) .get(BindingContext.TYPE, this) ?.let { typeFactory.fromKotlinType(it) } -fun JKType.toKtType(typeFactory: JKTypeFactory): KotlinType? = when (this) { - is JKClassType -> classReference.toKtType() - is JKJavaPrimitiveType -> typeFactory.fromPrimitiveType(this).toKtType(typeFactory) - else -> null -} - infix fun JKJavaPrimitiveType.isStrongerThan(other: JKJavaPrimitiveType) = jvmPrimitiveTypesPriority.getValue(this.jvmPrimitiveType.primitiveType) > jvmPrimitiveTypesPriority.getValue(other.jvmPrimitiveType.primitiveType) @@ -126,21 +110,6 @@ private val jvmPrimitiveTypesPriority = ) -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() - is JKUniverseClassSymbol -> - target.psi()?.getJavaClassDescriptor()//TODO null in case of a fake package - else -> TODO(this::class.java.toString()) - } - return classDescriptor?.defaultType -} - fun JKType.applyRecursive(transform: (JKType) -> JKType?): JKType = transform(this) ?: when (this) { is JKTypeParameterTypeImpl -> this diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitor.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitor.kt index 676411321ed..a3ea556c982 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitor.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitor.kt @@ -75,7 +75,7 @@ abstract class JKVisitor { open fun visitIfStatement(ifStatement: JKIfStatement) = visitStatement(ifStatement) open fun visitIfElseStatement(ifElseStatement: JKIfElseStatement) = visitIfStatement(ifElseStatement) open fun visitIfElseExpression(ifElseExpression: JKIfElseExpression) = visitExpression(ifElseExpression) - open fun visitAssignableExpression(assignableExpression: JKAssignableExpression) = visitExpression(assignableExpression) + open fun visitAssignableExpression(assignableExpression: JKExpression) = visitExpression(assignableExpression) open fun visitLambdaExpression(lambdaExpression: JKLambdaExpression) = visitExpression(lambdaExpression) open fun visitDelegationConstructorCall(delegationConstructorCall: JKDelegationConstructorCall) = visitMethodCallExpression(delegationConstructorCall) open fun visitLabel(label: JKLabel) = visitTreeElement(label) @@ -85,7 +85,7 @@ abstract class JKVisitor { open fun visitLabeledStatement(labeledStatement: JKLabeledStatement) = visitExpression(labeledStatement) open fun visitEmptyStatement(emptyStatement: JKEmptyStatement) = visitStatement(emptyStatement) open fun visitTypeParameterList(typeParameterList: JKTypeParameterList) = visitTreeElement(typeParameterList) - open fun visitTypeParameter(typeParameter: JKTypeParameter) = visitTreeElement(typeParameter) + open fun visitTypeParameter(typeParameter: JKTypeParameter) = visitDeclaration(typeParameter) open fun visitTypeParameterListOwner(typeParameterListOwner: JKTypeParameterListOwner) = visitTreeElement(typeParameterListOwner) open fun visitEnumConstant(enumConstant: JKEnumConstant) = visitVariable(enumConstant) open fun visitForInStatement(forInStatement: JKForInStatement) = visitStatement(forInStatement) @@ -128,7 +128,9 @@ abstract class JKVisitor { open fun visitKtAssignmentStatement(ktAssignmentStatement: JKKtAssignmentStatement) = visitStatement(ktAssignmentStatement) open fun visitKtCall(ktCall: JKKtCall) = visitMethodCallExpression(ktCall) open fun visitKtMethodCallExpression(ktMethodCallExpression: JKKtMethodCallExpression) = visitMethodCallExpression(ktMethodCallExpression) - open fun visitKtAlsoCallExpression(ktAlsoCallExpression: JKKtAlsoCallExpression) = visitKtMethodCallExpression(ktAlsoCallExpression) + open fun visitKtAssignmentChainLink(ktAssignmentChainLink: JKKtAssignmentChainLink) = visitExpression(ktAssignmentChainLink) + open fun visitAssignmentChainAlsoLink(assignmentChainAlsoLink: JKAssignmentChainAlsoLink) = visitKtAssignmentChainLink(assignmentChainAlsoLink) + open fun visitAssignmentChainLetLink(assignmentChainLetLink: JKAssignmentChainLetLink) = visitKtAssignmentChainLink(assignmentChainLetLink) open fun visitKtLiteralExpression(ktLiteralExpression: JKKtLiteralExpression) = visitLiteralExpression(ktLiteralExpression) open fun visitKtWhenStatement(ktWhenStatement: JKKtWhenStatement) = visitStatement(ktWhenStatement) open fun visitKtWhenCase(ktWhenCase: JKKtWhenCase) = visitTreeElement(ktWhenCase) @@ -142,4 +144,5 @@ abstract class JKVisitor { open fun visitKtTryExpression(ktTryExpression: JKKtTryExpression) = visitExpression(ktTryExpression) open fun visitKtTryCatchSection(ktTryCatchSection: JKKtTryCatchSection) = visitTreeElement(ktTryCatchSection) open fun visitKtAnnotationArrayInitializerExpression(ktAnnotationArrayInitializerExpression: JKKtAnnotationArrayInitializerExpression) = visitExpression(ktAnnotationArrayInitializerExpression) + open fun visitKtItExpression(ktItExpression: JKKtItExpression) = visitExpression(ktItExpression) } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitorWithCommentsPrinting.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitorWithCommentsPrinting.kt index a219e6ad6d0..d6bbfb3c952 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitorWithCommentsPrinting.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/visitors/JKVisitorWithCommentsPrinting.kt @@ -582,13 +582,13 @@ abstract class JKVisitorWithCommentsPrinting : JKVisitor() { open fun visitIfElseExpressionRaw(ifElseExpression: JKIfElseExpression) = visitExpressionRaw(ifElseExpression) - override fun visitAssignableExpression(assignableExpression: JKAssignableExpression) { + override fun visitAssignableExpression(assignableExpression: JKExpression) { printLeftNonCodeElements(assignableExpression) visitAssignableExpressionRaw(assignableExpression) printRightNonCodeElements(assignableExpression) } - open fun visitAssignableExpressionRaw(assignableExpression: JKAssignableExpression) = visitExpressionRaw(assignableExpression) + open fun visitAssignableExpressionRaw(assignableExpression: JKExpression) = visitExpressionRaw(assignableExpression) override fun visitLambdaExpression(lambdaExpression: JKLambdaExpression) { printLeftNonCodeElements(lambdaExpression) @@ -668,7 +668,7 @@ abstract class JKVisitorWithCommentsPrinting : JKVisitor() { printRightNonCodeElements(typeParameter) } - open fun visitTypeParameterRaw(typeParameter: JKTypeParameter) = visitTreeElementRaw(typeParameter) + open fun visitTypeParameterRaw(typeParameter: JKTypeParameter) = visitDeclarationRaw(typeParameter) override fun visitTypeParameterListOwner(typeParameterListOwner: JKTypeParameterListOwner) { printLeftNonCodeElements(typeParameterListOwner) @@ -1006,13 +1006,29 @@ abstract class JKVisitorWithCommentsPrinting : JKVisitor() { open fun visitKtMethodCallExpressionRaw(ktMethodCallExpression: JKKtMethodCallExpression) = visitMethodCallExpressionRaw(ktMethodCallExpression) - override fun visitKtAlsoCallExpression(ktAlsoCallExpression: JKKtAlsoCallExpression) { - printLeftNonCodeElements(ktAlsoCallExpression) - visitKtAlsoCallExpressionRaw(ktAlsoCallExpression) - printRightNonCodeElements(ktAlsoCallExpression) + override fun visitKtAssignmentChainLink(ktAssignmentChainLink: JKKtAssignmentChainLink) { + printLeftNonCodeElements(ktAssignmentChainLink) + visitKtAssignmentChainLinkRaw(ktAssignmentChainLink) + printRightNonCodeElements(ktAssignmentChainLink) } - open fun visitKtAlsoCallExpressionRaw(ktAlsoCallExpression: JKKtAlsoCallExpression) = visitKtMethodCallExpressionRaw(ktAlsoCallExpression) + open fun visitKtAssignmentChainLinkRaw(ktAssignmentChainLink: JKKtAssignmentChainLink) = visitExpressionRaw(ktAssignmentChainLink) + + override fun visitAssignmentChainAlsoLink(assignmentChainAlsoLink: JKAssignmentChainAlsoLink) { + printLeftNonCodeElements(assignmentChainAlsoLink) + visitAssignmentChainAlsoLinkRaw(assignmentChainAlsoLink) + printRightNonCodeElements(assignmentChainAlsoLink) + } + + open fun visitAssignmentChainAlsoLinkRaw(assignmentChainAlsoLink: JKAssignmentChainAlsoLink) = visitKtAssignmentChainLinkRaw(assignmentChainAlsoLink) + + override fun visitAssignmentChainLetLink(assignmentChainLetLink: JKAssignmentChainLetLink) { + printLeftNonCodeElements(assignmentChainLetLink) + visitAssignmentChainLetLinkRaw(assignmentChainLetLink) + printRightNonCodeElements(assignmentChainLetLink) + } + + open fun visitAssignmentChainLetLinkRaw(assignmentChainLetLink: JKAssignmentChainLetLink) = visitKtAssignmentChainLinkRaw(assignmentChainLetLink) override fun visitKtLiteralExpression(ktLiteralExpression: JKKtLiteralExpression) { printLeftNonCodeElements(ktLiteralExpression) @@ -1117,4 +1133,12 @@ abstract class JKVisitorWithCommentsPrinting : JKVisitor() { } open fun visitKtAnnotationArrayInitializerExpressionRaw(ktAnnotationArrayInitializerExpression: JKKtAnnotationArrayInitializerExpression) = visitExpressionRaw(ktAnnotationArrayInitializerExpression) + + override fun visitKtItExpression(ktItExpression: JKKtItExpression) { + printLeftNonCodeElements(ktItExpression) + visitKtItExpressionRaw(ktItExpression) + printRightNonCodeElements(ktItExpression) + } + + open fun visitKtItExpressionRaw(ktItExpression: JKKtItExpression) = visitExpressionRaw(ktItExpression) } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/types/JKTypeFactory.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/types/JKTypeFactory.kt index 41ad9fc1e44..a543d7bd08f 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/types/JKTypeFactory.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/types/JKTypeFactory.kt @@ -11,11 +11,15 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.j2k.ast.Nullability import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.nj2k.JKSymbolProvider import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol import org.jetbrains.kotlin.nj2k.symbols.JKTypeParameterSymbol import org.jetbrains.kotlin.nj2k.symbols.JKUnresolvedClassSymbol +import org.jetbrains.kotlin.nj2k.tree.JKClass +import org.jetbrains.kotlin.nj2k.tree.JKType +import org.jetbrains.kotlin.nj2k.tree.impl.* import org.jetbrains.kotlin.psi.KtTypeParameter import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.types.KotlinType diff --git a/nj2k/testData/newJ2k/assignmentExpression/assignmentsChain.java b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChain.java new file mode 100644 index 00000000000..b5dd53237ef --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChain.java @@ -0,0 +1,19 @@ +class Test { + public static void main(String[] args) { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + + a = b += c = d *= e; + //----- + a = b; + //----- + a += b; + //----- + a += b = c; + //----- + a = b += c; + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/assignmentsChain.kt b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChain.kt new file mode 100644 index 00000000000..584c996d951 --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChain.kt @@ -0,0 +1,32 @@ +internal object Test { + @JvmStatic + fun main(args: Array) { + var a = 0 + var b = 0 + var c = 0 + var d = 0 + val e = 0 + d *= e + c = d + b += c + a = b + //----- + + + a = b + //----- + + + a += b + //----- + + + b = c + a += b + //----- + + + b += c + a = b + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/assignmentsChainWithParenthesis.java b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChainWithParenthesis.java new file mode 100644 index 00000000000..e9ed730c5a3 --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChainWithParenthesis.java @@ -0,0 +1,19 @@ +class Test { + public static void main(String[] args) { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + + a = b += (c) = ((d *= e)); + //----- + a = (((b))); + //----- + a += (b); + //----- + a += b = (c); + //----- + a = ((b) += (c)); + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/assignmentsChainWithParenthesis.kt b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChainWithParenthesis.kt new file mode 100644 index 00000000000..55d993a5822 --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/assignmentsChainWithParenthesis.kt @@ -0,0 +1,30 @@ +internal object Test { + @JvmStatic + fun main(args: Array) { + var a = 0 + var b = 0 + var c = 0 + var d = 0 + val e = 0 + c = e.let { d *= it; d } + b += c + a = b + //----- + + + a = b + //----- + + + a += b + //----- + + + b = c + a += b + //----- + + + a = c.let { b += it; b } + } +} diff --git a/nj2k/testData/newJ2k/assignmentExpression/bitOperationPriorityComments.kt b/nj2k/testData/newJ2k/assignmentExpression/bitOperationPriorityComments.kt index 93e179fdaed..75eb4bea6bd 100644 --- a/nj2k/testData/newJ2k/assignmentExpression/bitOperationPriorityComments.kt +++ b/nj2k/testData/newJ2k/assignmentExpression/bitOperationPriorityComments.kt @@ -1 +1 @@ -5 /*operand '5'*/ shl /*left shift*/ 16 /*operand '16'*/ or (/*or*/ 1 /*operand '1'*/ shr /*right shift*/ 8 /*operand '8'*/) or /*or*/ 0 /*operand '0'*/ /*post comment*/ \ No newline at end of file +/*pre*/ 5 /*operand '5'*/ shl /*left shift*/ 16 /*operand '16'*/ or (/*or*/ 1 /*operand '1'*/ shr /*right shift*/ 8 /*operand '8'*/) or /*or*/ 0 /*operand '0'*/ /*post comment*/ \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/declarationAssignmentsChain.java b/nj2k/testData/newJ2k/assignmentExpression/declarationAssignmentsChain.java new file mode 100644 index 00000000000..af28d827823 --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/declarationAssignmentsChain.java @@ -0,0 +1,19 @@ +class Test { + public static void main(String[] args) { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + int e = 0; + //----- + int f = a = b += c = d *= e; + //----- + int g = a; + //----- + int h = a = b; + //----- + int i = a += b; + //----- + int j = a += b = c; + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/declarationAssignmentsChain.kt b/nj2k/testData/newJ2k/assignmentExpression/declarationAssignmentsChain.kt new file mode 100644 index 00000000000..8286302a29b --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/declarationAssignmentsChain.kt @@ -0,0 +1,35 @@ +internal object Test { + @JvmStatic + fun main(args: Array) { + var a = 0 + var b = 0 + var c = 0 + var d = 0 + val e = 0 + //----- + + d *= e + c = d + b += c + a = b + val f = a +//----- + val g = a + //----- + + + a = b + val h = a + //----- + + + a += b + val i = a + //----- + + + b = c + a += b + val j = a + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/expressionAssignmentWithParentheses.java b/nj2k/testData/newJ2k/assignmentExpression/expressionAssignmentWithParentheses.java new file mode 100644 index 00000000000..44e18f90581 --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/expressionAssignmentWithParentheses.java @@ -0,0 +1,14 @@ +class Test { + public static void main(String[] args) { + boolean a = true; + boolean b = true; + boolean c = true; + boolean d = true; + boolean e = true; + + if (a = b |= (c) = ((d &= e))) ; + while ((((((a = b)))))) ; + do { + } while ((((a) ^= (b)))); + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/expressionAssignmentWithParentheses.kt b/nj2k/testData/newJ2k/assignmentExpression/expressionAssignmentWithParentheses.kt new file mode 100644 index 00000000000..f028359de2f --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/expressionAssignmentWithParentheses.kt @@ -0,0 +1,14 @@ +internal object Test { + @JvmStatic + fun main(args: Array) { + var a = true + var b = true + var c = true + var d = true + val e = true + if (e.let { d = d and it; d }.also { c = it }.let { b = b or it; b }.also { a = it }); + while (b.also { a = it }); + do { + } while (b.let { a = a xor it; a }) + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/inExpressionAssignmentsChain.java b/nj2k/testData/newJ2k/assignmentExpression/inExpressionAssignmentsChain.java new file mode 100644 index 00000000000..a1b0436bb42 --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/inExpressionAssignmentsChain.java @@ -0,0 +1,15 @@ +class Test { + public static void main(String[] args) { + boolean a = true; + boolean b = true; + boolean c = true; + boolean d = true; + boolean e = true; + + if (a = b |= c = d &= e) ; + while (a = b) ; + do {} while (a ^= b); + System.out.println(a &= b = c); + System.out.println(a = b != c); + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/assignmentExpression/inExpressionAssignmentsChain.kt b/nj2k/testData/newJ2k/assignmentExpression/inExpressionAssignmentsChain.kt new file mode 100644 index 00000000000..1b6b7a3c007 --- /dev/null +++ b/nj2k/testData/newJ2k/assignmentExpression/inExpressionAssignmentsChain.kt @@ -0,0 +1,16 @@ +internal object Test { + @JvmStatic + fun main(args: Array) { + var a = true + var b = true + var c = true + var d = true + val e = true + if (e.let { d = d and it; d }.also { c = it }.let { b = b or it; b }.also { a = it }); + while (b.also { a = it }); + do { + } while (b.let { a = a xor it; a }) + println(c.also { b = it }.let { a = a and it; a }) + println(b != c.also { a = it }) + } +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/detectProperties/commentInInitStatement.kt b/nj2k/testData/newJ2k/detectProperties/commentInInitStatement.kt index 0b2475198d5..02bf732d5a5 100644 --- a/nj2k/testData/newJ2k/detectProperties/commentInInitStatement.kt +++ b/nj2k/testData/newJ2k/detectProperties/commentInInitStatement.kt @@ -1 +1,3 @@ -class Nya /*comment before*/(/*1*//*3*/ /*4*/private val i: Int) +class Nya /*comment before*/ +/* comment after*/ // and after again +(/*1*//*3*/ /*4*/private val i: Int) \ No newline at end of file diff --git a/nj2k/testData/newJ2k/issues/kt-19327.kt b/nj2k/testData/newJ2k/issues/kt-19327.kt index ec03905bffd..04084d4925c 100644 --- a/nj2k/testData/newJ2k/issues/kt-19327.kt +++ b/nj2k/testData/newJ2k/issues/kt-19327.kt @@ -2,6 +2,6 @@ import java.util.stream.Collectors internal class JavaCode { fun toJSON(collection: Collection): String { - return "[" + collection.stream().map { obj: Int -> obj.toString() }.collect(Collectors.joining(", ")).toString() + "]" + return "[" + collection.stream().map { obj: Int -> obj.toString() }.collect(Collectors.joining(", ")) + "]" } } \ No newline at end of file diff --git a/nj2k/testData/newJ2k/literalExpression/charToString.kt b/nj2k/testData/newJ2k/literalExpression/charToString.kt index 951b0c127c8..bd299968fbf 100644 --- a/nj2k/testData/newJ2k/literalExpression/charToString.kt +++ b/nj2k/testData/newJ2k/literalExpression/charToString.kt @@ -1,6 +1,5 @@ class CharToString { private val value: String? = null - fun test(): String { return '"'.toString() + value + '"' } diff --git a/nj2k/testData/newJ2k/mutableCollections/implementMutableIterator.java b/nj2k/testData/newJ2k/mutableCollections/implementMutableIterator.java deleted file mode 100644 index 07e7a5c7ed8..00000000000 --- a/nj2k/testData/newJ2k/mutableCollections/implementMutableIterator.java +++ /dev/null @@ -1,17 +0,0 @@ -import java.util.Iterator; - -public class TestMutableIterator implements Iterator { - @Override - public boolean hasNext() { - return false; - } - - @Override - public String next() { - return null; - } - - @Override - public void remove() { - } -} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt b/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt index 14c3802c195..d0eb8e6b025 100644 --- a/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt +++ b/nj2k/testData/newJ2k/mutableCollections/listOfMutableList.kt @@ -1,7 +1,7 @@ import java.util.ArrayList class Test { - internal var list: List> = ArrayList() + internal var list: List> = ArrayList() fun test() { list[0].add(1) } diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java index 3363095fcca..b0d2e62ace1 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java @@ -412,6 +412,16 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew runTest("nj2k/testData/newJ2k/assignmentExpression/assignmentAsExpression.java"); } + @TestMetadata("assignmentsChain.java") + public void testAssignmentsChain() throws Exception { + runTest("nj2k/testData/newJ2k/assignmentExpression/assignmentsChain.java"); + } + + @TestMetadata("assignmentsChainWithParenthesis.java") + public void testAssignmentsChainWithParenthesis() throws Exception { + runTest("nj2k/testData/newJ2k/assignmentExpression/assignmentsChainWithParenthesis.java"); + } + @TestMetadata("bitOperationPriority.java") public void testBitOperationPriority() throws Exception { runTest("nj2k/testData/newJ2k/assignmentExpression/bitOperationPriority.java"); @@ -422,11 +432,26 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew runTest("nj2k/testData/newJ2k/assignmentExpression/bitOperationPriorityComments.java"); } + @TestMetadata("declarationAssignmentsChain.java") + public void testDeclarationAssignmentsChain() throws Exception { + runTest("nj2k/testData/newJ2k/assignmentExpression/declarationAssignmentsChain.java"); + } + @TestMetadata("divideAssign.java") public void testDivideAssign() throws Exception { runTest("nj2k/testData/newJ2k/assignmentExpression/divideAssign.java"); } + @TestMetadata("expressionAssignmentWithParentheses.java") + public void testExpressionAssignmentWithParentheses() throws Exception { + runTest("nj2k/testData/newJ2k/assignmentExpression/expressionAssignmentWithParentheses.java"); + } + + @TestMetadata("inExpressionAssignmentsChain.java") + public void testInExpressionAssignmentsChain() throws Exception { + runTest("nj2k/testData/newJ2k/assignmentExpression/inExpressionAssignmentsChain.java"); + } + @TestMetadata("minusAssign.java") public void testMinusAssign() throws Exception { runTest("nj2k/testData/newJ2k/assignmentExpression/minusAssign.java");