mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
Fix class type parameter erasure within $default methods
This commit is contained in:
@@ -859,7 +859,10 @@ open class KotlinFileExtractor(
|
||||
// n + o'th parameter, where `o` is the parameter offset caused by adding any dispatch receiver to the parameter list.
|
||||
// Note we don't need to add the extension receiver here because `useValueParameter` always assumes an extension receiver
|
||||
// will be prepended if one exists.
|
||||
DeclarationStackAdjuster(f, OverriddenFunctionAttributes(id, id, locId, nonSyntheticParams, typeParameters = listOf())).use {
|
||||
// Note we have to get the real function ID here before entering this block, because otherwise we'll misrepresent the signature of a generic
|
||||
// function without its type variables -- for example, trying to address `f(T, List<T>)` as `f(Object, List)`.
|
||||
val realFunctionId = useFunction<DbCallable>(f)
|
||||
DeclarationStackAdjuster(f, OverriddenFunctionAttributes(id, id, locId, nonSyntheticParams, typeParameters = listOf(), isStatic = true)).use {
|
||||
val realParamsVarId = getValueParameterLabel(id, parameterTypes.size - 2)
|
||||
val intType = pluginContext.irBuiltIns.intType
|
||||
val paramIdxOffset = listOf(dispatchReceiver, f.extensionReceiverParameter).count { it != null }
|
||||
@@ -889,7 +892,6 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
// Now call the real function:
|
||||
val realFunctionId = useFunction<DbCallable>(f)
|
||||
if (f is IrConstructor) {
|
||||
tw.getFreshIdLabel<DbConstructorinvocationstmt>().also { thisCallId ->
|
||||
tw.writeStmts_constructorinvocationstmt(thisCallId, blockId, nextStmt++, id)
|
||||
@@ -5275,10 +5277,19 @@ open class KotlinFileExtractor(
|
||||
fun peek() = stack.peek()
|
||||
|
||||
fun findOverriddenAttributes(f: IrFunction) =
|
||||
stack.firstOrNull { it.first == f } ?.second
|
||||
stack.lastOrNull { it.first == f } ?.second
|
||||
|
||||
fun findFirst(f: (Pair<IrDeclaration, OverriddenFunctionAttributes?>) -> Boolean) =
|
||||
stack.findLast(f)
|
||||
}
|
||||
|
||||
data class OverriddenFunctionAttributes(val id: Label<out DbCallable>? = null, val sourceDeclarationId: Label<out DbCallable>? = null, val sourceLoc: Label<DbLocation>? = null, val valueParameters: List<IrValueParameter>? = null, val typeParameters: List<IrTypeParameter>? = null)
|
||||
data class OverriddenFunctionAttributes(
|
||||
val id: Label<out DbCallable>? = null,
|
||||
val sourceDeclarationId: Label<out DbCallable>? = null,
|
||||
val sourceLoc: Label<DbLocation>? = null,
|
||||
val valueParameters: List<IrValueParameter>? = null,
|
||||
val typeParameters: List<IrTypeParameter>? = null,
|
||||
val isStatic: Boolean? = null)
|
||||
|
||||
private fun peekDeclStackAsDeclarationParent(elementToReportOn: IrElement): IrDeclarationParent? {
|
||||
val trapWriter = tw
|
||||
|
||||
@@ -661,10 +661,17 @@ open class KotlinUsesExtractor(
|
||||
private fun isOnDeclarationStackWithoutTypeParameters(f: IrFunction) =
|
||||
this is KotlinFileExtractor && this.declarationStack.findOverriddenAttributes(f)?.typeParameters?.isEmpty() == true
|
||||
|
||||
private fun isStaticFunctionOnStackBeforeClass(c: IrClass) =
|
||||
this is KotlinFileExtractor && (this.declarationStack.findFirst { it.first == c || it.second?.isStatic == true })?.second?.isStatic == true
|
||||
|
||||
private fun isUnavailableTypeParameter(t: IrType) =
|
||||
t is IrSimpleType && t.classifier.owner.let { owner ->
|
||||
owner is IrTypeParameter && owner.parent.let { parent ->
|
||||
parent is IrFunction && isOnDeclarationStackWithoutTypeParameters(parent)
|
||||
when (parent) {
|
||||
is IrFunction -> isOnDeclarationStackWithoutTypeParameters(parent)
|
||||
is IrClass -> isStaticFunctionOnStackBeforeClass(parent)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -847,3 +847,154 @@ test.kt:
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [IntegerLiteral] 1
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 143| 12: [Class,GenericType,ParameterizedType] TestGenericFunction
|
||||
#-----| -2: (Generic Parameters)
|
||||
# 143| 0: [TypeVariable] T
|
||||
# 143| 1: [Constructor] TestGenericFunction
|
||||
# 143| 5: [BlockStmt] { ... }
|
||||
# 143| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 143| 1: [BlockStmt] { ... }
|
||||
# 145| 2: [Method] f
|
||||
#-----| 2: (Generic Parameters)
|
||||
# 145| 0: [TypeVariable] S
|
||||
# 145| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 145| 0: [Parameter] x
|
||||
# 145| 0: [TypeAccess] S
|
||||
# 145| 1: [Parameter] y
|
||||
# 145| 0: [TypeAccess] T
|
||||
# 145| 2: [Parameter] def1
|
||||
# 145| 0: [TypeAccess] T
|
||||
# 145| 3: [Parameter] def2
|
||||
# 145| 0: [TypeAccess] List<? extends T>
|
||||
# 145| 0: [WildcardTypeAccess] ? ...
|
||||
# 145| 0: [TypeAccess] T
|
||||
# 145| 4: [Parameter] def3
|
||||
# 145| 0: [TypeAccess] S
|
||||
# 145| 5: [Parameter] def4
|
||||
# 145| 0: [TypeAccess] List<? extends S>
|
||||
# 145| 0: [WildcardTypeAccess] ? ...
|
||||
# 145| 0: [TypeAccess] S
|
||||
# 145| 5: [BlockStmt] { ... }
|
||||
# 146| 0: [ExprStmt] <Expr>;
|
||||
# 146| 0: [MethodAccess] sink(...)
|
||||
# 146| -1: [TypeAccess] TestKt
|
||||
# 146| 0: [VarAccess] y
|
||||
# 145| 3: [Method] f$default
|
||||
# 145| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 145| 0: [Parameter] p0
|
||||
# 145| 0: [TypeAccess] TestGenericFunction<>
|
||||
# 145| 1: [Parameter] p1
|
||||
# 145| 0: [TypeAccess] Object
|
||||
# 145| 2: [Parameter] p2
|
||||
# 145| 0: [TypeAccess] Object
|
||||
# 145| 3: [Parameter] p3
|
||||
# 145| 0: [TypeAccess] Object
|
||||
# 145| 4: [Parameter] p4
|
||||
# 145| 0: [TypeAccess] List<>
|
||||
# 145| 5: [Parameter] p5
|
||||
# 145| 0: [TypeAccess] Object
|
||||
# 145| 6: [Parameter] p6
|
||||
# 145| 0: [TypeAccess] List<>
|
||||
# 145| 7: [Parameter] p7
|
||||
# 145| 0: [TypeAccess] int
|
||||
# 145| 8: [Parameter] p8
|
||||
# 145| 0: [TypeAccess] Object
|
||||
# 145| 5: [BlockStmt] { ... }
|
||||
# 145| 0: [IfStmt] if (...)
|
||||
# 145| 0: [EQExpr] ... == ...
|
||||
# 145| 0: [AndBitwiseExpr] ... & ...
|
||||
# 145| 0: [IntegerLiteral] 2
|
||||
# 145| 1: [VarAccess] p7
|
||||
# 145| 1: [IntegerLiteral] 0
|
||||
# 145| 1: [ExprStmt] <Expr>;
|
||||
# 145| 0: [AssignExpr] ...=...
|
||||
# 145| 0: [VarAccess] p2
|
||||
# 145| 1: [VarAccess] p1
|
||||
# 145| 1: [IfStmt] if (...)
|
||||
# 145| 0: [EQExpr] ... == ...
|
||||
# 145| 0: [AndBitwiseExpr] ... & ...
|
||||
# 145| 0: [IntegerLiteral] 4
|
||||
# 145| 1: [VarAccess] p7
|
||||
# 145| 1: [IntegerLiteral] 0
|
||||
# 145| 1: [ExprStmt] <Expr>;
|
||||
# 145| 0: [AssignExpr] ...=...
|
||||
# 145| 0: [VarAccess] p3
|
||||
# 145| 1: [NullLiteral] null
|
||||
# 145| 2: [IfStmt] if (...)
|
||||
# 145| 0: [EQExpr] ... == ...
|
||||
# 145| 0: [AndBitwiseExpr] ... & ...
|
||||
# 145| 0: [IntegerLiteral] 8
|
||||
# 145| 1: [VarAccess] p7
|
||||
# 145| 1: [IntegerLiteral] 0
|
||||
# 145| 1: [ExprStmt] <Expr>;
|
||||
# 145| 0: [AssignExpr] ...=...
|
||||
# 145| 0: [VarAccess] p4
|
||||
# 145| 1: [MethodAccess] listOf(...)
|
||||
# 145| -2: [TypeAccess] Object
|
||||
# 145| -1: [TypeAccess] CollectionsKt
|
||||
# 145| 0: [VarAccess] p2
|
||||
# 145| 3: [IfStmt] if (...)
|
||||
# 145| 0: [EQExpr] ... == ...
|
||||
# 145| 0: [AndBitwiseExpr] ... & ...
|
||||
# 145| 0: [IntegerLiteral] 16
|
||||
# 145| 1: [VarAccess] p7
|
||||
# 145| 1: [IntegerLiteral] 0
|
||||
# 145| 1: [ExprStmt] <Expr>;
|
||||
# 145| 0: [AssignExpr] ...=...
|
||||
# 145| 0: [VarAccess] p5
|
||||
# 145| 1: [NullLiteral] null
|
||||
# 145| 4: [IfStmt] if (...)
|
||||
# 145| 0: [EQExpr] ... == ...
|
||||
# 145| 0: [AndBitwiseExpr] ... & ...
|
||||
# 145| 0: [IntegerLiteral] 32
|
||||
# 145| 1: [VarAccess] p7
|
||||
# 145| 1: [IntegerLiteral] 0
|
||||
# 145| 1: [ExprStmt] <Expr>;
|
||||
# 145| 0: [AssignExpr] ...=...
|
||||
# 145| 0: [VarAccess] p6
|
||||
# 145| 1: [MethodAccess] listOf(...)
|
||||
# 145| -2: [TypeAccess] Object
|
||||
# 145| -1: [TypeAccess] CollectionsKt
|
||||
# 145| 0: [VarAccess] p1
|
||||
# 145| 5: [ReturnStmt] return ...
|
||||
# 145| 0: [MethodAccess] f(...)
|
||||
# 145| -1: [VarAccess] p0
|
||||
# 145| 0: [VarAccess] p1
|
||||
# 145| 1: [VarAccess] p2
|
||||
# 145| 2: [VarAccess] p3
|
||||
# 145| 3: [VarAccess] p4
|
||||
# 145| 4: [VarAccess] p5
|
||||
# 145| 5: [VarAccess] p6
|
||||
# 149| 4: [Method] user
|
||||
# 149| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 149| 0: [Parameter] inst
|
||||
# 149| 0: [TypeAccess] TestGenericFunction<String>
|
||||
# 149| 0: [TypeAccess] String
|
||||
# 149| 5: [BlockStmt] { ... }
|
||||
# 150| 0: [ExprStmt] <Expr>;
|
||||
# 150| 0: [MethodAccess] f$default(...)
|
||||
# 150| -1: [TypeAccess] TestGenericFunction<>
|
||||
# 150| 0: [VarAccess] inst
|
||||
# 150| 1: [StringLiteral] generic function sunk
|
||||
# 1| 2: [NullLiteral] null
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 1| 6: [NullLiteral] null
|
||||
# 1| 7: [IntegerLiteral] 1
|
||||
# 1| 8: [NullLiteral] null
|
||||
# 151| 1: [ExprStmt] <Expr>;
|
||||
# 151| 0: [MethodAccess] f$default(...)
|
||||
# 151| -1: [TypeAccess] TestGenericFunction<>
|
||||
# 151| 0: [VarAccess] inst
|
||||
# 151| 1: [StringLiteral] generic function sunk fp
|
||||
# 151| 2: [StringLiteral] generic function sunk 2
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
# 1| 5: [NullLiteral] null
|
||||
# 1| 6: [NullLiteral] null
|
||||
# 1| 7: [IntegerLiteral] 3
|
||||
# 1| 8: [NullLiteral] null
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import java
|
||||
|
||||
// This checks that all type parameter references are erased in the context of a $default function.
|
||||
predicate containsTypeVariables(Type t) {
|
||||
t != t.getErasure() and
|
||||
not t.getErasure().(GenericType).getRawType() = t
|
||||
}
|
||||
|
||||
from Expr e
|
||||
where
|
||||
e.getEnclosingCallable().getName().matches("%$default") and
|
||||
containsTypeVariables(e.getType())
|
||||
select e, e.getType()
|
||||
@@ -139,3 +139,16 @@ class TestGeneric<T> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestGenericFunction<T> {
|
||||
|
||||
fun <S : T> f(x: S, y: T = x, def1: T? = null, def2: List<T> = listOf(y), def3: S? = null, def4: List<S>? = listOf(x)) {
|
||||
sink(y)
|
||||
}
|
||||
|
||||
fun user(inst: TestGenericFunction<String>) {
|
||||
inst.f<String>("generic function sunk")
|
||||
inst.f("generic function sunk fp", "generic function sunk 2")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user