Skip to content

Commit 8523d21

Browse files
authored
Merge pull request github#10696 from tamasvajk/kotlin-lateinit
Kotlin: Extract `lateinit` modifier
2 parents e9835ec + 0bbc7ad commit 8523d21

File tree

10 files changed

+163
-3
lines changed

10 files changed

+163
-3
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,10 @@ open class KotlinFileExtractor(
12511251
}
12521252

12531253
extractVisibility(p, id, p.visibility)
1254+
1255+
if (p.isLateinit) {
1256+
addModifiers(id, "lateinit")
1257+
}
12541258
}
12551259
}
12561260
}
@@ -1406,6 +1410,9 @@ open class KotlinFileExtractor(
14061410
if (!v.isVar) {
14071411
addModifiers(varId, "final")
14081412
}
1413+
if (v.isLateinit) {
1414+
addModifiers(varId, "lateinit")
1415+
}
14091416
}
14101417
}
14111418

java/ql/lib/semmle/code/java/Modifier.qll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ abstract class Modifiable extends Element {
6767
/** Holds if this element has an `inline` modifier. */
6868
predicate isInline() { this.hasModifier("inline") }
6969

70-
/** Holds if this element has an `noinline` modifier. */
70+
/** Holds if this element has a `noinline` modifier. */
7171
predicate isNoinline() { this.hasModifier("noinline") }
7272

73-
/** Holds if this element has an `crossinline` modifier. */
73+
/** Holds if this element has a `crossinline` modifier. */
7474
predicate isCrossinline() { this.hasModifier("crossinline") }
7575

7676
/** Holds if this element has a `suspend` modifier. */
@@ -93,4 +93,7 @@ abstract class Modifiable extends Element {
9393

9494
/** Holds if this element has a `strictfp` modifier. */
9595
predicate isStrictfp() { this.hasModifier("strictfp") }
96+
97+
/** Holds if this element has a `lateinit` modifier. */
98+
predicate isLateinit() { this.hasModifier("lateinit") }
9699
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
test.kt:
2+
# 0| [CompilationUnit] test
3+
# 1| 1: [Class] LateInit
4+
# 1| 1: [Constructor] LateInit
5+
# 1| 5: [BlockStmt] { ... }
6+
# 1| 0: [SuperConstructorInvocationStmt] super(...)
7+
# 1| 1: [BlockStmt] { ... }
8+
# 2| 2: [FieldDeclaration] LateInit test0;
9+
# 2| -1: [TypeAccess] LateInit
10+
# 2| 3: [Method] getTest0$private
11+
# 2| 3: [TypeAccess] LateInit
12+
# 2| 5: [BlockStmt] { ... }
13+
# 2| 0: [ReturnStmt] return ...
14+
# 2| 0: [VarAccess] this.test0
15+
# 2| -1: [ThisAccess] this
16+
# 2| 4: [Method] setTest0$private
17+
# 2| 3: [TypeAccess] Unit
18+
#-----| 4: (Parameters)
19+
# 2| 0: [Parameter] <set-?>
20+
# 2| 0: [TypeAccess] LateInit
21+
# 2| 5: [BlockStmt] { ... }
22+
# 2| 0: [ExprStmt] <Expr>;
23+
# 2| 0: [AssignExpr] ...=...
24+
# 2| 0: [VarAccess] this.test0
25+
# 2| -1: [ThisAccess] this
26+
# 2| 1: [VarAccess] <set-?>
27+
# 4| 5: [Method] f
28+
# 4| 3: [TypeAccess] Unit
29+
# 4| 5: [BlockStmt] { ... }
30+
# 4| 0: [ReturnStmt] return ...
31+
# 4| 0: [MethodAccess] println(...)
32+
# 4| -1: [TypeAccess] ConsoleKt
33+
# 4| 0: [StringLiteral] a
34+
# 6| 6: [Method] init
35+
# 6| 3: [TypeAccess] LateInit
36+
# 6| 5: [BlockStmt] { ... }
37+
# 6| 0: [ReturnStmt] return ...
38+
# 6| 0: [ClassInstanceExpr] new LateInit(...)
39+
# 6| -3: [TypeAccess] LateInit
40+
# 8| 7: [Method] fn
41+
# 8| 3: [TypeAccess] Unit
42+
# 8| 5: [BlockStmt] { ... }
43+
# 9| 0: [ExprStmt] <Expr>;
44+
# 9| 0: [MethodAccess] f(...)
45+
# 9| -1: [MethodAccess] getTest0$private(...)
46+
# 9| -1: [ThisAccess] this
47+
# 10| 1: [ExprStmt] <Expr>;
48+
# 10| 0: [WhenExpr] when ...
49+
# 10| 0: [WhenBranch] ... -> ...
50+
# 10| 0: [MethodAccess] isInitialized(...)
51+
# 10| -1: [TypeAccess] LateinitKt
52+
# 10| 0: [PropertyRefExpr] ...::...
53+
# 10| -4: [AnonymousClass] new KMutableProperty0<LateInit>(...) { ... }
54+
# 10| 1: [Constructor]
55+
#-----| 4: (Parameters)
56+
# 10| 0: [Parameter] <dispatchReceiver>
57+
# 10| 5: [BlockStmt] { ... }
58+
# 10| 0: [SuperConstructorInvocationStmt] super(...)
59+
# 10| 1: [ExprStmt] <Expr>;
60+
# 10| 0: [AssignExpr] ...=...
61+
# 10| 0: [VarAccess] this.<dispatchReceiver>
62+
# 10| -1: [ThisAccess] this
63+
# 10| 1: [VarAccess] <dispatchReceiver>
64+
# 10| 2: [FieldDeclaration] LateInit <dispatchReceiver>;
65+
# 10| -1: [TypeAccess] LateInit
66+
# 10| 3: [Method] get
67+
# 10| 5: [BlockStmt] { ... }
68+
# 10| 0: [ReturnStmt] return ...
69+
# 10| 0: [MethodAccess] getTest0$private(...)
70+
# 10| -1: [VarAccess] this.<dispatchReceiver>
71+
# 10| -1: [ThisAccess] this
72+
# 10| 4: [Method] invoke
73+
# 10| 5: [BlockStmt] { ... }
74+
# 10| 0: [ReturnStmt] return ...
75+
# 10| 0: [MethodAccess] get(...)
76+
# 10| -1: [ThisAccess] this
77+
# 10| 5: [Method] set
78+
#-----| 4: (Parameters)
79+
# 10| 0: [Parameter] a0
80+
# 10| 5: [BlockStmt] { ... }
81+
# 10| 0: [ReturnStmt] return ...
82+
# 10| 0: [MethodAccess] setTest0$private(...)
83+
# 10| -1: [VarAccess] this.<dispatchReceiver>
84+
# 10| -1: [ThisAccess] this
85+
# 10| 0: [VarAccess] a0
86+
# 10| -3: [TypeAccess] KMutableProperty0<LateInit>
87+
# 10| 0: [TypeAccess] LateInit
88+
# 10| 0: [ThisAccess] this
89+
# 10| 1: [BlockStmt] { ... }
90+
# 13| 2: [LocalVariableDeclStmt] var ...;
91+
# 13| 1: [LocalVariableDeclExpr] test1
92+
# 14| 3: [ExprStmt] <Expr>;
93+
# 14| 0: [MethodAccess] f(...)
94+
# 14| -1: [VarAccess] test1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle/code/java/PrintAst.ql
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| test.kt:4:15:4:26 | println(...) | file://<external>/ConsoleKt.class:0:0:0:0 | println |
2+
| test.kt:9:9:9:13 | getTest0$private(...) | test.kt:2:22:2:40 | getTest0$private |
3+
| test.kt:9:15:9:17 | f(...) | test.kt:4:5:4:26 | f |
4+
| test.kt:10:13:10:23 | get(...) | test.kt:10:13:10:23 | get |
5+
| test.kt:10:13:10:23 | getTest0$private(...) | test.kt:2:22:2:40 | getTest0$private |
6+
| test.kt:10:13:10:23 | setTest0$private(...) | test.kt:2:22:2:40 | setTest0$private |
7+
| test.kt:10:25:10:37 | isInitialized(...) | file://<external>/LateinitKt.class:0:0:0:0 | isInitialized |
8+
| test.kt:14:15:14:17 | f(...) | test.kt:4:5:4:26 | f |
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
public class LateInit {
2+
private lateinit var test0: LateInit
3+
4+
fun f() = println("a")
5+
6+
fun init() = LateInit()
7+
8+
fun fn() {
9+
test0.f() // This is preceded by a null-check and a throw in bytecode, in IR it's a simple call
10+
if (this::test0.isInitialized) { // This is converted to a null-check in bytecode, in IR it's a call to `LateinitKt.isInitialized`
11+
}
12+
13+
lateinit var test1: LateInit
14+
test1.f() // This is replaced by `Intrinsics.throwUninitializedPropertyAccessException` in bytecode, in IR it's a simple call
15+
}
16+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import java
2+
3+
class MethodLocation extends Method {
4+
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
5+
exists(string fullPath | super.hasLocationInfo(fullPath, sl, sc, el, ec) |
6+
if exists(this.getFile().getRelativePath())
7+
then path = fullPath
8+
else path = fullPath.regexpReplaceAll(".*/", "<external>/")
9+
)
10+
}
11+
}
12+
13+
query predicate calls(MethodAccess ma, Method m) { ma.getMethod() = m }

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,13 @@
4545
| modifiers.kt:27:12:27:49 | fn5 | Method | inline |
4646
| modifiers.kt:27:12:27:49 | fn5 | Method | public |
4747
| modifiers.kt:27:20:27:44 | f | Parameter | crossinline |
48+
| modifiers.kt:30:1:36:1 | LateInit | Class | final |
49+
| modifiers.kt:30:1:36:1 | LateInit | Class | public |
50+
| modifiers.kt:30:8:36:1 | LateInit | Constructor | public |
51+
| modifiers.kt:31:5:31:40 | test0 | Field | private |
52+
| modifiers.kt:31:5:31:40 | test0 | Property | lateinit |
53+
| modifiers.kt:31:5:31:40 | test0 | Property | private |
54+
| modifiers.kt:31:22:31:40 | getTest0$private | Method | private |
55+
| modifiers.kt:31:22:31:40 | setTest0$private | Method | private |
56+
| modifiers.kt:33:5:35:5 | fn | Method | public |
57+
| modifiers.kt:34:9:34:36 | LateInit test1 | LocalVariableDecl | lateinit |

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,11 @@ open class X {
2626
inline fun fn4(noinline f: () -> Unit) { }
2727
inline fun fn5(crossinline f: () -> Unit) { }
2828
}
29+
30+
public class LateInit {
31+
private lateinit var test0: LateInit
32+
33+
fun fn() {
34+
lateinit var test1: LateInit
35+
}
36+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fieldDeclarations
4141
| properties.kt:28:5:29:22 | overrideGetter | properties.kt:29:13:29:22 | getOverrideGetter | properties.kt:28:5:29:22 | setOverrideGetter | properties.kt:28:5:29:22 | overrideGetter | public |
4242
| properties.kt:30:5:31:29 | overrideGetterUseField | properties.kt:31:13:31:29 | getOverrideGetterUseField | properties.kt:30:5:31:29 | setOverrideGetterUseField | properties.kt:30:5:31:29 | overrideGetterUseField | public |
4343
| properties.kt:32:5:33:29 | useField | properties.kt:33:13:33:29 | getUseField | file://:0:0:0:0 | <none> | properties.kt:32:5:33:29 | useField | public |
44-
| properties.kt:34:5:34:36 | lateInitVar | properties.kt:34:14:34:36 | getLateInitVar | properties.kt:34:14:34:36 | setLateInitVar | properties.kt:34:5:34:36 | lateInitVar | public |
44+
| properties.kt:34:5:34:36 | lateInitVar | properties.kt:34:14:34:36 | getLateInitVar | properties.kt:34:14:34:36 | setLateInitVar | properties.kt:34:5:34:36 | lateInitVar | lateinit, public |
4545
| properties.kt:35:5:35:32 | privateProp | properties.kt:35:13:35:32 | getPrivateProp$private | file://:0:0:0:0 | <none> | properties.kt:35:5:35:32 | privateProp | private |
4646
| properties.kt:36:5:36:36 | protectedProp | properties.kt:36:15:36:36 | getProtectedProp | file://:0:0:0:0 | <none> | properties.kt:36:5:36:36 | protectedProp | protected |
4747
| properties.kt:37:5:37:30 | publicProp | properties.kt:37:12:37:30 | getPublicProp | file://:0:0:0:0 | <none> | properties.kt:37:5:37:30 | publicProp | public |

0 commit comments

Comments
 (0)