From a3a93d826e0580ca609d76ccfe06e45cd363cd2e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 14 Oct 2024 14:38:56 +0200 Subject: [PATCH 1/3] KE2: Extract `String.plus` and `String?.plus` calls --- .../src/main/kotlin/KotlinFileExtractor.kt | 23 ------ .../src/main/kotlin/entities/Expression.kt | 75 +++++++++++++++---- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt index 9668d74dab40..4f715973faff 100644 --- a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt @@ -3695,29 +3695,6 @@ OLD: KE1 val dr = c.dispatchReceiver when { - isFunction(target, "kotlin", "String", "plus", false) -> { - val id = tw.getFreshIdLabel() - val type = useType(c.type) - tw.writeExprs_addexpr(id, type.javaResult.id, parent, idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - binopDisp(id) - } - isFunction(target, "kotlin", "String", "plus", true) -> { - findJdkIntrinsicOrWarn("stringPlus", c)?.let { stringPlusFn -> - extractRawMethodAccess( - stringPlusFn, - c, - c.type, - callable, - parent, - idx, - enclosingStmt, - listOf(c.extensionReceiver, c.getValueArgument(0)), - null, - null - ) - } - } isNumericFunction( target, "plus", diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 97a18aafb58a..65b9a476711f 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -8,7 +8,13 @@ import org.jetbrains.kotlin.analysis.api.resolution.KaSuccessCallInfo import org.jetbrains.kotlin.analysis.api.resolution.symbol import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionSymbol import org.jetbrains.kotlin.analysis.api.types.KaType +import org.jetbrains.kotlin.analysis.api.types.KaTypeNullability +import org.jetbrains.kotlin.analysis.api.types.symbol import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.CallableId +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.parsing.parseNumericLiteral import org.jetbrains.kotlin.psi.* @@ -215,25 +221,57 @@ OLD: KE1 } */ -private fun isFunction( +private fun isFunctionMatchingNames( + symbol: KaFunctionSymbol, + name: CallableId, + isExtension: Boolean = false, + nullability: KaTypeNullability = KaTypeNullability.UNKNOWN, + extensionReceiverClassName: ClassId? = null +): Boolean { + + if (symbol.callableId != name) + return false + + if (!isExtension) + return true + + val receiverType = symbol.receiverParameter?.type + if (receiverType == null) + return false + + if (receiverType.nullability != nullability) + return false + + if (receiverType.symbol?.classId != extensionReceiverClassName) + return false + + return true +} + +private fun isFunctionMatchingName( symbol: KaFunctionSymbol, packageName: String, - className: String, + className: String?, functionName: String ): Boolean { - return symbol.callableId?.packageName?.asString() == packageName && - symbol.callableId?.className?.asString() == className && - symbol.callableId?.callableName?.asString() == functionName + return isFunctionMatchingNames( + symbol, + CallableId( + FqName(packageName), + if (className == null) null else FqName(className), + Name.identifier(functionName) + ) + ) } -private fun isNumericFunction(target: KaFunctionSymbol, fName: String): Boolean { - return isFunction(target, "kotlin", "Int", fName) || - isFunction(target, "kotlin", "Byte", fName) || - isFunction(target, "kotlin", "Short", fName) || - isFunction(target, "kotlin", "Long", fName) || - isFunction(target, "kotlin", "Float", fName) || - isFunction(target, "kotlin", "Double", fName) +private fun isNumericFunction(target: KaFunctionSymbol, functionName: String): Boolean { + return isFunctionMatchingName(target, "kotlin", "Int", functionName) || + isFunctionMatchingName(target, "kotlin", "Byte", functionName) || + isFunctionMatchingName(target, "kotlin", "Short", functionName) || + isFunctionMatchingName(target, "kotlin", "Long", functionName) || + isFunctionMatchingName(target, "kotlin", "Float", functionName) || + isFunctionMatchingName(target, "kotlin", "Double", functionName) } /** @@ -267,7 +305,16 @@ private fun KotlinFileExtractor.extractBinaryExpression( TODO() } - if (isNumericFunction(target, "plus")) { + if (isNumericFunction(target, "plus") || + isFunctionMatchingName(target, "kotlin", "String", "plus") || + isFunctionMatchingNames( + target, + CallableId(FqName("kotlin"), null, Name.identifier("plus")), + isExtension = true, + nullability = KaTypeNullability.NULLABLE, + ClassId(FqName("kotlin"), Name.identifier("String")) + ) + ) { val id = tw.getFreshIdLabel() val type = useType(expression.expressionType) val exprParent = parent.expr(expression, callable) @@ -278,7 +325,7 @@ private fun KotlinFileExtractor.extractBinaryExpression( extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt) extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt) } else { - TODO() + TODO("Extract as method call") } } From 125797cd4f6ec0e3fe305fb51456c9c0ef66a17f Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 14 Oct 2024 20:31:52 +0200 Subject: [PATCH 2/3] Improve code quality --- .../src/main/kotlin/entities/Expression.kt | 57 +++++++------------ 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 65b9a476711f..39bf03930ae8 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -221,42 +221,31 @@ OLD: KE1 } */ -private fun isFunctionMatchingNames( - symbol: KaFunctionSymbol, +private fun KaFunctionSymbol.hasMatchingNames( name: CallableId, - isExtension: Boolean = false, + extensionReceiverClassName: ClassId? = null, nullability: KaTypeNullability = KaTypeNullability.UNKNOWN, - extensionReceiverClassName: ClassId? = null ): Boolean { - if (symbol.callableId != name) + if (this.callableId != name) return false - if (!isExtension) - return true - - val receiverType = symbol.receiverParameter?.type - if (receiverType == null) - return false - - if (receiverType.nullability != nullability) - return false - - if (receiverType.symbol?.classId != extensionReceiverClassName) - return false + val receiverType = this.receiverParameter?.type + if (receiverType != null && extensionReceiverClassName != null) { + return receiverType.nullability == nullability && + receiverType.symbol?.classId == extensionReceiverClassName + } - return true + return receiverType == null && extensionReceiverClassName == null } -private fun isFunctionMatchingName( - symbol: KaFunctionSymbol, +private fun KaFunctionSymbol.hasName( packageName: String, className: String?, functionName: String ): Boolean { - return isFunctionMatchingNames( - symbol, + return this.hasMatchingNames( CallableId( FqName(packageName), if (className == null) null else FqName(className), @@ -265,13 +254,13 @@ private fun isFunctionMatchingName( ) } -private fun isNumericFunction(target: KaFunctionSymbol, functionName: String): Boolean { - return isFunctionMatchingName(target, "kotlin", "Int", functionName) || - isFunctionMatchingName(target, "kotlin", "Byte", functionName) || - isFunctionMatchingName(target, "kotlin", "Short", functionName) || - isFunctionMatchingName(target, "kotlin", "Long", functionName) || - isFunctionMatchingName(target, "kotlin", "Float", functionName) || - isFunctionMatchingName(target, "kotlin", "Double", functionName) +private fun KaFunctionSymbol.isNumericWithName(functionName: String): Boolean { + return this.hasName("kotlin", "Int", functionName) || + this.hasName("kotlin", "Byte", functionName) || + this.hasName("kotlin", "Short", functionName) || + this.hasName("kotlin", "Long", functionName) || + this.hasName("kotlin", "Float", functionName) || + this.hasName("kotlin", "Double", functionName) } /** @@ -305,14 +294,12 @@ private fun KotlinFileExtractor.extractBinaryExpression( TODO() } - if (isNumericFunction(target, "plus") || - isFunctionMatchingName(target, "kotlin", "String", "plus") || - isFunctionMatchingNames( - target, + if (target.isNumericWithName("plus") || + target.hasName("kotlin", "String", "plus") || + target.hasMatchingNames( CallableId(FqName("kotlin"), null, Name.identifier("plus")), - isExtension = true, + ClassId(FqName("kotlin"), Name.identifier("String")), nullability = KaTypeNullability.NULLABLE, - ClassId(FqName("kotlin"), Name.identifier("String")) ) ) { val id = tw.getFreshIdLabel() From 7b198da95fcd3a6f0bd87255f94c98050d7e494e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 15 Oct 2024 10:29:14 +0200 Subject: [PATCH 3/3] Improve code quality --- .../src/main/kotlin/entities/Expression.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 39bf03930ae8..1a67f7abc42c 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -224,7 +224,7 @@ OLD: KE1 private fun KaFunctionSymbol.hasMatchingNames( name: CallableId, extensionReceiverClassName: ClassId? = null, - nullability: KaTypeNullability = KaTypeNullability.UNKNOWN, + nullability: KaTypeNullability? = null, ): Boolean { if (this.callableId != name) @@ -236,7 +236,9 @@ private fun KaFunctionSymbol.hasMatchingNames( receiverType.symbol?.classId == extensionReceiverClassName } - return receiverType == null && extensionReceiverClassName == null + return receiverType == null && + extensionReceiverClassName == null && + nullability == null } private fun KaFunctionSymbol.hasName(