diff --git a/java/ql/test/kotlin/library-tests/lateinit/PrintAst.expected b/java/ql/test/kotlin/library-tests/lateinit/PrintAst.expected new file mode 100644 index 00000000000..c2119ec6123 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/lateinit/PrintAst.expected @@ -0,0 +1,94 @@ +test.kt: +# 0| [CompilationUnit] test +# 1| 1: [Class] LateInit +# 1| 1: [Constructor] LateInit +# 1| 5: [BlockStmt] { ... } +# 1| 0: [SuperConstructorInvocationStmt] super(...) +# 1| 1: [BlockStmt] { ... } +# 2| 2: [FieldDeclaration] LateInit test0; +# 2| -1: [TypeAccess] LateInit +# 2| 3: [Method] getTest0$private +# 2| 3: [TypeAccess] LateInit +# 2| 5: [BlockStmt] { ... } +# 2| 0: [ReturnStmt] return ... +# 2| 0: [VarAccess] this.test0 +# 2| -1: [ThisAccess] this +# 2| 4: [Method] setTest0$private +# 2| 3: [TypeAccess] Unit +#-----| 4: (Parameters) +# 2| 0: [Parameter] +# 2| 0: [TypeAccess] LateInit +# 2| 5: [BlockStmt] { ... } +# 2| 0: [ExprStmt] ; +# 2| 0: [AssignExpr] ...=... +# 2| 0: [VarAccess] this.test0 +# 2| -1: [ThisAccess] this +# 2| 1: [VarAccess] +# 4| 5: [Method] f +# 4| 3: [TypeAccess] Unit +# 4| 5: [BlockStmt] { ... } +# 4| 0: [ReturnStmt] return ... +# 4| 0: [MethodAccess] println(...) +# 4| -1: [TypeAccess] ConsoleKt +# 4| 0: [StringLiteral] a +# 6| 6: [Method] init +# 6| 3: [TypeAccess] LateInit +# 6| 5: [BlockStmt] { ... } +# 6| 0: [ReturnStmt] return ... +# 6| 0: [ClassInstanceExpr] new LateInit(...) +# 6| -3: [TypeAccess] LateInit +# 8| 7: [Method] fn +# 8| 3: [TypeAccess] Unit +# 8| 5: [BlockStmt] { ... } +# 9| 0: [ExprStmt] ; +# 9| 0: [MethodAccess] f(...) +# 9| -1: [MethodAccess] getTest0$private(...) +# 9| -1: [ThisAccess] this +# 10| 1: [ExprStmt] ; +# 10| 0: [WhenExpr] when ... +# 10| 0: [WhenBranch] ... -> ... +# 10| 0: [MethodAccess] isInitialized(...) +# 10| -1: [TypeAccess] LateinitKt +# 10| 0: [PropertyRefExpr] ...::... +# 10| -4: [AnonymousClass] new KMutableProperty0(...) { ... } +# 10| 1: [Constructor] +#-----| 4: (Parameters) +# 10| 0: [Parameter] +# 10| 5: [BlockStmt] { ... } +# 10| 0: [SuperConstructorInvocationStmt] super(...) +# 10| 1: [ExprStmt] ; +# 10| 0: [AssignExpr] ...=... +# 10| 0: [VarAccess] this. +# 10| -1: [ThisAccess] this +# 10| 1: [VarAccess] +# 10| 2: [FieldDeclaration] LateInit ; +# 10| -1: [TypeAccess] LateInit +# 10| 3: [Method] get +# 10| 5: [BlockStmt] { ... } +# 10| 0: [ReturnStmt] return ... +# 10| 0: [MethodAccess] getTest0$private(...) +# 10| -1: [VarAccess] this. +# 10| -1: [ThisAccess] this +# 10| 4: [Method] invoke +# 10| 5: [BlockStmt] { ... } +# 10| 0: [ReturnStmt] return ... +# 10| 0: [MethodAccess] get(...) +# 10| -1: [ThisAccess] this +# 10| 5: [Method] set +#-----| 4: (Parameters) +# 10| 0: [Parameter] a0 +# 10| 5: [BlockStmt] { ... } +# 10| 0: [ReturnStmt] return ... +# 10| 0: [MethodAccess] setTest0$private(...) +# 10| -1: [VarAccess] this. +# 10| -1: [ThisAccess] this +# 10| 0: [VarAccess] a0 +# 10| -3: [TypeAccess] KMutableProperty0 +# 10| 0: [TypeAccess] LateInit +# 10| 0: [ThisAccess] this +# 10| 1: [BlockStmt] { ... } +# 13| 2: [LocalVariableDeclStmt] var ...; +# 13| 1: [LocalVariableDeclExpr] test1 +# 14| 3: [ExprStmt] ; +# 14| 0: [MethodAccess] f(...) +# 14| -1: [VarAccess] test1 diff --git a/java/ql/test/kotlin/library-tests/lateinit/PrintAst.qlref b/java/ql/test/kotlin/library-tests/lateinit/PrintAst.qlref new file mode 100644 index 00000000000..c7fd5faf239 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/lateinit/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/java/PrintAst.ql \ No newline at end of file diff --git a/java/ql/test/kotlin/library-tests/lateinit/test.expected b/java/ql/test/kotlin/library-tests/lateinit/test.expected new file mode 100644 index 00000000000..e3761785021 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/lateinit/test.expected @@ -0,0 +1,8 @@ +| test.kt:4:15:4:26 | println(...) | file:///ConsoleKt.class:0:0:0:0 | println | +| test.kt:9:9:9:13 | getTest0$private(...) | test.kt:2:22:2:40 | getTest0$private | +| test.kt:9:15:9:17 | f(...) | test.kt:4:5:4:26 | f | +| test.kt:10:13:10:23 | get(...) | test.kt:10:13:10:23 | get | +| test.kt:10:13:10:23 | getTest0$private(...) | test.kt:2:22:2:40 | getTest0$private | +| test.kt:10:13:10:23 | setTest0$private(...) | test.kt:2:22:2:40 | setTest0$private | +| test.kt:10:25:10:37 | isInitialized(...) | file:///LateinitKt.class:0:0:0:0 | isInitialized | +| test.kt:14:15:14:17 | f(...) | test.kt:4:5:4:26 | f | diff --git a/java/ql/test/kotlin/library-tests/lateinit/test.kt b/java/ql/test/kotlin/library-tests/lateinit/test.kt new file mode 100644 index 00000000000..3312f67511c --- /dev/null +++ b/java/ql/test/kotlin/library-tests/lateinit/test.kt @@ -0,0 +1,16 @@ +public class LateInit { + private lateinit var test0: LateInit + + fun f() = println("a") + + fun init() = LateInit() + + fun fn() { + test0.f() // This is preceded by a null-check and a throw in bytecode, in IR it's a simple call + if (this::test0.isInitialized) { // This is converted to a null-check in bytecode, in IR it's a call to `LateinitKt.isInitialized` + } + + lateinit var test1: LateInit + test1.f() // This is replaced by `Intrinsics.throwUninitializedPropertyAccessException` in bytecode, in IR it's a simple call + } +} diff --git a/java/ql/test/kotlin/library-tests/lateinit/test.ql b/java/ql/test/kotlin/library-tests/lateinit/test.ql new file mode 100644 index 00000000000..5f4a458da95 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/lateinit/test.ql @@ -0,0 +1,13 @@ +import java + +class MethodLocation extends Method { + override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { + exists(string fullPath | super.hasLocationInfo(fullPath, sl, sc, el, ec) | + if exists(this.getFile().getRelativePath()) + then path = fullPath + else path = fullPath.regexpReplaceAll(".*/", "/") + ) + } +} + +query predicate calls(MethodAccess ma, Method m) { ma.getMethod() = m }