@@ -999,9 +999,112 @@ open class KotlinFileExtractor(
999999 }
10001000 }
10011001
1002+ fun extractRawMethodAccess (
1003+ syntacticCallTarget : IrFunction ,
1004+ callsite : IrCall ,
1005+ enclosingCallable : Label <out DbCallable >,
1006+ callsiteParent : Label <out DbExprparent >,
1007+ childIdx : Int ,
1008+ enclosingStmt : Label <out DbStmt >,
1009+ valueArguments : List <IrExpression ?>,
1010+ dispatchReceiver : IrExpression ? ,
1011+ extensionReceiver : IrExpression ? ,
1012+ typeArguments : List <IrType > = listOf(),
1013+ extractClassTypeArguments : Boolean = false) {
1014+
1015+ val callTarget = syntacticCallTarget.target
1016+ val id = tw.getFreshIdLabel<DbMethodaccess >()
1017+ val type = useType(callsite.type)
1018+ val locId = tw.getLocation(callsite)
1019+ tw.writeExprs_methodaccess(id, type.javaResult.id, callsiteParent, childIdx)
1020+ tw.writeExprsKotlinType(id, type.kotlinResult.id)
1021+ tw.writeHasLocation(id, locId)
1022+ tw.writeCallableEnclosingExpr(id, enclosingCallable)
1023+ tw.writeStatementEnclosingExpr(id, enclosingStmt)
1024+
1025+ // type arguments at index -2, -3, ...
1026+ extractTypeArguments(typeArguments, callsite, id, enclosingCallable, enclosingStmt, - 2 , true )
1027+
1028+ if (callTarget.isLocalFunction()) {
1029+ val ids = getLocallyVisibleFunctionLabels(callTarget)
1030+
1031+ val methodId = ids.function
1032+ tw.writeCallableBinding(id, methodId)
1033+
1034+ val idNewexpr = tw.getFreshIdLabel<DbNewexpr >()
1035+ tw.writeExprs_newexpr(idNewexpr, ids.type.javaResult.id, id, - 1 )
1036+ tw.writeExprsKotlinType(idNewexpr, ids.type.kotlinResult.id)
1037+ tw.writeHasLocation(idNewexpr, locId)
1038+ tw.writeCallableEnclosingExpr(idNewexpr, enclosingCallable)
1039+ tw.writeStatementEnclosingExpr(idNewexpr, enclosingStmt)
1040+ tw.writeCallableBinding(idNewexpr, ids.constructor )
1041+
1042+ @Suppress(" UNCHECKED_CAST" )
1043+ tw.writeIsAnonymClass(ids.type.javaResult.id as Label <DbClass >, idNewexpr)
1044+
1045+ extractTypeAccess(pluginContext.irBuiltIns.anyType, enclosingCallable, idNewexpr, - 3 , callsite, enclosingStmt)
1046+ } else {
1047+ // Returns true if type is C<T1, T2, ...> where C is declared `class C<T1, T2, ...> { ... }`
1048+ fun isUnspecialised (type : IrSimpleType ) =
1049+ type.classifier.owner is IrClass &&
1050+ (type.classifier.owner as IrClass ).typeParameters.zip(type.arguments).all { paramAndArg ->
1051+ (paramAndArg.second as ? IrTypeProjection )?.let {
1052+ // Type arg refers to the class' own type parameter?
1053+ it.variance == Variance .INVARIANT &&
1054+ it.type.classifierOrNull?.owner == = paramAndArg.first
1055+ } ? : false
1056+ }
1057+
1058+ val drType = dispatchReceiver?.type
1059+ val methodId =
1060+ if (drType != null && extractClassTypeArguments && drType is IrSimpleType && ! isUnspecialised(drType))
1061+ useFunction<DbCallable >(callTarget, getDeclaringTypeArguments(callTarget, drType))
1062+ else
1063+ useFunction<DbCallable >(callTarget)
1064+
1065+ tw.writeCallableBinding(id, methodId)
1066+
1067+ if (dispatchReceiver != null ) {
1068+ extractExpressionExpr(dispatchReceiver, enclosingCallable, id, - 1 , enclosingStmt)
1069+ } else if (callTarget.isStaticMethodOfClass) {
1070+ extractTypeAccess(callTarget.parentAsClass.toRawType(), enclosingCallable, id, - 1 , callsite, enclosingStmt)
1071+ }
1072+ }
1073+
1074+ val idxOffset: Int
1075+ if (extensionReceiver != null ) {
1076+ extractExpressionExpr(extensionReceiver, enclosingCallable, id, 0 , enclosingStmt)
1077+ idxOffset = 1
1078+ } else {
1079+ idxOffset = 0
1080+ }
1081+
1082+ valueArguments.forEachIndexed { i, arg ->
1083+ if (arg != null ) {
1084+ extractExpressionExpr(arg, enclosingCallable, id, i + idxOffset, enclosingStmt)
1085+ }
1086+ }
1087+ }
1088+
1089+ fun findFunction (cls : IrClass , name : String ): IrFunction ? = cls.declarations.find { it is IrFunction && it.name.asString() == name } as IrFunction ?
1090+
1091+ val jvmIntrinsicsClass by lazy {
1092+ val result = pluginContext.referenceClass(FqName (" kotlin.jvm.internal.Intrinsics" ))?.owner
1093+ result?.let { extractExternalClassLater(it) }
1094+ result
1095+ }
1096+
1097+ fun findJdkIntrinsicOrWarn (name : String , warnAgainstElement : IrElement ): IrFunction ? {
1098+ val result = jvmIntrinsicsClass?.let { findFunction(it, name) }
1099+ if (result == null ) {
1100+ logger.warnElement(Severity .ErrorSevere , " Couldn't find JVM intrinsic function $name " , warnAgainstElement)
1101+ }
1102+ return result
1103+ }
1104+
10021105 fun extractCall (c : IrCall , callable : Label <out DbCallable >, parent : Label <out DbExprparent >, idx : Int , enclosingStmt : Label <out DbStmt >) {
10031106 with (" call" , c) {
1004- fun isFunction (pkgName : String , className : String , fName : String , hasQuestionMark : Boolean = false): Boolean {
1107+ fun isFunction (pkgName : String , className : String , fName : String , hasQuestionMark : Boolean? = false): Boolean {
10051108 val verbose = false
10061109 fun verboseln (s : String ) { if (verbose) println (s) }
10071110 verboseln(" Attempting match for $pkgName $className $fName " )
@@ -1012,10 +1115,14 @@ open class KotlinFileExtractor(
10121115 }
10131116 val extensionReceiverParameter = target.extensionReceiverParameter
10141117 val targetClass = if (extensionReceiverParameter == null ) {
1118+ if (hasQuestionMark == true ) {
1119+ verboseln(" Nullablility of type didn't match (target is not an extension method)" )
1120+ return false
1121+ }
10151122 target.parent
10161123 } else {
10171124 val st = extensionReceiverParameter.type as ? IrSimpleType
1018- if (st?.hasQuestionMark != hasQuestionMark) {
1125+ if (hasQuestionMark != null && st?.hasQuestionMark != hasQuestionMark) {
10191126 verboseln(" Nullablility of type didn't match" )
10201127 return false
10211128 }
@@ -1050,86 +1157,15 @@ open class KotlinFileExtractor(
10501157 isFunction(" kotlin" , " Float" , fName) ||
10511158 isFunction(" kotlin" , " Double" , fName)
10521159 }
1053-
1160+
10541161 fun extractMethodAccess (syntacticCallTarget : IrFunction , extractMethodTypeArguments : Boolean = true, extractClassTypeArguments : Boolean = false) {
1055- val callTarget = syntacticCallTarget.target
1056- val id = tw.getFreshIdLabel<DbMethodaccess >()
1057- val type = useType(c.type)
1058- val locId = tw.getLocation(c)
1059- tw.writeExprs_methodaccess(id, type.javaResult.id, parent, idx)
1060- tw.writeExprsKotlinType(id, type.kotlinResult.id)
1061- tw.writeHasLocation(id, locId)
1062- tw.writeCallableEnclosingExpr(id, callable)
1063- tw.writeStatementEnclosingExpr(id, enclosingStmt)
1064-
1065- if (extractMethodTypeArguments) {
1066- // type arguments at index -2, -3, ...
1067- extractTypeArguments(c, id, callable, enclosingStmt, - 2 , true )
1068- }
1069-
1070- if (callTarget.isLocalFunction()) {
1071- val ids = getLocallyVisibleFunctionLabels(callTarget)
1072-
1073- val methodId = ids.function
1074- tw.writeCallableBinding(id, methodId)
1075-
1076- val idNewexpr = tw.getFreshIdLabel<DbNewexpr >()
1077- tw.writeExprs_newexpr(idNewexpr, ids.type.javaResult.id, id, - 1 )
1078- tw.writeExprsKotlinType(idNewexpr, ids.type.kotlinResult.id)
1079- tw.writeHasLocation(idNewexpr, locId)
1080- tw.writeCallableEnclosingExpr(idNewexpr, callable)
1081- tw.writeStatementEnclosingExpr(idNewexpr, enclosingStmt)
1082- tw.writeCallableBinding(idNewexpr, ids.constructor )
1083-
1084- @Suppress(" UNCHECKED_CAST" )
1085- tw.writeIsAnonymClass(ids.type.javaResult.id as Label <DbClass >, idNewexpr)
1086-
1087- extractTypeAccess(pluginContext.irBuiltIns.anyType, callable, idNewexpr, - 3 , c, enclosingStmt)
1088- } else {
1089- val dr = c.dispatchReceiver
1090-
1091- // Returns true if type is C<T1, T2, ...> where C is declared `class C<T1, T2, ...> { ... }`
1092- fun isUnspecialised (type : IrSimpleType ) =
1093- type.classifier.owner is IrClass &&
1094- (type.classifier.owner as IrClass ).typeParameters.zip(type.arguments).all { paramAndArg ->
1095- (paramAndArg.second as ? IrTypeProjection )?.let {
1096- // Type arg refers to the class' own type parameter?
1097- it.variance == Variance .INVARIANT &&
1098- it.type.classifierOrNull?.owner == = paramAndArg.first
1099- } ? : false
1100- }
1101-
1102- val drType = dr?.type
1103- val methodId =
1104- if (drType != null && extractClassTypeArguments && drType is IrSimpleType && ! isUnspecialised(drType))
1105- useFunction<DbCallable >(callTarget, getDeclaringTypeArguments(callTarget, drType))
1106- else
1107- useFunction<DbCallable >(callTarget)
1108-
1109- tw.writeCallableBinding(id, methodId)
1110-
1111- if (dr != null ) {
1112- extractExpressionExpr(dr, callable, id, - 1 , enclosingStmt)
1113- } else if (callTarget.isStaticMethodOfClass) {
1114- extractTypeAccess(callTarget.parentAsClass.toRawType(), callable, id, - 1 , c, enclosingStmt)
1115- }
1116- }
1117-
1118- val er = c.extensionReceiver
1119- val idxOffset: Int
1120- if (er != null ) {
1121- extractExpressionExpr(er, callable, id, 0 , enclosingStmt)
1122- idxOffset = 1
1123- } else {
1124- idxOffset = 0
1125- }
1126-
1127- for (i in 0 until c.valueArgumentsCount) {
1128- val arg = c.getValueArgument(i)
1129- if (arg != null ) {
1130- extractExpressionExpr(arg, callable, id, i + idxOffset, enclosingStmt)
1131- }
1132- }
1162+ val typeArgs =
1163+ if (extractMethodTypeArguments)
1164+ (0 until c.typeArgumentsCount).map { c.getTypeArgument(it)!! }
1165+ else
1166+ listOf ()
1167+
1168+ extractRawMethodAccess(syntacticCallTarget, c, callable, parent, idx, enclosingStmt, (0 until c.valueArgumentsCount).map { c.getValueArgument(it) }, c.dispatchReceiver, c.extensionReceiver, typeArgs, extractClassTypeArguments)
11331169 }
11341170
11351171 fun extractSpecialEnumFunction (fnName : String ){
@@ -1153,11 +1189,11 @@ open class KotlinFileExtractor(
11531189 tw.writeCallableEnclosingExpr(id, callable)
11541190 tw.writeStatementEnclosingExpr(id, enclosingStmt)
11551191
1156- val dr = c.dispatchReceiver
1157- if (dr == null ) {
1158- logger.warnElement(Severity .ErrorSevere , " Dispatch receiver not found" , c)
1192+ val receiver = c.dispatchReceiver ? : c.extensionReceiver
1193+ if (receiver == null ) {
1194+ logger.warnElement(Severity .ErrorSevere , " Receiver not found" , c)
11591195 } else {
1160- extractExpressionExpr(dr , callable, id, 0 , enclosingStmt)
1196+ extractExpressionExpr(receiver , callable, id, 0 , enclosingStmt)
11611197 }
11621198 if (c.valueArgumentsCount < 1 ) {
11631199 logger.warnElement(Severity .ErrorSevere , " No RHS found" , c)
@@ -1178,21 +1214,17 @@ open class KotlinFileExtractor(
11781214 when {
11791215 c.origin == IrStatementOrigin .PLUS &&
11801216 (isNumericFunction(" plus" )
1181- || isFunction(" kotlin" , " String" , " plus" )) -> {
1217+ || isFunction(" kotlin" , " String" , " plus" , null )) -> {
11821218 val id = tw.getFreshIdLabel<DbAddexpr >()
11831219 val type = useType(c.type)
11841220 tw.writeExprs_addexpr(id, type.javaResult.id, parent, idx)
11851221 tw.writeExprsKotlinType(id, type.kotlinResult.id)
11861222 binopDisp(id)
11871223 }
11881224 isFunction(" kotlin" , " String" , " plus" , true ) -> {
1189- // TODO: this is not correct. `a + b` becomes `(a?:"\"null\"") + (b?:"\"null\"")`.
1190- val func = pluginContext.irBuiltIns.stringType.classOrNull?.owner?.declarations?.find { it is IrFunction && it.name.asString() == " plus" }
1191- if (func == null ) {
1192- logger.warnElement(Severity .ErrorSevere , " Couldn't find plus function on string type" , c)
1193- return
1225+ findJdkIntrinsicOrWarn(" stringPlus" , c)?.let { stringPlusFn ->
1226+ extractRawMethodAccess(stringPlusFn, c, callable, parent, idx, enclosingStmt, listOf (c.extensionReceiver, c.getValueArgument(0 )), null , null )
11941227 }
1195- extractMethodAccess(func as IrFunction )
11961228 }
11971229 c.origin == IrStatementOrigin .MINUS && isNumericFunction(" minus" ) -> {
11981230 val id = tw.getFreshIdLabel<DbSubexpr >()
@@ -1475,21 +1507,32 @@ open class KotlinFileExtractor(
14751507 }
14761508 }
14771509
1478- private fun <T : IrSymbol > extractTypeArguments (
1479- c : IrMemberAccessExpression <T >,
1480- id : Label <out DbExprparent >,
1481- callable : Label <out DbCallable >,
1510+ private fun extractTypeArguments (
1511+ typeArgs : List <IrType >,
1512+ elementForLocation : IrElement ,
1513+ parentExpr : Label <out DbExprparent >,
1514+ enclosingCallable : Label <out DbCallable >,
14821515 enclosingStmt : Label <out DbStmt >,
14831516 startIndex : Int = 0,
14841517 reverse : Boolean = false
14851518 ) {
1486- for (argIdx in 0 until c.typeArgumentsCount) {
1487- val arg = c.getTypeArgument(argIdx)!!
1519+ typeArgs.forEachIndexed { argIdx, arg ->
14881520 val mul = if (reverse) - 1 else 1
1489- extractTypeAccess(arg, callable, id , argIdx * mul + startIndex, c , enclosingStmt, TypeContext .GENERIC_ARGUMENT )
1521+ extractTypeAccess(arg, enclosingCallable, parentExpr , argIdx * mul + startIndex, elementForLocation , enclosingStmt, TypeContext .GENERIC_ARGUMENT )
14901522 }
14911523 }
14921524
1525+ private fun <T : IrSymbol > extractTypeArguments (
1526+ c : IrMemberAccessExpression <T >,
1527+ parentExpr : Label <out DbExprparent >,
1528+ enclosingCallable : Label <out DbCallable >,
1529+ enclosingStmt : Label <out DbStmt >,
1530+ startIndex : Int = 0,
1531+ reverse : Boolean = false
1532+ ) {
1533+ extractTypeArguments((0 until c.typeArgumentsCount).map { c.getTypeArgument(it)!! }, c, parentExpr, enclosingCallable, enclosingStmt, startIndex, reverse)
1534+ }
1535+
14931536 private fun extractConstructorCall (
14941537 e : IrFunctionAccessExpression ,
14951538 parent : Label <out DbExprparent >,
0 commit comments