Skip to content

Commit 7015661

Browse files
Kotlin: cover companion blocks and extensions
Add focused coverage for a companion-block function and companion extension function and property. Check declaration ownership, property accessors, resolved calls, and data flow. The existing extractor handles the lowered declarations and calls correctly. This commit adds coverage only and requires no extractor change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8595a36 commit 7015661

4 files changed

Lines changed: 76 additions & 0 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
declarations
2+
| test.kt:5:9:5:29 | empty | test.kt:3:1:7:1 | Box | Method | empty() |
3+
| test.kt:9:11:9:52 | create | test.kt:0:0:0:0 | TestKt | Method | create(java.lang.String) |
4+
| test.kt:12:5:12:19 | getDefault | test.kt:0:0:0:0 | TestKt | Method | getDefault() |
5+
calls
6+
| test.kt:19:14:19:29 | create(...) | test.kt:18:1:21:1 | test | test.kt:9:11:9:52 | create | test.kt:19:14:19:29 | TestKt |
7+
| test.kt:20:14:20:20 | getDefault(...) | test.kt:18:1:21:1 | test | test.kt:12:5:12:19 | getDefault | test.kt:20:14:20:20 | TestKt |
8+
properties
9+
| test.kt:11:11:12:19 | default | test.kt:0:0:0:0 | TestKt | test.kt:12:5:12:19 | getDefault |
10+
#select
11+
| test.kt:19:21:19:28 | source(...) | test.kt:19:14:19:35 | getValue(...) |
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// codeql-extractor-kotlin-options: -language-version 2.4 -Xcompanion-blocks-and-extensions
2+
3+
class Box(val value: String) {
4+
companion {
5+
fun empty() = Box("")
6+
}
7+
}
8+
9+
companion fun Box.create(value: String) = Box(value)
10+
11+
companion val Box.default: Box
12+
get() = Box("")
13+
14+
fun source(): String = ""
15+
16+
fun sink(value: String) {}
17+
18+
fun test() {
19+
sink(Box.create(source()).value)
20+
sink(Box.default.value)
21+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import java
2+
import semmle.code.java.dataflow.TaintTracking
3+
4+
predicate isCompanionCallable(Callable callable) {
5+
callable.getName() = ["empty", "create", "getDefault"]
6+
}
7+
8+
query predicate declarations(
9+
Callable callable, RefType declaringType, string primaryClass, string signature
10+
) {
11+
isCompanionCallable(callable) and
12+
callable.fromSource() and
13+
declaringType = callable.getDeclaringType() and
14+
primaryClass = callable.getAPrimaryQlClass() and
15+
signature = callable.getSignature()
16+
}
17+
18+
query predicate calls(MethodCall call, Callable caller, Method target, Expr qualifier) {
19+
caller.fromSource() and
20+
call.getEnclosingCallable() = caller and
21+
target = call.getMethod() and
22+
isCompanionCallable(target) and
23+
qualifier = call.getQualifier()
24+
}
25+
26+
query predicate properties(Property property, RefType declaringType, Method getter) {
27+
property.hasName("default") and
28+
property.fromSource() and
29+
getter = property.getGetter() and
30+
declaringType = getter.getDeclaringType()
31+
}
32+
33+
module Config implements DataFlow::ConfigSig {
34+
predicate isSource(DataFlow::Node n) { n.asExpr().(MethodCall).getMethod().hasName("source") }
35+
36+
predicate isSink(DataFlow::Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
37+
}
38+
39+
module Flow = TaintTracking::Global<Config>;
40+
41+
from DataFlow::Node source, DataFlow::Node sink
42+
where Flow::flow(source, sink)
43+
select source, sink
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test.ql

0 commit comments

Comments
 (0)