@@ -6,6 +6,7 @@ import com.github.codeql.utils.versions.isRawType
66import com.semmle.extractor.java.OdasaOutput
77import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
88import org.jetbrains.kotlin.backend.common.ir.allOverridden
9+ import org.jetbrains.kotlin.backend.common.ir.isFinalClass
910import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
1011import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
1112import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
@@ -850,6 +851,49 @@ open class KotlinUsesExtractor(
850851 (f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableCollection" )) ||
851852 (f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableList" ))
852853
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+
853897 /*
854898 * This is the normal getFunctionLabel function to use. If you want
855899 * to refer to the function in its source class then
@@ -956,8 +1000,10 @@ open class KotlinUsesExtractor(
9561000 // Collection.remove(Object) because Collection.remove(Collection::E) in the Kotlin universe.
9571001 // If this has happened, erase the type again to get the correct Java signature.
9581002 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 )
9591005 // 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)
9611007 // Finally, mimic the Java extractor's behaviour by naming functions with type parameters for their erased types;
9621008 // those without type parameters are named for the generic type.
9631009 val maybeErased = if (functionTypeParameters.isEmpty()) maybeSubbed else erase(maybeSubbed)
@@ -969,6 +1015,8 @@ open class KotlinUsesExtractor(
9691015 pluginContext.irBuiltIns.unitType
9701016 else
9711017 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.
9721020 val returnTypeId = useType(labelReturnType, TypeContext .RETURN ).javaResult.id
9731021 // This suffix is added to generic methods (and constructors) to match the Java extractor's behaviour.
9741022 // Comments in that extractor indicates it didn't want the label of the callable to clash with the raw
0 commit comments