mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Make varargs extraction more Java-like:
* Extract varargs as if they are ordinary positional arguments * Adapt the QL that distinguishes varargs from ordinary arguments to account for Kotlin's varargs which can occur in the middle of the arg list * Add a test checking dataflow through varargs which doesn't work yet due to array-get and array-set not being extracted as IndexExprs * Extract the special case arrayOf(*x) as a clone call, which is (equivalent to) the Java lowering of that operation
This commit is contained in:
committed by
Ian Lynagh
parent
7368b49b16
commit
96f3ea460f
@@ -441,17 +441,20 @@ open class KotlinFileExtractor(
|
||||
|
||||
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>): TypeResults {
|
||||
with("value parameter", vp) {
|
||||
return extractValueParameter(useValueParameter(vp, parent), vp.type, vp.name.asString(), tw.getLocation(vp), parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration))
|
||||
return extractValueParameter(useValueParameter(vp, parent), vp.type, vp.name.asString(), tw.getLocation(vp), parent, idx, typeSubstitution, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, paramSourceDeclaration: Label<out DbParam>): TypeResults {
|
||||
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, paramSourceDeclaration: Label<out DbParam>, isVararg: Boolean): TypeResults {
|
||||
val substitutedType = typeSubstitution?.let { it(t, TypeContext.OTHER, pluginContext) } ?: t
|
||||
val type = useType(substitutedType)
|
||||
tw.writeParams(id, type.javaResult.id, idx, parent, paramSourceDeclaration)
|
||||
tw.writeParamsKotlinType(id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeParamName(id, name)
|
||||
if (isVararg) {
|
||||
tw.writeIsVarargsParam(id)
|
||||
}
|
||||
return type
|
||||
}
|
||||
|
||||
@@ -1079,9 +1082,15 @@ open class KotlinFileExtractor(
|
||||
idxOffset = 0
|
||||
}
|
||||
|
||||
valueArguments.forEachIndexed { i, arg ->
|
||||
var i = 0
|
||||
valueArguments.forEach { arg ->
|
||||
if(arg != null) {
|
||||
extractExpressionExpr(arg, enclosingCallable, id, i + idxOffset, enclosingStmt)
|
||||
if (arg is IrVararg) {
|
||||
arg.elements.forEachIndexed { varargNo, vararg -> extractVarargElement(vararg, enclosingCallable, id, i + idxOffset + varargNo, enclosingStmt) }
|
||||
i += arg.elements.size
|
||||
} else {
|
||||
extractExpressionExpr(arg, enclosingCallable, id, (i++) + idxOffset, enclosingStmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1121,6 +1130,22 @@ open class KotlinFileExtractor(
|
||||
result
|
||||
}
|
||||
|
||||
val javaLangObject by lazy {
|
||||
val result = pluginContext.referenceClass(FqName("java.lang.Object"))?.owner
|
||||
result?.let { extractExternalClassLater(it) }
|
||||
result
|
||||
}
|
||||
|
||||
val objectCloneMethod by lazy {
|
||||
val result = javaLangObject?.declarations?.find {
|
||||
it is IrFunction && it.name.asString() == "clone"
|
||||
} as IrFunction?
|
||||
if (result == null) {
|
||||
logger.error("Couldn't find declaration java.lang.Object.clone(...)")
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun extractCall(c: IrCall, callable: Label<out DbCallable>, parent: Label<out DbExprparent>, idx: Int, enclosingStmt: Label<out DbStmt>) {
|
||||
with("call", c) {
|
||||
fun isFunction(pkgName: String, className: String, fName: String, hasQuestionMark: Boolean? = false): Boolean {
|
||||
@@ -1458,37 +1483,63 @@ open class KotlinFileExtractor(
|
||||
|| isBuiltinCallKotlin(c, "shortArrayOf")
|
||||
|| isBuiltinCallKotlin(c, "byteArrayOf")
|
||||
|| isBuiltinCallKotlin(c, "booleanArrayOf") -> {
|
||||
val id = tw.getFreshIdLabel<DbArraycreationexpr>()
|
||||
val type = useType(c.type)
|
||||
tw.writeExprs_arraycreationexpr(id, type.javaResult.id, parent, idx)
|
||||
tw.writeExprsKotlinType(id, type.kotlinResult.id)
|
||||
val locId = tw.getLocation(c)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, callable)
|
||||
|
||||
if (isBuiltinCallKotlin(c, "arrayOf")) {
|
||||
if (c.typeArgumentsCount == 1) {
|
||||
extractTypeArguments(c, id, callable, enclosingStmt,-1)
|
||||
} else {
|
||||
logger.errorElement("Expected to find one type argument in arrayOf call", c )
|
||||
|
||||
val arg = if (c.valueArgumentsCount == 1) c.getValueArgument(0) else {
|
||||
logger.errorElement("Expected to find only one (vararg) argument in ${c.symbol.owner.name.asString()} call", c)
|
||||
null
|
||||
}?.let {
|
||||
if (it is IrVararg) it else {
|
||||
logger.errorElement("Expected to find vararg argument in ${c.symbol.owner.name.asString()} call", c)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
// If this is [someType]ArrayOf(*x), x, otherwise null
|
||||
val clonedArray = arg?.let {
|
||||
if (arg.elements.size == 1) {
|
||||
val onlyElement = arg.elements[0]
|
||||
if (onlyElement is IrSpreadElement)
|
||||
onlyElement.expression
|
||||
else null
|
||||
} else null
|
||||
}
|
||||
|
||||
if (clonedArray != null) {
|
||||
// This is an array clone: extract is as a call to java.lang.Object.clone
|
||||
objectCloneMethod?.let {
|
||||
extractRawMethodAccess(it, c, callable, parent, idx, enclosingStmt, listOf(), clonedArray, null)
|
||||
}
|
||||
} else {
|
||||
val elementType = c.type.getArrayElementType(pluginContext.irBuiltIns)
|
||||
extractTypeAccess(elementType, callable, id, -1, c, enclosingStmt)
|
||||
}
|
||||
|
||||
if (c.valueArgumentsCount == 1) {
|
||||
val vararg = c.getValueArgument(0)
|
||||
if (vararg is IrVararg) {
|
||||
// This is array creation: extract it as a call to new ArrayType[] { ... }
|
||||
val id = tw.getFreshIdLabel<DbArraycreationexpr>()
|
||||
val type = useType(c.type)
|
||||
tw.writeExprs_arraycreationexpr(id, type.javaResult.id, parent, idx)
|
||||
tw.writeExprsKotlinType(id, type.kotlinResult.id)
|
||||
val locId = tw.getLocation(c)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, callable)
|
||||
|
||||
if (isBuiltinCallKotlin(c, "arrayOf")) {
|
||||
if (c.typeArgumentsCount == 1) {
|
||||
extractTypeArguments(c, id, callable, enclosingStmt,-1)
|
||||
} else {
|
||||
logger.errorElement("Expected to find one type argument in arrayOf call", c )
|
||||
}
|
||||
} else {
|
||||
val elementType = c.type.getArrayElementType(pluginContext.irBuiltIns)
|
||||
extractTypeAccess(elementType, callable, id, -1, c, enclosingStmt)
|
||||
}
|
||||
|
||||
arg?.let {
|
||||
val initId = tw.getFreshIdLabel<DbArrayinit>()
|
||||
tw.writeExprs_arrayinit(initId, type.javaResult.id, id, -2)
|
||||
tw.writeExprsKotlinType(initId, type.kotlinResult.id)
|
||||
tw.writeHasLocation(initId, locId)
|
||||
tw.writeCallableEnclosingExpr(initId, callable)
|
||||
tw.writeStatementEnclosingExpr(initId, enclosingStmt)
|
||||
vararg.elements.forEachIndexed { i, arg -> extractVarargElement(arg, callable, initId, i, enclosingStmt) }
|
||||
|
||||
val dim = vararg.elements.size
|
||||
it.elements.forEachIndexed { i, arg -> extractVarargElement(arg, callable, initId, i, enclosingStmt) }
|
||||
|
||||
val dim = it.elements.size
|
||||
val dimId = tw.getFreshIdLabel<DbIntegerliteral>()
|
||||
val dimType = useType(pluginContext.irBuiltIns.intType)
|
||||
tw.writeExprs_integerliteral(dimId, dimType.javaResult.id, id, 0)
|
||||
@@ -1497,11 +1548,7 @@ open class KotlinFileExtractor(
|
||||
tw.writeCallableEnclosingExpr(dimId, callable)
|
||||
tw.writeStatementEnclosingExpr(dimId, enclosingStmt)
|
||||
tw.writeNamestrings(dim.toString(), dim.toString(), dimId)
|
||||
} else {
|
||||
logger.errorElement("Expected to find vararg argument in ${c.symbol.owner.name.asString()} call", c)
|
||||
}
|
||||
} else {
|
||||
logger.errorElement("Expected to find only one (vararg) argument in ${c.symbol.owner.name.asString()} call", c)
|
||||
}
|
||||
}
|
||||
isBuiltinCall(c, "<unsafe-coerce>", "kotlin.jvm.internal") -> {
|
||||
@@ -2123,16 +2170,7 @@ open class KotlinFileExtractor(
|
||||
extractTypeOperatorCall(e, callable, exprParent.parent, exprParent.idx, exprParent.enclosingStmt)
|
||||
}
|
||||
is IrVararg -> {
|
||||
val exprParent = parent.expr(e, callable)
|
||||
val id = tw.getFreshIdLabel<DbVarargexpr>()
|
||||
val locId = tw.getLocation(e)
|
||||
val type = useType(e.type)
|
||||
tw.writeExprs_varargexpr(id, type.javaResult.id, exprParent.parent, exprParent.idx)
|
||||
tw.writeExprsKotlinType(id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeCallableEnclosingExpr(id, callable)
|
||||
tw.writeStatementEnclosingExpr(id, exprParent.enclosingStmt)
|
||||
e.elements.forEachIndexed { i, arg -> extractVarargElement(arg, callable, id, i, exprParent.enclosingStmt) }
|
||||
logger.errorElement("Unexpected IrVararg", e)
|
||||
}
|
||||
is IrGetObjectValue -> {
|
||||
// For `object MyObject { ... }`, the .class has an
|
||||
@@ -2349,7 +2387,7 @@ open class KotlinFileExtractor(
|
||||
stmtIdx: Int
|
||||
) {
|
||||
val paramId = tw.getFreshIdLabel<DbParam>()
|
||||
val paramType = extractValueParameter(paramId, type, paramName, locId, ids.constructor, paramIdx, null, paramId)
|
||||
val paramType = extractValueParameter(paramId, type, paramName, locId, ids.constructor, paramIdx, null, paramId, false)
|
||||
|
||||
val assignmentStmtId = tw.getFreshIdLabel<DbExprstmt>()
|
||||
tw.writeStmts_exprstmt(assignmentStmtId, ids.constructorBlock, stmtIdx, ids.constructor)
|
||||
@@ -2548,7 +2586,7 @@ open class KotlinFileExtractor(
|
||||
|
||||
val parameters = parameterTypes.mapIndexed { idx, p ->
|
||||
val paramId = tw.getFreshIdLabel<DbParam>()
|
||||
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, null, paramId)
|
||||
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, null, paramId, false)
|
||||
|
||||
Pair(paramId, paramType)
|
||||
}
|
||||
@@ -2695,18 +2733,17 @@ open class KotlinFileExtractor(
|
||||
|
||||
fun extractVarargElement(e: IrVarargElement, callable: Label<out DbCallable>, parent: Label<out DbExprparent>, idx: Int, enclosingStmt: Label<out DbStmt>) {
|
||||
with("vararg element", e) {
|
||||
when(e) {
|
||||
is IrExpression -> {
|
||||
extractExpressionExpr(e, callable, parent, idx, enclosingStmt)
|
||||
}
|
||||
is IrSpreadElement -> {
|
||||
// TODO:
|
||||
logger.errorElement("Unhandled IrSpreadElement", e)
|
||||
}
|
||||
val argExpr = when(e) {
|
||||
is IrExpression -> e
|
||||
is IrSpreadElement -> e.expression
|
||||
else -> {
|
||||
logger.errorElement("Unrecognised IrVarargElement: " + e.javaClass, e)
|
||||
null
|
||||
}
|
||||
}
|
||||
argExpr?.let {
|
||||
extractExpressionExpr(it, callable, parent, idx, enclosingStmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -745,11 +745,10 @@ case @expr.kind of
|
||||
| 81 = @notinstanceofexpr
|
||||
| 82 = @stmtexpr
|
||||
| 83 = @stringtemplateexpr
|
||||
| 84 = @varargexpr
|
||||
| 85 = @notnullexpr
|
||||
| 86 = @unsafecoerceexpr
|
||||
| 87 = @valueeqexpr
|
||||
| 88 = @valueneexpr
|
||||
| 84 = @notnullexpr
|
||||
| 85 = @unsafecoerceexpr
|
||||
| 86 = @valueeqexpr
|
||||
| 87 = @valueneexpr
|
||||
;
|
||||
|
||||
/** Holds if this `when` expression was written as an `if` expression. */
|
||||
|
||||
@@ -467,8 +467,6 @@ private module ControlFlowGraphImpl {
|
||||
or
|
||||
this instanceof StringTemplateExpr
|
||||
or
|
||||
this instanceof VarArgExpr
|
||||
or
|
||||
this instanceof ClassExpr
|
||||
or
|
||||
this instanceof RValue
|
||||
@@ -562,10 +560,6 @@ private module ControlFlowGraphImpl {
|
||||
result = e.getComponent(index)
|
||||
)
|
||||
or
|
||||
exists(VarArgExpr e | e = this |
|
||||
result = e.getComponent(index)
|
||||
)
|
||||
or
|
||||
index = 0 and result = this.(ClassExpr).getExpr()
|
||||
or
|
||||
index = 0 and result = this.(ReturnStmt).getResult()
|
||||
|
||||
@@ -2253,7 +2253,6 @@ class Argument extends Expr {
|
||||
predicate isExplicitVarargsArray() {
|
||||
exists(Array typ, Parameter p, Type ptyp |
|
||||
typ = this.getType() and
|
||||
pos = call.getNumArgument() - 1 and
|
||||
call.getCallee().getParameter(pos) = p and
|
||||
p.isVarargs() and
|
||||
ptyp = p.getType() and
|
||||
@@ -2275,11 +2274,13 @@ class Argument extends Expr {
|
||||
*/
|
||||
predicate isNthVararg(int arrayindex) {
|
||||
not this.isExplicitVarargsArray() and
|
||||
exists(Callable tgt |
|
||||
exists(Callable tgt, Parameter varargsParam, int varargsParamPos |
|
||||
call.getCallee() = tgt and
|
||||
tgt.isVarargs() and
|
||||
arrayindex = pos - tgt.getNumberOfParameters() + 1 and
|
||||
arrayindex >= 0
|
||||
tgt.getParameter(varargsParamPos) = varargsParam and
|
||||
varargsParam.isVarargs() and
|
||||
arrayindex = pos - varargsParamPos and
|
||||
arrayindex >= 0 and
|
||||
arrayindex <= (call.getNumArgument() - tgt.getNumberOfParameters())
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2375,29 +2376,6 @@ class StringTemplateExpr extends Expr, @stringtemplateexpr {
|
||||
override string getAPrimaryQlClass() { result = "StringTemplateExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Kotlin(TODO: Should Java make these too?) vararg expression.
|
||||
* This is the argument to a function that corresponds to a `vararg`
|
||||
* parameter.
|
||||
*/
|
||||
class VarArgExpr extends Expr, @varargexpr {
|
||||
/**
|
||||
* Gets the `i`th component of this vararg. TODO: Is this always Expr?
|
||||
*
|
||||
* For example, in the string template `"foo${bar}baz"`, the 0th
|
||||
* component is the string literal `"foo"`, the 1st component is
|
||||
* the variable access `bar`, and the 2nd component is the string
|
||||
* literal `"bar"`.
|
||||
*/
|
||||
Expr getComponent(int i) { result.isNthChildOf(this, i) }
|
||||
|
||||
override string toString() { result = "..." }
|
||||
|
||||
override string getHalsteadID() { result = "VarArgExpr" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VarArgExpr" }
|
||||
}
|
||||
|
||||
/** A Kotlin not-null expression. For example, `expr!!`. */
|
||||
class NotNullExpr extends UnaryExpr, @notnullexpr {
|
||||
override string toString() { result = "...!!" }
|
||||
|
||||
@@ -103,3 +103,13 @@ arrayCreationInit
|
||||
| arrayCreations.kt:19:43:19:61 | new Integer[] | arrayCreations.kt:19:43:19:61 | {...} | arrayCreations.kt:19:54:19:54 | 2 | 1 |
|
||||
| arrayCreations.kt:19:43:19:61 | new Integer[] | arrayCreations.kt:19:43:19:61 | {...} | arrayCreations.kt:19:57:19:57 | 3 | 2 |
|
||||
| arrayCreations.kt:19:43:19:61 | new Integer[] | arrayCreations.kt:19:43:19:61 | {...} | arrayCreations.kt:19:60:19:60 | 4 | 3 |
|
||||
cloneCalls
|
||||
| arrayCreations.kt:29:18:29:29 | clone(...) | file://:0:0:0:0 | Integer[] |
|
||||
| arrayCreations.kt:30:18:30:35 | clone(...) | file://:0:0:0:0 | double[] |
|
||||
| arrayCreations.kt:31:18:31:34 | clone(...) | file://:0:0:0:0 | float[] |
|
||||
| arrayCreations.kt:32:18:32:33 | clone(...) | file://:0:0:0:0 | long[] |
|
||||
| arrayCreations.kt:33:18:33:32 | clone(...) | file://:0:0:0:0 | int[] |
|
||||
| arrayCreations.kt:34:18:34:33 | clone(...) | file://:0:0:0:0 | char[] |
|
||||
| arrayCreations.kt:35:18:35:34 | clone(...) | file://:0:0:0:0 | short[] |
|
||||
| arrayCreations.kt:36:18:36:33 | clone(...) | file://:0:0:0:0 | byte[] |
|
||||
| arrayCreations.kt:37:18:37:36 | clone(...) | file://:0:0:0:0 | boolean[] |
|
||||
|
||||
@@ -25,5 +25,15 @@ class TestArrayCreation {
|
||||
val a13 = IntArray(5) { 1 }
|
||||
var a14 = IntArray(5) { it * 1 }
|
||||
val a15 = Array(4) { IntArray(2) }
|
||||
|
||||
val clone1 = arrayOf(*a1)
|
||||
val clone2 = doubleArrayOf(*a2)
|
||||
val clone3 = floatArrayOf(*a3)
|
||||
val clone4 = longArrayOf(*a4)
|
||||
val clone5 = intArrayOf(*a5)
|
||||
val clone6 = charArrayOf(*a6)
|
||||
val clone7 = shortArrayOf(*a7)
|
||||
val clone8 = byteArrayOf(*a8)
|
||||
val clone9 = booleanArrayOf(*a9)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,3 +12,7 @@ query predicate arrayCreationInit(ArrayCreationExpr ace, ArrayInit init, Expr e,
|
||||
ace.getInit() = init and
|
||||
init.getInit(idx) = e
|
||||
}
|
||||
|
||||
query predicate cloneCalls(MethodAccess ma, Type resultType) {
|
||||
ma.getMethod().getName() = "clone" and resultType = ma.getType()
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ cloneMethods
|
||||
| file://:0:0:0:0 | clone | clone() | file://:0:0:0:0 | int[] | file://:0:0:0:0 | int[] | file://:0:0:0:0 | Kotlin nullable FakeKotlinClass |
|
||||
| file://:0:0:0:0 | clone | clone() | file://:0:0:0:0 | int[][] | file://:0:0:0:0 | int[][] | file://:0:0:0:0 | Kotlin nullable FakeKotlinClass |
|
||||
sourceSignatures
|
||||
| arrayCreations.kt:3:1:29:1 | <obinit> | <obinit>() |
|
||||
| arrayCreations.kt:3:1:29:1 | TestArrayCreation | TestArrayCreation() |
|
||||
| arrayCreations.kt:4:3:28:3 | test1 | test1() |
|
||||
| arrayCreations.kt:3:1:39:1 | <obinit> | <obinit>() |
|
||||
| arrayCreations.kt:3:1:39:1 | TestArrayCreation | TestArrayCreation() |
|
||||
| arrayCreations.kt:4:3:38:3 | test1 | test1() |
|
||||
| arrayCreations.kt:22:29:22:33 | | |
|
||||
| arrayCreations.kt:22:29:22:33 | invoke | invoke(int) |
|
||||
| arrayCreations.kt:23:24:23:28 | | |
|
||||
|
||||
@@ -1,9 +1,60 @@
|
||||
| intList.kt:3:14:3:31 | listOf(...) | 0 | intList.kt:3:21:3:30 | ... |
|
||||
| test.kt:12:14:12:31 | listOf(...) | 0 | test.kt:12:21:12:30 | ... |
|
||||
| test.kt:13:5:13:34 | funWithOnlyVarArgs(...) | 0 | test.kt:13:24:13:33 | ... |
|
||||
| test.kt:14:5:14:50 | funWithArgsAndVarArgs(...) | 0 | test.kt:14:28:14:30 | foo |
|
||||
| test.kt:14:5:14:50 | funWithArgsAndVarArgs(...) | 1 | test.kt:14:34:14:37 | true |
|
||||
| test.kt:14:5:14:50 | funWithArgsAndVarArgs(...) | 2 | test.kt:14:40:14:49 | ... |
|
||||
| test.kt:15:5:15:53 | funWithMiddleVarArgs(...) | 0 | test.kt:15:27:15:29 | foo |
|
||||
| test.kt:15:5:15:53 | funWithMiddleVarArgs(...) | 1 | test.kt:15:33:15:42 | ... |
|
||||
| test.kt:15:5:15:53 | funWithMiddleVarArgs(...) | 2 | test.kt:15:49:15:52 | true |
|
||||
varargsParams
|
||||
| test.kt:6:24:6:37 | xs | file://:0:0:0:0 | int[] |
|
||||
| test.kt:10:50:10:63 | xs | file://:0:0:0:0 | int[] |
|
||||
| test.kt:14:37:14:50 | xs | file://:0:0:0:0 | int[] |
|
||||
explicitVarargsArguments
|
||||
| test.kt:24:25:24:29 | array | test.kt:24:5:24:30 | funWithOnlyVarArgs(...) |
|
||||
| test.kt:25:41:25:45 | array | test.kt:25:5:25:46 | funWithArgsAndVarArgs(...) |
|
||||
| test.kt:26:34:26:38 | array | test.kt:26:5:26:49 | funWithMiddleVarArgs(...) |
|
||||
implicitVarargsArguments
|
||||
| intList.kt:3:21:3:22 | 10 | intList.kt:3:14:3:31 | listOf(...) | 0 |
|
||||
| intList.kt:3:25:3:26 | 11 | intList.kt:3:14:3:31 | listOf(...) | 1 |
|
||||
| intList.kt:3:29:3:30 | 12 | intList.kt:3:14:3:31 | listOf(...) | 2 |
|
||||
| test.kt:19:21:19:22 | 10 | test.kt:19:14:19:31 | listOf(...) | 0 |
|
||||
| test.kt:19:25:19:26 | 11 | test.kt:19:14:19:31 | listOf(...) | 1 |
|
||||
| test.kt:19:29:19:30 | 12 | test.kt:19:14:19:31 | listOf(...) | 2 |
|
||||
| test.kt:21:24:21:25 | 20 | test.kt:21:5:21:34 | funWithOnlyVarArgs(...) | 0 |
|
||||
| test.kt:21:28:21:29 | 21 | test.kt:21:5:21:34 | funWithOnlyVarArgs(...) | 1 |
|
||||
| test.kt:21:32:21:33 | 22 | test.kt:21:5:21:34 | funWithOnlyVarArgs(...) | 2 |
|
||||
| test.kt:22:40:22:41 | 30 | test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 0 |
|
||||
| test.kt:22:44:22:45 | 31 | test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 1 |
|
||||
| test.kt:22:48:22:49 | 32 | test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 2 |
|
||||
| test.kt:23:33:23:34 | 41 | test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 0 |
|
||||
| test.kt:23:37:23:38 | 42 | test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 1 |
|
||||
| test.kt:23:41:23:42 | 43 | test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 2 |
|
||||
#select
|
||||
| intList.kt:3:14:3:31 | listOf(...) | 0 | intList.kt:3:21:3:22 | 10 |
|
||||
| intList.kt:3:14:3:31 | listOf(...) | 1 | intList.kt:3:25:3:26 | 11 |
|
||||
| intList.kt:3:14:3:31 | listOf(...) | 2 | intList.kt:3:29:3:30 | 12 |
|
||||
| test.kt:7:5:7:19 | sink(...) | 0 | test.kt:7:10:7:18 | get(...) |
|
||||
| test.kt:7:10:7:18 | get(...) | 0 | test.kt:7:13:7:17 | get(...) |
|
||||
| test.kt:7:13:7:17 | get(...) | 0 | test.kt:7:16:7:16 | 0 |
|
||||
| test.kt:11:5:11:19 | sink(...) | 0 | test.kt:11:10:11:18 | get(...) |
|
||||
| test.kt:11:10:11:18 | get(...) | 0 | test.kt:11:13:11:17 | get(...) |
|
||||
| test.kt:11:13:11:17 | get(...) | 0 | test.kt:11:16:11:16 | 0 |
|
||||
| test.kt:15:5:15:19 | sink(...) | 0 | test.kt:15:10:15:18 | get(...) |
|
||||
| test.kt:15:10:15:18 | get(...) | 0 | test.kt:15:13:15:17 | get(...) |
|
||||
| test.kt:15:13:15:17 | get(...) | 0 | test.kt:15:16:15:16 | 0 |
|
||||
| test.kt:19:14:19:31 | listOf(...) | 0 | test.kt:19:21:19:22 | 10 |
|
||||
| test.kt:19:14:19:31 | listOf(...) | 1 | test.kt:19:25:19:26 | 11 |
|
||||
| test.kt:19:14:19:31 | listOf(...) | 2 | test.kt:19:29:19:30 | 12 |
|
||||
| test.kt:21:5:21:34 | funWithOnlyVarArgs(...) | 0 | test.kt:21:24:21:25 | 20 |
|
||||
| test.kt:21:5:21:34 | funWithOnlyVarArgs(...) | 1 | test.kt:21:28:21:29 | 21 |
|
||||
| test.kt:21:5:21:34 | funWithOnlyVarArgs(...) | 2 | test.kt:21:32:21:33 | 22 |
|
||||
| test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 0 | test.kt:22:28:22:30 | foo |
|
||||
| test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 1 | test.kt:22:34:22:37 | true |
|
||||
| test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 2 | test.kt:22:40:22:41 | 30 |
|
||||
| test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 3 | test.kt:22:44:22:45 | 31 |
|
||||
| test.kt:22:5:22:50 | funWithArgsAndVarArgs(...) | 4 | test.kt:22:48:22:49 | 32 |
|
||||
| test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 0 | test.kt:23:27:23:29 | foo |
|
||||
| test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 1 | test.kt:23:33:23:34 | 41 |
|
||||
| test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 2 | test.kt:23:37:23:38 | 42 |
|
||||
| test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 3 | test.kt:23:41:23:42 | 43 |
|
||||
| test.kt:23:5:23:53 | funWithMiddleVarArgs(...) | 4 | test.kt:23:49:23:52 | true |
|
||||
| test.kt:24:5:24:30 | funWithOnlyVarArgs(...) | 0 | test.kt:24:25:24:29 | array |
|
||||
| test.kt:25:5:25:46 | funWithArgsAndVarArgs(...) | 0 | test.kt:25:28:25:30 | foo |
|
||||
| test.kt:25:5:25:46 | funWithArgsAndVarArgs(...) | 1 | test.kt:25:34:25:37 | true |
|
||||
| test.kt:25:5:25:46 | funWithArgsAndVarArgs(...) | 2 | test.kt:25:41:25:45 | array |
|
||||
| test.kt:26:5:26:49 | funWithMiddleVarArgs(...) | 0 | test.kt:26:27:26:29 | foo |
|
||||
| test.kt:26:5:26:49 | funWithMiddleVarArgs(...) | 1 | test.kt:26:34:26:38 | array |
|
||||
| test.kt:26:5:26:49 | funWithMiddleVarArgs(...) | 2 | test.kt:26:45:26:48 | true |
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
import java
|
||||
|
||||
query predicate varargsParams(Parameter p, Type t) {
|
||||
p.getCallable().fromSource() and
|
||||
p.isVarargs() and
|
||||
t = p.getType()
|
||||
}
|
||||
|
||||
query predicate explicitVarargsArguments(Argument a, Call c) {
|
||||
a.isExplicitVarargsArray() and
|
||||
a.getCall() = c
|
||||
}
|
||||
|
||||
query predicate implicitVarargsArguments(Argument a, Call c, int pos) {
|
||||
a.isNthVararg(pos) and
|
||||
a.getCall() = c
|
||||
}
|
||||
|
||||
from Call c, int i
|
||||
select c, i, c.getArgument(i)
|
||||
|
||||
18
java/ql/test/kotlin/library-tests/vararg/dataflow.ql
Normal file
18
java/ql/test/kotlin/library-tests/vararg/dataflow.ql
Normal file
@@ -0,0 +1,18 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "varargs-dataflow-test" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n.asExpr().(CompileTimeConstantExpr).getEnclosingCallable().fromSource()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
n.asExpr() = any(MethodAccess ma | ma.getMethod().getName() = "sink").getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Node source, DataFlow::Node sink, Config c
|
||||
where c.hasFlow(source, sink)
|
||||
select source, sink
|
||||
@@ -1,17 +1,27 @@
|
||||
|
||||
fun sink(sunk: Int) {
|
||||
|
||||
}
|
||||
|
||||
fun funWithOnlyVarArgs(vararg xs: Int) {
|
||||
sink(xs[xs[0]])
|
||||
}
|
||||
|
||||
fun funWithArgsAndVarArgs(x: String, y: Boolean, vararg xs: Int) {
|
||||
sink(xs[xs[0]])
|
||||
}
|
||||
|
||||
fun funWithMiddleVarArgs(x: String, vararg xs: Int, y: Boolean) {
|
||||
sink(xs[xs[0]])
|
||||
}
|
||||
|
||||
fun myFun() {
|
||||
val xs = listOf(10, 11, 12)
|
||||
val array = intArrayOf(100, 101, 102)
|
||||
funWithOnlyVarArgs(20, 21, 22)
|
||||
funWithArgsAndVarArgs("foo", true, 30, 31, 32)
|
||||
funWithMiddleVarArgs("foo", 41, 42, 43, y = true)
|
||||
funWithOnlyVarArgs(*array)
|
||||
funWithArgsAndVarArgs("foo", true, *array)
|
||||
funWithMiddleVarArgs("foo", *array, y = true)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
| intList.kt:3:21:3:30 | ... | 0 | intList.kt:3:21:3:22 | 10 |
|
||||
| intList.kt:3:21:3:30 | ... | 1 | intList.kt:3:25:3:26 | 11 |
|
||||
| intList.kt:3:21:3:30 | ... | 2 | intList.kt:3:29:3:30 | 12 |
|
||||
| test.kt:12:21:12:30 | ... | 0 | test.kt:12:21:12:22 | 10 |
|
||||
| test.kt:12:21:12:30 | ... | 1 | test.kt:12:25:12:26 | 11 |
|
||||
| test.kt:12:21:12:30 | ... | 2 | test.kt:12:29:12:30 | 12 |
|
||||
| test.kt:13:24:13:33 | ... | 0 | test.kt:13:24:13:25 | 20 |
|
||||
| test.kt:13:24:13:33 | ... | 1 | test.kt:13:28:13:29 | 21 |
|
||||
| test.kt:13:24:13:33 | ... | 2 | test.kt:13:32:13:33 | 22 |
|
||||
| test.kt:14:40:14:49 | ... | 0 | test.kt:14:40:14:41 | 30 |
|
||||
| test.kt:14:40:14:49 | ... | 1 | test.kt:14:44:14:45 | 31 |
|
||||
| test.kt:14:40:14:49 | ... | 2 | test.kt:14:48:14:49 | 32 |
|
||||
| test.kt:15:33:15:42 | ... | 0 | test.kt:15:33:15:34 | 41 |
|
||||
| test.kt:15:33:15:42 | ... | 1 | test.kt:15:37:15:38 | 42 |
|
||||
| test.kt:15:33:15:42 | ... | 2 | test.kt:15:41:15:42 | 43 |
|
||||
@@ -1,4 +0,0 @@
|
||||
import java
|
||||
|
||||
from VarArgExpr vae, int i
|
||||
select vae, i, vae.getComponent(i)
|
||||
Reference in New Issue
Block a user