@@ -6,6 +6,7 @@ import com.github.codeql.utils.versions.isRawType
6
6
import com.semmle.extractor.java.OdasaOutput
7
7
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
8
8
import org.jetbrains.kotlin.backend.common.ir.allOverridden
9
+ import org.jetbrains.kotlin.backend.common.ir.isFinalClass
9
10
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
10
11
import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
11
12
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
@@ -850,6 +851,49 @@ open class KotlinUsesExtractor(
850
851
(f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableCollection" )) ||
851
852
(f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableList" ))
852
853
854
+
855
+ private fun wildcardAdditionAllowed (v : Variance , t : IrType , inParameterContext : Boolean ) =
856
+ when {
857
+ t.hasAnnotation(FqName (" kotlin.jvm.JvmWildcard" )) -> true
858
+ ! inParameterContext -> false // By default, wildcards are only automatically added for method parameters.
859
+ t.hasAnnotation(FqName (" kotlin.jvm.JvmSuppressWildcards" )) -> false
860
+ v == Variance .IN_VARIANCE -> ! (t.isNullableAny() || t.isAny())
861
+ v == Variance .OUT_VARIANCE -> ((t as ? IrSimpleType )?.classOrNull?.owner?.isFinalClass) != true
862
+ else -> false
863
+ }
864
+
865
+ private fun addJavaLoweringArgumentWildcards (p : IrTypeParameter , t : IrTypeArgument , inParameterContext : Boolean ): IrTypeArgument =
866
+ (t as ? IrTypeProjection )?.let {
867
+ val newBase = addJavaLoweringWildcards(it.type, inParameterContext)
868
+ val newVariance =
869
+ if (it.variance == Variance .INVARIANT &&
870
+ p.variance != Variance .INVARIANT &&
871
+ wildcardAdditionAllowed(p.variance, it.type, inParameterContext))
872
+ p.variance
873
+ else
874
+ it.variance
875
+ if (newBase != = it.type || newVariance != it.variance)
876
+ makeTypeProjection(newBase, newVariance)
877
+ else
878
+ null
879
+ } ? : t
880
+
881
+ fun addJavaLoweringWildcards (t : IrType , inParameterContext : Boolean ): IrType =
882
+ (t as ? IrSimpleType )?.let {
883
+ val typeParams = it.classOrNull?.owner?.typeParameters ? : return t
884
+ val newArgs = typeParams.zip(it.arguments).map { pair ->
885
+ addJavaLoweringArgumentWildcards(
886
+ pair.first,
887
+ pair.second,
888
+ inParameterContext
889
+ )
890
+ }
891
+ return if (newArgs.zip(it.arguments).all { pair -> pair.first == = pair.second })
892
+ t
893
+ else
894
+ it.toBuilder().also { builder -> builder.arguments = newArgs }.buildSimpleType()
895
+ } ? : t
896
+
853
897
/*
854
898
* This is the normal getFunctionLabel function to use. If you want
855
899
* to refer to the function in its source class then
@@ -956,8 +1000,10 @@ open class KotlinUsesExtractor(
956
1000
// Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin universe.
957
1001
// If this has happened, erase the type again to get the correct Java signature.
958
1002
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
1003
+ // Add any wildcard types that the Kotlin compiler would add in the Java lowering of this function:
1004
+ val withAddedWildcards = addJavaLoweringWildcards(maybeAmendedForCollections, true )
959
1005
// Now substitute any class type parameters in:
960
- val maybeSubbed = maybeAmendedForCollections .substituteTypeAndArguments(substitutionMap, TypeContext .OTHER , pluginContext)
1006
+ val maybeSubbed = withAddedWildcards .substituteTypeAndArguments(substitutionMap, TypeContext .OTHER , pluginContext)
961
1007
// Finally, mimic the Java extractor's behaviour by naming functions with type parameters for their erased types;
962
1008
// those without type parameters are named for the generic type.
963
1009
val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
@@ -969,6 +1015,8 @@ open class KotlinUsesExtractor(
969
1015
pluginContext.irBuiltIns.unitType
970
1016
else
971
1017
erase(returnType.substituteTypeAndArguments(substitutionMap, TypeContext .RETURN , pluginContext))
1018
+ // Note that `addJavaLoweringWildcards` is not required here because the return type used to form the function
1019
+ // label is always erased.
972
1020
val returnTypeId = useType(labelReturnType, TypeContext .RETURN ).javaResult.id
973
1021
// This suffix is added to generic methods (and constructors) to match the Java extractor's behaviour.
974
1022
// Comments in that extractor indicates it didn't want the label of the callable to clash with the raw
0 commit comments