blob: 59701404c24fc8d94e903087a893dbeaee1dfa16 [file] [log] [blame]
Yigit Boyarfc93ae22020-09-07 11:31:18 -07001/*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Yigit Boyar8af3a3a2021-01-05 16:17:49 -080017package androidx.room.compiler.processing
Yigit Boyarfc93ae22020-09-07 11:31:18 -070018
Yigit Boyarfc93ae22020-09-07 11:31:18 -070019import androidx.room.compiler.processing.util.Source
Yigit Boyar52828c72020-12-09 12:48:28 -080020import androidx.room.compiler.processing.util.XTestInvocation
Yigit Boyare16d1bb2021-01-05 14:54:45 -080021import androidx.room.compiler.processing.util.compileFiles
Yigit Boyar3adf1082020-09-15 21:15:57 -070022import androidx.room.compiler.processing.util.getAllFieldNames
23import androidx.room.compiler.processing.util.getField
Yigit Boyardd1f1d02021-11-12 23:19:09 -080024import androidx.room.compiler.processing.util.getMethodByJvmName
Yigit Boyarb90c49e2020-12-08 13:38:05 -080025import androidx.room.compiler.processing.util.runProcessorTest
Yigit Boyarfc93ae22020-09-07 11:31:18 -070026import com.google.common.truth.Truth.assertThat
Yigit Boyare16d1bb2021-01-05 14:54:45 -080027import com.google.common.truth.Truth.assertWithMessage
Yigit Boyarfc93ae22020-09-07 11:31:18 -070028import com.squareup.javapoet.ClassName
Yigit Boyar3adf1082020-09-15 21:15:57 -070029import com.squareup.javapoet.ParameterizedTypeName
Yigit Boyar45550ee2020-10-19 09:12:33 -070030import com.squareup.javapoet.TypeName
31import com.squareup.javapoet.TypeVariableName
Yigit Boyarfc93ae22020-09-07 11:31:18 -070032import org.junit.Test
33import org.junit.runner.RunWith
34import org.junit.runners.JUnit4
35
36@RunWith(JUnit4::class)
Yigit Boyar8af3a3a2021-01-05 16:17:49 -080037class XTypeElementTest {
Yigit Boyarfc93ae22020-09-07 11:31:18 -070038 @Test
39 fun qualifiedNames() {
40 val src1 = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -040041 "Foo.kt",
42 """
Yigit Boyarfc93ae22020-09-07 11:31:18 -070043 class TopLevel
Jeff Gaston63c23102020-09-18 12:53:59 -040044 """.trimIndent()
Yigit Boyarfc93ae22020-09-07 11:31:18 -070045 )
46 val src2 = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -040047 "Bar.kt",
48 """
Yigit Boyarfc93ae22020-09-07 11:31:18 -070049 package foo.bar
50 class InFooBar
Jeff Gaston63c23102020-09-18 12:53:59 -040051 """.trimIndent()
Yigit Boyarfc93ae22020-09-07 11:31:18 -070052 )
Yigit Boyar524475f2021-02-08 09:49:34 -080053 val src3 = Source.java(
54 "foo.bar.Outer",
55 """
56 package foo.bar;
57 public class Outer {
58 public static class Nested {
59 }
60 }
61 """
62 )
Yigit Boyar52828c72020-12-09 12:48:28 -080063 runProcessorTest(
Yigit Boyar524475f2021-02-08 09:49:34 -080064 sources = listOf(src1, src2, src3)
Yigit Boyarfc93ae22020-09-07 11:31:18 -070065 ) { invocation ->
66 invocation.processingEnv.requireTypeElement("TopLevel").let {
67 assertThat(it.packageName).isEqualTo("")
68 assertThat(it.name).isEqualTo("TopLevel")
69 assertThat(it.qualifiedName).isEqualTo("TopLevel")
70 assertThat(it.className).isEqualTo(ClassName.get("", "TopLevel"))
71 }
72 invocation.processingEnv.requireTypeElement("foo.bar.InFooBar").let {
73 assertThat(it.packageName).isEqualTo("foo.bar")
74 assertThat(it.name).isEqualTo("InFooBar")
75 assertThat(it.qualifiedName).isEqualTo("foo.bar.InFooBar")
76 assertThat(it.className).isEqualTo(ClassName.get("foo.bar", "InFooBar"))
77 }
Yigit Boyar524475f2021-02-08 09:49:34 -080078 invocation.processingEnv.requireTypeElement("foo.bar.Outer").let {
79 assertThat(it.packageName).isEqualTo("foo.bar")
80 assertThat(it.name).isEqualTo("Outer")
81 assertThat(it.qualifiedName).isEqualTo("foo.bar.Outer")
82 assertThat(it.className).isEqualTo(
83 ClassName.get("foo.bar", "Outer")
84 )
85 }
86 invocation.processingEnv.requireTypeElement("foo.bar.Outer.Nested").let {
87 assertThat(it.packageName).isEqualTo("foo.bar")
88 assertThat(it.name).isEqualTo("Nested")
89 assertThat(it.qualifiedName).isEqualTo("foo.bar.Outer.Nested")
90 assertThat(it.className).isEqualTo(
91 ClassName.get("foo.bar", "Outer", "Nested")
92 )
93 }
Yigit Boyar52828c72020-12-09 12:48:28 -080094 if (invocation.isKsp) {
95 // these are KSP specific tests, typenames are tested elsewhere
96 invocation.processingEnv.requireTypeElement("java.lang.Integer").let {
97 // always return kotlin types, this is what compiler does
98 assertThat(it.packageName).isEqualTo("kotlin")
99 assertThat(it.name).isEqualTo("Int")
100 assertThat(it.qualifiedName).isEqualTo("kotlin.Int")
101 }
102 invocation.processingEnv.requireTypeElement("kotlin.Int").let {
103 assertThat(it.packageName).isEqualTo("kotlin")
104 assertThat(it.name).isEqualTo("Int")
105 assertThat(it.qualifiedName).isEqualTo("kotlin.Int")
106 }
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700107 }
108 }
109 }
110
111 @Test
112 fun typeAndSuperType() {
113 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400114 "foo.kt",
115 """
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700116 package foo.bar;
117 class Baz : MyInterface, AbstractClass() {
118 }
119 abstract class AbstractClass {}
120 interface MyInterface {}
Jeff Gaston63c23102020-09-18 12:53:59 -0400121 """.trimIndent()
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700122 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800123 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700124 invocation.processingEnv.requireTypeElement("foo.bar.Baz").let {
125 assertThat(it.superType).isEqualTo(
126 invocation.processingEnv.requireType("foo.bar.AbstractClass")
127 )
128 assertThat(it.type).isEqualTo(
129 invocation.processingEnv.requireType("foo.bar.Baz")
130 )
131 assertThat(it.isInterface()).isFalse()
132 assertThat(it.isKotlinObject()).isFalse()
133 assertThat(it.isAbstract()).isFalse()
134 }
135 invocation.processingEnv.requireTypeElement("foo.bar.AbstractClass").let {
Yigit Boyar52828c72020-12-09 12:48:28 -0800136 assertThat(it.superType).let {
137 // KSP does not return Object / Any as super class
138 if (invocation.isKsp) {
139 it.isNull()
140 } else {
141 it.isEqualTo(
142 invocation.processingEnv.requireType(TypeName.OBJECT)
143 )
144 }
145 }
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700146 assertThat(it.isAbstract()).isTrue()
147 assertThat(it.isInterface()).isFalse()
148 assertThat(it.type).isEqualTo(
149 invocation.processingEnv.requireType("foo.bar.AbstractClass")
150 )
151 }
152 invocation.processingEnv.requireTypeElement("foo.bar.MyInterface").let {
153 assertThat(it.superType).isNull()
154 assertThat(it.isInterface()).isTrue()
155 assertThat(it.type).isEqualTo(
156 invocation.processingEnv.requireType("foo.bar.MyInterface")
157 )
158 }
159 }
160 }
161
162 @Test
Wanying Dingc49bb012022-01-05 01:44:37 +0000163 fun superInterfaces() {
164 val src = Source.kotlin(
165 "foo.kt",
166 """
167 package foo.bar;
168 class Baz : MyInterface<String>, AbstractClass() {
169 }
170 abstract class AbstractClass {}
171 interface MyInterface<E> {}
172 """.trimIndent()
173 )
174 runProcessorTest(sources = listOf(src)) { invocation ->
175 invocation.processingEnv.requireTypeElement("foo.bar.Baz").let {
176 assertThat(it.superInterfaces).hasSize(1)
Yigit Boyarc1eb02a2022-01-13 16:11:00 -0800177 val superInterface = it.superInterfaces.first { type ->
178 type.rawType.toString() == "foo.bar.MyInterface"
179 }
Wanying Dingc49bb012022-01-05 01:44:37 +0000180 assertThat(superInterface.typeArguments).hasSize(1)
181 assertThat(superInterface.typeArguments[0].typeName)
182 .isEqualTo(ClassName.get("java.lang", "String"))
183 }
184 }
185 }
186
187 @Test
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700188 fun nestedClassName() {
189 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400190 "Foo.kt",
191 """
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700192 package foo.bar;
193 class Outer {
194 class Inner
195 }
Jeff Gaston63c23102020-09-18 12:53:59 -0400196 """.trimIndent()
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700197 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800198 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700199 invocation.processingEnv.requireTypeElement("foo.bar.Outer").let {
200 assertThat(it.className).isEqualTo(ClassName.get("foo.bar", "Outer"))
Wanying Ding8be77e32021-11-24 22:06:44 +0000201 assertThat(it.isNested()).isFalse()
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700202 assertThat(it.enclosingTypeElement).isNull()
203 }
204 invocation.processingEnv.requireTypeElement("foo.bar.Outer.Inner").let {
205 assertThat(it.className).isEqualTo(ClassName.get("foo.bar", "Outer", "Inner"))
206 assertThat(it.packageName).isEqualTo("foo.bar")
207 assertThat(it.name).isEqualTo("Inner")
Wanying Ding8be77e32021-11-24 22:06:44 +0000208 assertThat(it.isNested()).isTrue()
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700209 assertThat(it.enclosingTypeElement).isEqualTo(
210 invocation.processingEnv.requireTypeElement("foo.bar.Outer")
211 )
212 }
213 }
214 }
215
216 @Test
217 fun modifiers() {
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800218 val kotlinSrc = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400219 "Foo.kt",
220 """
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700221 open class OpenClass
222 abstract class AbstractClass
223 object MyObject
224 interface MyInterface
225 class Final
226 private class PrivateClass
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800227 class OuterKotlinClass {
228 inner class InnerKotlinClass
229 class NestedKotlinClass
230 }
Eli Hart6c8b6f82021-05-17 19:37:41 -0700231 annotation class KotlinAnnotation
232 data class DataClass(val foo: Int)
233 inline class InlineClass(val foo: Int)
234 fun interface FunInterface {
235 fun foo()
236 }
Jeff Gaston63c23102020-09-18 12:53:59 -0400237 """.trimIndent()
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700238 )
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800239 val javaSrc = Source.java(
240 "OuterJavaClass",
241 """
242 public class OuterJavaClass {
243 public class InnerJavaClass {}
244 public static class NestedJavaClass {}
245 }
246 """.trimIndent()
247 )
Eli Hart6c8b6f82021-05-17 19:37:41 -0700248 val javaAnnotationSrc = Source.java(
249 "JavaAnnotation",
250 """
251 public @interface JavaAnnotation {
252 }
253 """.trimIndent()
254 )
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800255 runProcessorTest(
Eli Hart6c8b6f82021-05-17 19:37:41 -0700256 sources = listOf(kotlinSrc, javaSrc, javaAnnotationSrc)
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800257 ) { invocation ->
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700258 fun getModifiers(element: XTypeElement): Set<String> {
259 val result = mutableSetOf<String>()
260 if (element.isAbstract()) result.add("abstract")
261 if (element.isFinal()) result.add("final")
262 if (element.isPrivate()) result.add("private")
263 if (element.isProtected()) result.add("protected")
264 if (element.isPublic()) result.add("public")
265 if (element.isKotlinObject()) result.add("object")
Eli Hart6c8b6f82021-05-17 19:37:41 -0700266 if (element.isCompanionObject()) result.add("companion")
267 if (element.isFunctionalInterface()) result.add("fun")
268 if (element.isClass()) result.add("class")
269 if (element.isDataClass()) result.add("data")
270 if (element.isValueClass()) result.add("value")
271 if (element.isExpect()) result.add("expect")
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700272 if (element.isInterface()) result.add("interface")
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800273 if (element.isStatic()) result.add("static")
Eli Hart6c8b6f82021-05-17 19:37:41 -0700274 if (element.isAnnotationClass()) result.add("annotation")
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700275 return result
276 }
277
278 fun getModifiers(qName: String): Set<String> = getModifiers(
279 invocation.processingEnv
280 .requireTypeElement(qName)
281 )
282
283 assertThat(getModifiers("OpenClass"))
Eli Hart6c8b6f82021-05-17 19:37:41 -0700284 .containsExactly("public", "class")
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700285 assertThat(getModifiers("AbstractClass"))
Eli Hart6c8b6f82021-05-17 19:37:41 -0700286 .containsExactly("abstract", "public", "class")
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700287 assertThat(getModifiers("MyObject"))
288 .containsExactly("final", "public", "object")
289 assertThat(getModifiers("MyInterface"))
Yigit Boyar52828c72020-12-09 12:48:28 -0800290 .containsExactly("abstract", "interface", "public")
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700291 assertThat(getModifiers("Final"))
Eli Hart6c8b6f82021-05-17 19:37:41 -0700292 .containsExactly("final", "public", "class")
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700293 assertThat(getModifiers("PrivateClass"))
Yigit Boyar52828c72020-12-09 12:48:28 -0800294 .containsExactlyElementsIn(
295 if (invocation.isKsp) {
Eli Hart6c8b6f82021-05-17 19:37:41 -0700296 listOf("private", "final", "class")
Yigit Boyar52828c72020-12-09 12:48:28 -0800297 } else {
298 // java does not support top level private classes.
Eli Hart6c8b6f82021-05-17 19:37:41 -0700299 listOf("final", "class")
Yigit Boyar52828c72020-12-09 12:48:28 -0800300 }
301 )
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800302 assertThat(getModifiers("OuterKotlinClass.InnerKotlinClass"))
Eli Hart6c8b6f82021-05-17 19:37:41 -0700303 .containsExactly("final", "public", "class")
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800304 assertThat(getModifiers("OuterKotlinClass.NestedKotlinClass"))
Eli Hart6c8b6f82021-05-17 19:37:41 -0700305 .containsExactly("final", "public", "static", "class")
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800306 assertThat(getModifiers("OuterJavaClass.InnerJavaClass"))
Eli Hart6c8b6f82021-05-17 19:37:41 -0700307 .containsExactly("public", "class")
Yigit Boyar8af3a3a2021-01-05 16:17:49 -0800308 assertThat(getModifiers("OuterJavaClass.NestedJavaClass"))
Eli Hart6c8b6f82021-05-17 19:37:41 -0700309 .containsExactly("public", "static", "class")
310 assertThat(getModifiers("JavaAnnotation"))
311 .containsExactly("abstract", "public", "annotation")
312 assertThat(getModifiers("KotlinAnnotation")).apply {
313 // KSP vs KAPT metadata have a difference in final vs abstract modifiers
314 // for annotation types.
315 if (invocation.isKsp) {
316 containsExactly("final", "public", "annotation")
317 } else {
318 containsExactly("abstract", "public", "annotation")
319 }
320 }
321 assertThat(getModifiers("DataClass"))
322 .containsExactly("public", "final", "class", "data")
323 assertThat(getModifiers("InlineClass"))
324 .containsExactly("public", "final", "class", "value")
Yigit Boyar5cabf8f2021-05-20 12:06:55 -0700325 assertThat(getModifiers("FunInterface"))
326 .containsExactly("public", "abstract", "interface", "fun")
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700327 }
328 }
329
330 @Test
331 fun kindName() {
332 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400333 "Foo.kt",
334 """
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700335 class MyClass
336 interface MyInterface
Jeff Gaston63c23102020-09-18 12:53:59 -0400337 """.trimIndent()
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700338 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800339 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyarfc93ae22020-09-07 11:31:18 -0700340 invocation.processingEnv.requireTypeElement("MyClass").let {
341 assertThat(it.kindName()).isEqualTo("class")
342 }
343 invocation.processingEnv.requireTypeElement("MyInterface").let {
344 assertThat(it.kindName()).isEqualTo("interface")
345 }
346 }
347 }
Yigit Boyar3adf1082020-09-15 21:15:57 -0700348
349 @Test
350 fun fieldBasic() {
351 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400352 "Foo.kt",
353 """
Yigit Boyar45550ee2020-10-19 09:12:33 -0700354 open class BaseClass<T>(val genericProp : T) {
355 fun baseMethod(input: T) {}
356 }
Yigit Boyar3adf1082020-09-15 21:15:57 -0700357 class SubClass(x : Int) : BaseClass<Int>(x) {
358 val subClassProp : String = "abc"
359 }
Jeff Gaston63c23102020-09-18 12:53:59 -0400360 """.trimIndent()
Yigit Boyar3adf1082020-09-15 21:15:57 -0700361 )
Yigit Boyarb90c49e2020-12-08 13:38:05 -0800362 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyar3adf1082020-09-15 21:15:57 -0700363 val baseClass = invocation.processingEnv.requireTypeElement("BaseClass")
364 assertThat(baseClass.getAllFieldNames()).containsExactly("genericProp")
Daniel Santiago Riveraa3deddd2021-06-08 13:21:11 -0700365 assertThat(baseClass.getDeclaredFields().map { it.name })
366 .containsExactly("genericProp")
Yigit Boyar3adf1082020-09-15 21:15:57 -0700367 val subClass = invocation.processingEnv.requireTypeElement("SubClass")
368 assertThat(subClass.getAllFieldNames()).containsExactly("genericProp", "subClassProp")
Daniel Santiago Riveraa3deddd2021-06-08 13:21:11 -0700369 assertThat(subClass.getDeclaredFields().map { it.name })
370 .containsExactly("subClassProp")
Yigit Boyar45550ee2020-10-19 09:12:33 -0700371
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800372 val baseMethod = baseClass.getMethodByJvmName("baseMethod")
Yigit Boyar45550ee2020-10-19 09:12:33 -0700373 baseMethod.asMemberOf(subClass.type).let { methodType ->
374 val genericArg = methodType.parameterTypes.first()
375 assertThat(genericArg.typeName).isEqualTo(TypeName.INT.box())
376 }
377
Yigit Boyar3adf1082020-09-15 21:15:57 -0700378 baseClass.getField("genericProp").let { field ->
Yigit Boyar54da4252021-11-09 01:26:04 +0000379 assertThat(field.type.typeName).isEqualTo(TypeVariableName.get("T"))
Yigit Boyar3adf1082020-09-15 21:15:57 -0700380 }
Yigit Boyarbb533e822020-11-10 18:23:54 -0800381
Yigit Boyar3adf1082020-09-15 21:15:57 -0700382 subClass.getField("genericProp").let { field ->
Yigit Boyar45550ee2020-10-19 09:12:33 -0700383 // this is tricky because even though it is non-null it, it should still be boxed
384 assertThat(field.type.typeName).isEqualTo(TypeName.INT.box())
Yigit Boyar3adf1082020-09-15 21:15:57 -0700385 }
386 }
387 }
388
389 @Test
390 fun fieldsOverride() {
391 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400392 "Foo.kt",
393 """
Yigit Boyar3adf1082020-09-15 21:15:57 -0700394 open class BaseClass(
395 open val value : List<Int>
396 )
397 class SubClass(
398 override val value : MutableList<Int>
399 ) : BaseClass(value)
Jeff Gaston63c23102020-09-18 12:53:59 -0400400 """.trimIndent()
Yigit Boyar3adf1082020-09-15 21:15:57 -0700401 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800402 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyar3adf1082020-09-15 21:15:57 -0700403 val baseClass = invocation.processingEnv.requireTypeElement("BaseClass")
404 assertThat(baseClass.getAllFieldNames()).containsExactly("value")
405 val subClass = invocation.processingEnv.requireTypeElement("SubClass")
406 assertThat(subClass.getAllFieldNames()).containsExactly("value")
407 assertThat(
408 baseClass.getField("value").type.typeName
409 ).isEqualTo(
Yigit Boyar45550ee2020-10-19 09:12:33 -0700410 ParameterizedTypeName.get(List::class.java, Integer::class.java)
Yigit Boyar3adf1082020-09-15 21:15:57 -0700411 )
412 assertThat(
413 subClass.getField("value").type.typeName
414 ).isEqualTo(
Yigit Boyar45550ee2020-10-19 09:12:33 -0700415 ParameterizedTypeName.get(List::class.java, Integer::class.java)
Yigit Boyar3adf1082020-09-15 21:15:57 -0700416 )
417 }
418 }
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700419
420 @Test
Yigit Boyar54a407a2021-06-23 18:59:22 -0700421 fun fieldsMethodsWithoutBacking() {
422 fun buildSrc(pkg: String) = Source.kotlin(
423 "Foo.kt",
424 """
425 package $pkg;
426 class Subject {
427 val realField: String = ""
428 get() = field
429 val noBackingVal: String
430 get() = ""
431 var noBackingVar: String
432 get() = ""
433 set(value) {}
434
435 companion object {
436 @JvmStatic
437 val staticRealField: String = ""
438 get() = field
439 @JvmStatic
440 val staticNoBackingVal: String
441 get() = ""
442 @JvmStatic
443 var staticNoBackingVar: String
444 get() = ""
445 set(value) {}
446 }
447 }
448 """.trimIndent()
449 )
450 val lib = compileFiles(listOf(buildSrc("lib")))
451 runProcessorTest(
452 sources = listOf(buildSrc("main")),
453 classpath = lib
454 ) { invocation ->
455 listOf("lib", "main").forEach { pkg ->
456 val subject = invocation.processingEnv.requireTypeElement("$pkg.Subject")
457 val declaredFields = subject.getDeclaredFields().map { it.name } -
458 listOf("Companion") // skip Companion, KAPT generates it
Jim Sproch666614b2021-08-18 07:43:56 -0700459 val expectedFields = listOf("realField", "staticRealField")
Yigit Boyar54a407a2021-06-23 18:59:22 -0700460 assertWithMessage(subject.qualifiedName)
461 .that(declaredFields)
462 .containsExactlyElementsIn(expectedFields)
463 val allFields = subject.getAllFieldsIncludingPrivateSupers().map { it.name } -
464 listOf("Companion") // skip Companion, KAPT generates it
465 assertWithMessage(subject.qualifiedName)
466 .that(allFields.toList())
467 .containsExactlyElementsIn(expectedFields)
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800468 val methodNames = subject.getDeclaredMethods().map { it.jvmName }
Yigit Boyar54a407a2021-06-23 18:59:22 -0700469 assertWithMessage(subject.qualifiedName)
470 .that(methodNames)
471 .containsAtLeast("getNoBackingVal", "getNoBackingVar", "setNoBackingVar")
472 assertWithMessage(subject.qualifiedName)
473 .that(methodNames)
474 .doesNotContain("setNoBackingVal")
475 }
476 }
477 }
478
479 @Test
480 fun abstractFields() {
481 fun buildSource(pkg: String) = Source.kotlin(
482 "Foo.kt",
483 """
484 package $pkg;
485 abstract class Subject {
486 val value: String = ""
487 abstract val abstractValue: String
488 companion object {
489 var realCompanion: String = ""
490 @JvmStatic
491 var jvmStatic: String = ""
492 }
493 }
494 """.trimIndent()
495 )
496
497 val lib = compileFiles(listOf(buildSource("lib")))
498 runProcessorTest(
499 sources = listOf(buildSource("main")),
500 classpath = lib
501 ) { invocation ->
502 listOf("lib", "main").forEach { pkg ->
503 val subject = invocation.processingEnv.requireTypeElement("$pkg.Subject")
504 val declaredFields = subject.getDeclaredFields().map { it.name } -
505 listOf("Companion")
Jim Sproch666614b2021-08-18 07:43:56 -0700506 val expectedFields = listOf("value", "realCompanion", "jvmStatic")
Yigit Boyar54a407a2021-06-23 18:59:22 -0700507 assertWithMessage(subject.qualifiedName)
508 .that(declaredFields)
509 .containsExactlyElementsIn(expectedFields)
510 }
511 }
512 }
513
514 @Test
Yigit Boyar6cd12c92021-07-25 09:54:26 -0700515 fun lateinitFields() {
516 fun buildSource(pkg: String) = Source.kotlin(
517 "Foo.kt",
518 """
519 package $pkg
520 class Subject {
521 lateinit var x:String
522 var y:String = "abc"
523 }
524 """.trimIndent()
525 )
526 runProcessorTest(
527 sources = listOf(buildSource("app")),
528 classpath = compileFiles(listOf(buildSource("lib")))
529 ) { invocation ->
530 listOf("app", "lib").forEach { pkg ->
531 val subject = invocation.processingEnv.requireTypeElement("$pkg.Subject")
532 assertWithMessage(subject.fallbackLocationText)
533 .that(subject.getDeclaredFields().map { it.name })
534 .containsExactly(
535 "x", "y"
536 )
537 assertWithMessage(subject.fallbackLocationText)
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800538 .that(subject.getDeclaredMethods().map { it.jvmName })
Yigit Boyar6cd12c92021-07-25 09:54:26 -0700539 .containsExactly(
540 "getX", "setX", "getY", "setY"
541 )
542 }
543 }
544 }
545
546 @Test
Yigit Boyar52828c72020-12-09 12:48:28 -0800547 fun fieldsInInterfaces() {
548 val src = Source.kotlin(
549 "Foo.kt",
550 """
551 interface MyInterface {
552 var x:Int
553 }
554 """.trimIndent()
555 )
556 runProcessorTest(sources = listOf(src)) { invocation ->
557 val element = invocation.processingEnv.requireTypeElement("MyInterface")
Yigit Boyarad311f12021-06-28 11:14:26 -0700558 assertThat(element.getAllFieldsIncludingPrivateSupers().toList()).isEmpty()
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800559 element.getMethodByJvmName("getX").let {
Yigit Boyar52828c72020-12-09 12:48:28 -0800560 assertThat(it.isAbstract()).isTrue()
561 }
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800562 element.getMethodByJvmName("setX").let {
Yigit Boyar52828c72020-12-09 12:48:28 -0800563 assertThat(it.isAbstract()).isTrue()
564 }
565 }
566 }
567
568 @Test
Yigit Boyar8da2dbe2020-12-15 13:14:28 -0800569 fun fieldsInAbstractClass() {
570 val src = Source.kotlin(
571 "Foo.kt",
572 """
573 abstract class MyAbstractClass {
574 @JvmField
575 var jvmVar: Int = 0
576 abstract var abstractVar: Int
577 var nonAbstractVar: Int = 0
578 }
579 """.trimIndent()
580 )
581 runProcessorTest(sources = listOf(src)) { invocation ->
582 val element = invocation.processingEnv.requireTypeElement("MyAbstractClass")
583 assertThat(
584 element.getAllFieldNames()
585 ).containsExactly(
586 "nonAbstractVar", "jvmVar"
587 )
588 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800589 element.getDeclaredMethods().map { it.jvmName }
Yigit Boyar8da2dbe2020-12-15 13:14:28 -0800590 ).containsExactly(
591 "getAbstractVar", "setAbstractVar",
592 "getNonAbstractVar", "setNonAbstractVar"
593 )
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800594 element.getMethodByJvmName("getAbstractVar").let {
Yigit Boyar8da2dbe2020-12-15 13:14:28 -0800595 assertThat(it.isAbstract()).isTrue()
596 }
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800597 element.getMethodByJvmName("setAbstractVar").let {
Yigit Boyar8da2dbe2020-12-15 13:14:28 -0800598 assertThat(it.isAbstract()).isTrue()
599 }
600
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800601 element.getMethodByJvmName("getNonAbstractVar").let {
Yigit Boyar8da2dbe2020-12-15 13:14:28 -0800602 assertThat(it.isAbstract()).isFalse()
603 }
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800604 element.getMethodByJvmName("setNonAbstractVar").let {
Yigit Boyar8da2dbe2020-12-15 13:14:28 -0800605 assertThat(it.isAbstract()).isFalse()
606 }
607 }
608 }
609
610 @Test
Yigit Boyare3e91962021-02-01 16:12:34 -0800611 fun propertyGettersSetters() {
612 val dependencyJavaSource = Source.java(
613 "DependencyJavaSubject.java",
614 """
615 class DependencyJavaSubject {
616 int myField;
617 private int mutable;
618 int immutable;
619 int getMutable() {return 3;}
620 void setMutable(int x) {}
621 int getImmutable() {return 3;}
622 }
623 """.trimIndent()
624 )
625 val dependencyKotlinSource = Source.kotlin(
626 "DependencyKotlinSubject.kt",
627 """
628 class DependencyKotlinSubject {
629 private val myField = 0
630 var mutable: Int = 0
631 val immutable:Int = 0
632 }
633 """.trimIndent()
634 )
635 val dependency = compileFiles(listOf(dependencyJavaSource, dependencyKotlinSource))
636 val javaSource = Source.java(
637 "JavaSubject.java",
638 """
639 class JavaSubject {
640 int myField;
641 private int mutable;
642 int immutable;
643 int getMutable() {return 3;}
644 void setMutable(int x) {}
645 int getImmutable() {return 3;}
646 }
647 """.trimIndent()
648 )
649 val kotlinSource = Source.kotlin(
650 "KotlinSubject.kt",
651 """
652 class KotlinSubject {
653 private val myField = 0
654 var mutable: Int = 0
655 val immutable:Int = 0
656 }
657 """.trimIndent()
658 )
659 runProcessorTest(
660 listOf(javaSource, kotlinSource),
Yigit Boyar985fad52021-06-29 12:32:16 -0700661 classpath = dependency
Yigit Boyare3e91962021-02-01 16:12:34 -0800662 ) { invocation ->
663 listOf(
664 "JavaSubject", "DependencyJavaSubject",
665 "KotlinSubject", "DependencyKotlinSubject"
666 ).map {
667 invocation.processingEnv.requireTypeElement(it)
668 }.forEach { subject ->
669 assertWithMessage(subject.qualifiedName)
670 .that(
671 subject.getDeclaredMethods().map {
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800672 it.jvmName
Yigit Boyare3e91962021-02-01 16:12:34 -0800673 }
674 ).containsExactly(
675 "getMutable", "setMutable", "getImmutable"
676 )
677 }
678 }
679 }
680
681 @Test
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700682 fun declaredAndInstanceMethods() {
683 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400684 "Foo.kt",
685 """
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700686 open class Base(x:Int) {
687 open fun baseFun(): Int = TODO()
688 suspend fun suspendFun(): Int = TODO()
689 private fun privateBaseFun(): Int = TODO()
690 companion object {
691 @JvmStatic
692 fun staticBaseFun(): Int = TODO()
693 fun companionMethod(): Int = TODO()
694 }
695 }
696 open class SubClass : Base {
697 constructor(y:Int): super(y) {
698 }
699 constructor(x:Int, y:Int): super(y) {
700 }
701 override fun baseFun(): Int = TODO()
702 fun subFun(): Int = TODO()
703 private fun privateSubFun(): Int = TODO()
704 companion object {
705 @JvmStatic
706 fun staticFun(): Int = TODO()
707 }
708 }
Jeff Gaston63c23102020-09-18 12:53:59 -0400709 """.trimIndent()
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700710 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800711 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700712 val base = invocation.processingEnv.requireTypeElement("Base")
Yigit Boyar52828c72020-12-09 12:48:28 -0800713 val objectMethodNames = invocation.objectMethodNames()
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800714 assertThat(base.getDeclaredMethods().jvmNames()).containsExactly(
Jeff Gaston63c23102020-09-18 12:53:59 -0400715 "baseFun", "suspendFun", "privateBaseFun", "staticBaseFun"
716 )
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700717
718 val sub = invocation.processingEnv.requireTypeElement("SubClass")
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800719 assertThat(sub.getDeclaredMethods().jvmNames()).containsExactly(
Jeff Gaston63c23102020-09-18 12:53:59 -0400720 "baseFun", "subFun", "privateSubFun", "staticFun"
721 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800722 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800723 sub.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames
Yigit Boyar52828c72020-12-09 12:48:28 -0800724 ).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700725 "baseFun", "suspendFun", "subFun"
726 )
727 }
728 }
729
730 @Test
Yigit Boyarf27e38c2021-07-08 11:13:50 -0700731 fun diamondOverride() {
732 fun buildSrc(pkg: String) = Source.kotlin(
733 "Foo.kt",
734 """
735 package $pkg;
736 interface Parent<T> {
737 fun parent(t: T)
738 }
739
740 interface Child1<T> : Parent<T> {
741 fun child1(t: T)
742 }
743
744 interface Child2<T> : Parent<T> {
745 fun child2(t: T)
746 }
747
748 abstract class Subject1 : Child1<String>, Child2<String>, Parent<String>
749 abstract class Subject2 : Child1<String>, Parent<String>
750 abstract class Subject3 : Child1<String>, Parent<String> {
751 abstract override fun parent(t: String)
752 }
753 """.trimIndent()
754 )
755
756 runProcessorTest(
757 sources = listOf(buildSrc("app")),
758 classpath = compileFiles(listOf(buildSrc("lib")))
759 ) { invocation ->
760 listOf("lib", "app").forEach { pkg ->
761 val objectMethodNames = invocation.processingEnv.requireTypeElement(Any::class)
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800762 .getAllMethods().jvmNames()
Yigit Boyarf27e38c2021-07-08 11:13:50 -0700763
764 fun XMethodElement.signature(
765 owner: XType
766 ): String {
767 val methodType = this.asMemberOf(owner)
768 val params = methodType.parameterTypes.joinToString(",") {
769 it.typeName.toString()
770 }
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800771 return "$jvmName($params):${returnType.typeName}"
Yigit Boyarf27e38c2021-07-08 11:13:50 -0700772 }
773
774 fun XTypeElement.allMethodSignatures(): List<String> = getAllMethods().filterNot {
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800775 it.jvmName in objectMethodNames
Yigit Boyarf27e38c2021-07-08 11:13:50 -0700776 }.map { it.signature(this.type) }.toList()
777 invocation.processingEnv.requireTypeElement("$pkg.Subject1").let { subject ->
778 assertWithMessage(subject.qualifiedName).that(
779 subject.allMethodSignatures()
780 ).containsExactly(
781 "child1(java.lang.String):void",
782 "child2(java.lang.String):void",
783 "parent(java.lang.String):void",
784 )
785 }
786 invocation.processingEnv.requireTypeElement("$pkg.Subject2").let { subject ->
787 assertWithMessage(subject.qualifiedName).that(
788 subject.allMethodSignatures()
789 ).containsExactly(
790 "child1(java.lang.String):void",
791 "parent(java.lang.String):void",
792 )
793 }
794 invocation.processingEnv.requireTypeElement("$pkg.Subject3").let { subject ->
795 assertWithMessage(subject.qualifiedName).that(
796 subject.allMethodSignatures()
797 ).containsExactly(
798 "child1(java.lang.String):void",
799 "parent(java.lang.String):void",
800 )
801 }
802 }
803 }
804 }
805
806 @Test
bcorso22aa8a62021-09-28 12:29:34 -0700807 fun overrideMethodWithCovariantReturnType() {
808 val src = Source.kotlin(
809 "ParentWithExplicitOverride.kt",
810 """
811 interface ParentWithExplicitOverride: ChildInterface, Child {
812 override fun child(): Child
813 }
814
815 interface ParentWithoutExplicitOverride: ChildInterface, Child
816
817 interface Child: ChildInterface {
818 override fun child(): Child
819 }
820
821 interface ChildInterface {
822 fun child(): ChildInterface
823 }
824 """.trimIndent()
825 )
826
827 runProcessorTest(sources = listOf(src)) { invocation ->
828 val objectMethodNames = invocation.processingEnv.requireTypeElement(Any::class)
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800829 .getAllMethods().jvmNames()
bcorso22aa8a62021-09-28 12:29:34 -0700830 fun XMethodElement.signature(
831 owner: XType
832 ): String {
833 val methodType = this.asMemberOf(owner)
834 val params = methodType.parameterTypes.joinToString(",") {
835 it.typeName.toString()
836 }
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800837 return "$jvmName($params):${returnType.typeName}"
bcorso22aa8a62021-09-28 12:29:34 -0700838 }
839
840 fun XTypeElement.allMethodSignatures(): List<String> = getAllMethods().filterNot {
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800841 it.jvmName in objectMethodNames
bcorso22aa8a62021-09-28 12:29:34 -0700842 }.map { it.signature(this.type) }.toList()
843
844 invocation.processingEnv.requireTypeElement(
845 "ParentWithExplicitOverride"
846 ).let { parent ->
847 assertWithMessage(parent.qualifiedName).that(
848 parent.allMethodSignatures()
849 ).containsExactly(
850 "child():Child"
851 )
852 }
853
bcorso22aa8a62021-09-28 12:29:34 -0700854 invocation.processingEnv.requireTypeElement(
855 "ParentWithoutExplicitOverride"
856 ).let { parent ->
857 assertWithMessage(parent.qualifiedName).that(
858 parent.allMethodSignatures()
859 ).containsExactly(
bcorso22aa8a62021-09-28 12:29:34 -0700860 "child():Child"
861 )
862 }
863 }
864 }
865
866 @Test
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700867 fun allMethods() {
868 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -0400869 "Foo.kt",
870 """
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700871 open class Base(x:Int) {
872 constructor(x:Int, y:Int): this(x) {
873 }
874 fun baseMethod(): Int = TODO()
875 open fun overriddenMethod(): Int = TODO()
876 private fun privateBaseMethod(): Int = TODO()
877 companion object {
878 @JvmStatic
879 private fun privateBaseCompanionMethod(): Int = TODO()
880 @JvmStatic
881 fun baseCompanionMethod(): Int = TODO()
882 }
883 }
884 interface MyInterface {
885 fun interfaceMethod(): Int = TODO()
886 }
887 class SubClass : Base, MyInterface {
888 constructor(x:Int): super(x) {
889 }
890 constructor(x:Int, y:Int): super(y) {
891 }
892 fun subMethod(): Int = TODO()
893 fun privateSubMethod(): Int = TODO()
894 override fun overriddenMethod(): Int = TODO()
895 override fun interfaceMethod(): Int = TODO()
896 companion object {
897 fun dontSeeThisOne(): Int = TODO()
898 @JvmStatic
899 fun subCompanionMethod(): Int = TODO()
900 }
901 }
Jeff Gaston63c23102020-09-18 12:53:59 -0400902 """.trimIndent()
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700903 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800904 runProcessorTest(sources = listOf(src)) { invocation ->
905 val objectMethodNames = invocation.objectMethodNames()
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700906 val klass = invocation.processingEnv.requireTypeElement("SubClass")
Yigit Boyar52828c72020-12-09 12:48:28 -0800907 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800908 klass.getAllMethods().jvmNames() - objectMethodNames
Yigit Boyar52828c72020-12-09 12:48:28 -0800909 ).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700910 "baseMethod", "overriddenMethod", "baseCompanionMethod",
911 "interfaceMethod", "subMethod", "privateSubMethod", "subCompanionMethod"
912 )
913 }
914 }
915
Yigit Boyarc1eb02a2022-01-13 16:11:00 -0800916 /**
917 * When JvmNames is used along with a suppression over the error, the behavior becomes
918 * complicated. Normally, JvmName annotation is not allowed in overrides and open methods, yet
919 * developers can still use it by putting a suppression over it. The compiler will generate a
920 * delegating method in these cases in the .class file, yet in KSP, we don't really see that
921 * method (also shouldn't ideally).
922 *
923 * This test is here to acknowledge that the behavior is inconsistent yet working as intended
924 * from XProcessing's perspective.
925 *
926 * Also see: https://youtrack.jetbrains.com/issue/KT-50782 as a sign why this suppression is
927 * not worth supporting :).
928 */
929 @Test
930 fun allMethods_withJvmNames() {
931 fun buildSource(pkg: String) = listOf(
932 Source.kotlin(
933 "Foo.kt",
934 """
935 package $pkg
936 interface Interface {
937 fun f1()
938 @JvmName("notF2")
939 @Suppress("INAPPLICABLE_JVM_NAME")
940 fun f2()
941 }
942 abstract class Subject : Interface {
943 @JvmName("notF1")
944 @Suppress("INAPPLICABLE_JVM_NAME")
945 override fun f1() {
946 }
947 }
948 """.trimIndent()
949 )
950 )
951
952 runProcessorTest(
953 sources = buildSource("app"),
954 classpath = compileFiles(buildSource("lib"))
955 ) { invocation ->
956 listOf("app", "lib").forEach {
957 val appSubject = invocation.processingEnv.requireTypeElement("$it.Subject")
958 val methodNames = appSubject.getAllMethods().map { it.name }.toList()
959 val methodJvmNames = appSubject.getAllMethods().map { it.jvmName }.toList()
960 val objectMethodNames = invocation.objectMethodNames()
961 if (invocation.isKsp) {
962 assertThat(methodNames - objectMethodNames).containsExactly(
963 "f1", "f2"
964 )
965 assertThat(methodJvmNames - objectMethodNames).containsExactly(
966 "notF1", "notF2"
967 )
968 } else {
969 assertThat(methodNames - objectMethodNames).containsExactly(
970 "f1", "f1", "f2"
971 )
972 assertThat(methodJvmNames - objectMethodNames).containsExactly(
973 "f1", "notF1", "notF2"
974 )
975 }
976 }
977 }
978 }
979
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700980 @Test
981 fun gettersSetters() {
Jeff Gaston63c23102020-09-18 12:53:59 -0400982 val src = Source.kotlin(
983 "Foo.kt",
984 """
Yigit Boyar0ce2f642020-09-30 17:21:08 -0700985 open class JustGetter(val x:Int) {
986 private val invisible:Int = TODO()
987 private var invisibleMutable:Int = TODO()
988 }
989 class GetterSetter(var y:Int) : JustGetter(y) {
990 private val subInvisible:Int = TODO()
991 private var subInvisibleMutable:Int = TODO()
992 }
Jeff Gaston63c23102020-09-18 12:53:59 -0400993 """.trimIndent()
994 )
Yigit Boyar52828c72020-12-09 12:48:28 -0800995 runProcessorTest(sources = listOf(src)) { invocation ->
996 val objectMethodNames = invocation.objectMethodNames()
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700997 invocation.processingEnv.requireTypeElement("JustGetter").let { base ->
Yigit Boyardd1f1d02021-11-12 23:19:09 -0800998 assertThat(base.getDeclaredMethods().jvmNames()).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -0700999 "getX"
1000 )
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001001 assertThat(base.getAllMethods().jvmNames() - objectMethodNames).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001002 "getX"
1003 )
Yigit Boyar52828c72020-12-09 12:48:28 -08001004 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001005 base.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames
Yigit Boyar52828c72020-12-09 12:48:28 -08001006 ).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001007 "getX"
1008 )
1009 }
1010 invocation.processingEnv.requireTypeElement("GetterSetter").let { sub ->
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001011 assertThat(sub.getDeclaredMethods().jvmNames()).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001012 "getY", "setY"
1013 )
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001014 assertThat(sub.getAllMethods().jvmNames() - objectMethodNames).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001015 "getX", "getY", "setY"
1016 )
Yigit Boyar52828c72020-12-09 12:48:28 -08001017 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001018 sub.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames
Yigit Boyar52828c72020-12-09 12:48:28 -08001019 ).containsExactly(
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001020 "getX", "getY", "setY"
1021 )
1022 }
1023 }
1024 }
1025
1026 @Test
Yigit Boyar54a407a2021-06-23 18:59:22 -07001027 fun companion() {
Jeff Gaston63c23102020-09-18 12:53:59 -04001028 val src = Source.kotlin(
1029 "Foo.kt",
1030 """
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001031 open class CompanionSubject {
1032 companion object {
1033 @JvmStatic
1034 var mutableStatic: String = "a"
1035 @JvmStatic
1036 val immutableStatic: String = "bar"
1037 val companionProp: Int = 3
Yigit Boyar54a407a2021-06-23 18:59:22 -07001038 @get:JvmStatic
1039 var companionProp_getterJvmStatic:Int =3
1040 @set:JvmStatic
1041 var companionProp_setterJvmStatic:Int =3
1042
1043 fun companionMethod() {
1044 }
1045
1046 @JvmStatic
1047 fun companionMethodWithJvmStatic() {}
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001048 }
1049 }
1050 class SubClass : CompanionSubject()
Jeff Gaston63c23102020-09-18 12:53:59 -04001051 """.trimIndent()
1052 )
Yigit Boyar54a407a2021-06-23 18:59:22 -07001053 runProcessorTest(sources = listOf(src)) { invocation ->
1054 val objectMethodNames = invocation.processingEnv.requireTypeElement(
1055 Any::class
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001056 ).getAllMethods().jvmNames()
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001057 val subject = invocation.processingEnv.requireTypeElement("CompanionSubject")
Yigit Boyar54a407a2021-06-23 18:59:22 -07001058 assertThat(subject.getAllFieldNames() - "Companion").containsExactly(
1059 "mutableStatic", "immutableStatic", "companionProp",
1060 "companionProp_getterJvmStatic", "companionProp_setterJvmStatic"
Yigit Boyar08a27162020-11-25 09:39:31 -08001061 )
Yigit Boyar54a407a2021-06-23 18:59:22 -07001062 val expectedMethodNames = listOf(
1063 "getMutableStatic", "setMutableStatic", "getImmutableStatic",
1064 "getCompanionProp_getterJvmStatic", "setCompanionProp_setterJvmStatic",
1065 "companionMethodWithJvmStatic"
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001066 )
Yigit Boyar54a407a2021-06-23 18:59:22 -07001067 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001068 subject.getDeclaredMethods().jvmNames()
Yigit Boyar54a407a2021-06-23 18:59:22 -07001069 ).containsExactlyElementsIn(
1070 expectedMethodNames
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001071 )
Yigit Boyar54a407a2021-06-23 18:59:22 -07001072 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001073 subject.getAllMethods().jvmNames() - objectMethodNames
Yigit Boyar54a407a2021-06-23 18:59:22 -07001074 ).containsExactlyElementsIn(
1075 expectedMethodNames
1076 )
1077 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001078 subject.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames
Yigit Boyar54a407a2021-06-23 18:59:22 -07001079 ).isEmpty()
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001080 val subClass = invocation.processingEnv.requireTypeElement("SubClass")
1081 assertThat(subClass.getDeclaredMethods()).isEmpty()
Yigit Boyar54a407a2021-06-23 18:59:22 -07001082 assertThat(
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001083 subClass.getAllMethods().jvmNames() - objectMethodNames
Yigit Boyar54a407a2021-06-23 18:59:22 -07001084 ).containsExactlyElementsIn(
1085 expectedMethodNames
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001086 )
Yigit Boyar54a407a2021-06-23 18:59:22 -07001087
1088 // make sure everything coming from companion is marked as static
1089 subject.getDeclaredFields().forEach {
1090 assertWithMessage(it.name).that(it.isStatic()).isTrue()
1091 }
1092 subject.getDeclaredMethods().forEach {
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001093 assertWithMessage(it.jvmName).that(it.isStatic()).isTrue()
Yigit Boyar54a407a2021-06-23 18:59:22 -07001094 }
1095
1096 // make sure asMemberOf works fine for statics
1097 val subClassType = subClass.type
1098 subject.getDeclaredFields().forEach {
1099 try {
1100 it.asMemberOf(subClassType)
1101 } catch (th: Throwable) {
1102 throw AssertionError("Couldn't run asMemberOf for ${it.name}")
1103 }
1104 }
1105 subject.getDeclaredMethods().forEach {
1106 try {
1107 it.asMemberOf(subClassType)
1108 } catch (th: Throwable) {
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001109 throw AssertionError("Couldn't run asMemberOf for ${it.jvmName}")
Yigit Boyar54a407a2021-06-23 18:59:22 -07001110 }
1111 }
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001112 }
1113 }
1114
1115 @Test
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001116 fun gettersSetters_interface() {
Jeff Gaston63c23102020-09-18 12:53:59 -04001117 val src = Source.kotlin(
1118 "Foo.kt",
1119 """
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001120 interface JustGetter {
1121 val x:Int
1122 }
1123 interface GetterSetter : JustGetter {
1124 var y:Int
1125 }
Jeff Gaston63c23102020-09-18 12:53:59 -04001126 """.trimIndent()
1127 )
Yigit Boyar52828c72020-12-09 12:48:28 -08001128 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001129 invocation.processingEnv.requireTypeElement("JustGetter").let { base ->
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001130 assertThat(base.getDeclaredMethods().jvmNames()).containsExactly(
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001131 "getX"
1132 )
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001133 assertThat(base.getAllMethods().jvmNames()).containsExactly(
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001134 "getX"
1135 )
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001136 assertThat(base.getAllNonPrivateInstanceMethods().jvmNames()).containsExactly(
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001137 "getX"
1138 )
1139 }
1140 invocation.processingEnv.requireTypeElement("GetterSetter").let { sub ->
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001141 assertThat(sub.getDeclaredMethods().jvmNames()).containsExactly(
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001142 "getY", "setY"
1143 )
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001144 assertThat(sub.getAllMethods().jvmNames()).containsExactly(
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001145 "getX", "getY", "setY"
1146 )
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001147 assertThat(sub.getAllNonPrivateInstanceMethods().jvmNames()).containsExactly(
Yigit Boyar0ce2f642020-09-30 17:21:08 -07001148 "getX", "getY", "setY"
1149 )
1150 }
1151 }
1152 }
1153
1154 @Test
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001155 fun constructors() {
1156 val src = Source.kotlin(
Jeff Gaston63c23102020-09-18 12:53:59 -04001157 "Foo.kt",
1158 """
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001159 interface MyInterface
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001160 class NoExplicitConstructor
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001161 open class Base(x:Int)
1162 open class ExplicitConstructor {
1163 constructor(x:Int)
1164 }
1165 open class BaseWithSecondary(x:Int) {
1166 constructor(y:String):this(3)
1167 }
1168 class Sub(x:Int) : Base(x)
1169 class SubWith3Constructors() : BaseWithSecondary("abc") {
1170 constructor(list:List<String>): this()
1171 constructor(list:List<String>, x:Int): this()
1172 }
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001173 abstract class AbstractNoExplicit
1174 abstract class AbstractExplicit(x:Int)
Jeff Gaston63c23102020-09-18 12:53:59 -04001175 """.trimIndent()
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001176 )
Yigit Boyarb90c49e2020-12-08 13:38:05 -08001177 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001178 val subjects = listOf(
1179 "MyInterface", "NoExplicitConstructor", "Base", "ExplicitConstructor",
1180 "BaseWithSecondary", "Sub", "SubWith3Constructors",
1181 "AbstractNoExplicit", "AbstractExplicit"
1182 )
1183 val constructorCounts = subjects.map {
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001184 it to invocation.processingEnv.requireTypeElement(it).getConstructors().size
1185 }
1186 assertThat(constructorCounts)
1187 .containsExactly(
1188 "MyInterface" to 0,
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001189 "NoExplicitConstructor" to 1,
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001190 "Base" to 1,
1191 "ExplicitConstructor" to 1,
1192 "BaseWithSecondary" to 2,
1193 "Sub" to 1,
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001194 "SubWith3Constructors" to 3,
1195 "AbstractNoExplicit" to 1,
1196 "AbstractExplicit" to 1
1197 )
1198
1199 val primaryConstructorParameterNames = subjects.map {
1200 it to invocation.processingEnv.requireTypeElement(it)
1201 .findPrimaryConstructor()
1202 ?.parameters?.map {
1203 it.name
1204 }
1205 }
1206 assertThat(primaryConstructorParameterNames)
1207 .containsExactly(
1208 "MyInterface" to null,
1209 "NoExplicitConstructor" to emptyList<String>(),
1210 "Base" to listOf("x"),
1211 "ExplicitConstructor" to null,
1212 "BaseWithSecondary" to listOf("x"),
1213 "Sub" to listOf("x"),
1214 "SubWith3Constructors" to emptyList<String>(),
1215 "AbstractNoExplicit" to emptyList<String>(),
1216 "AbstractExplicit" to listOf("x")
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001217 )
1218 }
1219 }
1220
1221 @Test
1222 fun jvmDefault() {
Jeff Gaston63c23102020-09-18 12:53:59 -04001223 val src = Source.kotlin(
1224 "Foo.kt",
1225 """
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001226 interface MyInterface {
1227 fun notJvmDefault()
1228 @JvmDefault
Yigit Boyar52828c72020-12-09 12:48:28 -08001229 fun jvmDefault() {}
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001230 }
Jeff Gaston63c23102020-09-18 12:53:59 -04001231 """.trimIndent()
1232 )
Yigit Boyar52828c72020-12-09 12:48:28 -08001233 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001234 val subject = invocation.processingEnv.requireTypeElement("MyInterface")
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001235 assertThat(subject.getMethodByJvmName("notJvmDefault").isJavaDefault()).isFalse()
1236 assertThat(subject.getMethodByJvmName("jvmDefault").isJavaDefault()).isTrue()
Yigit Boyar3c4adc62020-09-17 13:29:47 -07001237 }
1238 }
1239
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001240 @Test
1241 fun constructors_java() {
1242 val src = Source.java(
Jeff Gaston63c23102020-09-18 12:53:59 -04001243 "Source",
1244 """
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001245 import java.util.List;
1246 interface MyInterface {}
1247 class NoExplicitConstructor{}
1248 class Base {
1249 Base(int x){}
1250 }
1251 class ExplicitConstructor {
1252 ExplicitConstructor(int x){}
1253 }
1254 class BaseWithSecondary {
1255 BaseWithSecondary(int x){}
1256 BaseWithSecondary(String y){}
1257 }
1258 class Sub extends Base {
1259 Sub(int x) {
1260 super(x);
1261 }
1262 }
1263 class SubWith3Constructors extends BaseWithSecondary {
1264 SubWith3Constructors() {
1265 super(3);
1266 }
1267 SubWith3Constructors(List<String> list) {
1268 super(3);
1269 }
1270 SubWith3Constructors(List<String> list, int x) {
1271 super(3);
1272 }
1273 }
1274 abstract class AbstractNoExplicit {}
1275 abstract class AbstractExplicit {
1276 AbstractExplicit(int x) {}
1277 }
Jeff Gaston63c23102020-09-18 12:53:59 -04001278 """.trimIndent()
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001279 )
Yigit Boyarb90c49e2020-12-08 13:38:05 -08001280 runProcessorTest(sources = listOf(src)) { invocation ->
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001281 val subjects = listOf(
1282 "MyInterface", "NoExplicitConstructor", "Base", "ExplicitConstructor",
1283 "BaseWithSecondary", "Sub", "SubWith3Constructors",
1284 "AbstractNoExplicit", "AbstractExplicit"
1285 )
1286 val constructorCounts = subjects.map {
1287 it to invocation.processingEnv.requireTypeElement(it).getConstructors().size
1288 }
1289 assertThat(constructorCounts)
1290 .containsExactly(
1291 "MyInterface" to 0,
1292 "NoExplicitConstructor" to 1,
1293 "Base" to 1,
1294 "ExplicitConstructor" to 1,
1295 "BaseWithSecondary" to 2,
1296 "Sub" to 1,
1297 "SubWith3Constructors" to 3,
1298 "AbstractNoExplicit" to 1,
1299 "AbstractExplicit" to 1
1300 )
1301
1302 subjects.forEach {
Yigit Boyare16d1bb2021-01-05 14:54:45 -08001303 assertWithMessage(it)
Yigit Boyarb45f9cc2020-10-01 14:52:49 -07001304 .that(invocation.processingEnv.requireTypeElement(it).findPrimaryConstructor())
1305 .isNull()
1306 }
1307 }
1308 }
1309
Yigit Boyare16d1bb2021-01-05 14:54:45 -08001310 @Test
1311 fun enumTypeElement() {
1312 fun createSources(packageName: String) = listOf(
1313 Source.kotlin(
1314 "$packageName/KotlinEnum.kt",
1315 """
1316 package $packageName
1317 enum class KotlinEnum(private val x:Int) {
1318 VAL1(1),
1319 VAL2(2);
1320
1321 fun enumMethod():Unit {}
1322 }
1323 """.trimIndent()
1324 ),
1325 Source.java(
1326 "$packageName.JavaEnum",
1327 """
1328 package $packageName;
1329 public enum JavaEnum {
1330 VAL1(1),
1331 VAL2(2);
1332
1333 private int x;
1334
1335 JavaEnum(int x) {
1336 this.x = x;
1337 }
1338 void enumMethod() {}
1339 }
1340 """.trimIndent()
1341 )
1342 )
Yigit Boyare3e91962021-02-01 16:12:34 -08001343
Yigit Boyare16d1bb2021-01-05 14:54:45 -08001344 val classpath = compileFiles(
1345 createSources("lib")
1346 )
1347 runProcessorTest(
1348 sources = createSources("app"),
Yigit Boyar985fad52021-06-29 12:32:16 -07001349 classpath = classpath
Yigit Boyare16d1bb2021-01-05 14:54:45 -08001350 ) { invocation ->
1351 listOf(
1352 "lib.KotlinEnum", "lib.JavaEnum",
1353 "app.KotlinEnum", "app.JavaEnum"
1354 ).forEach { qName ->
1355 val typeElement = invocation.processingEnv.requireTypeElement(qName)
1356 assertWithMessage("$qName is enum")
1357 .that(typeElement.isEnum())
1358 .isTrue()
1359 assertWithMessage("$qName does not report enum constants in methods")
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001360 .that(typeElement.getDeclaredMethods().map { it.jvmName })
Yigit Boyare16d1bb2021-01-05 14:54:45 -08001361 .run {
1362 contains("enumMethod")
1363 containsNoneOf("VAL1", "VAL2")
1364 }
Yigit Boyar1d5ffb62021-01-08 11:47:10 -08001365 assertWithMessage("$qName can return enum constants")
Eli Hart21aacea2021-06-09 11:55:33 -05001366 .that((typeElement as XEnumTypeElement).entries.map { it.name })
Yigit Boyar1d5ffb62021-01-08 11:47:10 -08001367 .containsExactly("VAL1", "VAL2")
1368 assertWithMessage("$qName does not report enum constants in fields")
1369 .that(typeElement.getAllFieldNames())
1370 .run {
1371 contains("x")
1372 containsNoneOf("VAL1", "VAL2")
1373 }
Yigit Boyar6ab4a1f2021-06-30 09:53:33 -07001374 assertWithMessage("$qName does not report enum constants in declared fields")
1375 .that(typeElement.getDeclaredFields().map { it.name })
1376 .containsExactly("x")
Yigit Boyare16d1bb2021-01-05 14:54:45 -08001377 }
1378 }
1379 }
1380
Eli Hart29da9632021-06-05 12:41:09 -07001381 @Test
1382 fun enclosedTypes() {
1383 val src = Source.kotlin(
1384 "Foo.kt",
1385 """
1386 class TopLevelClass {
1387 class NestedClass
1388 object NestedObject
1389 interface NestedInterface
1390 enum class NestedEnum {
1391 A, B
1392 }
1393 companion object {
1394 val foo = 1
1395 }
1396 }
1397 """.trimIndent()
1398 )
1399 runProcessorTest(sources = listOf(src)) { invocation ->
1400 val topLevelClass = invocation.processingEnv.requireTypeElement("TopLevelClass")
1401 val enclosedTypeElements = topLevelClass.getEnclosedTypeElements()
1402
1403 assertThat(enclosedTypeElements)
1404 .containsExactly(
1405 invocation.processingEnv.requireTypeElement("TopLevelClass.NestedClass"),
1406 invocation.processingEnv.requireTypeElement("TopLevelClass.NestedObject"),
1407 invocation.processingEnv.requireTypeElement("TopLevelClass.NestedInterface"),
1408 invocation.processingEnv.requireTypeElement("TopLevelClass.NestedEnum"),
1409 invocation.processingEnv.requireTypeElement("TopLevelClass.Companion"),
1410 )
1411 }
1412 }
1413
1414 @Test
1415 fun enclosedTypes_java() {
1416 val src = Source.java(
1417 "Source",
1418 """
1419 class TopLevelClass {
1420 class InnerClass { }
1421 static class NestedClass { }
1422 interface NestedInterface { }
1423 enum NestedEnum {
1424 A, B
1425 }
1426 }
1427 """.trimIndent()
1428 )
1429 runProcessorTest(sources = listOf(src)) { invocation ->
1430 val topLevelClass = invocation.processingEnv.requireTypeElement("TopLevelClass")
1431 val enclosedTypeElements = topLevelClass.getEnclosedTypeElements()
1432
1433 assertThat(enclosedTypeElements)
1434 .containsExactly(
1435 invocation.processingEnv.requireTypeElement("TopLevelClass.InnerClass"),
1436 invocation.processingEnv.requireTypeElement("TopLevelClass.NestedClass"),
1437 invocation.processingEnv.requireTypeElement("TopLevelClass.NestedInterface"),
1438 invocation.processingEnv.requireTypeElement("TopLevelClass.NestedEnum"),
1439 )
1440 }
1441 }
1442
Kuan-Ying Chou125ea922022-01-24 18:05:12 +00001443 @Test
1444 fun kotlinObjects() {
1445 val kotlinSrc = Source.kotlin(
1446 "Test.kt",
1447 """
1448 package foo.bar
1449 class KotlinClass {
1450 companion object
1451 object NestedObject
1452 }
1453 """.trimIndent()
1454 )
1455 runProcessorTest(listOf(kotlinSrc)) { invocation ->
1456 val kotlinClass = invocation.processingEnv.requireTypeElement(
1457 "foo.bar.KotlinClass")
1458 val companionObjects = kotlinClass.getEnclosedTypeElements().filter {
1459 it.isCompanionObject()
1460 }
1461 assertThat(companionObjects.size).isEqualTo(1)
1462 val companionObj = companionObjects.first()
1463 assertThat(companionObj.isKotlinObject()).isTrue()
1464 }
1465 }
1466
Yigit Boyar52828c72020-12-09 12:48:28 -08001467 /**
1468 * it is good to exclude methods coming from Object when testing as they differ between KSP
1469 * and KAPT but irrelevant for Room.
1470 */
1471 private fun XTestInvocation.objectMethodNames() = processingEnv
1472 .requireTypeElement("java.lang.Object")
1473 .getAllMethods()
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001474 .jvmNames()
Yigit Boyar52828c72020-12-09 12:48:28 -08001475
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001476 private fun Sequence<XMethodElement>.jvmNames() = map {
1477 it.jvmName
Yigit Boyarad311f12021-06-28 11:14:26 -07001478 }.toList()
1479
Yigit Boyardd1f1d02021-11-12 23:19:09 -08001480 private fun List<XMethodElement>.jvmNames() = map {
1481 it.jvmName
Yigit Boyarad311f12021-06-28 11:14:26 -07001482 }.toList()
Yigit Boyar3adf1082020-09-15 21:15:57 -07001483}