[go: nahoru, domu]

blob: a6e15517e8792512a503d8ee5511f32cfd13a151 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.room.compiler.processing.ksp
import androidx.kruth.assertThat
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.className
import androidx.room.compiler.processing.util.getField
import androidx.room.compiler.processing.util.getMethodByJvmName
import androidx.room.compiler.processing.util.runKspTest
import androidx.room.compiler.processing.util.runProcessorTest
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.WildcardTypeName
import org.junit.Test
class KSAsMemberOfTest {
@Test
fun asMemberOfInheritance() {
val src = Source.kotlin(
"Foo.kt",
"""
open class BaseClass<T, R>(val genericProp : T) {
val normalInt:Int = 3
val listOfGeneric : List<T> = TODO()
val mapOfStringToGeneric2 : Map<String, R> = TODO()
val pairOfGenerics : Pair<T, R> = TODO()
}
class SubClass(x : Int) : BaseClass<Int, List<String>>(x) {
val subClassProp : String = "abc"
}
""".trimIndent()
)
runProcessorTest(sources = listOf(src)) { invocation ->
val base = invocation.processingEnv.requireTypeElement("BaseClass")
val sub = invocation.processingEnv.requireType("SubClass")
base.getField("normalInt").let { prop ->
assertThat(
prop.asMemberOf(sub).typeName
).isEqualTo(
TypeName.INT
)
}
base.getField("genericProp").let { prop ->
assertThat(
prop.asMemberOf(sub).typeName
).isEqualTo(
TypeName.INT.box()
)
}
base.getField("listOfGeneric").let { prop ->
assertThat(
prop.asMemberOf(sub).typeName
).isEqualTo(
ParameterizedTypeName.get(
List::class.className(),
TypeName.INT.box()
)
)
}
val listOfStringsTypeName =
ParameterizedTypeName.get(
List::class.className(),
WildcardTypeName.subtypeOf(String::class.className())
)
base.getField("mapOfStringToGeneric2").let { prop ->
assertThat(
prop.asMemberOf(sub).typeName
).isEqualTo(
ParameterizedTypeName.get(
Map::class.className(),
String::class.className(),
listOfStringsTypeName
)
)
}
base.getField("pairOfGenerics").let { prop ->
assertThat(
prop.asMemberOf(sub).typeName
).isEqualTo(
ParameterizedTypeName.get(
Pair::class.className(),
TypeName.INT.box(), listOfStringsTypeName
)
)
}
}
}
@Test
fun asMemberOfNullabilityResolution() {
val src = Source.kotlin(
"Foo.kt",
"""
open class MyInterface<T> {
val inheritedProp: T = TODO()
var nullableProp: T? = TODO()
val inheritedGenericProp: List<T> = TODO()
val nullableGenericProp: List<T?> = TODO()
}
abstract class NonNullSubject : MyInterface<String>()
abstract class NullableSubject: MyInterface<String?>()
""".trimIndent()
)
runKspTest(sources = listOf(src)) { invocation ->
val myInterface = invocation.processingEnv.requireTypeElement("MyInterface")
val nonNullSubject = invocation.processingEnv.requireType("NonNullSubject")
val nullableSubject = invocation.processingEnv.requireType("NullableSubject")
val inheritedProp = myInterface.getField("inheritedProp")
assertThat(
inheritedProp.asMemberOf(nonNullSubject).nullability
).isEqualTo(XNullability.NONNULL)
assertThat(
inheritedProp.asMemberOf(nullableSubject).nullability
).isEqualTo(XNullability.NULLABLE)
val nullableProp = myInterface.getField("nullableProp")
assertThat(
nullableProp.asMemberOf(nonNullSubject).nullability
).isEqualTo(XNullability.NULLABLE)
assertThat(
nullableProp.asMemberOf(nullableSubject).nullability
).isEqualTo(XNullability.NULLABLE)
val inheritedGenericProp = myInterface.getField("inheritedGenericProp")
inheritedGenericProp.asMemberOf(nonNullSubject).let {
assertThat(it.nullability).isEqualTo(XNullability.NONNULL)
assertThat(
it.typeArguments.first().nullability
).isEqualTo(XNullability.NONNULL)
}
inheritedGenericProp.asMemberOf(nullableSubject).let {
assertThat(it.nullability).isEqualTo(XNullability.NONNULL)
assertThat(
it.typeArguments.first().nullability
).isEqualTo(XNullability.NULLABLE)
}
val nullableGenericProp = myInterface.getField("nullableGenericProp")
nullableGenericProp.asMemberOf(nonNullSubject).let {
assertThat(it.nullability).isEqualTo(XNullability.NONNULL)
assertThat(
it.typeArguments.first().nullability
).isEqualTo(XNullability.NULLABLE)
}
nullableGenericProp.asMemberOf(nullableSubject).let {
assertThat(it.nullability).isEqualTo(XNullability.NONNULL)
assertThat(
it.typeArguments.first().nullability
).isEqualTo(XNullability.NULLABLE)
}
}
}
@Test
fun asMemberOfStatics() {
val kotlinSrc = Source.kotlin(
"KotlinClass.kt",
"""
class KotlinClass {
companion object {
@JvmStatic
var staticProp: String = ""
@JvmStatic
fun staticFun(x:Int) {}
}
}
""".trimIndent()
)
val javaSrc = Source.java(
"JavaClass",
"""
class JavaClass {
void staticFun(int x) {}
static String staticProp;
}
""".trimIndent()
)
runKspTest(sources = listOf(kotlinSrc, javaSrc)) { invocation ->
listOf("KotlinClass", "JavaClass").forEach {
val typeElement = invocation.processingEnv.requireTypeElement(it)
typeElement.getMethodByJvmName("staticFun").let { staticFun ->
val asMember = staticFun.asMemberOf(typeElement.type)
assertThat(asMember.returnType.typeName).isEqualTo(TypeName.VOID)
assertThat(
asMember.parameterTypes.single().typeName
).isEqualTo(TypeName.INT)
// different codepath, execute it as well
assertThat(
staticFun.parameters.single().asMemberOf(typeElement.type).typeName
).isEqualTo(TypeName.INT)
}
typeElement.getField("staticProp").let { staticProp ->
assertThat(
staticProp.asMemberOf(typeElement.type).typeName
).isEqualTo(
ClassName.get(String::class.java)
)
}
}
}
}
}