mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Kotlin: Fix isUnspecialised to handle generic classes inside generic methods
This commit is contained in:
@@ -1450,7 +1450,7 @@ open class KotlinFileExtractor(
|
||||
extractNewExprForLocalFunction(ids, id, locId, enclosingCallable, enclosingStmt)
|
||||
} else {
|
||||
val methodId =
|
||||
if (extractClassTypeArguments && drType is IrSimpleType && !isUnspecialised(drType)) {
|
||||
if (extractClassTypeArguments && drType is IrSimpleType && !isUnspecialised(drType, logger)) {
|
||||
|
||||
val extractionMethod = if (isFunctionInvoke) {
|
||||
// For `kotlin.FunctionX` and `kotlin.reflect.KFunctionX` interfaces, we're making sure that we
|
||||
|
||||
@@ -220,7 +220,7 @@ open class KotlinUsesExtractor(
|
||||
val extractedTypeArgs = when {
|
||||
extractClass.symbol.isKFunction() && typeArgs != null && typeArgs.isNotEmpty() -> listOf(typeArgs.last())
|
||||
extractClass.fqNameWhenAvailable == FqName("kotlin.jvm.functions.FunctionN") && typeArgs != null && typeArgs.isNotEmpty() -> listOf(typeArgs.last())
|
||||
typeArgs != null && isUnspecialised(c, typeArgs) -> listOf()
|
||||
typeArgs != null && isUnspecialised(c, typeArgs, logger) -> listOf()
|
||||
else -> typeArgs
|
||||
}
|
||||
|
||||
@@ -479,7 +479,7 @@ open class KotlinUsesExtractor(
|
||||
fun useSimpleTypeClass(c: IrClass, args: List<IrTypeArgument>?, hasQuestionMark: Boolean): TypeResults {
|
||||
if (c.isAnonymousObject) {
|
||||
args?.let {
|
||||
if (it.isNotEmpty() && !isUnspecialised(c, it)) {
|
||||
if (it.isNotEmpty() && !isUnspecialised(c, it, logger)) {
|
||||
logger.error("Unexpected specialised instance of generic anonymous class")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.github.codeql.utils
|
||||
|
||||
import com.github.codeql.KotlinUsesExtractor
|
||||
import com.github.codeql.Logger
|
||||
import com.github.codeql.getJavaEquivalentClassId
|
||||
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
|
||||
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
@@ -25,6 +26,7 @@ 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.kotlinFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -215,27 +217,34 @@ private fun matchingTypeParameters(l: IrTypeParameter?, r: IrTypeParameter): Boo
|
||||
}
|
||||
|
||||
// Returns true if type is C<T1, T2, ...> where C is declared `class C<T1, T2, ...> { ... }`
|
||||
fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List<IrTypeArgument>): Boolean {
|
||||
fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List<IrTypeArgument>, logger: Logger): Boolean {
|
||||
return isUnspecialised(paramsContainer, args, logger, paramsContainer)
|
||||
}
|
||||
|
||||
private fun isUnspecialised(paramsContainer: IrTypeParametersContainer, args: List<IrTypeArgument>, logger: Logger, origParamsContainer: IrTypeParametersContainer): 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 &&
|
||||
matchingTypeParameters(it.type.classifierOrNull?.owner as? IrTypeParameter, paramAndArg.first)
|
||||
matchingTypeParameters(it.type.classifierOrNull?.owner as? IrTypeParameter, paramAndArg.first)
|
||||
} ?: false
|
||||
}
|
||||
val remainingArgs = args.drop(paramsContainer.typeParameters.size)
|
||||
|
||||
val parentClass = paramsContainer.parents.firstIsInstanceOrNull<IrClass>()
|
||||
val parentTypeContainer = paramsContainer.parents.firstIsInstanceOrNull<IrTypeParametersContainer>()
|
||||
|
||||
val parentUnspecialised = when {
|
||||
remainingArgs.isEmpty() -> true
|
||||
parentClass == null -> false
|
||||
else -> isUnspecialised(parentClass, remainingArgs)
|
||||
parentTypeContainer == null -> {
|
||||
logger.error("Found more type arguments than parameters: ${origParamsContainer.kotlinFqName.asString()}")
|
||||
false
|
||||
}
|
||||
else -> isUnspecialised(parentTypeContainer, remainingArgs, logger, origParamsContainer)
|
||||
}
|
||||
return unspecialisedHere && parentUnspecialised
|
||||
}
|
||||
|
||||
// Returns true if type is C<T1, T2, ...> where C is declared `class C<T1, T2, ...> { ... }`
|
||||
fun isUnspecialised(type: IrSimpleType) = (type.classifier.owner as? IrClass)?.let {
|
||||
isUnspecialised(it, type.arguments)
|
||||
fun isUnspecialised(type: IrSimpleType, logger: Logger) = (type.classifier.owner as? IrClass)?.let {
|
||||
isUnspecialised(it, type.arguments, logger)
|
||||
} ?: false
|
||||
|
||||
Reference in New Issue
Block a user