Preserve formatting of parenthesis in calls too

This commit is contained in:
Valentin Kipyatkov
2016-08-19 22:13:58 +03:00
parent 87294207f9
commit 38edb58e60
15 changed files with 173 additions and 111 deletions
@@ -14,7 +14,8 @@ class A {
return JetBundle.message( return JetBundle.message(
"x.in.y", "x.in.y",
DescriptorRenderer.COMPACT.render(declarationDescriptor), DescriptorRenderer.COMPACT.render(declarationDescriptor),
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(containingDescriptor)) IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(containingDescriptor)
)
} }
} }
} }
@@ -63,6 +63,16 @@ class CodeConverter(
fun convertExpressions(expressions: List<PsiExpression>): List<Expression> fun convertExpressions(expressions: List<PsiExpression>): List<Expression>
= expressions.map { convertExpression(it) } = expressions.map { convertExpression(it) }
fun convertArgumentList(list: PsiExpressionList): ArgumentList {
val lPar = list.node.findChildByType(JavaTokenType.LPARENTH)?.psi
val rPar = list.node.findChildByType(JavaTokenType.RPARENTH)?.psi
return ArgumentList(
convertExpressions(list.expressions),
LPar().assignPrototype(lPar, CommentsAndSpacesInheritance.LINE_BREAKS),
RPar().assignPrototype(rPar, CommentsAndSpacesInheritance.LINE_BREAKS)
).assignPrototype(list)
}
fun convertExpression(expression: PsiExpression?, shouldParenthesize: Boolean = false): Expression { fun convertExpression(expression: PsiExpression?, shouldParenthesize: Boolean = false): Expression {
if (expression == null) return Expression.Empty if (expression == null) return Expression.Empty
@@ -127,7 +137,7 @@ class CodeConverter(
convertedExpression = LiteralExpression(text) convertedExpression = LiteralExpression(text)
} }
else if (expectedTypeStr == "char") { else if (expectedTypeStr == "char") {
convertedExpression = MethodCallExpression.build(convertedExpression, "toChar", emptyList(), emptyList(), false) convertedExpression = MethodCallExpression.buildNonNull(convertedExpression, "toChar")
} }
} }
else if (expression is PsiPrefixExpression && expression.isLiteralWithSign()) { else if (expression is PsiPrefixExpression && expression.isLiteralWithSign()) {
@@ -137,7 +147,7 @@ class CodeConverter(
else { else {
val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedTypeStr] val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedTypeStr]
if (conversion != null) { if (conversion != null) {
convertedExpression = MethodCallExpression.buildNotNull(convertedExpression, conversion) convertedExpression = MethodCallExpression.buildNonNull(convertedExpression, conversion)
} }
} }
} }
@@ -146,7 +156,7 @@ class CodeConverter(
} }
fun convertedExpressionType(expression: PsiExpression, expectedType: PsiType): Type { fun convertedExpressionType(expression: PsiExpression, expectedType: PsiType): Type {
var convertedExpression = convertExpression(expression) val convertedExpression = convertExpression(expression)
val actualType = expression.type ?: return ErrorType() val actualType = expression.type ?: return ErrorType()
var resultType = typeConverter.convertType(actualType, if (convertedExpression.isNullable) Nullability.Nullable else Nullability.NotNull) var resultType = typeConverter.convertType(actualType, if (convertedExpression.isNullable) Nullability.Nullable else Nullability.NotNull)
@@ -317,8 +317,11 @@ class Converter private constructor(
if (field is PsiEnumConstant) { if (field is PsiEnumConstant) {
assert(getMethod == null && setMethod == null) assert(getMethod == null && setMethod == null)
val argumentList = field.argumentList val argumentList = field.argumentList
val params = deferredElement { codeConverter -> val params = if (argumentList != null && argumentList.expressions.isNotEmpty()) {
ExpressionList(codeConverter.convertExpressions(argumentList?.expressions ?: arrayOf<PsiExpression>())).assignPrototype(argumentList) deferredElement { codeConverter -> codeConverter.convertArgumentList(argumentList) }
}
else {
null
} }
val body = field.initializingClass?.let { convertAnonymousClassBody(it) } val body = field.initializingClass?.let { convertAnonymousClassBody(it) }
return EnumConstant(name, annotations, modifiers, params, body) return EnumConstant(name, annotations, modifiers, params, body)
@@ -118,8 +118,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val expectedNullability = if (operationTokenType in NON_NULL_OPERAND_OPS) Nullability.NotNull else null val expectedNullability = if (operationTokenType in NON_NULL_OPERAND_OPS) Nullability.NotNull else null
val leftOperandExpectedType = getOperandExpectedType(left, right, operationTokenType) val leftOperandExpectedType = getOperandExpectedType(left, right, operationTokenType)
var leftConverted = codeConverter.convertExpression(left, leftOperandExpectedType, expectedNullability) val leftConverted = codeConverter.convertExpression(left, leftOperandExpectedType, expectedNullability)
var rightConverted = codeConverter.convertExpression( val rightConverted = codeConverter.convertExpression(
right, right,
if (leftOperandExpectedType == null) if (leftOperandExpectedType == null)
getOperandExpectedType(right, left, operationTokenType) getOperandExpectedType(right, left, operationTokenType)
@@ -129,7 +129,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
) )
if (operationTokenType == JavaTokenType.GTGTGT) { if (operationTokenType == JavaTokenType.GTGTGT) {
result = MethodCallExpression.buildNotNull(leftConverted, "ushr", listOf(rightConverted)) result = MethodCallExpression.buildNonNull(leftConverted, "ushr", ArgumentList.withNoPrototype(rightConverted))
} }
else { else {
var operator = Operator(operationTokenType) var operator = Operator(operationTokenType)
@@ -509,7 +509,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val operand = codeConverter.convertExpression(expression.operand, expression.operand!!.type) val operand = codeConverter.convertExpression(expression.operand, expression.operand!!.type)
val token = expression.operationTokenType val token = expression.operationTokenType
if (token == JavaTokenType.TILDE) { if (token == JavaTokenType.TILDE) {
result = MethodCallExpression.buildNotNull(operand, "inv") result = MethodCallExpression.buildNonNull(operand, "inv")
} }
else if (token == JavaTokenType.EXCL && operand is BinaryExpression && operand.op.asString() == "==") { // happens when equals is converted to == else if (token == JavaTokenType.EXCL && operand is BinaryExpression && operand.op.asString() == "==") { // happens when equals is converted to ==
result = BinaryExpression(operand.left, operand.right, Operator(JavaTokenType.NE).assignPrototype(expression.operand)) result = BinaryExpression(operand.left, operand.right, Operator(JavaTokenType.NE).assignPrototype(expression.operand))
@@ -623,7 +623,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val typeConversion = PRIMITIVE_TYPE_CONVERSIONS[typeText] val typeConversion = PRIMITIVE_TYPE_CONVERSIONS[typeText]
val operandConverted = codeConverter.convertExpression(operand) val operandConverted = codeConverter.convertExpression(operand)
if (operandType is PsiPrimitiveType && typeConversion != null) { if (operandType is PsiPrimitiveType && typeConversion != null) {
result = MethodCallExpression.buildNotNull(operandConverted, typeConversion) result = MethodCallExpression.buildNonNull(operandConverted, typeConversion)
} }
else { else {
val nullability = if (operandConverted.isNullable && !expression.isQualifier()) val nullability = if (operandConverted.isNullable && !expression.isQualifier())
@@ -659,8 +659,9 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
result = PolyadicExpression(args, operators).assignPrototype(expression) result = PolyadicExpression(args, operators).assignPrototype(expression)
} }
private fun convertArguments(expression: PsiCallExpression, isExtension: Boolean = false): List<Expression> { private fun convertArguments(expression: PsiCallExpression, isExtension: Boolean = false): ArgumentList {
var arguments = expression.argumentList?.expressions?.toList() ?: listOf() val argumentList = expression.argumentList
var arguments = argumentList?.expressions?.toList() ?: listOf()
if (isExtension && arguments.isNotEmpty()) { if (isExtension && arguments.isNotEmpty()) {
arguments = arguments.drop(1) arguments = arguments.drop(1)
} }
@@ -670,7 +671,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val commentsAndSpacesInheritance = CommentsAndSpacesInheritance.LINE_BREAKS val commentsAndSpacesInheritance = CommentsAndSpacesInheritance.LINE_BREAKS
return if (arguments.size == parameters.size) { val convertedArguments = if (arguments.size == parameters.size) {
arguments.mapIndexed { i, argument -> arguments.mapIndexed { i, argument ->
val expectedNullability = typeConverter.variableNullability(parameters[i]) val expectedNullability = typeConverter.variableNullability(parameters[i])
val converted = codeConverter.convertExpression(argument, parameters[i].type, expectedNullability) val converted = codeConverter.convertExpression(argument, parameters[i].type, expectedNullability)
@@ -685,6 +686,15 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
else { else {
arguments.map { codeConverter.convertExpression(it).assignPrototype(it, commentsAndSpacesInheritance) } arguments.map { codeConverter.convertExpression(it).assignPrototype(it, commentsAndSpacesInheritance) }
} }
val lPar = argumentList?.node?.findChildByType(JavaTokenType.LPARENTH)?.psi
val rPar = argumentList?.node?.findChildByType(JavaTokenType.RPARENTH)?.psi
return ArgumentList(
convertedArguments,
LPar().assignPrototype(lPar, CommentsAndSpacesInheritance.LINE_BREAKS),
RPar().assignPrototype(rPar, CommentsAndSpacesInheritance.LINE_BREAKS)
).assignPrototype(argumentList)
} }
override fun visitLambdaExpression(expression: PsiLambdaExpression) { override fun visitLambdaExpression(expression: PsiLambdaExpression) {
@@ -772,7 +782,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
val specialMethod = method?.let { SpecialMethod.match(it, callParams.size, converter.services) } val specialMethod = method?.let { SpecialMethod.match(it, callParams.size, converter.services) }
val statement: Statement = if (expression.isConstructor) { val statement: Statement = if (expression.isConstructor) {
MethodCallExpression.build(null, convertMethodReferenceQualifier(qualifier), callParams.map { it.first }, emptyList(), false) val argumentList = ArgumentList.withNoPrototype(callParams.map { it.first })
MethodCallExpression.buildNonNull(null, convertMethodReferenceQualifier(qualifier), argumentList)
} }
else if (specialMethod != null) { else if (specialMethod != null) {
val factory = PsiElementFactory.SERVICE.getInstance(converter.project) val factory = PsiElementFactory.SERVICE.getInstance(converter.project)
@@ -800,7 +811,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
} }
else { else {
val referenceName = expression.referenceName!! val referenceName = expression.referenceName!!
MethodCallExpression.build(receiver?.first, referenceName, callParams.map { it.first }, emptyList(), false) val argumentList = ArgumentList.withNoPrototype(callParams.map { it.first })
MethodCallExpression.buildNonNull(receiver?.first, referenceName, argumentList)
} }
statement.assignNoPrototype() statement.assignNoPrototype()
@@ -822,12 +834,10 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
} }
else { else {
val convertedFunctionalType = converter.typeConverter.convertType(functionalType) val convertedFunctionalType = converter.typeConverter.convertType(functionalType)
result = MethodCallExpression.build( result = MethodCallExpression.buildNonNull(
null, null,
convertedFunctionalType.canonicalCode(), convertedFunctionalType.canonicalCode(),
listOf(lambdaExpression), ArgumentList.withNoPrototype(lambdaExpression)
emptyList(),
false
) )
} }
} }
@@ -138,7 +138,8 @@ class ForConverter(
block.generateCode(builder) block.generateCode(builder)
} }
else { else {
val call = MethodCallExpression.build(null, "run", listOf(LambdaExpression(null, block)), listOf(), false) val argumentList = ArgumentList.withNoPrototype(LambdaExpression(null, block))
val call = MethodCallExpression.buildNonNull(null, "run", argumentList)
call.generateCode(builder) call.generateCode(builder)
} }
} }
@@ -256,7 +257,7 @@ class ForConverter(
if (indices == null) return null if (indices == null) return null
return if (reversed) return if (reversed)
MethodCallExpression.build(indices.assignNoPrototype(), "reversed", listOf(), listOf(), false) MethodCallExpression.buildNonNull(indices.assignNoPrototype(), "reversed")
else else
indices indices
} }
@@ -208,68 +208,80 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
COLLECTIONS_EMPTY_LIST(Collections::class.java.name, "emptyList", 0) { COLLECTIONS_EMPTY_LIST(Collections::class.java.name, "emptyList", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
= MethodCallExpression.build(null, "emptyList", listOf(), typeArgumentsConverted, false) = MethodCallExpression.buildNonNull(null, "emptyList", ArgumentList.withNoPrototype(), typeArgumentsConverted)
}, },
COLLECTIONS_EMPTY_SET(Collections::class.java.name, "emptySet", 0) { COLLECTIONS_EMPTY_SET(Collections::class.java.name, "emptySet", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
= MethodCallExpression.build(null, "emptySet", listOf(), typeArgumentsConverted, false) = MethodCallExpression.buildNonNull(null, "emptySet", ArgumentList.withNoPrototype(), typeArgumentsConverted)
}, },
COLLECTIONS_EMPTY_MAP(Collections::class.java.name, "emptyMap", 0) { COLLECTIONS_EMPTY_MAP(Collections::class.java.name, "emptyMap", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
= MethodCallExpression.build(null, "emptyMap", listOf(), typeArgumentsConverted, false) = MethodCallExpression.buildNonNull(null, "emptyMap", ArgumentList.withNoPrototype(), typeArgumentsConverted)
}, },
COLLECTIONS_SINGLETON_LIST(Collections::class.java.name, "singletonList", 1) { COLLECTIONS_SINGLETON_LIST(Collections::class.java.name, "singletonList", 1) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression {
= MethodCallExpression.build(null, "listOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false) val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpression(arguments.single()))
return MethodCallExpression.buildNonNull(null, "listOf", argumentList, typeArgumentsConverted)
}
}, },
COLLECTIONS_SINGLETON(Collections::class.java.name, "singleton", 1) { COLLECTIONS_SINGLETON(Collections::class.java.name, "singleton", 1) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression {
= MethodCallExpression.build(null, "setOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false) val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpression(arguments.single()))
return MethodCallExpression.buildNonNull(null, "setOf", argumentList, typeArgumentsConverted)
}
}, },
STRING_TRIM(JAVA_LANG_STRING, "trim", 0) { STRING_TRIM(JAVA_LANG_STRING, "trim", 0) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? { override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? {
val comparison = BinaryExpression(Identifier.withNoPrototype("it", isNullable = false), LiteralExpression("' '").assignNoPrototype(), Operator(JavaTokenType.LE).assignNoPrototype()).assignNoPrototype() val comparison = BinaryExpression(Identifier.withNoPrototype("it", isNullable = false), LiteralExpression("' '").assignNoPrototype(), Operator(JavaTokenType.LE).assignNoPrototype()).assignNoPrototype()
return MethodCallExpression.buildNotNull( val argumentList = ArgumentList.withNoPrototype(LambdaExpression(null, Block.of(comparison).assignNoPrototype()))
codeConverter.convertExpression(qualifier), "trim", return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "trim", argumentList)
listOf(LambdaExpression(null, Block.of(comparison).assignNoPrototype())), emptyList())
} }
}, },
STRING_REPLACE_ALL(JAVA_LANG_STRING, "replaceAll", 2) { STRING_REPLACE_ALL(JAVA_LANG_STRING, "replaceAll", 2) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression {
= MethodCallExpression.build(codeConverter.convertExpression(qualifier), "replace", val argumentList = ArgumentList.withNoPrototype(
listOf( codeConverter.convertToRegex(arguments[0]),
codeConverter.convertToRegex(arguments[0]), codeConverter.convertExpression(arguments[1])
codeConverter.convertExpression(arguments[1]) )
), emptyList(), false) return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "replace", argumentList)
}
}, },
STRING_REPLACE_FIRST(JAVA_LANG_STRING, "replaceFirst", 2) { STRING_REPLACE_FIRST(JAVA_LANG_STRING, "replaceFirst", 2) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression {
= MethodCallExpression.build(codeConverter.convertExpression(qualifier), "replaceFirst", return MethodCallExpression.buildNonNull(
listOf( codeConverter.convertExpression(qualifier), "replaceFirst",
codeConverter.convertToRegex(arguments[0]), ArgumentList.withNoPrototype(
codeConverter.convertExpression(arguments[1]) codeConverter.convertToRegex(arguments[0]),
), emptyList(), false) codeConverter.convertExpression(arguments[1])
)
)
}
}, },
STRING_MATCHES(JAVA_LANG_STRING, "matches", 1) { STRING_MATCHES(JAVA_LANG_STRING, "matches", 1) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression {
= MethodCallExpression.build(codeConverter.convertExpression(qualifier), "matches", listOf(codeConverter.convertToRegex(arguments.single())), emptyList(), false) val argumentList = ArgumentList.withNoPrototype(codeConverter.convertToRegex(arguments.single()))
return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "matches", argumentList)
}
}, },
STRING_SPLIT(JAVA_LANG_STRING, "split", 1) { STRING_SPLIT(JAVA_LANG_STRING, "split", 1) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? { override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? {
val splitCall = MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), "split", listOf(codeConverter.convertToRegex(arguments.single())), emptyList()).assignNoPrototype() val splitCall = MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "split",
val isEmptyCall = MethodCallExpression.buildNotNull(Identifier.withNoPrototype("it", isNullable = false), "isEmpty", emptyList(), emptyList()).assignNoPrototype() ArgumentList.withNoPrototype(codeConverter.convertToRegex(arguments.single()))
).assignNoPrototype()
val isEmptyCall = MethodCallExpression.buildNonNull(Identifier.withNoPrototype("it", isNullable = false), "isEmpty").assignNoPrototype()
val isEmptyCallBlock = Block.of(isEmptyCall).assignNoPrototype() val isEmptyCallBlock = Block.of(isEmptyCall).assignNoPrototype()
val dropLastCall = MethodCallExpression.buildNotNull(splitCall, "dropLastWhile", listOf(LambdaExpression(null, isEmptyCallBlock).assignNoPrototype())).assignNoPrototype() val dropLastCall = MethodCallExpression.buildNonNull(splitCall, "dropLastWhile",
return MethodCallExpression.buildNotNull(dropLastCall, "toTypedArray", emptyList(), emptyList()) ArgumentList.withNoPrototype(LambdaExpression(null, isEmptyCallBlock).assignNoPrototype())).assignNoPrototype()
return MethodCallExpression.buildNonNull(dropLastCall, "toTypedArray")
} }
}, },
@@ -281,7 +293,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
val limit = evaluator.computeConstantExpression(arguments[1], /* throwExceptionOnOverflow = */ false) as? Int val limit = evaluator.computeConstantExpression(arguments[1], /* throwExceptionOnOverflow = */ false) as? Int
val splitArguments = when { val splitArguments = when {
limit == null -> // not a constant limit == null -> // not a constant
listOf(patternArgument, MethodCallExpression.buildNotNull(limitArgument, "coerceAtLeast", listOf(LiteralExpression("0").assignNoPrototype()), emptyList()).assignNoPrototype()) listOf(patternArgument, MethodCallExpression.buildNonNull(limitArgument, "coerceAtLeast", ArgumentList.withNoPrototype(LiteralExpression("0").assignNoPrototype())).assignNoPrototype())
limit < 0 -> // negative, same behavior as split(regex) in kotlin limit < 0 -> // negative, same behavior as split(regex) in kotlin
listOf(patternArgument) listOf(patternArgument)
limit == 0 -> // zero, same replacement as for split without limit limit == 0 -> // zero, same replacement as for split without limit
@@ -290,8 +302,8 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
listOf(patternArgument, limitArgument) listOf(patternArgument, limitArgument)
} }
val splitCall = MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), "split", splitArguments, emptyList()).assignNoPrototype() val splitCall = MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "split", ArgumentList.withNoPrototype(splitArguments)).assignNoPrototype()
return MethodCallExpression.buildNotNull(splitCall, "toTypedArray", emptyList(), emptyList()) return MethodCallExpression.buildNonNull(splitCall, "toTypedArray")
} }
}, },
@@ -299,8 +311,10 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean
= super.matches(method, superMethodsSearcher) && method.parameterList.parameters.last().type.canonicalText == "java.lang.Iterable<? extends java.lang.CharSequence>" = super.matches(method, superMethodsSearcher) && method.parameterList.parameters.last().type.canonicalText == "java.lang.Iterable<? extends java.lang.CharSequence>"
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression? {
= MethodCallExpression.buildNotNull(codeConverter.convertExpression(arguments[1]), "joinToString", codeConverter.convertExpressions(arguments.take(1)), emptyList()) val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpressions(arguments.take(1)))
return MethodCallExpression.buildNonNull(codeConverter.convertExpression(arguments[1]), "joinToString", argumentList)
}
}, },
STRING_JOIN_VARARG(JAVA_LANG_STRING, "join", null) { STRING_JOIN_VARARG(JAVA_LANG_STRING, "join", null) {
@@ -312,10 +326,10 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
return STRING_JOIN.convertCall(qualifier, arguments, typeArgumentsConverted, codeConverter) return STRING_JOIN.convertCall(qualifier, arguments, typeArgumentsConverted, codeConverter)
} }
else { else {
return MethodCallExpression.buildNotNull( return MethodCallExpression.buildNonNull(
MethodCallExpression.buildNotNull(null, "arrayOf", codeConverter.convertExpressions(arguments.drop(1))).assignNoPrototype(), MethodCallExpression.buildNonNull(null, "arrayOf", ArgumentList.withNoPrototype(codeConverter.convertExpressions(arguments.drop(1)))).assignNoPrototype(),
"joinToString", "joinToString",
codeConverter.convertExpressions(arguments.take(1)) ArgumentList.withNoPrototype(codeConverter.convertExpressions (arguments.take(1)))
) )
} }
} }
@@ -351,18 +365,20 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
val charsetArg = arguments.lastOrNull()?.check { it.type?.canonicalText == JAVA_LANG_STRING } val charsetArg = arguments.lastOrNull()?.check { it.type?.canonicalText == JAVA_LANG_STRING }
val convertedArguments = codeConverter.convertExpressions(arguments).map { val convertedArguments = codeConverter.convertExpressions(arguments).map {
if (charsetArg != null && it.prototypes?.singleOrNull()?.element == charsetArg) if (charsetArg != null && it.prototypes?.singleOrNull()?.element == charsetArg)
MethodCallExpression.buildNotNull(null, "charset", listOf(it)).assignNoPrototype() MethodCallExpression.buildNonNull(null, "charset", ArgumentList.withNoPrototype(it)).assignNoPrototype()
else else
it it
} }
return MethodCallExpression.build(codeConverter.convertExpression(qualifier), "toByteArray", convertedArguments, emptyList(), false) return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "toByteArray", ArgumentList.withNoPrototype(convertedArguments))
} }
}, },
STRING_GET_CHARS(JAVA_LANG_STRING, "getChars", 4) { STRING_GET_CHARS(JAVA_LANG_STRING, "getChars", 4) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression {
// reorder parameters: srcBegin(0), srcEnd(1), dst(2), dstOffset(3) -> destination(2), destinationOffset(3), startIndex(0), endIndex(1) // reorder parameters: srcBegin(0), srcEnd(1), dst(2), dstOffset(3) -> destination(2), destinationOffset(3), startIndex(0), endIndex(1)
= MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), "toCharArray", codeConverter.convertExpressions(arguments.slice(listOf(2, 3, 0, 1)))) val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpressions(arguments.slice(listOf(2, 3, 0, 1))))
return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "toCharArray", argumentList)
}
}, },
STRING_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "valueOf", null) { STRING_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "valueOf", null) {
@@ -373,7 +389,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
} }
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
= MethodCallExpression.build(null, "String", codeConverter.convertExpressions(arguments), emptyList(), false) = MethodCallExpression.buildNonNull(null, "String", ArgumentList.withNoPrototype(codeConverter.convertExpressions (arguments)))
}, },
STRING_COPY_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "copyValueOf", null) { STRING_COPY_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "copyValueOf", null) {
@@ -389,7 +405,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
STRING_VALUE_OF(JAVA_LANG_STRING, "valueOf", 1) { STRING_VALUE_OF(JAVA_LANG_STRING, "valueOf", 1) {
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter)
= MethodCallExpression.build(codeConverter.convertExpression(arguments.single(), true), "toString", emptyList(), emptyList(), false) = MethodCallExpression.buildNonNull(codeConverter.convertExpression(arguments.single(), true), "toString")
}, },
SYSTEM_OUT_PRINTLN(PrintStream::class.java.name, "println", null) { SYSTEM_OUT_PRINTLN(PrintStream::class.java.name, "println", null) {
@@ -425,14 +441,16 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
protected fun Array<PsiExpression>.notNull() = map { it to Nullability.NotNull } protected fun Array<PsiExpression>.notNull() = map { it to Nullability.NotNull }
protected fun convertWithChangedName(name: String, qualifier: PsiExpression?, arguments: List<Pair<PsiExpression, Nullability>>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter) protected fun convertWithChangedName(name: String, qualifier: PsiExpression?, arguments: List<Pair<PsiExpression, Nullability>>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression {
= MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), name, arguments.map { codeConverter.convertExpression(it.first, null, it.second) }, typeArgumentsConverted) val argumentList = ArgumentList.withNoPrototype(arguments.map { codeConverter.convertExpression(it.first, null, it.second) })
return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), name, argumentList, typeArgumentsConverted)
}
protected fun convertMethodCallWithReceiverCast(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression? { protected fun convertMethodCallWithReceiverCast(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): MethodCallExpression? {
val convertedArguments = arguments.map { codeConverter.convertExpression(it) } val convertedArguments = arguments.map { codeConverter.convertExpression(it) }
val qualifierWithCast = castQualifierToType(codeConverter, qualifier!!, qualifiedClassName!!) val qualifierWithCast = castQualifierToType(codeConverter, qualifier!!, qualifiedClassName!!)
if (qualifierWithCast != null) { if (qualifierWithCast != null) {
return MethodCallExpression.build(qualifierWithCast, methodName, convertedArguments, typeArgumentsConverted, false) return MethodCallExpression.buildNonNull(qualifierWithCast, methodName, ArgumentList.withNoPrototype(convertedArguments), typeArgumentsConverted)
} }
return null return null
} }
@@ -470,11 +488,12 @@ private fun convertSystemOutMethodCall(
if (qqualifier.canonicalText != "java.lang.System") return null if (qqualifier.canonicalText != "java.lang.System") return null
if (qualifier.referenceName != "out") return null if (qualifier.referenceName != "out") return null
if (typeArgumentsConverted.isNotEmpty()) return null if (typeArgumentsConverted.isNotEmpty()) return null
return MethodCallExpression.build(null, methodName, arguments.map { codeConverter.convertExpression(it) }, emptyList(), false) val argumentList = ArgumentList.withNoPrototype(arguments.map { codeConverter.convertExpression(it) })
return MethodCallExpression.buildNonNull(null, methodName, argumentList)
} }
private fun CodeConverter.convertToRegex(expression: PsiExpression?): Expression private fun CodeConverter.convertToRegex(expression: PsiExpression?): Expression
= MethodCallExpression.build(convertExpression(expression, true), "toRegex", emptyList(), emptyList(), false).assignNoPrototype() = MethodCallExpression.buildNonNull(convertExpression(expression, true), "toRegex").assignNoPrototype()
private fun addIgnoreCaseArgument( private fun addIgnoreCaseArgument(
qualifier: PsiExpression?, qualifier: PsiExpression?,
@@ -486,8 +505,10 @@ private fun addIgnoreCaseArgument(
): Expression { ): Expression {
val ignoreCaseExpression = ignoreCaseArgument?.let { codeConverter.convertExpression(it) } ?: LiteralExpression("true").assignNoPrototype() val ignoreCaseExpression = ignoreCaseArgument?.let { codeConverter.convertExpression(it) } ?: LiteralExpression("true").assignNoPrototype()
val ignoreCaseArgumentExpression = AssignmentExpression(Identifier.withNoPrototype("ignoreCase"), ignoreCaseExpression, Operator.EQ).assignNoPrototype() val ignoreCaseArgumentExpression = AssignmentExpression(Identifier.withNoPrototype("ignoreCase"), ignoreCaseExpression, Operator.EQ).assignNoPrototype()
return MethodCallExpression.build(codeConverter.convertExpression(qualifier), methodName, val argumentList = ArgumentList.withNoPrototype(arguments.map { codeConverter.convertExpression(it, null, Nullability.NotNull) } + ignoreCaseArgumentExpression)
arguments.map { codeConverter.convertExpression(it, null, Nullability.NotNull) } + ignoreCaseArgumentExpression, return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier),
typeArgumentsConverted, false) methodName,
argumentList,
typeArgumentsConverted)
} }
@@ -54,18 +54,18 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
val descriptionExpr = statement.assertDescription val descriptionExpr = statement.assertDescription
val condition = codeConverter.convertExpression(statement.assertCondition) val condition = codeConverter.convertExpression(statement.assertCondition)
if (descriptionExpr == null) { if (descriptionExpr == null) {
result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition)) result = MethodCallExpression.buildNonNull(null, "assert", ArgumentList.withNoPrototype(condition))
} }
else { else {
val description = codeConverter.convertExpression(descriptionExpr) val description = codeConverter.convertExpression(descriptionExpr)
val lambda = LambdaExpression(null, Block.of(description).assignNoPrototype()) val lambda = LambdaExpression(null, Block.of(description).assignNoPrototype())
result = MethodCallExpression.build(null, "assert", listOf(condition, lambda), listOf(), false) result = MethodCallExpression.buildNonNull(null, "assert", ArgumentList.withNoPrototype(condition, lambda))
} }
} }
override fun visitBlockStatement(statement: PsiBlockStatement) { override fun visitBlockStatement(statement: PsiBlockStatement) {
val block = codeConverter.convertBlock(statement.codeBlock) val block = codeConverter.convertBlock(statement.codeBlock)
result = MethodCallExpression.build(null, "run", listOf(LambdaExpression(null, block).assignNoPrototype()), listOf(), false) result = MethodCallExpression.buildNonNull(null, "run", ArgumentList.withNoPrototype(LambdaExpression(null, block).assignNoPrototype()))
} }
override fun visitBreakStatement(statement: PsiBreakStatement) { override fun visitBreakStatement(statement: PsiBreakStatement) {
@@ -218,7 +218,7 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter {
val parameter = LambdaParameter(Identifier.withNoPrototype(variable.name!!), null).assignNoPrototype() val parameter = LambdaParameter(Identifier.withNoPrototype(variable.name!!), null).assignNoPrototype()
val parameterList = ParameterList(listOf(parameter), lPar = null, rPar = null).assignNoPrototype() val parameterList = ParameterList(listOf(parameter), lPar = null, rPar = null).assignNoPrototype()
val lambda = LambdaExpression(parameterList, block) val lambda = LambdaExpression(parameterList, block)
expression = MethodCallExpression.build(codeConverter.convertExpression(variable.initializer), "use", listOf(lambda), listOf(), false) expression = MethodCallExpression.buildNonNull(codeConverter.convertExpression(variable.initializer), "use", ArgumentList.withNoPrototype(lambda))
expression.assignNoPrototype() expression.assignNoPrototype()
block = Block.of(expression).assignNoPrototype() block = Block.of(expression).assignNoPrototype()
} }
+2 -2
View File
@@ -34,8 +34,8 @@ fun getDefaultInitializer(property: Property): Expression? {
when (t.name.name) { when (t.name.name) {
"Boolean" -> LiteralExpression("false") "Boolean" -> LiteralExpression("false")
"Char" -> LiteralExpression("' '") "Char" -> LiteralExpression("' '")
"Double" -> MethodCallExpression.buildNotNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.DOUBLE.toString()) "Double" -> MethodCallExpression.buildNonNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.DOUBLE.toString())
"Float" -> MethodCallExpression.buildNotNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.FLOAT.toString()) "Float" -> MethodCallExpression.buildNonNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.FLOAT.toString())
else -> LiteralExpression("0") else -> LiteralExpression("0")
} }
} }
@@ -19,11 +19,22 @@ package org.jetbrains.kotlin.j2k.ast
import org.jetbrains.kotlin.j2k.CodeBuilder import org.jetbrains.kotlin.j2k.CodeBuilder
import org.jetbrains.kotlin.j2k.append import org.jetbrains.kotlin.j2k.append
class ExpressionList(val expressions: List<Expression>) : Expression() { class ArgumentList(
val expressions: List<Expression>,
val lPar: LPar,
val rPar: RPar
) : Expression() {
override fun generateCode(builder: CodeBuilder) { override fun generateCode(builder: CodeBuilder) {
builder.append(lPar)
builder.append(expressions, ", ") builder.append(expressions, ", ")
builder.append(rPar)
} }
override val isEmpty: Boolean companion object {
get() = expressions.isEmpty() fun withNoPrototype(arguments: List<Expression>): ArgumentList {
return ArgumentList(arguments, LPar().assignNoPrototype(), RPar().assignNoPrototype()).assignNoPrototype()
}
fun withNoPrototype(vararg arguments: Expression): ArgumentList = withNoPrototype(arguments.asList())
}
} }
@@ -22,19 +22,19 @@ class EnumConstant(
val identifier: Identifier, val identifier: Identifier,
annotations: Annotations, annotations: Annotations,
modifiers: Modifiers, modifiers: Modifiers,
val params: DeferredElement<ExpressionList>, val params: DeferredElement<ArgumentList>?,
val body: AnonymousClassBody? val body: AnonymousClassBody?
) : Member(annotations, modifiers) { ) : Member(annotations, modifiers) {
override fun generateCode(builder: CodeBuilder) { override fun generateCode(builder: CodeBuilder) {
builder append annotations append identifier builder.append(annotations).append(identifier)
if (!params.isEmpty) { if (params != null) {
builder append "(" append params append ")" builder.append(params)
} }
if (body != null) { if (body != null) {
builder append body builder.append(body)
} }
} }
} }
@@ -257,5 +257,5 @@ fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List<Ex
"arrayOf<" + arrayType.elementType.canonicalCode() + ">" "arrayOf<" + arrayType.elementType.canonicalCode() + ">"
else else
"arrayOf" "arrayOf"
return MethodCallExpression.buildNotNull(null, createArrayFunction, initializers) return MethodCallExpression.buildNonNull(null, createArrayFunction, ArgumentList.withNoPrototype(initializers))
} }
@@ -21,37 +21,41 @@ import org.jetbrains.kotlin.j2k.append
class MethodCallExpression( class MethodCallExpression(
val methodExpression: Expression, val methodExpression: Expression,
val arguments: List<Expression>, val argumentList: ArgumentList,
val typeArguments: List<Type>, val typeArguments: List<Type>,
override val isNullable: Boolean override val isNullable: Boolean
) : Expression() { ) : Expression() {
override fun generateCode(builder: CodeBuilder) { override fun generateCode(builder: CodeBuilder) {
builder.appendOperand(this, methodExpression).append(typeArguments, ", ", "<", ">") builder.appendOperand(this, methodExpression).append(typeArguments, ", ", "<", ">")
builder.append("(").append(arguments, ", ").append(")") builder.append(argumentList)
} }
companion object { companion object {
fun buildNotNull(receiver: Expression?, fun buildNonNull(
methodName: String, receiver: Expression?,
arguments: List<Expression> = listOf(), methodName: String,
typeArguments: List<Type> = listOf()): MethodCallExpression argumentList: ArgumentList = ArgumentList.withNoPrototype(),
= build(receiver, methodName, arguments, typeArguments, false) typeArguments: List<Type> = emptyList()
): MethodCallExpression = build(receiver, methodName, argumentList, typeArguments, false)
fun buildNullable(receiver: Expression?, fun buildNullable(
methodName: String, receiver: Expression?,
arguments: List<Expression> = listOf(), methodName: String,
typeArguments: List<Type> = listOf()): MethodCallExpression argumentList: ArgumentList = ArgumentList.withNoPrototype(),
= build(receiver, methodName, arguments, typeArguments, true) typeArguments: List<Type> = emptyList()
): MethodCallExpression = build(receiver, methodName, argumentList, typeArguments, true)
fun build(receiver: Expression?, fun build(
methodName: String, receiver: Expression?,
arguments: List<Expression>, methodName: String,
typeArguments: List<Type>, argumentList: ArgumentList,
isNullable: Boolean): MethodCallExpression { typeArguments: List<Type>,
isNullable: Boolean
): MethodCallExpression {
val identifier = Identifier.withNoPrototype(methodName, isNullable = false) val identifier = Identifier.withNoPrototype(methodName, isNullable = false)
return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier).assignNoPrototype() else identifier, return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier).assignNoPrototype() else identifier,
arguments, argumentList,
typeArguments, typeArguments,
isNullable) isNullable)
} }
@@ -17,11 +17,10 @@
package org.jetbrains.kotlin.j2k.ast package org.jetbrains.kotlin.j2k.ast
import org.jetbrains.kotlin.j2k.CodeBuilder import org.jetbrains.kotlin.j2k.CodeBuilder
import org.jetbrains.kotlin.j2k.append
class NewClassExpression( class NewClassExpression(
val name: ReferenceElement?, val name: ReferenceElement?,
val arguments: List<Expression>, val argumentList: ArgumentList,
val qualifier: Expression = Expression.Empty, val qualifier: Expression = Expression.Empty,
val anonymousClass: AnonymousClassBody? = null val anonymousClass: AnonymousClassBody? = null
) : Expression() { ) : Expression() {
@@ -40,7 +39,7 @@ class NewClassExpression(
} }
if (anonymousClass == null || !anonymousClass.extendsInterface) { if (anonymousClass == null || !anonymousClass.extendsInterface) {
builder.append("(").append(arguments, ", ").append(")") builder.append(argumentList)
} }
if (anonymousClass != null) { if (anonymousClass != null) {
@@ -5,6 +5,7 @@ class F {
void f2(int[] array) { void f2(int[] array) {
f1(1, 2, f1(1, 2,
3, 4, 3, 4,
array); array
);
} }
} }
@@ -5,6 +5,7 @@ internal class F {
fun f2(array: IntArray) { fun f2(array: IntArray) {
f1(1, 2, f1(1, 2,
3, 4, 3, 4,
*array) *array
)
} }
} }