mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Fix type substitution and source locations in SAM-converted generic interface implementations
For example, in implementing Producer<T> by an actual lambda of type () -> Int, the return type should be Int, not T. This produced type-variable-out-of-scope consistency check failures.
This commit is contained in:
@@ -322,17 +322,7 @@ open class KotlinFileExtractor(
|
|||||||
val typeParamSubstitution =
|
val typeParamSubstitution =
|
||||||
when (argsIncludingOuterClasses) {
|
when (argsIncludingOuterClasses) {
|
||||||
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
|
null -> { x: IrType, _: TypeContext, _: IrPluginContext -> x.toRawType() }
|
||||||
else -> {
|
else -> makeGenericSubstitutionFunction(c, argsIncludingOuterClasses)
|
||||||
makeTypeGenericSubstitutionMap(c, argsIncludingOuterClasses).let {
|
|
||||||
{ x: IrType, useContext: TypeContext, pluginContext: IrPluginContext ->
|
|
||||||
x.substituteTypeAndArguments(
|
|
||||||
it,
|
|
||||||
useContext,
|
|
||||||
pluginContext
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.declarations.map {
|
c.declarations.map {
|
||||||
@@ -499,12 +489,12 @@ open class KotlinFileExtractor(
|
|||||||
return FieldResult(instanceId, instanceName)
|
return FieldResult(instanceId, instanceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean): TypeResults {
|
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean, locOverride: Label<DbLocation>? = null): TypeResults {
|
||||||
with("value parameter", vp) {
|
with("value parameter", vp) {
|
||||||
val location = getLocation(vp, classTypeArgsIncludingOuterClasses)
|
val location = locOverride ?: getLocation(vp, classTypeArgsIncludingOuterClasses)
|
||||||
val id = useValueParameter(vp, parent)
|
val id = useValueParameter(vp, parent)
|
||||||
if (extractTypeAccess) {
|
if (extractTypeAccess) {
|
||||||
extractTypeAccessRecursive(vp.type, location, id, -1)
|
extractTypeAccessRecursive(typeSubstitution?.let { it(vp.type, TypeContext.OTHER, pluginContext) } ?: vp.type, location, id, -1)
|
||||||
}
|
}
|
||||||
return extractValueParameter(id, vp.type, vp.name.asString(), location, parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
|
return extractValueParameter(id, vp.type, vp.name.asString(), location, parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
|
||||||
}
|
}
|
||||||
@@ -664,7 +654,7 @@ open class KotlinFileExtractor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, idOverride: Label<DbMethod>? = null): Label<out DbCallable>? {
|
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, idOverride: Label<DbMethod>? = null, locOverride: Label<DbLocation>? = null): Label<out DbCallable>? {
|
||||||
if (isFake(f)) return null
|
if (isFake(f)) return null
|
||||||
|
|
||||||
with("function", f) {
|
with("function", f) {
|
||||||
@@ -682,7 +672,7 @@ open class KotlinFileExtractor(
|
|||||||
useFunction<DbCallable>(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true)
|
useFunction<DbCallable>(f, parentId, classTypeArgsIncludingOuterClasses, noReplace = true)
|
||||||
|
|
||||||
val sourceDeclaration =
|
val sourceDeclaration =
|
||||||
if (typeSubstitution != null)
|
if (typeSubstitution != null && idOverride == null)
|
||||||
useFunction(f)
|
useFunction(f)
|
||||||
else
|
else
|
||||||
id
|
id
|
||||||
@@ -690,13 +680,13 @@ open class KotlinFileExtractor(
|
|||||||
val extReceiver = f.extensionReceiverParameter
|
val extReceiver = f.extensionReceiverParameter
|
||||||
val idxOffset = if (extReceiver != null) 1 else 0
|
val idxOffset = if (extReceiver != null) 1 else 0
|
||||||
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
|
val paramTypes = f.valueParameters.mapIndexed { i, vp ->
|
||||||
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses)
|
extractValueParameter(vp, id, i + idxOffset, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
|
||||||
}
|
}
|
||||||
val allParamTypes = if (extReceiver != null) {
|
val allParamTypes = if (extReceiver != null) {
|
||||||
val extendedType = useType(extReceiver.type)
|
val extendedType = useType(extReceiver.type)
|
||||||
tw.writeKtExtensionFunctions(id.cast<DbMethod>(), extendedType.javaResult.id, extendedType.kotlinResult.id)
|
tw.writeKtExtensionFunctions(id.cast<DbMethod>(), extendedType.javaResult.id, extendedType.kotlinResult.id)
|
||||||
|
|
||||||
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses)
|
val t = extractValueParameter(extReceiver, id, 0, null, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, locOverride)
|
||||||
listOf(t) + paramTypes
|
listOf(t) + paramTypes
|
||||||
} else {
|
} else {
|
||||||
paramTypes
|
paramTypes
|
||||||
@@ -706,7 +696,7 @@ open class KotlinFileExtractor(
|
|||||||
|
|
||||||
val substReturnType = typeSubstitution?.let { it(f.returnType, TypeContext.RETURN, pluginContext) } ?: f.returnType
|
val substReturnType = typeSubstitution?.let { it(f.returnType, TypeContext.RETURN, pluginContext) } ?: f.returnType
|
||||||
|
|
||||||
val locId = getLocation(f, classTypeArgsIncludingOuterClasses)
|
val locId = locOverride ?: getLocation(f, classTypeArgsIncludingOuterClasses)
|
||||||
|
|
||||||
if (f.symbol is IrConstructorSymbol) {
|
if (f.symbol is IrConstructorSymbol) {
|
||||||
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
|
val unitType = useType(pluginContext.irBuiltIns.unitType, TypeContext.RETURN)
|
||||||
@@ -726,7 +716,7 @@ open class KotlinFileExtractor(
|
|||||||
tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id)
|
tw.writeMethodsKotlinType(methodId, returnType.kotlinResult.id)
|
||||||
|
|
||||||
if (extractMethodAndParameterTypeAccesses) {
|
if (extractMethodAndParameterTypeAccesses) {
|
||||||
extractTypeAccessRecursive(f.returnType, locId, id, -1)
|
extractTypeAccessRecursive(substReturnType, locId, id, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shortName.nameInDB != shortName.kotlinName) {
|
if (shortName.nameInDB != shortName.kotlinName) {
|
||||||
@@ -4002,7 +3992,12 @@ open class KotlinFileExtractor(
|
|||||||
helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1)
|
helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1)
|
||||||
|
|
||||||
// add implementation function
|
// add implementation function
|
||||||
extractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, null, null, ids.function)
|
val classTypeArgs = (e.type as? IrSimpleType)?.arguments
|
||||||
|
val typeSub = classTypeArgs?.let { makeGenericSubstitutionFunction(typeOwner, it) }
|
||||||
|
|
||||||
|
fun trySub(t: IrType, context: TypeContext) = if (typeSub == null) t else typeSub(t, context, pluginContext)
|
||||||
|
|
||||||
|
extractFunction(samMember, classId, extractBody = false, extractMethodAndParameterTypeAccesses = true, typeSub, classTypeArgs, idOverride = ids.function, locOverride = tw.getLocation(e))
|
||||||
|
|
||||||
//body
|
//body
|
||||||
val blockId = tw.getFreshIdLabel<DbBlock>()
|
val blockId = tw.getFreshIdLabel<DbBlock>()
|
||||||
@@ -4025,7 +4020,7 @@ open class KotlinFileExtractor(
|
|||||||
|
|
||||||
// Call to original `invoke`:
|
// Call to original `invoke`:
|
||||||
val callId = tw.getFreshIdLabel<DbMethodaccess>()
|
val callId = tw.getFreshIdLabel<DbMethodaccess>()
|
||||||
val callType = useType(samMember.returnType)
|
val callType = useType(trySub(samMember.returnType, TypeContext.RETURN))
|
||||||
tw.writeExprs_methodaccess(callId, callType.javaResult.id, returnId, 0)
|
tw.writeExprs_methodaccess(callId, callType.javaResult.id, returnId, 0)
|
||||||
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
|
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
|
||||||
extractCommonExpr(callId)
|
extractCommonExpr(callId)
|
||||||
@@ -4049,7 +4044,7 @@ open class KotlinFileExtractor(
|
|||||||
|
|
||||||
fun extractArgument(p: IrValueParameter, idx: Int, parent: Label<out DbExprparent>) {
|
fun extractArgument(p: IrValueParameter, idx: Int, parent: Label<out DbExprparent>) {
|
||||||
val argsAccessId = tw.getFreshIdLabel<DbVaraccess>()
|
val argsAccessId = tw.getFreshIdLabel<DbVaraccess>()
|
||||||
val paramType = useType(p.type)
|
val paramType = useType(trySub(p.type, TypeContext.OTHER))
|
||||||
tw.writeExprs_varaccess(argsAccessId, paramType.javaResult.id, parent, idx)
|
tw.writeExprs_varaccess(argsAccessId, paramType.javaResult.id, parent, idx)
|
||||||
tw.writeExprsKotlinType(argsAccessId, paramType.kotlinResult.id)
|
tw.writeExprsKotlinType(argsAccessId, paramType.kotlinResult.id)
|
||||||
extractCommonExpr(argsAccessId)
|
extractCommonExpr(argsAccessId)
|
||||||
|
|||||||
@@ -215,6 +215,17 @@ open class KotlinUsesExtractor(
|
|||||||
fun makeTypeGenericSubstitutionMap(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>) =
|
fun makeTypeGenericSubstitutionMap(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>) =
|
||||||
getTypeParametersInScope(c).map({ it.symbol }).zip(argsIncludingOuterClasses.map { it.withQuestionMark(true) }).toMap()
|
getTypeParametersInScope(c).map({ it.symbol }).zip(argsIncludingOuterClasses.map { it.withQuestionMark(true) }).toMap()
|
||||||
|
|
||||||
|
fun makeGenericSubstitutionFunction(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>) =
|
||||||
|
makeTypeGenericSubstitutionMap(c, argsIncludingOuterClasses).let {
|
||||||
|
{ x: IrType, useContext: TypeContext, pluginContext: IrPluginContext ->
|
||||||
|
x.substituteTypeAndArguments(
|
||||||
|
it,
|
||||||
|
useContext,
|
||||||
|
pluginContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The Kotlin compiler internal representation of Outer<A, B>.Inner<C, D>.InnerInner<E, F>.someFunction<G, H>.LocalClass<I, J> is LocalClass<I, J, G, H, E, F, C, D, A, B>. This function returns [A, B, C, D, E, F, G, H, I, J].
|
// The Kotlin compiler internal representation of Outer<A, B>.Inner<C, D>.InnerInner<E, F>.someFunction<G, H>.LocalClass<I, J> is LocalClass<I, J, G, H, E, F, C, D, A, B>. This function returns [A, B, C, D, E, F, G, H, I, J].
|
||||||
fun orderTypeArgsLeftToRight(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?): List<IrTypeArgument>? {
|
fun orderTypeArgsLeftToRight(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?): List<IrTypeArgument>? {
|
||||||
if(argsIncludingOuterClasses.isNullOrEmpty())
|
if(argsIncludingOuterClasses.isNullOrEmpty())
|
||||||
|
|||||||
Reference in New Issue
Block a user