Skip to content

Commit 07c2f6e

Browse files
authored
Merge pull request github#9155 from smowton/smowton/fix/field-initializer-flow
Kotlin: Fix initializer field flow by extracting field finality
2 parents eacb9f1 + 305ddb2 commit 07c2f6e

File tree

6 files changed

+54
-5
lines changed

6 files changed

+54
-5
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -778,19 +778,22 @@ open class KotlinFileExtractor(
778778
with("field", f) {
779779
DeclarationStackAdjuster(f).use {
780780
declarationStack.push(f)
781-
return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f))
781+
return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
782782
}
783783
}
784784
}
785785

786786

787-
private fun extractField(id: Label<out DbField>, name: String, type: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean): Label<out DbField> {
787+
private fun extractField(id: Label<out DbField>, name: String, type: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean, isFinal: Boolean): Label<out DbField> {
788788
val t = useType(type)
789789
tw.writeFields(id, name, t.javaResult.id, parentId, id)
790790
tw.writeFieldsKotlinType(id, t.kotlinResult.id)
791791
tw.writeHasLocation(id, locId)
792792

793793
extractVisibility(errorElement, id, visibility)
794+
if (isFinal) {
795+
addModifiers(id, "final")
796+
}
794797

795798
if (!isExternalDeclaration) {
796799
val fieldDeclarationId = tw.getFreshIdLabel<DbFielddecl>()
@@ -2949,12 +2952,12 @@ open class KotlinFileExtractor(
29492952

29502953
// only one of the following can be non-null:
29512954
if (dispatchReceiver != null) {
2952-
extractField(dispatchFieldId!!, "<dispatchReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, false)
2955+
extractField(dispatchFieldId!!, "<dispatchReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true)
29532956
extractParameterToFieldAssignmentInConstructor("<dispatchReceiver>", dispatchReceiver.type, dispatchFieldId, 0, firstAssignmentStmtIdx)
29542957
}
29552958

29562959
if (extensionReceiver != null) {
2957-
extractField(extensionFieldId!!, "<extensionReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, false)
2960+
extractField(extensionFieldId!!, "<extensionReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true)
29582961
extractParameterToFieldAssignmentInConstructor( "<extensionReceiver>", extensionReceiver.type, extensionFieldId, 0 + extensionParameterIndex, firstAssignmentStmtIdx + extensionParameterIndex)
29592962
}
29602963
}
@@ -4005,7 +4008,7 @@ open class KotlinFileExtractor(
40054008

40064009
// add field
40074010
val fieldId = tw.getFreshIdLabel<DbField>()
4008-
extractField(fieldId, "<fn>", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, false)
4011+
extractField(fieldId, "<fn>", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, isExternalDeclaration = false, isFinal = true)
40094012

40104013
// adjust constructor
40114014
helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
isFinalField
2+
| test.kt:3:3:3:18 | x |
3+
#select
4+
| test.kt:3:3:3:18 | this.x | test.kt:6:10:6:10 | getX(...) |
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Test {
2+
3+
val x = "Source"
4+
5+
fun test() {
6+
sink(x)
7+
}
8+
9+
fun sink(s: String) { }
10+
11+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import java
2+
import semmle.code.java.dataflow.DataFlow
3+
4+
class Config extends DataFlow::Configuration {
5+
Config() { this = "Config" }
6+
7+
override predicate isSource(DataFlow::Node n) {
8+
n.asExpr().(CompileTimeConstantExpr).getStringValue() = "Source"
9+
}
10+
11+
override predicate isSink(DataFlow::Node n) {
12+
n.asExpr().(Argument).getCall().getCallee().getName() = "sink"
13+
}
14+
}
15+
16+
query predicate isFinalField(Field f) {
17+
exists(FieldDeclaration f2 | f = f2.getAField()) and f.isFinal()
18+
}
19+
20+
from DataFlow::Node source, DataFlow::Node sink
21+
where any(Config c).hasFlow(source, sink)
22+
select source, sink

java/ql/test/kotlin/library-tests/modifiers/modifiers.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
| modifiers.kt:1:1:25:1 | X | Class | public |
22
| modifiers.kt:1:6:25:1 | X | Constructor | public |
3+
| modifiers.kt:2:5:2:21 | a | Field | final |
34
| modifiers.kt:2:5:2:21 | a | Field | private |
45
| modifiers.kt:2:5:2:21 | a | Property | private |
56
| modifiers.kt:2:13:2:21 | getA$private | Method | private |
7+
| modifiers.kt:3:5:3:23 | b | Field | final |
68
| modifiers.kt:3:5:3:23 | b | Field | private |
79
| modifiers.kt:3:5:3:23 | b | Property | protected |
810
| modifiers.kt:3:15:3:23 | getB | Method | protected |
11+
| modifiers.kt:4:5:4:22 | c | Field | final |
912
| modifiers.kt:4:5:4:22 | c | Field | private |
1013
| modifiers.kt:4:5:4:22 | c | Property | internal |
1114
| modifiers.kt:4:14:4:22 | getC | Method | internal |
15+
| modifiers.kt:5:5:5:34 | d | Field | final |
1216
| modifiers.kt:5:5:5:34 | d | Field | private |
1317
| modifiers.kt:5:5:5:34 | d | Property | public |
1418
| modifiers.kt:5:5:5:34 | getD | Method | public |
1519
| modifiers.kt:7:5:9:5 | Nested | Class | final |
1620
| modifiers.kt:7:5:9:5 | Nested | Class | protected |
1721
| modifiers.kt:7:15:9:5 | Nested | Constructor | public |
22+
| modifiers.kt:8:9:8:29 | e | Field | final |
1823
| modifiers.kt:8:9:8:29 | e | Field | private |
1924
| modifiers.kt:8:9:8:29 | e | Property | public |
2025
| modifiers.kt:8:16:8:29 | getE | Method | public |

java/ql/test/kotlin/library-tests/variables/variables.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ isFinal
33
| variables.kt:8:9:8:26 | int local2 | non-final |
44
| variables.kt:10:9:10:26 | int local3 | final |
55
compileTimeConstant
6+
| variables.kt:3:5:3:21 | prop |
7+
| variables.kt:3:5:3:21 | this.prop |
68
| variables.kt:7:17:7:22 | local1 |
9+
| variables.kt:15:1:15:21 | VariablesKt.topLevel |
10+
| variables.kt:15:1:15:21 | VariablesKt.topLevel |
711
#select
812
| variables.kt:3:5:3:21 | prop | int | variables.kt:3:21:3:21 | 1 |
913
| variables.kt:5:20:5:29 | param | int | file://:0:0:0:0 | <none> |

0 commit comments

Comments
 (0)