@@ -7,6 +7,7 @@ import com.semmle.extractor.java.OdasaOutput
77import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
88import org.jetbrains.kotlin.backend.common.ir.allOverridden
99import org.jetbrains.kotlin.backend.common.ir.isFinalClass
10+ import org.jetbrains.kotlin.backend.common.lower.parents
1011import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
1112import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
1213import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
@@ -21,6 +22,8 @@ import org.jetbrains.kotlin.ir.types.impl.*
2122import org.jetbrains.kotlin.ir.util.*
2223import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
2324import org.jetbrains.kotlin.load.java.JvmAbi
25+ import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
26+ import org.jetbrains.kotlin.load.java.structure.*
2427import org.jetbrains.kotlin.name.FqName
2528import org.jetbrains.kotlin.name.Name
2629import org.jetbrains.kotlin.name.SpecialNames
@@ -852,23 +855,30 @@ open class KotlinUsesExtractor(
852855 (f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableList" ))
853856
854857
855- private fun wildcardAdditionAllowed (v : Variance , t : IrType , inParameterContext : Boolean ) =
858+ private val jvmWildcardAnnotation = FqName (" kotlin.jvm.JvmWildcard" )
859+ private val jvmWildcardSuppressionAnnotaton = FqName (" kotlin.jvm.JvmSuppressWildcards" )
860+
861+ private fun wildcardAdditionAllowed (v : Variance , t : IrType , addByDefault : Boolean ) =
856862 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
863+ t.hasAnnotation(jvmWildcardAnnotation ) -> true
864+ ! addByDefault -> false
865+ t.hasAnnotation(jvmWildcardSuppressionAnnotaton ) -> false
860866 v == Variance .IN_VARIANCE -> ! (t.isNullableAny() || t.isAny())
861867 v == Variance .OUT_VARIANCE -> ((t as ? IrSimpleType )?.classOrNull?.owner?.isFinalClass) != true
862868 else -> false
863869 }
864870
865- private fun addJavaLoweringArgumentWildcards (p : IrTypeParameter , t : IrTypeArgument , inParameterContext : Boolean ): IrTypeArgument =
871+ private fun addJavaLoweringArgumentWildcards (p : IrTypeParameter , t : IrTypeArgument , addByDefault : Boolean , javaType : JavaType ? ): IrTypeArgument =
866872 (t as ? IrTypeProjection )?.let {
867- val newBase = addJavaLoweringWildcards(it.type, inParameterContext )
873+ val newBase = addJavaLoweringWildcards(it.type, addByDefault, javaType )
868874 val newVariance =
869875 if (it.variance == Variance .INVARIANT &&
870876 p.variance != Variance .INVARIANT &&
871- wildcardAdditionAllowed(p.variance, it.type, inParameterContext))
877+ // The next line forbids inferring a wildcard type when we have a corresponding Java type with conflicting variance.
878+ // For example, Java might declare f(Comparable<CharSequence> cs), in which case we shouldn't add a `? super ...`
879+ // wildcard. Note if javaType is unknown (e.g. this is a Kotlin source element), we assume wildcards should be added.
880+ (javaType?.let { jt -> jt is JavaWildcardType && jt.isExtends == (p.variance == Variance .OUT_VARIANCE ) } != false ) &&
881+ wildcardAdditionAllowed(p.variance, it.type, addByDefault))
872882 p.variance
873883 else
874884 it.variance
@@ -878,14 +888,22 @@ open class KotlinUsesExtractor(
878888 null
879889 } ? : t
880890
881- fun addJavaLoweringWildcards (t : IrType , inParameterContext : Boolean ): IrType =
891+ fun getJavaTypeArgument (jt : JavaType , idx : Int ) =
892+ when (jt) {
893+ is JavaClassifierType -> jt.typeArguments.getOrNull(idx)
894+ is JavaArrayType -> if (idx == 0 ) jt.componentType else null
895+ else -> null
896+ }
897+
898+ fun addJavaLoweringWildcards (t : IrType , addByDefault : Boolean , javaType : JavaType ? ): IrType =
882899 (t as ? IrSimpleType )?.let {
883900 val typeParams = it.classOrNull?.owner?.typeParameters ? : return t
884- val newArgs = typeParams.zip(it.arguments).map { pair ->
901+ val newArgs = typeParams.zip(it.arguments).mapIndexed { idx, pair ->
885902 addJavaLoweringArgumentWildcards(
886903 pair.first,
887904 pair.second,
888- inParameterContext
905+ addByDefault,
906+ javaType?.let { jt -> getJavaTypeArgument(jt, idx) }
889907 )
890908 }
891909 return if (newArgs.zip(it.arguments).all { pair -> pair.first == = pair.second })
@@ -927,6 +945,14 @@ open class KotlinUsesExtractor(
927945 return otherKeySet.returnType.codeQlWithHasQuestionMark(false )
928946 }
929947
948+ @OptIn(ObsoleteDescriptorBasedAPI ::class )
949+ fun getJavaMethod (f : IrFunction ) = (f.descriptor.source as ? JavaSourceElement )?.javaElement as ? JavaMethod
950+
951+ fun hasWildcardSuppressionAnnotation (d : IrDeclaration ) =
952+ d.hasAnnotation(jvmWildcardSuppressionAnnotaton) ||
953+ // Note not using `parentsWithSelf` as that only works if `d` is an IrDeclarationParent
954+ d.parents.any { (it as ? IrAnnotationContainer )?.hasAnnotation(jvmWildcardSuppressionAnnotaton) == true }
955+
930956 /*
931957 * There are some pairs of classes (e.g. `kotlin.Throwable` and
932958 * `java.lang.Throwable`) which are really just 2 different names
@@ -947,7 +973,9 @@ open class KotlinUsesExtractor(
947973 f.extensionReceiverParameter,
948974 getFunctionTypeParameters(f),
949975 classTypeArgsIncludingOuterClasses,
950- overridesCollectionsMethodWithAlteredParameterTypes(f)
976+ overridesCollectionsMethodWithAlteredParameterTypes(f),
977+ getJavaMethod(f),
978+ ! hasWildcardSuppressionAnnotation(f)
951979 )
952980
953981 /*
@@ -977,6 +1005,11 @@ open class KotlinUsesExtractor(
9771005 // If true, this method implements a Java Collections interface (Collection, Map or List) and may need
9781006 // parameter erasure to match the way this class will appear to an external consumer of the .class file.
9791007 overridesCollectionsMethod : Boolean ,
1008+ // The Java signature of this callable, if known.
1009+ javaSignature : JavaMethod ? ,
1010+ // If true, Java wildcards implied by Kotlin type parameter variance should be added by default to this function's value parameters' types.
1011+ // (Return-type wildcard addition is always off by default)
1012+ addParameterWildcardsByDefault : Boolean ,
9801013 // The prefix used in the label. "callable", unless a property label is created, then it's "property".
9811014 prefix : String = "callable"
9821015 ): String {
@@ -1001,7 +1034,7 @@ open class KotlinUsesExtractor(
10011034 // If this has happened, erase the type again to get the correct Java signature.
10021035 val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
10031036 // Add any wildcard types that the Kotlin compiler would add in the Java lowering of this function:
1004- val withAddedWildcards = addJavaLoweringWildcards(maybeAmendedForCollections, true )
1037+ val withAddedWildcards = addJavaLoweringWildcards(maybeAmendedForCollections, addParameterWildcardsByDefault, javaSignature?. let { sig -> sig.valueParameters[it.index].type } )
10051038 // Now substitute any class type parameters in:
10061039 val maybeSubbed = withAddedWildcards.substituteTypeAndArguments(substitutionMap, TypeContext .OTHER , pluginContext)
10071040 // Finally, mimic the Java extractor's behaviour by naming functions with type parameters for their erased types;
@@ -1473,7 +1506,7 @@ open class KotlinUsesExtractor(
14731506 val returnType = getter?.returnType ? : setter?.valueParameters?.singleOrNull()?.type ? : pluginContext.irBuiltIns.unitType
14741507 val typeParams = getFunctionTypeParameters(func)
14751508
1476- getFunctionLabel(p.parent, parentId, p.name.asString(), listOf (), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false , prefix = " property" )
1509+ getFunctionLabel(p.parent, parentId, p.name.asString(), listOf (), returnType, ext, typeParams, classTypeArgsIncludingOuterClasses, overridesCollectionsMethod = false , javaSignature = null , addParameterWildcardsByDefault = false , prefix = " property" )
14771510 }
14781511 }
14791512
0 commit comments