@@ -10,12 +10,14 @@ import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
10
10
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
11
11
import org.jetbrains.kotlin.builtins.StandardNames
12
12
import org.jetbrains.kotlin.descriptors.*
13
+ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
13
14
import org.jetbrains.kotlin.ir.declarations.*
14
15
import org.jetbrains.kotlin.ir.expressions.*
15
16
import org.jetbrains.kotlin.ir.symbols.*
16
17
import org.jetbrains.kotlin.ir.types.*
17
18
import org.jetbrains.kotlin.ir.types.impl.*
18
19
import org.jetbrains.kotlin.ir.util.*
20
+ import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
19
21
import org.jetbrains.kotlin.load.java.JvmAbi
20
22
import org.jetbrains.kotlin.name.FqName
21
23
import org.jetbrains.kotlin.name.Name
@@ -32,6 +34,17 @@ open class KotlinUsesExtractor(
32
34
val pluginContext : IrPluginContext ,
33
35
val globalExtensionState : KotlinExtractorGlobalState
34
36
) {
37
+
38
+ val javaLangObject by lazy {
39
+ val result = pluginContext.referenceClass(FqName (" java.lang.Object" ))?.owner
40
+ result?.let { extractExternalClassLater(it) }
41
+ result
42
+ }
43
+
44
+ val javaLangObjectType by lazy {
45
+ javaLangObject?.typeWith()
46
+ }
47
+
35
48
fun usePackage (pkg : String ): Label <out DbPackage > {
36
49
return extractPackage(pkg)
37
50
}
@@ -790,6 +803,52 @@ open class KotlinUsesExtractor(
790
803
else -> null
791
804
}
792
805
806
+ val javaUtilCollection by lazy {
807
+ val result = pluginContext.referenceClass(FqName (" java.util.Collection" ))?.owner
808
+ result?.let { extractExternalClassLater(it) }
809
+ result
810
+ }
811
+
812
+ val wildcardCollectionType by lazy {
813
+ javaUtilCollection?.let {
814
+ it.symbol.typeWithArguments(listOf (IrStarProjectionImpl ))
815
+ }
816
+ }
817
+
818
+ private fun makeCovariant (t : IrTypeArgument ) =
819
+ t.typeOrNull?.let { makeTypeProjection(it, Variance .OUT_VARIANCE ) } ? : t
820
+
821
+ private fun makeArgumentsCovariant (t : IrType ) = (t as ? IrSimpleType )?.let {
822
+ t.toBuilder().also { b -> b.arguments = b.arguments.map(this ::makeCovariant) }.buildSimpleType()
823
+ } ? : t
824
+
825
+ fun eraseCollectionsMethodParameterType (t : IrType , collectionsMethodName : String , paramIdx : Int ) =
826
+ when (collectionsMethodName) {
827
+ " contains" , " remove" , " containsKey" , " containsValue" , " get" , " indexOf" , " lastIndexOf" -> javaLangObjectType
828
+ " getOrDefault" -> if (paramIdx == 0 ) javaLangObjectType else null
829
+ " containsAll" , " removeAll" , " retainAll" -> wildcardCollectionType
830
+ // Kotlin defines these like addAll(Collection<E>); Java uses addAll(Collection<? extends E>)
831
+ " putAll" , " addAll" -> makeArgumentsCovariant(t)
832
+ else -> null
833
+ } ? : t
834
+
835
+ private fun overridesFunctionDefinedOn (f : IrFunction , packageName : String , className : String ) =
836
+ (f as ? IrSimpleFunction )?.let {
837
+ it.overriddenSymbols.any { overridden ->
838
+ overridden.owner.parentClassOrNull?.let { defnClass ->
839
+ defnClass.name.asString() == className &&
840
+ defnClass.packageFqName?.asString() == packageName
841
+ } ? : false
842
+ }
843
+ } ? : false
844
+
845
+ @OptIn(ObsoleteDescriptorBasedAPI ::class )
846
+ fun overridesCollectionsMethodWithAlteredParameterTypes (f : IrFunction ) =
847
+ BuiltinMethodsWithSpecialGenericSignature .getOverriddenBuiltinFunctionWithErasedValueParametersInJava(f.descriptor) != null ||
848
+ (f.name.asString() == " putAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableMap" )) ||
849
+ (f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableCollection" )) ||
850
+ (f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableList" ))
851
+
793
852
/*
794
853
* This is the normal getFunctionLabel function to use. If you want
795
854
* to refer to the function in its source class then
@@ -811,8 +870,19 @@ open class KotlinUsesExtractor(
811
870
* `java.lang.Throwable`, which isn't what we want. So we have to
812
871
* allow it to be passed in.
813
872
*/
873
+ @OptIn(ObsoleteDescriptorBasedAPI ::class )
814
874
fun getFunctionLabel (f : IrFunction , maybeParentId : Label <out DbElement >? , classTypeArgsIncludingOuterClasses : List <IrTypeArgument >? ) =
815
- getFunctionLabel(f.parent, maybeParentId, getFunctionShortName(f).nameInDB, f.valueParameters, f.returnType, f.extensionReceiverParameter, getFunctionTypeParameters(f), classTypeArgsIncludingOuterClasses)
875
+ getFunctionLabel(
876
+ f.parent,
877
+ maybeParentId,
878
+ getFunctionShortName(f).nameInDB,
879
+ f.valueParameters,
880
+ f.returnType,
881
+ f.extensionReceiverParameter,
882
+ getFunctionTypeParameters(f),
883
+ classTypeArgsIncludingOuterClasses,
884
+ overridesCollectionsMethodWithAlteredParameterTypes(f)
885
+ )
816
886
817
887
/*
818
888
* This function actually generates the label for a function.
@@ -838,6 +908,9 @@ open class KotlinUsesExtractor(
838
908
functionTypeParameters : List <IrTypeParameter >,
839
909
// The type arguments of enclosing classes of the function.
840
910
classTypeArgsIncludingOuterClasses : List <IrTypeArgument >? ,
911
+ // If true, this method implements a Java Collections interface (Collection, Map or List) and may need
912
+ // parameter erasure to match the way this class will appear to an external consumer of the .class file.
913
+ overridesCollectionsMethod : Boolean ,
841
914
// The prefix used in the label. "callable", unless a property label is created, then it's "property".
842
915
prefix : String = "callable"
843
916
): String {
@@ -856,14 +929,19 @@ open class KotlinUsesExtractor(
856
929
enclosingClass?.let { notNullClass -> makeTypeGenericSubstitutionMap(notNullClass, notNullArgs) }
857
930
}
858
931
}
859
- val getIdForFunctionLabel = { it: IrValueParameter ->
860
- // Mimic the Java extractor's behaviour: functions with type parameters are named for their erased types;
932
+ val getIdForFunctionLabel = { it: IndexedValue <IrValueParameter > ->
933
+ // Kotlin rewrites certain Java collections types adding additional generic constraints-- for example,
934
+ // Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin universe.
935
+ // If this has happened, erase the type again to get the correct Java signature.
936
+ val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
937
+ // Now substitute any class type parameters in:
938
+ val maybeSubbed = maybeAmendedForCollections.substituteTypeAndArguments(substitutionMap, TypeContext .OTHER , pluginContext)
939
+ // Finally, mimic the Java extractor's behaviour by naming functions with type parameters for their erased types;
861
940
// those without type parameters are named for the generic type.
862
- val maybeSubbed = it.type.substituteTypeAndArguments(substitutionMap, TypeContext .OTHER , pluginContext)
863
941
val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
864
942
" {${useType(maybeErased).javaResult.id} }"
865
943
}
866
- val paramTypeIds = allParams.joinToString(separator = " ," , transform = getIdForFunctionLabel)
944
+ val paramTypeIds = allParams.withIndex(). joinToString(separator = " ," , transform = getIdForFunctionLabel)
867
945
val labelReturnType =
868
946
if (name == " <init>" )
869
947
pluginContext.irBuiltIns.unitType
@@ -1325,7 +1403,7 @@ open class KotlinUsesExtractor(
1325
1403
val returnType = getter?.returnType ? : setter?.valueParameters?.singleOrNull()?.type ? : pluginContext.irBuiltIns.unitType
1326
1404
val typeParams = getFunctionTypeParameters(func)
1327
1405
1328
- getFunctionLabel(p.parent, parentId, p.name.asString(), listOf (), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, " property" )
1406
+ getFunctionLabel(p.parent, parentId, p.name.asString(), listOf (), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false , prefix = " property" )
1329
1407
}
1330
1408
}
1331
1409
0 commit comments