New J2K: do not recalculate types for binary & unary expressions and rewrite assignment expressions conversion

#KT-33679 fixed
This commit is contained in:
Ilya Kirillov
2019-09-05 19:40:15 +03:00
parent c93d810685
commit dca0dc1933
45 changed files with 775 additions and 889 deletions
@@ -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),
@@ -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
@@ -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)
@@ -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<JKBlockStatement>().block.statements.first().cast<JKKtAssignmentStatement>().expression =
JKFieldAccessExpressionImpl(
symbolProvider.provideUniverseSymbol(
JKParameterImpl(JKTypeElementImpl(JKContextType), JKNameIdentifierImpl("it"))
)
)//TODO introduce symbol
}
return recurse(
JKQualifiedExpressionImpl(
element.expression,
JKKtQualifierImpl.DOT,
alsoExpression
)
)
}
}
@@ -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<JKStatement>()
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<JKVariable>()?.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<JKStatement> {
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
)
}
}
@@ -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] }
}
@@ -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
}
}
}
@@ -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() }
}
}
@@ -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<JKStatement>? {
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)
)
}
}
@@ -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)
}
}
@@ -366,11 +366,10 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
if (expression !is JKMethodCallExpression) error("Expression should be JKMethodCallExpression")
val firstArgument = expression.parent.cast<JKQualifiedExpression>()::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<JKArgument> = emptyList()) =
private fun JKExpression. callOn(symbol: JKMethodSymbol, arguments: List<JKArgument> = 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<JKQualifiedExpression>()
@@ -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
)
)
}
@@ -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)
}
}
@@ -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<JKExpression>, operators: List<JKOperator>): 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)
}
}
}
@@ -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<JKInheritanceInfo>() != 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 <reified T : JKType> 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)
}
}
+26 -148
View File
@@ -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<KtNamedFunction>()
.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<PsiClass>()?.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<JKDeclaration>): JKClass =
@@ -438,4 +301,19 @@ fun <T : JKExpression> T.nullIfStubExpression(): T? =
fun JKExpression.qualified(qualifier: JKExpression?) =
if (qualifier != null && qualifier !is JKStubExpression) {
JKQualifiedExpressionImpl(qualifier, JKJavaQualifierImpl.DOT, this)
} else this
} else this
fun JKExpression.callOn(
symbol: JKMethodSymbol,
arguments: List<JKExpression> = emptyList(),
typeArguments: List<JKTypeElement> = emptyList()
) = JKQualifiedExpressionImpl(
this,
JKKtQualifierImpl.DOT,
JKKtCallExpressionImpl(
symbol,
JKArgumentListImpl(arguments.map { JKArgumentImpl(it) }),
JKTypeArgumentListImpl(typeArguments)
)
)
+103 -5
View File
@@ -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<IElementType, JKOperatorToken> = 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 {
@@ -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<JKDeclaration>) : JKDeclarationStatement(),
@@ -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<JKExpression>, 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(
@@ -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<JKLambdaExpressionImpl>().statement
set(it) {
arguments.arguments.first().value.cast<JKLambdaExpressionImpl>().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)
}
@@ -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<JKParameter>
val returnType: JKTypeElement
@@ -95,7 +95,7 @@ interface JKJavaPolyadicExpression : JKExpression {
}
interface JKJavaAssignmentExpression : JKExpression, JKBranchElement {
var field: JKAssignableExpression
var field: JKExpression
var expression: JKExpression
var operator: JKOperator
}
@@ -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<JKAnnotationMemberValue>
}
interface JKKtItExpression : JKExpression {
val type: JKType
}
@@ -53,6 +53,14 @@ fun JKTreeElement.commentsFromInside(): List<JKCommentElement> {
inline fun <reified T : JKNonCodeElementsListOwner> T.withNonCodeElementsFrom(other: JKNonCodeElementsListOwner): T =
also { it.takeNonCodeElementsFrom(other) }
inline fun <reified T : JKNonCodeElementsListOwner> List<T>.withNonCodeElementsFrom(other: JKNonCodeElementsListOwner): List<T> =
also {
if (isNotEmpty()) {
it.first().leftNonCodeElements += other.leftNonCodeElements
it.last().rightNonCodeElements += other.rightNonCodeElements
}
}
fun JKNonCodeElementsListOwner.clearNonCodeElements() {
leftNonCodeElements = emptyList()
rightNonCodeElements = emptyList()
@@ -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<JKExpressionStatement>()?.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<PsiClassType>()?.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<PsiClass>()?.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
@@ -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)
}
@@ -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)
}
@@ -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
@@ -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;
}
}
@@ -0,0 +1,32 @@
internal object Test {
@JvmStatic
fun main(args: Array<String>) {
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
}
}
@@ -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));
}
}
@@ -0,0 +1,30 @@
internal object Test {
@JvmStatic
fun main(args: Array<String>) {
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 }
}
}
@@ -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*/
/*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*/
@@ -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;
}
}
@@ -0,0 +1,35 @@
internal object Test {
@JvmStatic
fun main(args: Array<String>) {
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
}
}
@@ -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))));
}
}
@@ -0,0 +1,14 @@
internal object Test {
@JvmStatic
fun main(args: Array<String>) {
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 })
}
}
@@ -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);
}
}
@@ -0,0 +1,16 @@
internal object Test {
@JvmStatic
fun main(args: Array<String>) {
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 })
}
}
@@ -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)
+1 -1
View File
@@ -2,6 +2,6 @@ import java.util.stream.Collectors
internal class JavaCode {
fun toJSON(collection: Collection<Int>): String {
return "[" + collection.stream().map { obj: Int -> obj.toString() }.collect(Collectors.joining(", ")).toString() + "]"
return "[" + collection.stream().map { obj: Int -> obj.toString() }.collect(Collectors.joining(", ")) + "]"
}
}
@@ -1,6 +1,5 @@
class CharToString {
private val value: String? = null
fun test(): String {
return '"'.toString() + value + '"'
}
@@ -1,17 +0,0 @@
import java.util.Iterator;
public class TestMutableIterator implements Iterator<String> {
@Override
public boolean hasNext() {
return false;
}
@Override
public String next() {
return null;
}
@Override
public void remove() {
}
}
@@ -1,7 +1,7 @@
import java.util.ArrayList
class Test {
internal var list: List<List<Int>> = ArrayList()
internal var list: List<MutableList<Int>> = ArrayList()
fun test() {
list[0].add(1)
}
@@ -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");