Don't introduce call to deprecated "StringBuilder.append(String)"
Merge-request: KT-MR-6705 Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
+21
-21
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.common.lower.at
|
|||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -24,7 +23,6 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
/**
|
/**
|
||||||
* This pass replaces calls to:
|
* This pass replaces calls to:
|
||||||
* - StringBuilder.append(Any?) with StringBuilder.append(String?)
|
* - StringBuilder.append(Any?) with StringBuilder.append(String?)
|
||||||
* - StringBuilder.append(Any) with StringBuilder.append(String)
|
|
||||||
* - String.plus(Any?) with String.plusImpl(String)
|
* - String.plus(Any?) with String.plusImpl(String)
|
||||||
* - String?.plus(Any?) with String.plusImpl(String)
|
* - String?.plus(Any?) with String.plusImpl(String)
|
||||||
* For this, toString() is called for non-String arguments. This call can be later devirtualized, improving escape analysis
|
* For this, toString() is called for non-String arguments. This call can be later devirtualized, improving escape analysis
|
||||||
@@ -39,10 +37,6 @@ internal class StringConcatenationTypeNarrowing(val context: Context) : FileLowe
|
|||||||
private val namePlusImpl = Name.identifier("plusImpl")
|
private val namePlusImpl = Name.identifier("plusImpl")
|
||||||
private val nameAppend = Name.identifier("append")
|
private val nameAppend = Name.identifier("append")
|
||||||
|
|
||||||
private val appendStringFunction = stringBuilder.functions.single { // StringBuilder.append(String)
|
|
||||||
it.name == nameAppend &&
|
|
||||||
it.valueParameters.singleOrNull()?.type?.isString() == true
|
|
||||||
}
|
|
||||||
private val appendNullableStringFunction = stringBuilder.functions.single { // StringBuilder.append(String?)
|
private val appendNullableStringFunction = stringBuilder.functions.single { // StringBuilder.append(String?)
|
||||||
it.name == nameAppend &&
|
it.name == nameAppend &&
|
||||||
it.valueParameters.singleOrNull()?.type?.isNullableString() == true
|
it.valueParameters.singleOrNull()?.type?.isNullableString() == true
|
||||||
@@ -67,16 +61,8 @@ internal class StringConcatenationTypeNarrowing(val context: Context) : FileLowe
|
|||||||
return with(expression) {
|
return with(expression) {
|
||||||
builder.at(this)
|
builder.at(this)
|
||||||
when (symbol) {
|
when (symbol) {
|
||||||
appendAnyFunction.symbol -> { // StringBuilder.append(Any?)
|
appendAnyFunction.symbol -> // StringBuilder.append(Any?)
|
||||||
val argument = getValueArgument(0)!!
|
buildConcatenationCall(appendNullableStringFunction, dispatchReceiver!!, buildArgForAppend(getValueArgument(0)!!))
|
||||||
if (argument.type.isNullable()) {
|
|
||||||
// Transform `StringBuilder.append(Any?)` to `StringBuilder.append(ARG?.toString())`, using "StringBuilder.append(String?)"
|
|
||||||
buildConcatenationCall(appendNullableStringFunction, dispatchReceiver!!, buildNullableArgToNullableString(argument))
|
|
||||||
} else {
|
|
||||||
// Transform `StringBuilder.append(Any)` to `StringBuilder.append(ARG.toString())`, using "StringBuilder.append(String)"
|
|
||||||
buildConcatenationCall(appendStringFunction, dispatchReceiver!!, buildNonNullableArgToString(argument))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.irBuiltIns.memberStringPlus ->
|
context.irBuiltIns.memberStringPlus ->
|
||||||
buildConcatenationCall(plusImplFunction, dispatchReceiver!!, buildNullableArgToString(getValueArgument(0)!!))
|
buildConcatenationCall(plusImplFunction, dispatchReceiver!!, buildNullableArgToString(getValueArgument(0)!!))
|
||||||
@@ -89,7 +75,7 @@ internal class StringConcatenationTypeNarrowing(val context: Context) : FileLowe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrCall.buildConcatenationCall(function: IrSimpleFunction, receiver: IrExpression, argument: IrExpression): IrExpression =
|
private fun buildConcatenationCall(function: IrSimpleFunction, receiver: IrExpression, argument: IrExpression): IrExpression =
|
||||||
builder.irCall(function.symbol, function.returnType, valueArgumentsCount = 1, typeArgumentsCount = 0)
|
builder.irCall(function.symbol, function.returnType, valueArgumentsCount = 1, typeArgumentsCount = 0)
|
||||||
.apply {
|
.apply {
|
||||||
putValueArgument(0, argument)
|
putValueArgument(0, argument)
|
||||||
@@ -99,6 +85,7 @@ internal class StringConcatenationTypeNarrowing(val context: Context) : FileLowe
|
|||||||
/** Builds snippet of type String
|
/** Builds snippet of type String
|
||||||
* - "if(argument==null) "null" else argument.toString()", if argument's type is nullable. Note: fortunately, all "null" string structures are unified
|
* - "if(argument==null) "null" else argument.toString()", if argument's type is nullable. Note: fortunately, all "null" string structures are unified
|
||||||
* - "argument.toString()", otherwise
|
* - "argument.toString()", otherwise
|
||||||
|
* Note: should side effects are possible, temporary val is introduced
|
||||||
*/
|
*/
|
||||||
private fun buildNullableArgToString(argument: IrExpression): IrExpression =
|
private fun buildNullableArgToString(argument: IrExpression): IrExpression =
|
||||||
if (argument.type.isNullable()) {
|
if (argument.type.isNullable()) {
|
||||||
@@ -108,13 +95,26 @@ internal class StringConcatenationTypeNarrowing(val context: Context) : FileLowe
|
|||||||
} else buildNonNullableArgToString(argument)
|
} else buildNonNullableArgToString(argument)
|
||||||
|
|
||||||
/** Builds snippet of type String?
|
/** Builds snippet of type String?
|
||||||
* "if(argument==null) null else argument.toString()", that is similar to "argument?.toString()"
|
* - "if(argument==null) null else argument.toString()" (that is similar to "argument?.toString()"), if argument's type is nullable.
|
||||||
|
* - "argument.toString()", otherwise
|
||||||
|
* Note: should side effects are possible, temporary val is introduced
|
||||||
*/
|
*/
|
||||||
private fun buildNullableArgToNullableString(argument: IrExpression): IrExpression =
|
private fun buildArgForAppend(argument: IrExpression): IrExpression =
|
||||||
builder.irBlock {
|
if (argument.type.isNullable()) {
|
||||||
nullableArgToStringType(argument, context.irBuiltIns.stringType.makeNullable(), irNull())
|
// Transform argument of `StringBuilder.append(Any?)` to `ARG?.toString()`, of type "String?"
|
||||||
|
builder.irBlock {
|
||||||
|
nullableArgToStringType(argument, context.irBuiltIns.stringType.makeNullable(), irNull())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Transform argument of `StringBuilder.append(Any)` to `ARG.toString()`, of type "String"
|
||||||
|
buildNonNullableArgToString(argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Builds snippet of type String:
|
||||||
|
* val arg = argument
|
||||||
|
* if (arg==null) ifNull else arg.toString()
|
||||||
|
* In case "argument" is IrGetValue => temporary val is omitted due to side effect absence
|
||||||
|
*/
|
||||||
private fun IrBlockBuilder.nullableArgToStringType(argument: IrExpression, stringType: IrType, ifNull: IrExpression) {
|
private fun IrBlockBuilder.nullableArgToStringType(argument: IrExpression, stringType: IrType, ifNull: IrExpression) {
|
||||||
val (firstExpression, secondExpression) = twoExpressionsForSubsequentUsages(argument)
|
val (firstExpression, secondExpression) = twoExpressionsForSubsequentUsages(argument)
|
||||||
+irIfThenElse(
|
+irIfThenElse(
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ fun appendMaybeAny(maybeAny: Any?): String {
|
|||||||
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual#appendAny(kotlin.Any)
|
// CHECK-LABEL: define %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual#appendAny(kotlin.Any)
|
||||||
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual.Foo#toString(){}kotlin.String"
|
// CHECK: %struct.ObjHeader* @"kfun:codegen.stringConcatenationTypeNarrowing.kt53119_append_manual.Foo#toString(){}kotlin.String"
|
||||||
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String)
|
// CHECK: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append(kotlin.String?)
|
||||||
|
|
||||||
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
// CHECK-NOT: Foo#toString(){}kotlin.String"
|
||||||
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
// CHECK-NOT: %struct.ObjHeader* @"kfun:kotlin.text.StringBuilder#append
|
||||||
|
|||||||
Reference in New Issue
Block a user