diff --git a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt index 74b49a4993bd..ff7cd7b86c76 100644 --- a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt @@ -2979,93 +2979,6 @@ OLD: KE1 val dr = c.dispatchReceiver when { - isNumericFunction( - target, - "plus", - "minus", - "times", - "div", - "rem", - "and", - "or", - "xor", - "shl", - "shr", - "ushr" - ) -> { - val type = useType(c.type) - val id: Label = - when (val targetName = target.name.asString()) { - "minus" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_subexpr(id, type.javaResult.id, parent, idx) - id - } - "times" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_mulexpr(id, type.javaResult.id, parent, idx) - id - } - "div" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_divexpr(id, type.javaResult.id, parent, idx) - id - } - "rem" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_remexpr(id, type.javaResult.id, parent, idx) - id - } - "and" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_andbitexpr(id, type.javaResult.id, parent, idx) - id - } - "or" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_orbitexpr(id, type.javaResult.id, parent, idx) - id - } - "xor" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_xorbitexpr(id, type.javaResult.id, parent, idx) - id - } - "shl" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_lshiftexpr(id, type.javaResult.id, parent, idx) - id - } - "shr" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_rshiftexpr(id, type.javaResult.id, parent, idx) - id - } - "ushr" -> { - val id = tw.getFreshIdLabel() - tw.writeExprs_urshiftexpr(id, type.javaResult.id, parent, idx) - id - } - else -> { - logger.errorElement("Unhandled binary target name: $targetName", c) - return - } - } - tw.writeExprsKotlinType(id, type.kotlinResult.id) - if ( - isFunction( - target, - "kotlin", - "Byte or Short", - { it == "Byte" || it == "Short" }, - "and", - "or", - "xor" - ) - ) - binopExt(id) - else binopDisp(id) - } // != gets desugared into not and ==. Here we resugar it. c.origin == IrStatementOrigin.EXCLEQ && isFunction(target, "kotlin", "Boolean", "not") && @@ -3079,18 +2992,6 @@ OLD: KE1 tw.writeExprsKotlinType(id, type.kotlinResult.id) binOp(id, dr, callable, enclosingStmt) } - c.origin == IrStatementOrigin.EXCLEQEQ && - isFunction(target, "kotlin", "Boolean", "not") && - c.valueArgumentsCount == 0 && - dr != null && - dr is IrCall && - isBuiltinCallInternal(dr, "EQEQEQ") -> { - val id = tw.getFreshIdLabel() - val type = useType(c.type) - tw.writeExprs_neexpr(id, type.javaResult.id, parent, idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - binOp(id, dr, callable, enclosingStmt) - } c.origin == IrStatementOrigin.EXCLEQ && isFunction(target, "kotlin", "Boolean", "not") && c.valueArgumentsCount == 0 && @@ -3150,46 +3051,6 @@ OLD: KE1 // We need to handle all the builtin operators defines in BuiltInOperatorNames in // compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt // as they can't be extracted as external dependencies. - isBuiltinCallInternal(c, "less") -> { - if (c.origin != IrStatementOrigin.LT) { - logger.warnElement("Unexpected origin for LT: ${c.origin}", c) - } - val id = tw.getFreshIdLabel() - val type = useType(c.type) - tw.writeExprs_ltexpr(id, type.javaResult.id, parent, idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - binOp(id, c, callable, enclosingStmt) - } - isBuiltinCallInternal(c, "lessOrEqual") -> { - if (c.origin != IrStatementOrigin.LTEQ) { - logger.warnElement("Unexpected origin for LTEQ: ${c.origin}", c) - } - val id = tw.getFreshIdLabel() - val type = useType(c.type) - tw.writeExprs_leexpr(id, type.javaResult.id, parent, idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - binOp(id, c, callable, enclosingStmt) - } - isBuiltinCallInternal(c, "greater") -> { - if (c.origin != IrStatementOrigin.GT) { - logger.warnElement("Unexpected origin for GT: ${c.origin}", c) - } - val id = tw.getFreshIdLabel() - val type = useType(c.type) - tw.writeExprs_gtexpr(id, type.javaResult.id, parent, idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - binOp(id, c, callable, enclosingStmt) - } - isBuiltinCallInternal(c, "greaterOrEqual") -> { - if (c.origin != IrStatementOrigin.GTEQ) { - logger.warnElement("Unexpected origin for GTEQ: ${c.origin}", c) - } - val id = tw.getFreshIdLabel() - val type = useType(c.type) - tw.writeExprs_geexpr(id, type.javaResult.id, parent, idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - binOp(id, c, callable, enclosingStmt) - } isBuiltinCallInternal(c, "EQEQ") -> { if (c.origin != IrStatementOrigin.EQEQ) { logger.warnElement("Unexpected origin for EQEQ: ${c.origin}", c) @@ -3200,16 +3061,6 @@ OLD: KE1 tw.writeExprsKotlinType(id, type.kotlinResult.id) binOp(id, c, callable, enclosingStmt) } - isBuiltinCallInternal(c, "EQEQEQ") -> { - if (c.origin != IrStatementOrigin.EQEQEQ) { - logger.warnElement("Unexpected origin for EQEQEQ: ${c.origin}", c) - } - val id = tw.getFreshIdLabel() - val type = useType(c.type) - tw.writeExprs_eqexpr(id, type.javaResult.id, parent, idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - binOp(id, c, callable, enclosingStmt) - } isBuiltinCallInternal(c, "ieee754equals") -> { if (c.origin != IrStatementOrigin.EQEQ) { logger.warnElement("Unexpected origin for ieee754equals: ${c.origin}", c) diff --git a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt index 15b8028a9f0a..dd62df86d98c 100644 --- a/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt +++ b/java/kotlin-extractor2/src/main/kotlin/entities/Expression.kt @@ -256,13 +256,14 @@ private fun KaFunctionSymbol.hasName( ) } -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) +private fun KaFunctionSymbol?.isNumericWithName(functionName: String): Boolean { + return this != null && + (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)) } context(KaSession) @@ -297,37 +298,84 @@ private fun KotlinFileExtractor.extractBinaryExpression( val op = expression.operationToken val target = expression.resolveCallTarget()?.symbol - when (op) { - KtTokens.PLUS -> { - if (target == null) { - TODO() - } - - if (target.isNumericWithName("plus") || - target.hasName("kotlin", "String", "plus") || - target.hasMatchingNames( - CallableId(FqName("kotlin"), null, Name.identifier("plus")), - ClassId(FqName("kotlin"), Name.identifier("String")), - nullability = KaTypeNullability.NULLABLE, - ) - ) { - val id = tw.getFreshIdLabel() - val type = useType(expression.expressionType) - val exprParent = parent.expr(expression, callable) - tw.writeExprs_addexpr(id, type.javaResult.id, exprParent.parent, exprParent.idx) - tw.writeExprsKotlinType(id, type.kotlinResult.id) - - extractExprContext(id, tw.getLocation(expression), callable, exprParent.enclosingStmt) - extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt) - extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt) - } else { - TODO("Extract as method call") + if (op == KtTokens.PLUS && target.isBinaryPlus()) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_addexpr) + } else if (op == KtTokens.MINUS && target.isNumericWithName("minus")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_subexpr) + } else if (op == KtTokens.MUL && target.isNumericWithName("times")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_mulexpr) + } else if (op == KtTokens.DIV && target.isNumericWithName("div")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_divexpr) + } else if (op == KtTokens.PERC && target.isNumericWithName("rem")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_remexpr) + } else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("and")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_andbitexpr) + } else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("or")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_orbitexpr) + } else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("xor")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_xorbitexpr) + } else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("shl")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_lshiftexpr) + } else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("shr")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_rshiftexpr) + } else if (op == KtTokens.IDENTIFIER && target.isNumericWithName("ushr")) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_urshiftexpr) + } else if (op == KtTokens.EQEQEQ && target == null) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_eqexpr) + } else if (op == KtTokens.EXCLEQEQEQ && target == null) { + extractBinaryExpression(expression, callable, parent, tw::writeExprs_neexpr) + } else if (op in listOf(KtTokens.LT, KtTokens.GT, KtTokens.LTEQ, KtTokens.GTEQ)) { + if (target.isNumericWithName("compareTo")) { + when (op) { + KtTokens.LT -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_ltexpr) + KtTokens.GT -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_gtexpr) + KtTokens.LTEQ -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_leexpr) + KtTokens.GTEQ -> extractBinaryExpression(expression, callable, parent, tw::writeExprs_geexpr) + else -> TODO("error") } + } else { + TODO("Extract lowered equivalent call, such as `a.compareTo(b) < 0`") } - else -> TODO() + } else { + // todo: other operators, such as .., ..<, in, !in, =, +=, -=, *=, /=, %=, ==, !=, + TODO("Extract as method call") } +} + +private fun KaFunctionSymbol?.isBinaryPlus(): Boolean { + return this != null && ( + this.isNumericWithName("plus") || + this.hasName("kotlin", "String", "plus") || + /* The target for `(null as String?) + null` is `public operator fun String?.plus(other: Any?): String` */ + this.hasMatchingNames( + CallableId(FqName("kotlin"), null, Name.identifier("plus")), + ClassId(FqName("kotlin"), Name.identifier("String")), + nullability = KaTypeNullability.NULLABLE, + )) +} +context(KaSession) +private fun KotlinFileExtractor.extractBinaryExpression( + expression: KtBinaryExpression, + callable: Label, + parent: StmtExprParent, + extractExpression: ( + id: Label, + typeid: Label, + parent: Label, + idx: Int + ) -> Unit +) { + val id = tw.getFreshIdLabel() + val type = useType(expression.expressionType) + val exprParent = parent.expr(expression, callable) + extractExpression(id, type.javaResult.id, exprParent.parent, exprParent.idx) + tw.writeExprsKotlinType(id, type.kotlinResult.id) + + extractExprContext(id, tw.getLocation(expression), callable, exprParent.enclosingStmt) + extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt) + extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt) } context(KaSession)