Skip to content

Commit 47762cf

Browse files
nbirilloisomethaneelena-lyulina
authored
Add IR supporting (#53)
* IR analysis and transformations (#41) * Implement IR analysis and transformations * Fixme/parametrized type util (#45) * test transforming into parametrized type * add parametrized types for tests, try to fix parametrized inheritance (no luck) * Fix toParanetrizedType and add tests * Remove unused parameter * Add ssh debug action * Fix github actions * Fix tests by sorting comparing lists * Optimize imports and remove function that not used anymore * Add more generic tests * Remove debug output * Fix comment formatting * Fix PR comments * Update readme and add version (#46) * Change version * Use remote maven in examples * Change version * Downgrade version * Update examples and readme to enable IR (#48) * Update examples and readme to enable IR * Bugfix/supertypes naming (#49) * Fix subtypes -> supertypes * Fix kotlin docs and small typos in comments * Fix PR comments * Issue 47/check error cases (#50) * Add enum cases, refactor reflekt call testing * Fix examples a little bit * Add an example with start protection Co-authored-by: elena-lyulina <[email protected]> * Upgrade version and add more examples Co-authored-by: Maria Malysheva <[email protected]> Co-authored-by: Elena Lyulina <[email protected]> Co-authored-by: elena-lyulina <[email protected]>
1 parent eb66830 commit 47762cf

File tree

700 files changed

+5951
-4111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

700 files changed

+5951
-4111
lines changed

README.md

+22-21
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ user analysis. The first one will be called Reflekt, and the second SmartReflekt
2121

2222
**Restrictions**. Reflekt analyses only `.kt` files (in the psoject and in the libraries); uses
2323
Kotlin `1.4.20`. Reflekt does not currently support incremental compilation.
24+
25+
**Note**, we use [Intermediate Representation](https://kotlinlang.org/docs/whatsnew14.html#unified-backends-and-extensibility) of code in this plugin.
26+
It means, that Reflekt can be used for all available platforms: JVM, Native and JavaScript.
2427
___
2528

2629
## Table of contents
@@ -40,11 +43,11 @@ add the following lines in the `plugins` section:
4043

4144
```kotlin
4245
plugins {
43-
// Version of Kotlin should be 1.4.20+
44-
kotlin("jvm") version "1.4.20" apply true
46+
// Version of Kotlin should be 1.4.30+ that supports IR backend
47+
kotlin("jvm") version "1.5.10" apply true
4548

4649
// Please, use the latest Reflekt version
47-
id("io.reflekt") version "0.1.0" apply true
50+
id("io.reflekt") version "0.2.0" apply true
4851

4952
// Necessary only for this example, for Kotless library
5053
id("io.kotless") version "0.1.6" apply true
@@ -81,7 +84,7 @@ the following lines in the `dependencies` section:
8184
```kotlin
8285
dependencies {
8386
// The version here and the version in the plugins sections should be equal
84-
implementation("io.reflekt", "reflekt-dsl", "0.1.0")
87+
implementation("io.reflekt", "reflekt-dsl", "0.2.0")
8588

8689
// Necessary for this example
8790
compileOnly("io.kotless", "kotless-lang", "0.1.6")
@@ -114,21 +117,19 @@ _Please note that the `librariesToIntrospect` argument should contain only the d
114117
use in the `dependencies` section. These dependencies may be implemented in Java or Kotlin language,
115118
but the analysis will be made only on Kotlin files._
116119

117-
To avoid some bugs, please add the following compilation settings for Java and Kotlin in
118-
the `build.gradle.kts` file:
120+
To avoid some bugs and enable IR, please add the following compilation settings
121+
for Java and Kotlin in the `build.gradle.kts` file:
119122

120123
```kotlin
121-
val compileKotlin: KotlinCompile by tasks
122-
compileKotlin.kotlinOptions {
123-
jvmTarget = "11"
124-
languageVersion = "1.4"
125-
apiVersion = "1.4"
126-
}
127-
val compileTestKotlin: KotlinCompile by tasks
128-
compileTestKotlin.kotlinOptions {
129-
jvmTarget = "11"
130-
languageVersion = "1.4"
131-
apiVersion = "1.4"
124+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
125+
126+
tasks.withType<KotlinCompile> {
127+
kotlinOptions {
128+
useIR = true
129+
languageVersion = "1.5"
130+
apiVersion = "1.5"
131+
jvmTarget = "11"
132+
}
132133
}
133134
```
134135

@@ -150,10 +151,10 @@ kotlin.incremental = false
150151
Now you can use the Reflekt plugin to find objects, classes, and functions in your project:
151152

152153
```kotlin
153-
val objects = Reflekt.objects().withSubType<AInterface>()
154+
val objects = Reflekt.objects().withSupertype<AInterface>()
154155
.withAnnotations<AInterface>(FirstAnnotation::class, SecondAnnotation::class).toList()
155156

156-
val classes = Reflekt.classes().withSubType<BInterface>().toSet()
157+
val classes = Reflekt.classes().withSupertype<BInterface>().toSet()
157158

158159
val functions = Reflekt.functions().withAnnotations<() -> Unit>().toList()
159160
```
@@ -197,10 +198,10 @@ write this version in the plugins and dependencies sections.
197198
- [x] Compile-time reflection by custom users' filters for `multi-module` projects
198199
by [SmartReflekt DSL](./reflekt-dsl/src/main/kotlin/io/reflekt/SmartReflekt.kt)
199200
- [x] project's files
200-
- [x] external libraries
201+
- [ ] external libraries
202+
- [x] Bytecode generation -> IR generation
201203
- [ ] Incremental compilation process
202204
- [ ] Search in all modules of the project
203-
- [ ] Bytecode generation -> IR generation
204205
- [ ] Code generation.
205206

206207
_Note: We analyze modules independently of each other. If an object\class\function is in module A,

build.gradle.kts

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile
22

33
group = "io.reflekt"
4-
version = "0.1.0"
4+
version = "0.2.0"
55

66
plugins {
77
id("tanvd.kosogor") version "1.0.10" apply true
8-
kotlin("jvm") version "1.4.20" apply true
8+
kotlin("jvm") version "1.5.10" apply true
99
id("com.github.gmazzo.buildconfig") version "2.0.2" apply false
1010
`maven-publish`
11+
kotlin("kapt") version "1.5.10" apply true
1112
}
1213

1314
allprojects {
@@ -18,8 +19,8 @@ allprojects {
1819
tasks.withType<KotlinJvmCompile> {
1920
kotlinOptions {
2021
jvmTarget = "11"
21-
languageVersion = "1.4"
22-
apiVersion = "1.4"
22+
languageVersion = "1.5"
23+
apiVersion = "1.5"
2324
}
2425
}
2526

examples/build.gradle.kts

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import io.reflekt.plugin.reflekt
2-
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile
2+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
33

44
group = rootProject.group
55
version = rootProject.version
66

77
plugins {
88
id("tanvd.kosogor") version "1.0.10" apply true
9-
id("io.reflekt") version "0.1.0" apply true
10-
kotlin("jvm") version "1.4.20" apply true
9+
id("io.reflekt") version "0.2.0" apply true
10+
kotlin("jvm") version "1.5.10" apply true
1111
}
1212

1313
allprojects {
@@ -17,22 +17,24 @@ allprojects {
1717
plugin("io.reflekt")
1818
}
1919

20-
tasks.withType<KotlinJvmCompile> {
20+
tasks.withType<KotlinCompile> {
2121
kotlinOptions {
22+
useIR = true
23+
languageVersion = "1.5"
24+
apiVersion = "1.5"
2225
jvmTarget = "11"
23-
languageVersion = "1.4"
24-
apiVersion = "1.4"
2526
}
2627
}
2728

2829
dependencies {
29-
implementation("io.reflekt", "reflekt-dsl", "0.1.0")
30+
implementation("io.reflekt", "reflekt-dsl", "0.2.0")
3031
implementation("com.github.gumtreediff", "core", "2.1.2")
3132
}
3233

3334
repositories {
3435
mavenCentral()
3536
google()
37+
// mavenLocal()
3638
maven(url = uri("https://packages.jetbrains.team/maven/p/reflekt/reflekt"))
3739
}
3840

examples/first-module/src/main/kotlin/io/reflekt/example/Functions.kt

+17
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,20 @@ class TestFunctions {
3333
}
3434
}
3535
}
36+
37+
fun fooBoolean(): Boolean {
38+
println("public second example foo")
39+
return true
40+
}
41+
42+
inline fun <reified T> fooArray(): Array<T> = emptyArray()
43+
44+
fun <T> fooList(): List<T> = emptyList()
45+
46+
class MyInClass<in T>
47+
48+
fun <T> fooMyInClass(): MyInClass<T> = MyInClass()
49+
50+
fun withStar(a: List<*>) { }
51+
52+
fun <T: Number> withBound(a: T) { }

examples/first-module/src/main/kotlin/io/reflekt/example/Main.kt

+62-17
Original file line numberDiff line numberDiff line change
@@ -8,54 +8,99 @@ class Test(var a: List<Any>, b: List<Any>)
88

99
fun main() {
1010
val tmp = Test(emptyList(), emptyList())
11-
tmp.a = listOf(Reflekt.objects().withSubType<AInterface>().withAnnotations<AInterface>(FirstAnnotation::class))
12-
println(tmp)
11+
tmp.a = Reflekt.objects().withSupertype<AInterface>().withAnnotations<AInterface>(FirstAnnotation::class).toList()
12+
println(tmp.a)
1313

14-
val objects = Reflekt.objects().withSubType<AInterface>().withAnnotations<AInterface>(FirstAnnotation::class, SecondAnnotation::class).toList()
14+
val objects = Reflekt.objects().withSupertype<AInterface>().withAnnotations<AInterface>(FirstAnnotation::class, SecondAnnotation::class).toList()
1515
println(objects)
16-
val objects1 = Reflekt.objects().withSubType<AInterface>()
16+
val objects1 = Reflekt.objects().withSupertype<AInterface>()
1717
.withAnnotations<AInterface>(FirstAnnotation::class, SecondAnnotation::class).toList()
1818
println(objects1)
1919

20-
val objects2 = Reflekt.objects().withSubTypes(AInterface::class, A1::class)
20+
val objects2 = Reflekt.objects().withSupertypes(AInterface::class, A1::class)
2121
.withAnnotations<AInterface>(FirstAnnotation::class, SecondAnnotation::class).toList()
2222
println(objects2)
2323

24-
val objects3 = Reflekt.objects().withSubTypes(AInterface::class, A1::class)
24+
val objects3 = Reflekt.objects().withSupertypes(AInterface::class, A1::class)
2525
.withAnnotations<AInterface>(FirstAnnotation::class).toList()
2626
println(objects3)
2727

2828
val objects4 = Reflekt.objects().withAnnotations<AInterface>(FirstAnnotation::class).toList()
2929
println(objects4)
3030
val objects5 = Reflekt.objects().withAnnotations<AInterface>(FirstAnnotation::class).toList()
3131
println(objects5)
32-
val objects6 = Reflekt.objects().withAnnotations<A1>(FirstAnnotation::class).withSubType<AInterface>().toList()
32+
val objects6 = Reflekt.objects().withAnnotations<A1>(FirstAnnotation::class).withSupertype<AInterface>().toList()
3333
println(objects6)
34-
val objects7 = Reflekt.objects().withAnnotations<A1>(FirstAnnotation::class).withSubTypes(AInterface::class).toList()
34+
val objects7 = Reflekt.objects().withAnnotations<A1>(FirstAnnotation::class).withSupertypes(AInterface::class).toList()
3535
println(objects7)
36-
val objects8 = Reflekt.objects().withSubType<AInterface>().toList()
36+
val objects8 = Reflekt.objects().withSupertype<AInterface>().toList()
3737
println(objects8)
3838

39-
val classes1 = Reflekt.classes().withSubType<AInterface>().toList()
39+
val classes1 = Reflekt.classes().withSupertype<AInterface>().toList()
4040
println(classes1)
41-
val classes2 = Reflekt.classes().withSubType<BInterface>().toSet()
41+
val classes2 = Reflekt.classes().withSupertype<BInterface>().toSet()
4242
println(classes2)
4343
val classes3 = Reflekt.classes().withAnnotations<B2>(FirstAnnotation::class, SecondAnnotation::class).toList()
4444
println(classes3)
4545

46-
val classes4 = Reflekt.classes().withSubType<Action>().toList()
46+
val classes4 = Reflekt.classes().withSupertype<Action>().toList()
4747
println(classes4)
4848

4949
val functions = Reflekt.functions().withAnnotations<() -> Unit>(FirstAnnotation::class).toList()
5050
println(functions)
5151

52-
val smartClasses = SmartReflekt.classes<BInterface>().filter { it.isData() }.resolve()
53-
println(smartClasses)
54-
55-
val smartObjects = SmartReflekt.objects<BInterface>().filter { it.isCompanion() }.resolve()
56-
println(smartObjects)
52+
// TODO: it does not work (error with TestFunctions$Companion), see issue#52: https://github.com/JetBrains-Research/reflekt/issues/52
53+
// val smartClasses = SmartReflekt.classes<BInterface>().filter { it.isData() }.resolve()
54+
// println(smartClasses)
55+
//
56+
// val smartObjects = SmartReflekt.objects<BInterface>().filter { it.isCompanion() }.resolve()
57+
// println(smartObjects)
5758

5859
val smartFunctions = SmartReflekt.functions<() -> Unit>().filter { it.isTopLevel && it.name == "foo" }.resolve()
5960
println(smartFunctions)
6061
smartFunctions.forEach { it() }
62+
63+
val fooBoolean = SmartReflekt.functions<() -> Boolean>().filter { it.isTopLevel && it.name == "fooBoolean" }.resolve().onEach { it() }
64+
.map { it.toString() }.toSet()
65+
println("fooBoolean: $fooBoolean")
66+
67+
val fooStar = SmartReflekt.functions<(List<*>) -> Unit>().filter { it.isTopLevel && it.name == "withStar" }.resolve().onEach { it(listOf(1)) }
68+
.map { it.toString() }.toSet()
69+
println("fooStar: $fooStar")
70+
71+
// TODO: we will support gnerics with bounds
72+
// val fooBound = SmartReflekt.functions<(Number) -> Unit>().filter { it.isTopLevel && it.name == "withBound" }.resolve().onEach { it(listOf(1)) }
73+
// .map { it.toString() }.toSet()
74+
// println("fooBound: $fooBound")
75+
76+
/**
77+
* Such calls still fail, but it seems it's not a Reflekt problem since Kotlin doesn't consider our functions as subtypes of the given signature.
78+
*/
79+
80+
// val fooArray = SmartReflekt.functions<Function0<Array<*>>>().filter { it.isTopLevel && it.name == "fooArray" }.resolve().onEach { it() }.map { it.toString() }.toSet()
81+
// println(fooArray)
82+
//
83+
// val fooList = SmartReflekt.functions<Function0<List<*>>>().filter { it.isTopLevel && it.name == "fooList" }.resolve().onEach { it() }.map { it.toString() }.toSet()
84+
// println(fooList)
85+
//
86+
// val fooMyInClass = SmartReflekt.functions<Function0<MyInClass<*>>>().filter { it.isTopLevel && it.name == "fooMyInClass" }.resolve().onEach { it() }.map { it.toString() }.toSet()
87+
// println(fooMyInClass)
88+
89+
/**
90+
* The simplest way to check it's to pass our functions as a parameter of an argument with the given signature:
91+
*/
92+
// arrayTestFun(::fooArray)
93+
// listTestFun(::fooList)
94+
// myInClassTestFun(::fooMyInClass)
95+
96+
/**
97+
* For each of the functions Kotlin says [NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER] Not enough information to infer type variable T
98+
* Maybe we need to check https://kotlinlang.org/spec/type-system.html#mixed-site-variance
99+
*/
61100
}
101+
102+
fun arrayTestFun(funToTest: Function0<Array<*>>) {}
103+
104+
fun listTestFun(funToTest: Function0<List<*>>) {}
105+
106+
fun myInClassTestFun(funToTest: Function0<MyInClass<*>>) {}

examples/settings.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pluginManagement {
1515

1616
repositories {
1717
gradlePluginPortal()
18+
// mavenLocal()
1819
//add the dependency to Reflekt Maven repository
1920
maven(url = uri("https://packages.jetbrains.team/maven/p/reflekt/reflekt"))
2021
}

reflekt-core/src/main/kotlin/io/reflekt/util/Util.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ object Util {
1616
* Just needs to be consistent with the artifactId in reflekt-plugin build.gradle.kts#publishJar
1717
*/
1818
const val GRADLE_ARTIFACT_ID = "reflekt-plugin"
19-
const val VERSION = "0.1.0"
19+
const val VERSION = "0.2.0"
2020

2121
val ENABLED_OPTION_INFO = MyCliOption(
2222
name = "enabled",

0 commit comments

Comments
 (0)