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), FunctionAsAnonymousObjectToLambdaConversion(context),
ReturnStatementInLambdaExpressionConversion(context), ReturnStatementInLambdaExpressionConversion(context),
BoxedTypeOperationsConversion(context), BoxedTypeOperationsConversion(context),
AssignmentAsExpressionToAlsoConversion(context), AnyWithStringConcatenationConversion(context),
AssignmentStatementValCreationConversion(context), AssignmentExpressionUnfoldingConversion(context),
AssignmentStatementOperatorConversion(context),
AssignmentStatementSimplifyValConversion(context),
AssignmentStatementSimplifyAlsoConversion(context),
AssignmentStatementSplitAlsoConversion(context),
PolyadicExpressionConversion(context),
OperatorExpressionConversion(context),
AddParenthesisForLineBreaksInBinaryExpression(context), AddParenthesisForLineBreaksInBinaryExpression(context),
ThrowStatementConversion(context), ThrowStatementConversion(context),
ArrayInitializerConversion(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.JavaTokenType.THIS_KEYWORD
import com.intellij.psi.impl.source.tree.ChildRole import com.intellij.psi.impl.source.tree.ChildRole
import com.intellij.psi.impl.source.tree.CompositeElement 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.PsiClassObjectAccessExpressionImpl
import com.intellij.psi.impl.source.tree.java.PsiLabeledStatementImpl import com.intellij.psi.impl.source.tree.java.PsiLabeledStatementImpl
import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl
@@ -138,14 +139,17 @@ class JavaToJKTreeBuilder constructor(
is PsiConditionalExpression -> JKIfElseExpressionImpl( is PsiConditionalExpression -> JKIfElseExpressionImpl(
condition.toJK(), thenExpression.toJK(), elseExpression.toJK() condition.toJK(), thenExpression.toJK(), elseExpression.toJK()
) )
is PsiPolyadicExpression -> JKJavaPolyadicExpressionImpl( is PsiPolyadicExpression -> {
operands.map { it.toJK() }, val token = JKOperatorToken.fromElementType(operationTokenType)
Array(operands.lastIndex) { index -> val type = type?.toJK() ?: typeFactory.types.nullableAny
getTokenBeforeOperand(operands[index + 1]) val jkOperands = operands.map { it.toJK().parenthesizeIfBinaryExpression() }
}.map { jkOperands.reduce { acc, operand ->
it?.tokenType?.toJK() ?: throwCanNotConvertError() JKBinaryExpressionImpl(acc, operand, JKKtOperatorImpl(token, type))
}.let { folded ->
if (jkOperands.any { it.containsNewLine() }) folded.parenthesize()
else folded
} }
) }
is PsiArrayInitializerExpression -> toJK() is PsiArrayInitializerExpression -> toJK()
is PsiLambdaExpression -> toJK() is PsiLambdaExpression -> toJK()
is PsiClassObjectAccessExpressionImpl -> toJK() is PsiClassObjectAccessExpressionImpl -> toJK()
@@ -180,9 +184,9 @@ class JavaToJKTreeBuilder constructor(
fun PsiAssignmentExpression.toJK(): JKJavaAssignmentExpression { fun PsiAssignmentExpression.toJK(): JKJavaAssignmentExpression {
return JKJavaAssignmentExpressionImpl( return JKJavaAssignmentExpressionImpl(
lExpression.toJK() as JKAssignableExpression, lExpression.toJK(),
rExpression.toJK(), rExpression.toJK(),
operationSign.tokenType.toJK() createOperator(operationSign.tokenType, type)
).also { ).also {
it.assignNonCodeElements(this) it.assignNonCodeElements(this)
} }
@@ -192,16 +196,22 @@ class JavaToJKTreeBuilder constructor(
val token = when (operationSign.tokenType) { val token = when (operationSign.tokenType) {
JavaTokenType.EQEQ, JavaTokenType.NE -> JavaTokenType.EQEQ, JavaTokenType.NE ->
when { when {
canKeepEqEq(lOperand, rOperand) -> operationSign.tokenType canKeepEqEq(lOperand, rOperand) -> JKOperatorToken.fromElementType(operationSign.tokenType)
operationSign.tokenType == JavaTokenType.EQEQ -> KtTokens.EQEQEQ operationSign.tokenType == JavaTokenType.EQEQ -> JKOperatorToken.fromElementType(KtTokens.EQEQEQ)
else -> KtTokens.EXCLEQEQEQ 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 { 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 { fun PsiPrefixExpression.toJK(): JKExpression = when (operationSign.tokenType) {
return JKPrefixExpressionImpl(operand.toJK(), operationSign.tokenType.toJK()).also { JavaTokenType.TILDE -> operand.toJK().callOn(symbolProvider.provideMethodSymbol("kotlin.Int.inv"))
it.assignNonCodeElements(this) else -> JKPrefixExpressionImpl(operand.toJK(), createOperator(operationSign.tokenType, type))
} }.also {
it.assignNonCodeElements(this)
} }
fun PsiPostfixExpression.toJK(): JKExpression { fun PsiPostfixExpression.toJK(): JKExpression =
return JKPostfixExpressionImpl(operand.toJK(), operationSign.tokenType.toJK()).also { JKPostfixExpressionImpl(operand.toJK(), createOperator(operationSign.tokenType, type)).also {
it.assignNonCodeElements(this) it.assignNonCodeElements(this)
} }
}
fun PsiLambdaExpression.toJK(): JKExpression { fun PsiLambdaExpression.toJK(): JKExpression {
return JKLambdaExpressionImpl( return JKLambdaExpressionImpl(
@@ -326,7 +340,7 @@ class JavaToJKTreeBuilder constructor(
propertyAccessExpression propertyAccessExpression
) )
else propertyAccessExpression else propertyAccessExpression
} else propertyAccessExpression.qualified(qualifier) as JKAssignableExpression } else propertyAccessExpression.qualified(qualifier) as JKExpression
when (if (isExtension) parameterCount - 1 else parameterCount) { when (if (isExtension) parameterCount - 1 else parameterCount) {
0 /* getter */ -> 0 /* getter */ ->
@@ -337,7 +351,7 @@ class JavaToJKTreeBuilder constructor(
JKJavaAssignmentExpressionImpl( JKJavaAssignmentExpressionImpl(
propertyAccess, propertyAccess,
argument, argument,
JKJavaOperatorImpl.tokenToOperator[JavaTokenType.EQ]!! createOperator(JavaTokenType.EQ, type)//TODO correct type
) )
} }
else -> throwCanNotConvertError("expected getter or setter call") else -> throwCanNotConvertError("expected getter or setter call")
@@ -513,14 +527,15 @@ class JavaToJKTreeBuilder constructor(
val jkExpressions = expressions.map { it.toJK() } val jkExpressions = expressions.map { it.toJK() }
return ((parent as? PsiCall)?.resolveMethod() return ((parent as? PsiCall)?.resolveMethod()
?.let { method -> ?.let { method ->
val lastExpressionType = expressions.lastOrNull()?.type
if (jkExpressions.size == method.parameterList.parameters.size if (jkExpressions.size == method.parameterList.parameters.size
&& method.parameterList.parameters.getOrNull(jkExpressions.lastIndex)?.isVarArgs == true && method.parameterList.parameters.getOrNull(jkExpressions.lastIndex)?.isVarArgs == true
&& expressions.lastOrNull()?.type is PsiArrayType && lastExpressionType is PsiArrayType
) { ) {
val staredExpression = val staredExpression =
JKPrefixExpressionImpl( JKPrefixExpressionImpl(
jkExpressions.last(), jkExpressions.last(),
JKKtSpreadOperator JKKtSpreadOperator(lastExpressionType.toJK())
).withNonCodeElementsFrom(jkExpressions.last()) ).withNonCodeElementsFrom(jkExpressions.last())
jkExpressions.dropLast(1) + staredExpression jkExpressions.dropLast(1) + staredExpression
} else jkExpressions } else jkExpressions
@@ -659,6 +659,9 @@ class NewCodeBuilder(context: NewJ2kConverterContext) {
} }
} }
override fun visitKtItExpressionRaw(ktItExpression: JKKtItExpression) {
printer.printWithNoIndent("it")
}
override fun visitClassBodyRaw(classBody: JKClassBody) { override fun visitClassBodyRaw(classBody: JKClassBody) {
val declarationsToPrint = classBody.declarations.filterNot { it is JKKtPrimaryConstructor } val declarationsToPrint = classBody.declarations.filterNot { it is JKKtPrimaryConstructor }
@@ -818,11 +821,27 @@ class NewCodeBuilder(context: NewJ2kConverterContext) {
override fun visitKtAssignmentStatementRaw(ktAssignmentStatement: JKKtAssignmentStatement) { override fun visitKtAssignmentStatementRaw(ktAssignmentStatement: JKKtAssignmentStatement) {
ktAssignmentStatement.field.accept(this) ktAssignmentStatement.field.accept(this)
printer.printWithNoIndent(" ") printer.printWithNoIndent(" ")
printer.printWithNoIndent(ktAssignmentStatement.operator.token.text) printer.printWithNoIndent(ktAssignmentStatement.token.text)
printer.printWithNoIndent(" ") printer.printWithNoIndent(" ")
ktAssignmentStatement.expression.accept(this) 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) { override fun visitKtWhenStatementRaw(ktWhenStatement: JKKtWhenStatement) {
printer.printWithNoIndent("when(") printer.printWithNoIndent("when(")
ktWhenStatement.expression.accept(this) 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") if (expression !is JKMethodCallExpression) error("Expression should be JKMethodCallExpression")
val firstArgument = expression.parent.cast<JKQualifiedExpression>()::receiver.detached() val firstArgument = expression.parent.cast<JKQualifiedExpression>()::receiver.detached()
val secondArgument = expression.arguments.arguments.first()::value.detached() val secondArgument = expression.arguments.arguments.first()::value.detached()
kotlinBinaryExpression( JKBinaryExpressionImpl(
firstArgument, firstArgument,
secondArgument, secondArgument,
KtTokens.PLUS, JKKtOperatorImpl(JKOperatorToken.PLUS, typeFactory.types.possiblyNullString)
typeFactory
) )
} withReplaceType ReplaceType.REPLACE_WITH_QUALIFIER, } withReplaceType ReplaceType.REPLACE_WITH_QUALIFIER,
@@ -390,27 +389,26 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
else expression else expression
.also { .also {
arguments.arguments = arguments.arguments.dropLast(1) arguments.arguments = arguments.arguments.dropLast(1)
}.let { }.callOn(
it.callOn( symbolProvider.provideMethodSymbol("kotlin.collections.dropLastWhile"),
symbolProvider.provideMethodSymbol("kotlin.collections.dropLastWhile"), listOf(
JKLambdaExpressionImpl( JKLambdaExpressionImpl(
JKFieldAccessExpressionImpl( JKFieldAccessExpressionImpl(
JKUnresolvedField(//TODO replace with `it` parameter JKUnresolvedField(//TODO replace with `it` parameter
"it", "it",
typeFactory typeFactory
) )
).callOn(symbolProvider.provideMethodSymbol("kotlin.text.isEmpty")) ).callOn(symbolProvider.provideMethodSymbol("kotlin.text.isEmpty")).asStatement(),
.asStatement(),
emptyList() emptyList()
) )
) )
} )
} }
else -> expression.also { else -> expression.also {
val lastArgument = arguments.arguments.last().value.copyTreeAndDetach() val lastArgument = arguments.arguments.last().value.copyTreeAndDetach()
.callOn( .callOn(
symbolProvider.provideMethodSymbol("kotlin.ranges.coerceAtLeast"), symbolProvider.provideMethodSymbol("kotlin.ranges.coerceAtLeast"),
JKKtLiteralExpressionImpl("0", JKLiteralExpression.LiteralType.INT) listOf(JKKtLiteralExpressionImpl("0", JKLiteralExpression.LiteralType.INT))
) )
arguments.arguments = arguments.arguments.dropLast(1) + JKArgumentImpl(lastArgument) arguments.arguments = arguments.arguments.dropLast(1) + JKArgumentImpl(lastArgument)
} }
@@ -428,7 +426,7 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
JKArgumentListImpl( JKArgumentListImpl(
JKLambdaExpressionImpl( JKLambdaExpressionImpl(
JKExpressionStatementImpl( JKExpressionStatementImpl(
kotlinBinaryExpression( JKBinaryExpressionImpl(
JKFieldAccessExpressionImpl( JKFieldAccessExpressionImpl(
JKUnresolvedField(//TODO replace with `it` parameter JKUnresolvedField(//TODO replace with `it` parameter
"it", "it",
@@ -436,8 +434,10 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
) )
), ),
JKKtLiteralExpressionImpl("' '", JKLiteralExpression.LiteralType.CHAR), JKKtLiteralExpressionImpl("' '", JKLiteralExpression.LiteralType.CHAR),
KtTokens.LTEQ, JKKtOperatorImpl(
typeFactory JKOperatorToken.LTEQ,
typeFactory.types.boolean
)
) )
), ),
emptyList() emptyList()
@@ -469,7 +469,7 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
).groupBy { it.from.fqName } ).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( JKQualifiedExpressionImpl(
this, this,
JKKtQualifierImpl.DOT, 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 = private fun isSystemOutCall(expression: JKExpression): Boolean =
expression.parent expression.parent
?.safeAs<JKQualifiedExpression>() ?.safeAs<JKQualifiedExpression>()
@@ -182,11 +182,13 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
convertBound(bound, 0), convertBound(bound, 0),
context context
) )
else -> kotlinBinaryExpression( else -> JKBinaryExpressionImpl(
start, start,
convertBound(bound, if (inclusiveComparison) 0 else -1), convertBound(bound, if (inclusiveComparison) 0 else -1),
JKKtSingleValueOperatorToken(KtTokens.RANGE), JKKtOperatorImpl(
typeFactory JKOperatorToken.RANGE,
typeFactory.types.nullableAny //todo range type
)
) )
} }
} }
@@ -199,12 +201,14 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
return JKKtLiteralExpressionImpl((value + correction).toString(), bound.type) return JKKtLiteralExpressionImpl((value + correction).toString(), bound.type)
} }
val sign = if (correction > 0) KtTokens.PLUS else KtTokens.MINUS val sign = if (correction > 0) JKOperatorToken.PLUS else JKOperatorToken.MINUS
return kotlinBinaryExpression( return JKBinaryExpressionImpl(
bound, bound,
JKKtLiteralExpressionImpl(abs(correction).toString(), JKLiteralExpression.LiteralType.INT), JKKtLiteralExpressionImpl(abs(correction).toString(), JKLiteralExpression.LiteralType.INT),
JKKtSingleValueOperatorToken(sign), JKKtOperatorImpl(
typeFactory sign,
typeFactory.types.int
)
) )
} }
@@ -5,77 +5,27 @@
package org.jetbrains.kotlin.nj2k.conversions 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.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.kotlinBinaryExpression import org.jetbrains.kotlin.nj2k.callOn
import org.jetbrains.kotlin.nj2k.kotlinPostfixExpression
import org.jetbrains.kotlin.nj2k.kotlinPrefixExpression
import org.jetbrains.kotlin.nj2k.tree.* 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 { override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKOperatorExpression) return recurse(element) if (element !is JKBinaryExpression) return recurse(element)
val operator = element.operator as? JKJavaOperatorImpl ?: return recurse(element) if (element.operator.token == JKOperatorToken.PLUS
&& element.right.type(typeFactory)?.isStringType() == true
return when (element) { && element.left.type(typeFactory)?.isStringType() == false
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
) { ) {
val toStringCall = return recurse(
JKKtCallExpressionImpl( JKBinaryExpressionImpl(
symbolProvider.provideMethodSymbol("kotlin.Any.toString"), element::left.detached().callOn(symbolProvider.provideMethodSymbol("kotlin.Any.toString")),
JKArgumentListImpl() 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) element.type = element.type.mapType(element)
} }
is JKJavaNewExpression -> { is JKJavaNewExpression -> {
val newClassSymbol = element.classSymbol.mapClassSymbol(null) val newClassSymbol = element.classSymbol.mapClassSymbol()
return recurse( return recurse(
JKJavaNewExpressionImpl( JKJavaNewExpressionImpl(
newClassSymbol, newClassSymbol,
@@ -55,7 +55,6 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab
} }
} }
private fun JKType.fixRawType(typeElement: JKTypeElement?) = private fun JKType.fixRawType(typeElement: JKTypeElement?) =
when (typeElement?.parent) { when (typeElement?.parent) {
is JKClassLiteralExpression -> this is JKClassLiteralExpression -> this
@@ -71,7 +70,7 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab
private fun JKType.mapType(typeElement: JKTypeElement?): JKType = private fun JKType.mapType(typeElement: JKTypeElement?): JKType =
when (this) { when (this) {
is JKJavaPrimitiveType -> mapPrimitiveType() is JKJavaPrimitiveType -> mapPrimitiveType()
is JKClassType -> mapClassType(typeElement) is JKClassType -> mapClassType()
is JKJavaVoidType -> typeFactory.types.unit is JKJavaVoidType -> typeFactory.types.unit
is JKJavaArrayType -> is JKJavaArrayType ->
@@ -94,18 +93,17 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab
else -> this else -> this
}.fixRawType(typeElement) }.fixRawType(typeElement)
private fun JKClassSymbol.mapClassSymbol(typeElement: JKTypeElement?): JKClassSymbol { private fun JKClassSymbol.mapClassSymbol(): JKClassSymbol {
if (this is JKUniverseClassSymbol) return this if (this is JKUniverseClassSymbol) return this
if (typeElement?.parentOfType<JKInheritanceInfo>() != null) return this
val newFqName = kotlinCollectionClassName() val newFqName = kotlinCollectionClassName()
?: kotlinStandardType() ?: kotlinStandardType()
?: fqName ?: fqName
return symbolProvider.provideClassSymbol(newFqName) return symbolProvider.provideClassSymbol(newFqName)
} }
private fun JKClassType.mapClassType(typeElement: JKTypeElement?): JKClassType = private fun JKClassType.mapClassType(): JKClassType =
JKClassTypeImpl( JKClassTypeImpl(
classReference.mapClassSymbol(typeElement), classReference.mapClassSymbol(),
parameters.map { it.mapType(null) }, parameters.map { it.mapType(null) },
nullability nullability
) )
@@ -118,13 +116,8 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab
return JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqName))?.asString() return JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqName))?.asString()
} }
private fun JKJavaPrimitiveType.mapPrimitiveType(): JKClassType { private fun JKJavaPrimitiveType.mapPrimitiveType(): JKClassType =
val fqName = jvmPrimitiveType.primitiveType.typeFqName typeFactory.fromPrimitiveType(this)
return JKClassTypeImpl(
symbolProvider.provideClassSymbol(fqName),
nullability = Nullability.NotNull
)
}
private inline fun <reified T : JKType> T.addTypeParametersToRawProjectionType(typeParameter: JKType): T = private inline fun <reified T : JKType> T.addTypeParametersToRawProjectionType(typeParameter: JKType): T =
if (this is JKClassType && parameters.isEmpty()) { if (this is JKClassType && parameters.isEmpty()) {
@@ -147,7 +140,6 @@ class TypeMappingConversion(context: NewJ2kConverterContext) : RecursiveApplicab
companion object { companion object {
private val ktFunctionRegex = "kotlin\\.jvm\\.functions\\.Function\\d+".toRegex() private val ktFunctionRegex = "kotlin\\.jvm\\.functions\\.Function\\d+".toRegex()
private fun isKtFunction(fqName: String) = private fun isKtFunction(fqName: String) = ktFunctionRegex.matches(fqName)
ktFunctionRegex.matches(fqName)
} }
} }
+26 -148
View File
@@ -5,67 +5,18 @@
package org.jetbrains.kotlin.nj2k package org.jetbrains.kotlin.nj2k
import com.intellij.psi.PsiClass
import com.intellij.psi.tree.TokenSet 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.lexer.KtTokens
import org.jetbrains.kotlin.nj2k.conversions.RecursiveApplicableConversionBase 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.*
import org.jetbrains.kotlin.nj2k.tree.impl.* 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.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.cast
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs 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() = fun JKOperator.isEquals() =
(token as? JKKtSingleValueOperatorToken)?.psiToken in equalsOperators (token as? JKKtSingleValueOperatorToken)?.psiToken in equalsOperators
@@ -77,98 +28,6 @@ private val equalsOperators =
KtTokens.EXCLEQ 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( fun untilToExpression(
from: JKExpression, from: JKExpression,
to: JKExpression, to: JKExpression,
@@ -199,6 +58,8 @@ fun JKExpression.parenthesizeIfBinaryExpression() =
else -> this else -> this
} }
fun JKExpression.parenthesize() = JKParenthesizedExpressionImpl(this)
fun rangeExpression( fun rangeExpression(
from: JKExpression, from: JKExpression,
to: JKExpression, to: JKExpression,
@@ -277,7 +138,7 @@ fun stringLiteral(content: String, typeFactory: JKTypeFactory): JKExpression {
val newlineSeparator = if (i == lines.size - 1) "" else "\\n" val newlineSeparator = if (i == lines.size - 1) "" else "\\n"
JKKtLiteralExpressionImpl("\"$line$newlineSeparator\"", JKLiteralExpression.LiteralType.STRING) JKKtLiteralExpressionImpl("\"$line$newlineSeparator\"", JKLiteralExpression.LiteralType.STRING)
}.reduce { acc: JKExpression, literalExpression: JKKtLiteralExpression -> }.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) = fun equalsExpression(left: JKExpression, right: JKExpression, typeFactory: JKTypeFactory) =
kotlinBinaryExpression( JKBinaryExpressionImpl(
left, left,
right, right,
KtTokens.EQEQ, JKKtOperatorImpl(
typeFactory JKOperatorToken.EQEQ,
typeFactory.types.boolean
)
) )
fun createCompanion(declarations: List<JKDeclaration>): JKClass = fun createCompanion(declarations: List<JKDeclaration>): JKClass =
@@ -438,4 +301,19 @@ fun <T : JKExpression> T.nullIfStubExpression(): T? =
fun JKExpression.qualified(qualifier: JKExpression?) = fun JKExpression.qualified(qualifier: JKExpression?) =
if (qualifier != null && qualifier !is JKStubExpression) { if (qualifier != null && qualifier !is JKStubExpression) {
JKQualifiedExpressionImpl(qualifier, JKJavaQualifierImpl.DOT, this) 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 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.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 { interface JKOperator {
val token: JKOperatorToken val token: JKOperatorToken
val precedence: Int val returnType: JKType
} }
interface JKOperatorToken { interface JKOperatorToken {
val text: String 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 { interface JKKtOperatorToken : JKOperatorToken
val operatorName: String
}
interface JKQualifier interface JKQualifier
interface JKElement { interface JKElement {
@@ -159,7 +159,7 @@ class JKQualifiedExpressionImpl(
class JKExpressionStatementImpl(expression: JKExpression) : JKExpressionStatement(), PsiOwner by PsiOwnerImpl() { class JKExpressionStatementImpl(expression: JKExpression) : JKExpressionStatement(), PsiOwner by PsiOwnerImpl() {
override fun accept(visitor: JKVisitor) = visitor.visitExpressionStatement(this) 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(), class JKDeclarationStatementImpl(declaredStatements: List<JKDeclaration>) : JKDeclarationStatement(),
@@ -92,125 +92,9 @@ class JKJavaLiteralExpressionImpl(
} }
} }
class JKJavaOperatorToken(val psiToken: IElementType) : JKOperatorToken { class JKJavaOperatorToken(val psiToken: IElementType) : JKOperatorToken {
override val text: String override val text: String
get() = when (psiToken) { get() = error("Java token should not be printed, it should be replaces with corresponding Kotlin one")
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)
}
}
} }
sealed class JKJavaQualifierImpl : JKQualifier { sealed class JKJavaQualifierImpl : JKQualifier {
@@ -342,13 +226,13 @@ class JKJavaPolyadicExpressionImpl(operands: List<JKExpression>, override var to
} }
class JKJavaAssignmentExpressionImpl( class JKJavaAssignmentExpressionImpl(
field: JKAssignableExpression, field: JKExpression,
expression: JKExpression, expression: JKExpression,
override var operator: JKOperator override var operator: JKOperator
) : JKBranchElementBase(), JKJavaAssignmentExpression, PsiOwner by PsiOwnerImpl() { ) : JKBranchElementBase(), JKJavaAssignmentExpression, PsiOwner by PsiOwnerImpl() {
override fun accept(visitor: JKVisitor) = visitor.visitJavaAssignmentExpression(this) override fun accept(visitor: JKVisitor) = visitor.visitJavaAssignmentExpression(this)
override var field: JKAssignableExpression by child(field) override var field by child(field)
override var expression: JKExpression by child(expression) override var expression by child(expression)
} }
class JKJavaSwitchStatementImpl( class JKJavaSwitchStatementImpl(
@@ -104,64 +104,51 @@ class JKKtLiteralExpressionImpl(
} }
class JKKtSingleValueOperatorToken(val psiToken: KtSingleValueToken) : JKKtOperatorToken { 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 override val text: String = psiToken.value
} }
object JKKtSpreadOperatorToken : JKKtOperatorToken { object JKKtSpreadOperatorToken : JKKtOperatorToken {
override val text: String = "*" 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 token: JKOperatorToken = JKKtSpreadOperatorToken
override val precedence: Int
get() = TODO()
} }
class JKKtWordOperatorToken(override val text: String) : JKKtOperatorToken { class JKKtWordOperatorToken(override val text: String) : JKKtOperatorToken
override val operatorName: String = text
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() { class JKAssignmentChainLetLinkImpl(
constructor(singleValueToken: KtSingleValueToken, returnType: JKType) : this( receiver: JKExpression,
JKKtSingleValueOperatorToken(singleValueToken), assignmentStatement: JKKtAssignmentStatement,
returnType 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 override fun accept(visitor: JKVisitor) = visitor.visitAssignmentChainLetLink(this)
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)
} }
class JKKtAssignmentStatementImpl( class JKKtAssignmentStatementImpl(
field: JKAssignableExpression, field: JKExpression,
expression: JKExpression, expression: JKExpression,
override var operator: JKOperator override var token: JKOperatorToken
) : JKKtAssignmentStatement() { ) : JKKtAssignmentStatement() {
override var field: JKAssignableExpression by child(field) override var field: JKExpression by child(field)
override var expression by child(expression) override var expression by child(expression)
override fun accept(visitor: JKVisitor) = visitor.visitKtAssignmentStatement(this) 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 var visibilityElement by child(JKVisibilityModifierElementImpl(Visibility.PUBLIC))
override fun accept(visitor: JKVisitor) = visitor.visitKtEmptyGetterOrSetter(this) 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 class JKExpressionStatement : JKStatement() {
abstract val expression: JKExpression abstract var expression: JKExpression
} }
abstract class JKDeclarationStatement : JKStatement() { abstract class JKDeclarationStatement : JKStatement() {
@@ -315,7 +315,7 @@ interface JKPrefixExpression : JKUnaryExpression
interface JKPostfixExpression : JKUnaryExpression interface JKPostfixExpression : JKUnaryExpression
interface JKQualifiedExpression : JKExpression, JKAssignableExpression { interface JKQualifiedExpression : JKExpression {
var receiver: JKExpression var receiver: JKExpression
var operator: JKQualifier var operator: JKQualifier
var selector: JKExpression var selector: JKExpression
@@ -334,11 +334,11 @@ interface JKMethodCallExpression : JKExpression, JKTypeArgumentListOwner, JKBran
var arguments: JKArgumentList var arguments: JKArgumentList
} }
interface JKFieldAccessExpression : JKAssignableExpression { interface JKFieldAccessExpression : JKExpression {
val identifier: JKFieldSymbol val identifier: JKFieldSymbol
} }
interface JKPackageAccessExpression : JKAssignableExpression { interface JKPackageAccessExpression : JKExpression {
val identifier: JKPackageSymbol val identifier: JKPackageSymbol
} }
@@ -346,7 +346,7 @@ interface JKClassAccessExpression : JKExpression {
val identifier: JKClassSymbol val identifier: JKClassSymbol
} }
interface JKArrayAccessExpression : JKAssignableExpression { interface JKArrayAccessExpression : JKExpression {
var expression: JKExpression var expression: JKExpression
var indexExpression: JKExpression var indexExpression: JKExpression
} }
@@ -447,8 +447,6 @@ interface JKIfElseExpression : JKExpression {
var elseBranch: JKExpression var elseBranch: JKExpression
} }
interface JKAssignableExpression : JKExpression
interface JKLambdaExpression : JKExpression { interface JKLambdaExpression : JKExpression {
var parameters: List<JKParameter> var parameters: List<JKParameter>
val returnType: JKTypeElement val returnType: JKTypeElement
@@ -95,7 +95,7 @@ interface JKJavaPolyadicExpression : JKExpression {
} }
interface JKJavaAssignmentExpression : JKExpression, JKBranchElement { interface JKJavaAssignmentExpression : JKExpression, JKBranchElement {
var field: JKAssignableExpression var field: JKExpression
var expression: JKExpression var expression: JKExpression
var operator: JKOperator var operator: JKOperator
} }
@@ -42,19 +42,24 @@ abstract class JKKtConstructor : JKMethod(), JKOtherModifiersOwner {
abstract class JKKtPrimaryConstructor : JKKtConstructor() abstract class JKKtPrimaryConstructor : JKKtConstructor()
abstract class JKKtAssignmentStatement : JKStatement() { abstract class JKKtAssignmentStatement : JKStatement() {
abstract var field: JKAssignableExpression abstract var field: JKExpression
abstract var expression: JKExpression abstract var expression: JKExpression
abstract var operator: JKOperator abstract var token: JKOperatorToken
} }
interface JKKtCall : JKMethodCallExpression interface JKKtCall : JKMethodCallExpression
interface JKKtMethodCallExpression : JKMethodCallExpression interface JKKtMethodCallExpression : JKMethodCallExpression
interface JKKtAlsoCallExpression : JKKtMethodCallExpression { interface JKKtAssignmentChainLink : JKExpression {
var statement: JKStatement val receiver: JKExpression
val assignmentStatement: JKKtAssignmentStatement
val field: JKExpression
} }
interface JKAssignmentChainAlsoLink : JKKtAssignmentChainLink
interface JKAssignmentChainLetLink : JKKtAssignmentChainLink
interface JKKtLiteralExpression : JKLiteralExpression interface JKKtLiteralExpression : JKLiteralExpression
abstract class JKKtWhenStatement : JKStatement() { abstract class JKKtWhenStatement : JKStatement() {
@@ -108,4 +113,8 @@ interface JKKtTryCatchSection : JKTreeElement {
interface JKKtAnnotationArrayInitializerExpression : JKExpression, JKBranchElement { interface JKKtAnnotationArrayInitializerExpression : JKExpression, JKBranchElement {
val initializers: List<JKAnnotationMemberValue> 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 = inline fun <reified T : JKNonCodeElementsListOwner> T.withNonCodeElementsFrom(other: JKNonCodeElementsListOwner): T =
also { it.takeNonCodeElementsFrom(other) } 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() { fun JKNonCodeElementsListOwner.clearNonCodeElements() {
leftNonCodeElements = emptyList() leftNonCodeElements = emptyList()
rightNonCodeElements = emptyList() rightNonCodeElements = emptyList()
@@ -11,16 +11,11 @@ import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiType import com.intellij.psi.PsiType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType 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.analyze
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.j2k.ast.Nullability import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.nj2k.JKSymbolProvider import org.jetbrains.kotlin.nj2k.JKSymbolProvider
import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol 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.tree.impl.*
import org.jetbrains.kotlin.nj2k.types.* import org.jetbrains.kotlin.nj2k.types.*
import org.jetbrains.kotlin.psi.KtClass 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.BindingContext
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode 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 import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun JKExpression.type(typeFactory: JKTypeFactory): JKType? = fun JKExpression.type(typeFactory: JKTypeFactory): JKType? =
@@ -73,6 +66,10 @@ fun JKExpression.type(typeFactory: JKTypeFactory): JKType? =
is JKLabeledStatement -> is JKLabeledStatement ->
statement.safeAs<JKExpressionStatement>()?.expression?.type(typeFactory) statement.safeAs<JKExpressionStatement>()?.expression?.type(typeFactory)
is JKMethodReferenceExpression -> JKNoTypeImpl //TODO 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()) else -> TODO(this::class.java.toString())
} }
@@ -82,33 +79,20 @@ fun JKType.asTypeElement() =
fun JKClassSymbol.asType(nullability: Nullability = Nullability.Default): JKClassType = fun JKClassSymbol.asType(nullability: Nullability = Nullability.Default): JKClassType =
JKClassTypeImpl(this, emptyList(), nullability) 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 val PsiType.isKotlinFunctionalType: Boolean
get() { get() {
val fqName = safeAs<PsiClassType>()?.resolve()?.getKotlinFqName() ?: return false val fqName = safeAs<PsiClassType>()?.resolve()?.getKotlinFqName() ?: return false
return functionalTypeRegex.matches(fqName.asString()) return functionalTypeRegex.matches(fqName.asString())
} }
private val functionalTypeRegex = """(kotlin\.jvm\.functions|kotlin)\.Function[\d+]""".toRegex() private val functionalTypeRegex = """(kotlin\.jvm\.functions|kotlin)\.Function[\d+]""".toRegex()
fun KtTypeReference.toJK(typeFactory: JKTypeFactory): JKType? = fun KtTypeReference.toJK(typeFactory: JKTypeFactory): JKType? =
analyze(BodyResolveMode.PARTIAL) analyze(BodyResolveMode.PARTIAL)
.get(BindingContext.TYPE, this) .get(BindingContext.TYPE, this)
?.let { typeFactory.fromKotlinType(it) } ?.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) = infix fun JKJavaPrimitiveType.isStrongerThan(other: JKJavaPrimitiveType) =
jvmPrimitiveTypesPriority.getValue(this.jvmPrimitiveType.primitiveType) > jvmPrimitiveTypesPriority.getValue(this.jvmPrimitiveType.primitiveType) >
jvmPrimitiveTypesPriority.getValue(other.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 = fun JKType.applyRecursive(transform: (JKType) -> JKType?): JKType =
transform(this) ?: when (this) { transform(this) ?: when (this) {
is JKTypeParameterTypeImpl -> this is JKTypeParameterTypeImpl -> this
@@ -75,7 +75,7 @@ abstract class JKVisitor {
open fun visitIfStatement(ifStatement: JKIfStatement) = visitStatement(ifStatement) open fun visitIfStatement(ifStatement: JKIfStatement) = visitStatement(ifStatement)
open fun visitIfElseStatement(ifElseStatement: JKIfElseStatement) = visitIfStatement(ifElseStatement) open fun visitIfElseStatement(ifElseStatement: JKIfElseStatement) = visitIfStatement(ifElseStatement)
open fun visitIfElseExpression(ifElseExpression: JKIfElseExpression) = visitExpression(ifElseExpression) 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 visitLambdaExpression(lambdaExpression: JKLambdaExpression) = visitExpression(lambdaExpression)
open fun visitDelegationConstructorCall(delegationConstructorCall: JKDelegationConstructorCall) = visitMethodCallExpression(delegationConstructorCall) open fun visitDelegationConstructorCall(delegationConstructorCall: JKDelegationConstructorCall) = visitMethodCallExpression(delegationConstructorCall)
open fun visitLabel(label: JKLabel) = visitTreeElement(label) open fun visitLabel(label: JKLabel) = visitTreeElement(label)
@@ -85,7 +85,7 @@ abstract class JKVisitor {
open fun visitLabeledStatement(labeledStatement: JKLabeledStatement) = visitExpression(labeledStatement) open fun visitLabeledStatement(labeledStatement: JKLabeledStatement) = visitExpression(labeledStatement)
open fun visitEmptyStatement(emptyStatement: JKEmptyStatement) = visitStatement(emptyStatement) open fun visitEmptyStatement(emptyStatement: JKEmptyStatement) = visitStatement(emptyStatement)
open fun visitTypeParameterList(typeParameterList: JKTypeParameterList) = visitTreeElement(typeParameterList) 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 visitTypeParameterListOwner(typeParameterListOwner: JKTypeParameterListOwner) = visitTreeElement(typeParameterListOwner)
open fun visitEnumConstant(enumConstant: JKEnumConstant) = visitVariable(enumConstant) open fun visitEnumConstant(enumConstant: JKEnumConstant) = visitVariable(enumConstant)
open fun visitForInStatement(forInStatement: JKForInStatement) = visitStatement(forInStatement) open fun visitForInStatement(forInStatement: JKForInStatement) = visitStatement(forInStatement)
@@ -128,7 +128,9 @@ abstract class JKVisitor {
open fun visitKtAssignmentStatement(ktAssignmentStatement: JKKtAssignmentStatement) = visitStatement(ktAssignmentStatement) open fun visitKtAssignmentStatement(ktAssignmentStatement: JKKtAssignmentStatement) = visitStatement(ktAssignmentStatement)
open fun visitKtCall(ktCall: JKKtCall) = visitMethodCallExpression(ktCall) open fun visitKtCall(ktCall: JKKtCall) = visitMethodCallExpression(ktCall)
open fun visitKtMethodCallExpression(ktMethodCallExpression: JKKtMethodCallExpression) = visitMethodCallExpression(ktMethodCallExpression) 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 visitKtLiteralExpression(ktLiteralExpression: JKKtLiteralExpression) = visitLiteralExpression(ktLiteralExpression)
open fun visitKtWhenStatement(ktWhenStatement: JKKtWhenStatement) = visitStatement(ktWhenStatement) open fun visitKtWhenStatement(ktWhenStatement: JKKtWhenStatement) = visitStatement(ktWhenStatement)
open fun visitKtWhenCase(ktWhenCase: JKKtWhenCase) = visitTreeElement(ktWhenCase) open fun visitKtWhenCase(ktWhenCase: JKKtWhenCase) = visitTreeElement(ktWhenCase)
@@ -142,4 +144,5 @@ abstract class JKVisitor {
open fun visitKtTryExpression(ktTryExpression: JKKtTryExpression) = visitExpression(ktTryExpression) open fun visitKtTryExpression(ktTryExpression: JKKtTryExpression) = visitExpression(ktTryExpression)
open fun visitKtTryCatchSection(ktTryCatchSection: JKKtTryCatchSection) = visitTreeElement(ktTryCatchSection) open fun visitKtTryCatchSection(ktTryCatchSection: JKKtTryCatchSection) = visitTreeElement(ktTryCatchSection)
open fun visitKtAnnotationArrayInitializerExpression(ktAnnotationArrayInitializerExpression: JKKtAnnotationArrayInitializerExpression) = visitExpression(ktAnnotationArrayInitializerExpression) 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) open fun visitIfElseExpressionRaw(ifElseExpression: JKIfElseExpression) = visitExpressionRaw(ifElseExpression)
override fun visitAssignableExpression(assignableExpression: JKAssignableExpression) { override fun visitAssignableExpression(assignableExpression: JKExpression) {
printLeftNonCodeElements(assignableExpression) printLeftNonCodeElements(assignableExpression)
visitAssignableExpressionRaw(assignableExpression) visitAssignableExpressionRaw(assignableExpression)
printRightNonCodeElements(assignableExpression) printRightNonCodeElements(assignableExpression)
} }
open fun visitAssignableExpressionRaw(assignableExpression: JKAssignableExpression) = visitExpressionRaw(assignableExpression) open fun visitAssignableExpressionRaw(assignableExpression: JKExpression) = visitExpressionRaw(assignableExpression)
override fun visitLambdaExpression(lambdaExpression: JKLambdaExpression) { override fun visitLambdaExpression(lambdaExpression: JKLambdaExpression) {
printLeftNonCodeElements(lambdaExpression) printLeftNonCodeElements(lambdaExpression)
@@ -668,7 +668,7 @@ abstract class JKVisitorWithCommentsPrinting : JKVisitor() {
printRightNonCodeElements(typeParameter) printRightNonCodeElements(typeParameter)
} }
open fun visitTypeParameterRaw(typeParameter: JKTypeParameter) = visitTreeElementRaw(typeParameter) open fun visitTypeParameterRaw(typeParameter: JKTypeParameter) = visitDeclarationRaw(typeParameter)
override fun visitTypeParameterListOwner(typeParameterListOwner: JKTypeParameterListOwner) { override fun visitTypeParameterListOwner(typeParameterListOwner: JKTypeParameterListOwner) {
printLeftNonCodeElements(typeParameterListOwner) printLeftNonCodeElements(typeParameterListOwner)
@@ -1006,13 +1006,29 @@ abstract class JKVisitorWithCommentsPrinting : JKVisitor() {
open fun visitKtMethodCallExpressionRaw(ktMethodCallExpression: JKKtMethodCallExpression) = visitMethodCallExpressionRaw(ktMethodCallExpression) open fun visitKtMethodCallExpressionRaw(ktMethodCallExpression: JKKtMethodCallExpression) = visitMethodCallExpressionRaw(ktMethodCallExpression)
override fun visitKtAlsoCallExpression(ktAlsoCallExpression: JKKtAlsoCallExpression) { override fun visitKtAssignmentChainLink(ktAssignmentChainLink: JKKtAssignmentChainLink) {
printLeftNonCodeElements(ktAlsoCallExpression) printLeftNonCodeElements(ktAssignmentChainLink)
visitKtAlsoCallExpressionRaw(ktAlsoCallExpression) visitKtAssignmentChainLinkRaw(ktAssignmentChainLink)
printRightNonCodeElements(ktAlsoCallExpression) 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) { override fun visitKtLiteralExpression(ktLiteralExpression: JKKtLiteralExpression) {
printLeftNonCodeElements(ktLiteralExpression) printLeftNonCodeElements(ktLiteralExpression)
@@ -1117,4 +1133,12 @@ abstract class JKVisitorWithCommentsPrinting : JKVisitor() {
} }
open fun visitKtAnnotationArrayInitializerExpressionRaw(ktAnnotationArrayInitializerExpression: JKKtAnnotationArrayInitializerExpression) = visitExpressionRaw(ktAnnotationArrayInitializerExpression) 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.j2k.ast.Nullability
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.nj2k.JKSymbolProvider import org.jetbrains.kotlin.nj2k.JKSymbolProvider
import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol
import org.jetbrains.kotlin.nj2k.symbols.JKTypeParameterSymbol import org.jetbrains.kotlin.nj2k.symbols.JKTypeParameterSymbol
import org.jetbrains.kotlin.nj2k.symbols.JKUnresolvedClassSymbol 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.psi.KtTypeParameter
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.types.KotlinType 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 { internal class JavaCode {
fun toJSON(collection: Collection<Int>): String { 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 { class CharToString {
private val value: String? = null private val value: String? = null
fun test(): String { fun test(): String {
return '"'.toString() + value + '"' 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 import java.util.ArrayList
class Test { class Test {
internal var list: List<List<Int>> = ArrayList() internal var list: List<MutableList<Int>> = ArrayList()
fun test() { fun test() {
list[0].add(1) list[0].add(1)
} }
@@ -412,6 +412,16 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
runTest("nj2k/testData/newJ2k/assignmentExpression/assignmentAsExpression.java"); 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") @TestMetadata("bitOperationPriority.java")
public void testBitOperationPriority() throws Exception { public void testBitOperationPriority() throws Exception {
runTest("nj2k/testData/newJ2k/assignmentExpression/bitOperationPriority.java"); runTest("nj2k/testData/newJ2k/assignmentExpression/bitOperationPriority.java");
@@ -422,11 +432,26 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
runTest("nj2k/testData/newJ2k/assignmentExpression/bitOperationPriorityComments.java"); 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") @TestMetadata("divideAssign.java")
public void testDivideAssign() throws Exception { public void testDivideAssign() throws Exception {
runTest("nj2k/testData/newJ2k/assignmentExpression/divideAssign.java"); 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") @TestMetadata("minusAssign.java")
public void testMinusAssign() throws Exception { public void testMinusAssign() throws Exception {
runTest("nj2k/testData/newJ2k/assignmentExpression/minusAssign.java"); runTest("nj2k/testData/newJ2k/assignmentExpression/minusAssign.java");