Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 1 | /* |
| 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 Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 17 | package androidx.room.compiler.processing |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 18 | |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 19 | import androidx.room.compiler.processing.util.Source |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 20 | import androidx.room.compiler.processing.util.XTestInvocation |
Yigit Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 21 | import androidx.room.compiler.processing.util.compileFiles |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 22 | import androidx.room.compiler.processing.util.getAllFieldNames |
| 23 | import androidx.room.compiler.processing.util.getField |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 24 | import androidx.room.compiler.processing.util.getMethodByJvmName |
Yigit Boyar | b90c49e | 2020-12-08 13:38:05 -0800 | [diff] [blame] | 25 | import androidx.room.compiler.processing.util.runProcessorTest |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 26 | import com.google.common.truth.Truth.assertThat |
Yigit Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 27 | import com.google.common.truth.Truth.assertWithMessage |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 28 | import com.squareup.javapoet.ClassName |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 29 | import com.squareup.javapoet.ParameterizedTypeName |
Yigit Boyar | 45550ee | 2020-10-19 09:12:33 -0700 | [diff] [blame] | 30 | import com.squareup.javapoet.TypeName |
| 31 | import com.squareup.javapoet.TypeVariableName |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 32 | import org.junit.Test |
| 33 | import org.junit.runner.RunWith |
| 34 | import org.junit.runners.JUnit4 |
| 35 | |
| 36 | @RunWith(JUnit4::class) |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 37 | class XTypeElementTest { |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 38 | @Test |
| 39 | fun qualifiedNames() { |
| 40 | val src1 = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 41 | "Foo.kt", |
| 42 | """ |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 43 | class TopLevel |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 44 | """.trimIndent() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 45 | ) |
| 46 | val src2 = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 47 | "Bar.kt", |
| 48 | """ |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 49 | package foo.bar |
| 50 | class InFooBar |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 51 | """.trimIndent() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 52 | ) |
Yigit Boyar | 524475f | 2021-02-08 09:49:34 -0800 | [diff] [blame] | 53 | 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 Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 63 | runProcessorTest( |
Yigit Boyar | 524475f | 2021-02-08 09:49:34 -0800 | [diff] [blame] | 64 | sources = listOf(src1, src2, src3) |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 65 | ) { 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 Boyar | 524475f | 2021-02-08 09:49:34 -0800 | [diff] [blame] | 78 | 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 Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 94 | 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 Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | @Test |
| 112 | fun typeAndSuperType() { |
| 113 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 114 | "foo.kt", |
| 115 | """ |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 116 | package foo.bar; |
| 117 | class Baz : MyInterface, AbstractClass() { |
| 118 | } |
| 119 | abstract class AbstractClass {} |
| 120 | interface MyInterface {} |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 121 | """.trimIndent() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 122 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 123 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 124 | 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 Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 136 | 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 Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 146 | 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 Ding | c49bb01 | 2022-01-05 01:44:37 +0000 | [diff] [blame] | 163 | 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 Boyar | c1eb02a | 2022-01-13 16:11:00 -0800 | [diff] [blame] | 177 | val superInterface = it.superInterfaces.first { type -> |
| 178 | type.rawType.toString() == "foo.bar.MyInterface" |
| 179 | } |
Wanying Ding | c49bb01 | 2022-01-05 01:44:37 +0000 | [diff] [blame] | 180 | 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 Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 188 | fun nestedClassName() { |
| 189 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 190 | "Foo.kt", |
| 191 | """ |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 192 | package foo.bar; |
| 193 | class Outer { |
| 194 | class Inner |
| 195 | } |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 196 | """.trimIndent() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 197 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 198 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 199 | invocation.processingEnv.requireTypeElement("foo.bar.Outer").let { |
| 200 | assertThat(it.className).isEqualTo(ClassName.get("foo.bar", "Outer")) |
Wanying Ding | 8be77e3 | 2021-11-24 22:06:44 +0000 | [diff] [blame] | 201 | assertThat(it.isNested()).isFalse() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 202 | 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 Ding | 8be77e3 | 2021-11-24 22:06:44 +0000 | [diff] [blame] | 208 | assertThat(it.isNested()).isTrue() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 209 | assertThat(it.enclosingTypeElement).isEqualTo( |
| 210 | invocation.processingEnv.requireTypeElement("foo.bar.Outer") |
| 211 | ) |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | @Test |
| 217 | fun modifiers() { |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 218 | val kotlinSrc = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 219 | "Foo.kt", |
| 220 | """ |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 221 | open class OpenClass |
| 222 | abstract class AbstractClass |
| 223 | object MyObject |
| 224 | interface MyInterface |
| 225 | class Final |
| 226 | private class PrivateClass |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 227 | class OuterKotlinClass { |
| 228 | inner class InnerKotlinClass |
| 229 | class NestedKotlinClass |
| 230 | } |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 231 | 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 Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 237 | """.trimIndent() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 238 | ) |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 239 | 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 Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 248 | val javaAnnotationSrc = Source.java( |
| 249 | "JavaAnnotation", |
| 250 | """ |
| 251 | public @interface JavaAnnotation { |
| 252 | } |
| 253 | """.trimIndent() |
| 254 | ) |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 255 | runProcessorTest( |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 256 | sources = listOf(kotlinSrc, javaSrc, javaAnnotationSrc) |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 257 | ) { invocation -> |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 258 | 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 Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 266 | 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 Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 272 | if (element.isInterface()) result.add("interface") |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 273 | if (element.isStatic()) result.add("static") |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 274 | if (element.isAnnotationClass()) result.add("annotation") |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 275 | 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 Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 284 | .containsExactly("public", "class") |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 285 | assertThat(getModifiers("AbstractClass")) |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 286 | .containsExactly("abstract", "public", "class") |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 287 | assertThat(getModifiers("MyObject")) |
| 288 | .containsExactly("final", "public", "object") |
| 289 | assertThat(getModifiers("MyInterface")) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 290 | .containsExactly("abstract", "interface", "public") |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 291 | assertThat(getModifiers("Final")) |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 292 | .containsExactly("final", "public", "class") |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 293 | assertThat(getModifiers("PrivateClass")) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 294 | .containsExactlyElementsIn( |
| 295 | if (invocation.isKsp) { |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 296 | listOf("private", "final", "class") |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 297 | } else { |
| 298 | // java does not support top level private classes. |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 299 | listOf("final", "class") |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 300 | } |
| 301 | ) |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 302 | assertThat(getModifiers("OuterKotlinClass.InnerKotlinClass")) |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 303 | .containsExactly("final", "public", "class") |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 304 | assertThat(getModifiers("OuterKotlinClass.NestedKotlinClass")) |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 305 | .containsExactly("final", "public", "static", "class") |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 306 | assertThat(getModifiers("OuterJavaClass.InnerJavaClass")) |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 307 | .containsExactly("public", "class") |
Yigit Boyar | 8af3a3a | 2021-01-05 16:17:49 -0800 | [diff] [blame] | 308 | assertThat(getModifiers("OuterJavaClass.NestedJavaClass")) |
Eli Hart | 6c8b6f8 | 2021-05-17 19:37:41 -0700 | [diff] [blame] | 309 | .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 Boyar | 5cabf8f | 2021-05-20 12:06:55 -0700 | [diff] [blame] | 325 | assertThat(getModifiers("FunInterface")) |
| 326 | .containsExactly("public", "abstract", "interface", "fun") |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 327 | } |
| 328 | } |
| 329 | |
| 330 | @Test |
| 331 | fun kindName() { |
| 332 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 333 | "Foo.kt", |
| 334 | """ |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 335 | class MyClass |
| 336 | interface MyInterface |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 337 | """.trimIndent() |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 338 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 339 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | fc93ae2 | 2020-09-07 11:31:18 -0700 | [diff] [blame] | 340 | 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 Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 348 | |
| 349 | @Test |
| 350 | fun fieldBasic() { |
| 351 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 352 | "Foo.kt", |
| 353 | """ |
Yigit Boyar | 45550ee | 2020-10-19 09:12:33 -0700 | [diff] [blame] | 354 | open class BaseClass<T>(val genericProp : T) { |
| 355 | fun baseMethod(input: T) {} |
| 356 | } |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 357 | class SubClass(x : Int) : BaseClass<Int>(x) { |
| 358 | val subClassProp : String = "abc" |
| 359 | } |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 360 | """.trimIndent() |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 361 | ) |
Yigit Boyar | b90c49e | 2020-12-08 13:38:05 -0800 | [diff] [blame] | 362 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 363 | val baseClass = invocation.processingEnv.requireTypeElement("BaseClass") |
| 364 | assertThat(baseClass.getAllFieldNames()).containsExactly("genericProp") |
Daniel Santiago Rivera | a3deddd | 2021-06-08 13:21:11 -0700 | [diff] [blame] | 365 | assertThat(baseClass.getDeclaredFields().map { it.name }) |
| 366 | .containsExactly("genericProp") |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 367 | val subClass = invocation.processingEnv.requireTypeElement("SubClass") |
| 368 | assertThat(subClass.getAllFieldNames()).containsExactly("genericProp", "subClassProp") |
Daniel Santiago Rivera | a3deddd | 2021-06-08 13:21:11 -0700 | [diff] [blame] | 369 | assertThat(subClass.getDeclaredFields().map { it.name }) |
| 370 | .containsExactly("subClassProp") |
Yigit Boyar | 45550ee | 2020-10-19 09:12:33 -0700 | [diff] [blame] | 371 | |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 372 | val baseMethod = baseClass.getMethodByJvmName("baseMethod") |
Yigit Boyar | 45550ee | 2020-10-19 09:12:33 -0700 | [diff] [blame] | 373 | baseMethod.asMemberOf(subClass.type).let { methodType -> |
| 374 | val genericArg = methodType.parameterTypes.first() |
| 375 | assertThat(genericArg.typeName).isEqualTo(TypeName.INT.box()) |
| 376 | } |
| 377 | |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 378 | baseClass.getField("genericProp").let { field -> |
Yigit Boyar | 54da425 | 2021-11-09 01:26:04 +0000 | [diff] [blame] | 379 | assertThat(field.type.typeName).isEqualTo(TypeVariableName.get("T")) |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 380 | } |
Yigit Boyar | bb533e82 | 2020-11-10 18:23:54 -0800 | [diff] [blame] | 381 | |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 382 | subClass.getField("genericProp").let { field -> |
Yigit Boyar | 45550ee | 2020-10-19 09:12:33 -0700 | [diff] [blame] | 383 | // 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 Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 385 | } |
| 386 | } |
| 387 | } |
| 388 | |
| 389 | @Test |
| 390 | fun fieldsOverride() { |
| 391 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 392 | "Foo.kt", |
| 393 | """ |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 394 | open class BaseClass( |
| 395 | open val value : List<Int> |
| 396 | ) |
| 397 | class SubClass( |
| 398 | override val value : MutableList<Int> |
| 399 | ) : BaseClass(value) |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 400 | """.trimIndent() |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 401 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 402 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 403 | 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 Boyar | 45550ee | 2020-10-19 09:12:33 -0700 | [diff] [blame] | 410 | ParameterizedTypeName.get(List::class.java, Integer::class.java) |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 411 | ) |
| 412 | assertThat( |
| 413 | subClass.getField("value").type.typeName |
| 414 | ).isEqualTo( |
Yigit Boyar | 45550ee | 2020-10-19 09:12:33 -0700 | [diff] [blame] | 415 | ParameterizedTypeName.get(List::class.java, Integer::class.java) |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 416 | ) |
| 417 | } |
| 418 | } |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 419 | |
| 420 | @Test |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 421 | 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 Sproch | 666614b | 2021-08-18 07:43:56 -0700 | [diff] [blame] | 459 | val expectedFields = listOf("realField", "staticRealField") |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 460 | 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 468 | val methodNames = subject.getDeclaredMethods().map { it.jvmName } |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 469 | 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 Sproch | 666614b | 2021-08-18 07:43:56 -0700 | [diff] [blame] | 506 | val expectedFields = listOf("value", "realCompanion", "jvmStatic") |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 507 | assertWithMessage(subject.qualifiedName) |
| 508 | .that(declaredFields) |
| 509 | .containsExactlyElementsIn(expectedFields) |
| 510 | } |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | @Test |
Yigit Boyar | 6cd12c9 | 2021-07-25 09:54:26 -0700 | [diff] [blame] | 515 | 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 538 | .that(subject.getDeclaredMethods().map { it.jvmName }) |
Yigit Boyar | 6cd12c9 | 2021-07-25 09:54:26 -0700 | [diff] [blame] | 539 | .containsExactly( |
| 540 | "getX", "setX", "getY", "setY" |
| 541 | ) |
| 542 | } |
| 543 | } |
| 544 | } |
| 545 | |
| 546 | @Test |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 547 | 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 Boyar | ad311f1 | 2021-06-28 11:14:26 -0700 | [diff] [blame] | 558 | assertThat(element.getAllFieldsIncludingPrivateSupers().toList()).isEmpty() |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 559 | element.getMethodByJvmName("getX").let { |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 560 | assertThat(it.isAbstract()).isTrue() |
| 561 | } |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 562 | element.getMethodByJvmName("setX").let { |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 563 | assertThat(it.isAbstract()).isTrue() |
| 564 | } |
| 565 | } |
| 566 | } |
| 567 | |
| 568 | @Test |
Yigit Boyar | 8da2dbe | 2020-12-15 13:14:28 -0800 | [diff] [blame] | 569 | 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 589 | element.getDeclaredMethods().map { it.jvmName } |
Yigit Boyar | 8da2dbe | 2020-12-15 13:14:28 -0800 | [diff] [blame] | 590 | ).containsExactly( |
| 591 | "getAbstractVar", "setAbstractVar", |
| 592 | "getNonAbstractVar", "setNonAbstractVar" |
| 593 | ) |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 594 | element.getMethodByJvmName("getAbstractVar").let { |
Yigit Boyar | 8da2dbe | 2020-12-15 13:14:28 -0800 | [diff] [blame] | 595 | assertThat(it.isAbstract()).isTrue() |
| 596 | } |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 597 | element.getMethodByJvmName("setAbstractVar").let { |
Yigit Boyar | 8da2dbe | 2020-12-15 13:14:28 -0800 | [diff] [blame] | 598 | assertThat(it.isAbstract()).isTrue() |
| 599 | } |
| 600 | |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 601 | element.getMethodByJvmName("getNonAbstractVar").let { |
Yigit Boyar | 8da2dbe | 2020-12-15 13:14:28 -0800 | [diff] [blame] | 602 | assertThat(it.isAbstract()).isFalse() |
| 603 | } |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 604 | element.getMethodByJvmName("setNonAbstractVar").let { |
Yigit Boyar | 8da2dbe | 2020-12-15 13:14:28 -0800 | [diff] [blame] | 605 | assertThat(it.isAbstract()).isFalse() |
| 606 | } |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | @Test |
Yigit Boyar | e3e9196 | 2021-02-01 16:12:34 -0800 | [diff] [blame] | 611 | 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 Boyar | 985fad5 | 2021-06-29 12:32:16 -0700 | [diff] [blame] | 661 | classpath = dependency |
Yigit Boyar | e3e9196 | 2021-02-01 16:12:34 -0800 | [diff] [blame] | 662 | ) { 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 672 | it.jvmName |
Yigit Boyar | e3e9196 | 2021-02-01 16:12:34 -0800 | [diff] [blame] | 673 | } |
| 674 | ).containsExactly( |
| 675 | "getMutable", "setMutable", "getImmutable" |
| 676 | ) |
| 677 | } |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | @Test |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 682 | fun declaredAndInstanceMethods() { |
| 683 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 684 | "Foo.kt", |
| 685 | """ |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 686 | 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 Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 709 | """.trimIndent() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 710 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 711 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 712 | val base = invocation.processingEnv.requireTypeElement("Base") |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 713 | val objectMethodNames = invocation.objectMethodNames() |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 714 | assertThat(base.getDeclaredMethods().jvmNames()).containsExactly( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 715 | "baseFun", "suspendFun", "privateBaseFun", "staticBaseFun" |
| 716 | ) |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 717 | |
| 718 | val sub = invocation.processingEnv.requireTypeElement("SubClass") |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 719 | assertThat(sub.getDeclaredMethods().jvmNames()).containsExactly( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 720 | "baseFun", "subFun", "privateSubFun", "staticFun" |
| 721 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 722 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 723 | sub.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 724 | ).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 725 | "baseFun", "suspendFun", "subFun" |
| 726 | ) |
| 727 | } |
| 728 | } |
| 729 | |
| 730 | @Test |
Yigit Boyar | f27e38c | 2021-07-08 11:13:50 -0700 | [diff] [blame] | 731 | 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 762 | .getAllMethods().jvmNames() |
Yigit Boyar | f27e38c | 2021-07-08 11:13:50 -0700 | [diff] [blame] | 763 | |
| 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 771 | return "$jvmName($params):${returnType.typeName}" |
Yigit Boyar | f27e38c | 2021-07-08 11:13:50 -0700 | [diff] [blame] | 772 | } |
| 773 | |
| 774 | fun XTypeElement.allMethodSignatures(): List<String> = getAllMethods().filterNot { |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 775 | it.jvmName in objectMethodNames |
Yigit Boyar | f27e38c | 2021-07-08 11:13:50 -0700 | [diff] [blame] | 776 | }.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 |
bcorso | 22aa8a6 | 2021-09-28 12:29:34 -0700 | [diff] [blame] | 807 | 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 829 | .getAllMethods().jvmNames() |
bcorso | 22aa8a6 | 2021-09-28 12:29:34 -0700 | [diff] [blame] | 830 | 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 837 | return "$jvmName($params):${returnType.typeName}" |
bcorso | 22aa8a6 | 2021-09-28 12:29:34 -0700 | [diff] [blame] | 838 | } |
| 839 | |
| 840 | fun XTypeElement.allMethodSignatures(): List<String> = getAllMethods().filterNot { |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 841 | it.jvmName in objectMethodNames |
bcorso | 22aa8a6 | 2021-09-28 12:29:34 -0700 | [diff] [blame] | 842 | }.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 | |
bcorso | 22aa8a6 | 2021-09-28 12:29:34 -0700 | [diff] [blame] | 854 | invocation.processingEnv.requireTypeElement( |
| 855 | "ParentWithoutExplicitOverride" |
| 856 | ).let { parent -> |
| 857 | assertWithMessage(parent.qualifiedName).that( |
| 858 | parent.allMethodSignatures() |
| 859 | ).containsExactly( |
bcorso | 22aa8a6 | 2021-09-28 12:29:34 -0700 | [diff] [blame] | 860 | "child():Child" |
| 861 | ) |
| 862 | } |
| 863 | } |
| 864 | } |
| 865 | |
| 866 | @Test |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 867 | fun allMethods() { |
| 868 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 869 | "Foo.kt", |
| 870 | """ |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 871 | 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 Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 902 | """.trimIndent() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 903 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 904 | runProcessorTest(sources = listOf(src)) { invocation -> |
| 905 | val objectMethodNames = invocation.objectMethodNames() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 906 | val klass = invocation.processingEnv.requireTypeElement("SubClass") |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 907 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 908 | klass.getAllMethods().jvmNames() - objectMethodNames |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 909 | ).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 910 | "baseMethod", "overriddenMethod", "baseCompanionMethod", |
| 911 | "interfaceMethod", "subMethod", "privateSubMethod", "subCompanionMethod" |
| 912 | ) |
| 913 | } |
| 914 | } |
| 915 | |
Yigit Boyar | c1eb02a | 2022-01-13 16:11:00 -0800 | [diff] [blame] | 916 | /** |
| 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 Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 980 | @Test |
| 981 | fun gettersSetters() { |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 982 | val src = Source.kotlin( |
| 983 | "Foo.kt", |
| 984 | """ |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 985 | 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 Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 993 | """.trimIndent() |
| 994 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 995 | runProcessorTest(sources = listOf(src)) { invocation -> |
| 996 | val objectMethodNames = invocation.objectMethodNames() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 997 | invocation.processingEnv.requireTypeElement("JustGetter").let { base -> |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 998 | assertThat(base.getDeclaredMethods().jvmNames()).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 999 | "getX" |
| 1000 | ) |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1001 | assertThat(base.getAllMethods().jvmNames() - objectMethodNames).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1002 | "getX" |
| 1003 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1004 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1005 | base.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1006 | ).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1007 | "getX" |
| 1008 | ) |
| 1009 | } |
| 1010 | invocation.processingEnv.requireTypeElement("GetterSetter").let { sub -> |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1011 | assertThat(sub.getDeclaredMethods().jvmNames()).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1012 | "getY", "setY" |
| 1013 | ) |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1014 | assertThat(sub.getAllMethods().jvmNames() - objectMethodNames).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1015 | "getX", "getY", "setY" |
| 1016 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1017 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1018 | sub.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1019 | ).containsExactly( |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1020 | "getX", "getY", "setY" |
| 1021 | ) |
| 1022 | } |
| 1023 | } |
| 1024 | } |
| 1025 | |
| 1026 | @Test |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1027 | fun companion() { |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1028 | val src = Source.kotlin( |
| 1029 | "Foo.kt", |
| 1030 | """ |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1031 | 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 Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1038 | @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 Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1048 | } |
| 1049 | } |
| 1050 | class SubClass : CompanionSubject() |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1051 | """.trimIndent() |
| 1052 | ) |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1053 | runProcessorTest(sources = listOf(src)) { invocation -> |
| 1054 | val objectMethodNames = invocation.processingEnv.requireTypeElement( |
| 1055 | Any::class |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1056 | ).getAllMethods().jvmNames() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1057 | val subject = invocation.processingEnv.requireTypeElement("CompanionSubject") |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1058 | assertThat(subject.getAllFieldNames() - "Companion").containsExactly( |
| 1059 | "mutableStatic", "immutableStatic", "companionProp", |
| 1060 | "companionProp_getterJvmStatic", "companionProp_setterJvmStatic" |
Yigit Boyar | 08a2716 | 2020-11-25 09:39:31 -0800 | [diff] [blame] | 1061 | ) |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1062 | val expectedMethodNames = listOf( |
| 1063 | "getMutableStatic", "setMutableStatic", "getImmutableStatic", |
| 1064 | "getCompanionProp_getterJvmStatic", "setCompanionProp_setterJvmStatic", |
| 1065 | "companionMethodWithJvmStatic" |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1066 | ) |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1067 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1068 | subject.getDeclaredMethods().jvmNames() |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1069 | ).containsExactlyElementsIn( |
| 1070 | expectedMethodNames |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1071 | ) |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1072 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1073 | subject.getAllMethods().jvmNames() - objectMethodNames |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1074 | ).containsExactlyElementsIn( |
| 1075 | expectedMethodNames |
| 1076 | ) |
| 1077 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1078 | subject.getAllNonPrivateInstanceMethods().jvmNames() - objectMethodNames |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1079 | ).isEmpty() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1080 | val subClass = invocation.processingEnv.requireTypeElement("SubClass") |
| 1081 | assertThat(subClass.getDeclaredMethods()).isEmpty() |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1082 | assertThat( |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1083 | subClass.getAllMethods().jvmNames() - objectMethodNames |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1084 | ).containsExactlyElementsIn( |
| 1085 | expectedMethodNames |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1086 | ) |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1087 | |
| 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1093 | assertWithMessage(it.jvmName).that(it.isStatic()).isTrue() |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1094 | } |
| 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1109 | throw AssertionError("Couldn't run asMemberOf for ${it.jvmName}") |
Yigit Boyar | 54a407a | 2021-06-23 18:59:22 -0700 | [diff] [blame] | 1110 | } |
| 1111 | } |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1112 | } |
| 1113 | } |
| 1114 | |
| 1115 | @Test |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1116 | fun gettersSetters_interface() { |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1117 | val src = Source.kotlin( |
| 1118 | "Foo.kt", |
| 1119 | """ |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1120 | interface JustGetter { |
| 1121 | val x:Int |
| 1122 | } |
| 1123 | interface GetterSetter : JustGetter { |
| 1124 | var y:Int |
| 1125 | } |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1126 | """.trimIndent() |
| 1127 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1128 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1129 | invocation.processingEnv.requireTypeElement("JustGetter").let { base -> |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1130 | assertThat(base.getDeclaredMethods().jvmNames()).containsExactly( |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1131 | "getX" |
| 1132 | ) |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1133 | assertThat(base.getAllMethods().jvmNames()).containsExactly( |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1134 | "getX" |
| 1135 | ) |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1136 | assertThat(base.getAllNonPrivateInstanceMethods().jvmNames()).containsExactly( |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1137 | "getX" |
| 1138 | ) |
| 1139 | } |
| 1140 | invocation.processingEnv.requireTypeElement("GetterSetter").let { sub -> |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1141 | assertThat(sub.getDeclaredMethods().jvmNames()).containsExactly( |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1142 | "getY", "setY" |
| 1143 | ) |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1144 | assertThat(sub.getAllMethods().jvmNames()).containsExactly( |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1145 | "getX", "getY", "setY" |
| 1146 | ) |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1147 | assertThat(sub.getAllNonPrivateInstanceMethods().jvmNames()).containsExactly( |
Yigit Boyar | 0ce2f64 | 2020-09-30 17:21:08 -0700 | [diff] [blame] | 1148 | "getX", "getY", "setY" |
| 1149 | ) |
| 1150 | } |
| 1151 | } |
| 1152 | } |
| 1153 | |
| 1154 | @Test |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1155 | fun constructors() { |
| 1156 | val src = Source.kotlin( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1157 | "Foo.kt", |
| 1158 | """ |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1159 | interface MyInterface |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1160 | class NoExplicitConstructor |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1161 | 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 Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1173 | abstract class AbstractNoExplicit |
| 1174 | abstract class AbstractExplicit(x:Int) |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1175 | """.trimIndent() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1176 | ) |
Yigit Boyar | b90c49e | 2020-12-08 13:38:05 -0800 | [diff] [blame] | 1177 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1178 | val subjects = listOf( |
| 1179 | "MyInterface", "NoExplicitConstructor", "Base", "ExplicitConstructor", |
| 1180 | "BaseWithSecondary", "Sub", "SubWith3Constructors", |
| 1181 | "AbstractNoExplicit", "AbstractExplicit" |
| 1182 | ) |
| 1183 | val constructorCounts = subjects.map { |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1184 | it to invocation.processingEnv.requireTypeElement(it).getConstructors().size |
| 1185 | } |
| 1186 | assertThat(constructorCounts) |
| 1187 | .containsExactly( |
| 1188 | "MyInterface" to 0, |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1189 | "NoExplicitConstructor" to 1, |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1190 | "Base" to 1, |
| 1191 | "ExplicitConstructor" to 1, |
| 1192 | "BaseWithSecondary" to 2, |
| 1193 | "Sub" to 1, |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1194 | "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 Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1217 | ) |
| 1218 | } |
| 1219 | } |
| 1220 | |
| 1221 | @Test |
| 1222 | fun jvmDefault() { |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1223 | val src = Source.kotlin( |
| 1224 | "Foo.kt", |
| 1225 | """ |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1226 | interface MyInterface { |
| 1227 | fun notJvmDefault() |
| 1228 | @JvmDefault |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1229 | fun jvmDefault() {} |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1230 | } |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1231 | """.trimIndent() |
| 1232 | ) |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1233 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1234 | val subject = invocation.processingEnv.requireTypeElement("MyInterface") |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1235 | assertThat(subject.getMethodByJvmName("notJvmDefault").isJavaDefault()).isFalse() |
| 1236 | assertThat(subject.getMethodByJvmName("jvmDefault").isJavaDefault()).isTrue() |
Yigit Boyar | 3c4adc6 | 2020-09-17 13:29:47 -0700 | [diff] [blame] | 1237 | } |
| 1238 | } |
| 1239 | |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1240 | @Test |
| 1241 | fun constructors_java() { |
| 1242 | val src = Source.java( |
Jeff Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1243 | "Source", |
| 1244 | """ |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1245 | 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 Gaston | 63c2310 | 2020-09-18 12:53:59 -0400 | [diff] [blame] | 1278 | """.trimIndent() |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1279 | ) |
Yigit Boyar | b90c49e | 2020-12-08 13:38:05 -0800 | [diff] [blame] | 1280 | runProcessorTest(sources = listOf(src)) { invocation -> |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1281 | 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 Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 1303 | assertWithMessage(it) |
Yigit Boyar | b45f9cc | 2020-10-01 14:52:49 -0700 | [diff] [blame] | 1304 | .that(invocation.processingEnv.requireTypeElement(it).findPrimaryConstructor()) |
| 1305 | .isNull() |
| 1306 | } |
| 1307 | } |
| 1308 | } |
| 1309 | |
Yigit Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 1310 | @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 Boyar | e3e9196 | 2021-02-01 16:12:34 -0800 | [diff] [blame] | 1343 | |
Yigit Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 1344 | val classpath = compileFiles( |
| 1345 | createSources("lib") |
| 1346 | ) |
| 1347 | runProcessorTest( |
| 1348 | sources = createSources("app"), |
Yigit Boyar | 985fad5 | 2021-06-29 12:32:16 -0700 | [diff] [blame] | 1349 | classpath = classpath |
Yigit Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 1350 | ) { 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1360 | .that(typeElement.getDeclaredMethods().map { it.jvmName }) |
Yigit Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 1361 | .run { |
| 1362 | contains("enumMethod") |
| 1363 | containsNoneOf("VAL1", "VAL2") |
| 1364 | } |
Yigit Boyar | 1d5ffb6 | 2021-01-08 11:47:10 -0800 | [diff] [blame] | 1365 | assertWithMessage("$qName can return enum constants") |
Eli Hart | 21aacea | 2021-06-09 11:55:33 -0500 | [diff] [blame] | 1366 | .that((typeElement as XEnumTypeElement).entries.map { it.name }) |
Yigit Boyar | 1d5ffb6 | 2021-01-08 11:47:10 -0800 | [diff] [blame] | 1367 | .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 Boyar | 6ab4a1f | 2021-06-30 09:53:33 -0700 | [diff] [blame] | 1374 | assertWithMessage("$qName does not report enum constants in declared fields") |
| 1375 | .that(typeElement.getDeclaredFields().map { it.name }) |
| 1376 | .containsExactly("x") |
Yigit Boyar | e16d1bb | 2021-01-05 14:54:45 -0800 | [diff] [blame] | 1377 | } |
| 1378 | } |
| 1379 | } |
| 1380 | |
Eli Hart | 29da963 | 2021-06-05 12:41:09 -0700 | [diff] [blame] | 1381 | @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 Chou | 125ea92 | 2022-01-24 18:05:12 +0000 | [diff] [blame] | 1443 | @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 Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1467 | /** |
| 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 Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1474 | .jvmNames() |
Yigit Boyar | 52828c7 | 2020-12-09 12:48:28 -0800 | [diff] [blame] | 1475 | |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1476 | private fun Sequence<XMethodElement>.jvmNames() = map { |
| 1477 | it.jvmName |
Yigit Boyar | ad311f1 | 2021-06-28 11:14:26 -0700 | [diff] [blame] | 1478 | }.toList() |
| 1479 | |
Yigit Boyar | dd1f1d0 | 2021-11-12 23:19:09 -0800 | [diff] [blame] | 1480 | private fun List<XMethodElement>.jvmNames() = map { |
| 1481 | it.jvmName |
Yigit Boyar | ad311f1 | 2021-06-28 11:14:26 -0700 | [diff] [blame] | 1482 | }.toList() |
Yigit Boyar | 3adf108 | 2020-09-15 21:15:57 -0700 | [diff] [blame] | 1483 | } |