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