Kotlin: Fix varargs dataflow, and varargs default handling

Dataflow requires accounting for the fact that the varargs parameter isn't necessarily last in the parameter list in a couple more places. Default handling just requires that if the only null parameter is the varargs argument, and it has no default value, then no $default method is required-- the caller is expected to simply pass nothing (at QL
/ source level) or an empty array (at JVM level).
This commit is contained in:
Chris Smowton
2022-10-20 15:50:07 +01:00
parent 471a596dfb
commit 1fe9e8457f
9 changed files with 473 additions and 16 deletions

View File

@@ -1884,7 +1884,7 @@ open class KotlinFileExtractor(
IrConstImpl.defaultValueForType(0, 0, getDefaultsMethodLastArgType(callTarget))
)
extractCallValueArguments(id, valueArgsWithDummies + extraArgs, enclosingStmt, enclosingCallable, nextIdx)
extractCallValueArguments(id, valueArgsWithDummies + extraArgs, enclosingStmt, enclosingCallable, nextIdx, extractVarargAsArray = true)
}
private fun getFunctionInvokeMethod(typeArgs: List<IrTypeArgument>): IrFunction? {
@@ -1961,8 +1961,12 @@ open class KotlinFileExtractor(
superQualifierSymbol: IrClassSymbol? = null) {
val locId = tw.getLocation(locElement)
val varargParam = syntacticCallTarget.valueParameters.withIndex().find { it.value.isVararg }
// If the vararg param is the only one not specified, and it has no default value, then we don't need to call a $default method,
// as omitting it already implies passing an empty vararg array.
val nullAllowedIdx = if (varargParam != null && varargParam.value.defaultValue == null) varargParam.index else -1
if (valueArguments.any { it == null }) {
if (valueArguments.withIndex().any { (index, it) -> it == null && index != nullAllowedIdx }) {
extractsDefaultsCall(
syntacticCallTarget,
locId,
@@ -2082,11 +2086,11 @@ open class KotlinFileExtractor(
private fun extractCallValueArguments(callId: Label<out DbExprparent>, call: IrFunctionAccessExpression, enclosingStmt: Label<out DbStmt>, enclosingCallable: Label<out DbCallable>, idxOffset: Int) =
extractCallValueArguments(callId, (0 until call.valueArgumentsCount).map { call.getValueArgument(it) }, enclosingStmt, enclosingCallable, idxOffset)
private fun extractCallValueArguments(callId: Label<out DbExprparent>, valueArguments: List<IrExpression?>, enclosingStmt: Label<out DbStmt>, enclosingCallable: Label<out DbCallable>, idxOffset: Int) {
private fun extractCallValueArguments(callId: Label<out DbExprparent>, valueArguments: List<IrExpression?>, enclosingStmt: Label<out DbStmt>, enclosingCallable: Label<out DbCallable>, idxOffset: Int, extractVarargAsArray: Boolean = false) {
var i = 0
valueArguments.forEach { arg ->
if(arg != null) {
if (arg is IrVararg) {
if (arg is IrVararg && !extractVarargAsArray) {
arg.elements.forEachIndexed { varargNo, vararg -> extractVarargElement(vararg, enclosingCallable, callId, i + idxOffset + varargNo, enclosingStmt) }
i += arg.elements.size
} else {