diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 2c58842e9e4..3b9454755f1 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -122,10 +122,7 @@ open class KotlinUsesExtractor( } fun getJavaEquivalentClass(c: IrClass) = - c.fqNameWhenAvailable?.toUnsafe() - ?.let { JavaToKotlinClassMap.mapKotlinToJava(it) } - ?.let { pluginContext.referenceClass(it.asSingleFqName()) } - ?.owner + getJavaEquivalentClassId(c)?.let { pluginContext.referenceClass(it.asSingleFqName()) }?.owner /** * Gets a KotlinFileExtractor based on this one, except it attributes locations to the file that declares the given class. diff --git a/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt b/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt index cdcdd535a2c..5a9713087eb 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/ClassNames.kt @@ -7,7 +7,9 @@ import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource @@ -84,4 +86,7 @@ fun getContainingClassOrSelf(decl: IrDeclaration): IrClass? { is IrClass -> decl else -> decl.parentClassOrNull } -} \ No newline at end of file +} + +fun getJavaEquivalentClassId(c: IrClass) = + c.fqNameWhenAvailable?.toUnsafe()?.let { JavaToKotlinClassMap.mapKotlinToJava(it) } \ No newline at end of file diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt index 5e0d392ca64..b297e917de2 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt @@ -1,6 +1,7 @@ package com.github.codeql.utils import com.github.codeql.KotlinUsesExtractor +import com.github.codeql.getJavaEquivalentClassId import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.descriptors.ClassKind @@ -19,6 +20,7 @@ import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.util.classId import org.jetbrains.kotlin.ir.util.constructedClassType import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.parentAsClass @@ -195,13 +197,25 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument = typealias TypeSubstitution = (IrType, KotlinUsesExtractor.TypeContext, IrPluginContext) -> IrType +fun matchingTypeParameters(l: IrTypeParameter?, r: IrTypeParameter): Boolean { + if (l === r) + return true + if (l == null) + return false + // Special case: match List's E and MutableList's E, for example, because in the JVM lowering they will map to the same thing. + val lParent = l.parent as? IrClass ?: return false + val rParent = r.parent as? IrClass ?: return false + val lJavaId = getJavaEquivalentClassId(lParent) ?: lParent.classId + return (getJavaEquivalentClassId(rParent) ?: rParent.classId) == lJavaId && l.name == r.name +} + // Returns true if type is C where C is declared `class C { ... }` fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List): Boolean { val unspecialisedHere = paramsContainer.typeParameters.zip(args).all { paramAndArg -> (paramAndArg.second as? IrTypeProjection)?.let { // Type arg refers to the class' own type parameter? it.variance == Variance.INVARIANT && - it.type.classifierOrNull?.owner === paramAndArg.first + matchingTypeParameters(it.type.classifierOrNull?.owner as? IrTypeParameter, paramAndArg.first) } ?: false } val remainingArgs = args.drop(paramsContainer.typeParameters.size)