mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Kotlin: support argument-range specifications for $default methods
This commit is contained in:
@@ -8,6 +8,9 @@ class LibClass {
|
|||||||
fun memberWithDefaults(x: Int, y: Int = 1) = 0
|
fun memberWithDefaults(x: Int, y: Int = 1) = 0
|
||||||
fun String.extensionMemberWithDefaults(x: Int, y: Int = 1) = 0
|
fun String.extensionMemberWithDefaults(x: Int, y: Int = 1) = 0
|
||||||
|
|
||||||
|
fun multiParameterTest(x: Int, y: Int, z: Int, w: Int = 0) = 0
|
||||||
|
fun Int.multiParameterExtensionTest(x: Int, y: Int, w: Int = 0) = 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SomeToken {}
|
class SomeToken {}
|
||||||
@@ -30,4 +33,3 @@ class SinkClass(x: Int, y: Int = 1) {
|
|||||||
fun String.extensionMemberSink(x: Int, y: Int = 1) {}
|
fun String.extensionMemberSink(x: Int, y: Int = 1) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ private class Models extends SummaryModelCsv {
|
|||||||
";LibKt;true;topLevelWithDefaults;(int,int);;Argument[0];ReturnValue;value;manual",
|
";LibKt;true;topLevelWithDefaults;(int,int);;Argument[0];ReturnValue;value;manual",
|
||||||
";LibKt;true;extensionWithDefaults;(String,int,int);;Argument[1];ReturnValue;value;manual",
|
";LibKt;true;extensionWithDefaults;(String,int,int);;Argument[1];ReturnValue;value;manual",
|
||||||
";LibClass;true;memberWithDefaults;(int,int);;Argument[0];ReturnValue;value;manual",
|
";LibClass;true;memberWithDefaults;(int,int);;Argument[0];ReturnValue;value;manual",
|
||||||
";LibClass;true;extensionMemberWithDefaults;(String,int,int);;Argument[1];ReturnValue;value;manual"
|
";LibClass;true;extensionMemberWithDefaults;(String,int,int);;Argument[1];ReturnValue;value;manual",
|
||||||
|
";LibClass;true;multiParameterTest;(int,int,int,int);;Argument[0..1];ReturnValue;value;manual",
|
||||||
|
";LibClass;true;multiParameterExtensionTest;(int,int,int,int);;Argument[0, 1];ReturnValue;value;manual",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,20 @@ fun test(c: LibClass, sourcec: SourceClass, sinkc: SinkClass) {
|
|||||||
sink(c.memberWithDefaults(source(), 0)) // $ flow
|
sink(c.memberWithDefaults(source(), 0)) // $ flow
|
||||||
sink(c.memberWithDefaults(source())) // $ flow
|
sink(c.memberWithDefaults(source())) // $ flow
|
||||||
|
|
||||||
|
sink(c.multiParameterTest(source(), 0, 0)) // $ flow
|
||||||
|
sink(c.multiParameterTest(0, source(), 0)) // $ flow
|
||||||
|
sink(c.multiParameterTest(0, 0, source()))
|
||||||
|
|
||||||
with(c) {
|
with(c) {
|
||||||
sink("Hello world".extensionMemberWithDefaults(source(), 0)) // $ flow
|
sink("Hello world".extensionMemberWithDefaults(source(), 0)) // $ flow
|
||||||
sink("Hello world".extensionMemberWithDefaults(source())) // $ flow
|
sink("Hello world".extensionMemberWithDefaults(source())) // $ flow
|
||||||
};
|
}
|
||||||
|
|
||||||
|
with(c) {
|
||||||
|
sink(source().multiParameterExtensionTest(0, 0)) // $ flow
|
||||||
|
sink(0.multiParameterExtensionTest(source(), 0)) // $ flow
|
||||||
|
sink(0.multiParameterExtensionTest(0, source()))
|
||||||
|
}
|
||||||
|
|
||||||
run {
|
run {
|
||||||
val st = SomeToken()
|
val st = SomeToken()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ private import FlowSummaryImpl::Private
|
|||||||
private import FlowSummaryImpl::Public
|
private import FlowSummaryImpl::Public
|
||||||
private import semmle.code.java.dataflow.ExternalFlow
|
private import semmle.code.java.dataflow.ExternalFlow
|
||||||
private import semmle.code.java.dataflow.FlowSummary as FlowSummary
|
private import semmle.code.java.dataflow.FlowSummary as FlowSummary
|
||||||
|
private import semmle.code.java.dataflow.internal.AccessPathSyntax as AccessPathSyntax
|
||||||
|
|
||||||
class SummarizedCallableBase = FlowSummary::SummarizedCallableBase;
|
class SummarizedCallableBase = FlowSummary::SummarizedCallableBase;
|
||||||
|
|
||||||
@@ -84,6 +85,9 @@ private predicate relatedArgSpec(Callable c, string spec) {
|
|||||||
* for the additional dispatch receiver parameter that occurs in the default-parameter proxy's argument
|
* for the additional dispatch receiver parameter that occurs in the default-parameter proxy's argument
|
||||||
* list. When no adjustment is required (e.g. for constructors, or non-argument-based specs), `defaultArgsSpec`
|
* list. When no adjustment is required (e.g. for constructors, or non-argument-based specs), `defaultArgsSpec`
|
||||||
* equals `originalArgSpec`.
|
* equals `originalArgSpec`.
|
||||||
|
*
|
||||||
|
* Note in the case where `originalArgSpec` uses an integer range, like `Argument[1..3]...`, this will produce multiple
|
||||||
|
* results for `defaultsArgSpec`, like `{Argument[2]..., Argument[3]..., Argument[4]...}`.
|
||||||
*/
|
*/
|
||||||
private predicate correspondingKotlinParameterDefaultsArgSpec(
|
private predicate correspondingKotlinParameterDefaultsArgSpec(
|
||||||
Callable originalCallable, Callable defaultsCallable, string originalArgSpec,
|
Callable originalCallable, Callable defaultsCallable, string originalArgSpec,
|
||||||
@@ -98,19 +102,21 @@ private predicate correspondingKotlinParameterDefaultsArgSpec(
|
|||||||
exists(string regex |
|
exists(string regex |
|
||||||
// Note I use a regex and not AccessPathToken because this feeds summaryElement et al,
|
// Note I use a regex and not AccessPathToken because this feeds summaryElement et al,
|
||||||
// which would introduce mutual recursion with the definition of AccessPathToken.
|
// which would introduce mutual recursion with the definition of AccessPathToken.
|
||||||
regex = "Argument\\[([0-9]+)\\](.*)" and
|
regex = "Argument\\[([0-9,\\. ]+)\\](.*)" and
|
||||||
(
|
(
|
||||||
exists(string oldArgNumber, string rest, int paramOffset |
|
exists(string oldArgNumber, string rest, int paramOffset |
|
||||||
oldArgNumber = originalArgSpec.regexpCapture(regex, 1) and
|
oldArgNumber = originalArgSpec.regexpCapture(regex, 1) and
|
||||||
rest = originalArgSpec.regexpCapture(regex, 2) and
|
rest = originalArgSpec.regexpCapture(regex, 2) and
|
||||||
paramOffset =
|
paramOffset =
|
||||||
(
|
defaultsCallable.getNumberOfParameters() -
|
||||||
defaultsCallable.getNumberOfParameters() -
|
(originalCallable.getNumberOfParameters() + 2) and
|
||||||
(originalCallable.getNumberOfParameters() + 2)
|
exists(int oldArgParsed |
|
||||||
) and
|
oldArgParsed = AccessPathSyntax::AccessPath::parseInt(oldArgNumber.splitAt(",").trim())
|
||||||
if ktExtensionFunctions(originalCallable, _, _) and oldArgNumber = "0"
|
|
|
||||||
then defaultsArgSpec = originalArgSpec
|
if ktExtensionFunctions(originalCallable, _, _) and oldArgParsed = 0
|
||||||
else defaultsArgSpec = "Argument[" + (oldArgNumber.toInt() + paramOffset) + "]" + rest
|
then defaultsArgSpec = "Argument[0]"
|
||||||
|
else defaultsArgSpec = "Argument[" + (oldArgParsed + paramOffset) + "]" + rest
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
not originalArgSpec.regexpMatch(regex) and
|
not originalArgSpec.regexpMatch(regex) and
|
||||||
|
|||||||
Reference in New Issue
Block a user