@@ -7,6 +7,7 @@ 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
9
import org.jetbrains.kotlin.backend.common.ir.isFinalClass
10
+ import org.jetbrains.kotlin.backend.common.lower.parents
10
11
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
11
12
import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
12
13
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
@@ -21,6 +22,8 @@ import org.jetbrains.kotlin.ir.types.impl.*
21
22
import org.jetbrains.kotlin.ir.util.*
22
23
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
23
24
import org.jetbrains.kotlin.load.java.JvmAbi
25
+ import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
26
+ import org.jetbrains.kotlin.load.java.structure.*
24
27
import org.jetbrains.kotlin.name.FqName
25
28
import org.jetbrains.kotlin.name.Name
26
29
import org.jetbrains.kotlin.name.SpecialNames
@@ -852,23 +855,30 @@ open class KotlinUsesExtractor(
852
855
(f.name.asString() == " addAll" && overridesFunctionDefinedOn(f, " kotlin.collections" , " MutableList" ))
853
856
854
857
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 ) =
856
862
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
860
866
v == Variance .IN_VARIANCE -> ! (t.isNullableAny() || t.isAny())
861
867
v == Variance .OUT_VARIANCE -> ((t as ? IrSimpleType )?.classOrNull?.owner?.isFinalClass) != true
862
868
else -> false
863
869
}
864
870
865
- private fun addJavaLoweringArgumentWildcards (p : IrTypeParameter , t : IrTypeArgument , inParameterContext : Boolean ): IrTypeArgument =
871
+ private fun addJavaLoweringArgumentWildcards (p : IrTypeParameter , t : IrTypeArgument , addByDefault : Boolean , javaType : JavaType ? ): IrTypeArgument =
866
872
(t as ? IrTypeProjection )?.let {
867
- val newBase = addJavaLoweringWildcards(it.type, inParameterContext )
873
+ val newBase = addJavaLoweringWildcards(it.type, addByDefault, javaType )
868
874
val newVariance =
869
875
if (it.variance == Variance .INVARIANT &&
870
876
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))
872
882
p.variance
873
883
else
874
884
it.variance
@@ -878,14 +888,22 @@ open class KotlinUsesExtractor(
878
888
null
879
889
} ? : t
880
890
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 =
882
899
(t as ? IrSimpleType )?.let {
883
900
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 ->
885
902
addJavaLoweringArgumentWildcards(
886
903
pair.first,
887
904
pair.second,
888
- inParameterContext
905
+ addByDefault,
906
+ javaType?.let { jt -> getJavaTypeArgument(jt, idx) }
889
907
)
890
908
}
891
909
return if (newArgs.zip(it.arguments).all { pair -> pair.first == = pair.second })
@@ -927,6 +945,14 @@ open class KotlinUsesExtractor(
927
945
return otherKeySet.returnType.codeQlWithHasQuestionMark(false )
928
946
}
929
947
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
+
930
956
/*
931
957
* There are some pairs of classes (e.g. `kotlin.Throwable` and
932
958
* `java.lang.Throwable`) which are really just 2 different names
@@ -947,7 +973,9 @@ open class KotlinUsesExtractor(
947
973
f.extensionReceiverParameter,
948
974
getFunctionTypeParameters(f),
949
975
classTypeArgsIncludingOuterClasses,
950
- overridesCollectionsMethodWithAlteredParameterTypes(f)
976
+ overridesCollectionsMethodWithAlteredParameterTypes(f),
977
+ getJavaMethod(f),
978
+ ! hasWildcardSuppressionAnnotation(f)
951
979
)
952
980
953
981
/*
@@ -977,6 +1005,11 @@ open class KotlinUsesExtractor(
977
1005
// If true, this method implements a Java Collections interface (Collection, Map or List) and may need
978
1006
// parameter erasure to match the way this class will appear to an external consumer of the .class file.
979
1007
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 ,
980
1013
// The prefix used in the label. "callable", unless a property label is created, then it's "property".
981
1014
prefix : String = "callable"
982
1015
): String {
@@ -1001,7 +1034,7 @@ open class KotlinUsesExtractor(
1001
1034
// If this has happened, erase the type again to get the correct Java signature.
1002
1035
val maybeAmendedForCollections = if (overridesCollectionsMethod) eraseCollectionsMethodParameterType(it.value.type, name, it.index) else it.value.type
1003
1036
// 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 } )
1005
1038
// Now substitute any class type parameters in:
1006
1039
val maybeSubbed = withAddedWildcards.substituteTypeAndArguments(substitutionMap, TypeContext .OTHER , pluginContext)
1007
1040
// Finally, mimic the Java extractor's behaviour by naming functions with type parameters for their erased types;
@@ -1473,7 +1506,7 @@ open class KotlinUsesExtractor(
1473
1506
val returnType = getter?.returnType ? : setter?.valueParameters?.singleOrNull()?.type ? : pluginContext.irBuiltIns.unitType
1474
1507
val typeParams = getFunctionTypeParameters(func)
1475
1508
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" )
1477
1510
}
1478
1511
}
1479
1512
0 commit comments