[Commonizer] Implement basic tests for CirTree deserializers

This commit is contained in:
sebastian.sellmair
2021-03-29 18:26:01 +02:00
parent 8c941fc203
commit c03d995e07
6 changed files with 672 additions and 0 deletions
@@ -0,0 +1,163 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.tree.deserializer
import com.intellij.openapi.util.io.FileUtil
import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.common.CommonDependenciesContainer
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.commonizer.mergedtree.CirFictitiousFunctionClassifiers
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.*
import org.jetbrains.kotlin.commonizer.utils.MockModulesProvider
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.test.util.KtTestUtil
import java.io.File
abstract class AbstractCirTreeDeserializerTest : KtUsefulTestCase() {
annotation class ModuleBuilderDsl
data class SourceFile(val name: String, @Language("kotlin") val content: String)
data class Module(val name: String, val sourceFiles: List<SourceFile>)
@ModuleBuilderDsl
class ModuleBuilder {
var name: String = "test-module"
var sourceFiles: List<SourceFile> = emptyList()
fun source(name: String = "test.kt", @Language("kotlin") content: String) {
sourceFiles = sourceFiles + SourceFile(name, content)
}
fun build() = Module(name, sourceFiles.toList())
}
@ModuleBuilderDsl
fun module(builder: ModuleBuilder.() -> Unit): Module {
return ModuleBuilder().also(builder).build()
}
fun deserializeModule(builder: ModuleBuilder.() -> Unit): CirTreeModule {
val module = module(builder)
val moduleFolder = FileUtil.createTempDirectory(module.name, null)
module.sourceFiles.forEach { sourceFile ->
moduleFolder.resolve(sourceFile.name).writeText(sourceFile.content)
}
val moduleDescriptor = createModuleDescriptor(moduleFolder, module)
val metadata = MockModulesProvider.SERIALIZER.serializeModule(moduleDescriptor)
val typeResolver = CirTypeResolver.create(
CirProvidedClassifiers.of(
CirFictitiousFunctionClassifiers,
CirProvidedClassifiers.by(MockModulesProvider.create(moduleDescriptor)),
CirProvidedClassifiers.by(MockModulesProvider.create(DefaultBuiltIns.Instance.builtInsModule))
)
)
return defaultCirTreeModuleDeserializer(metadata, typeResolver)
}
fun deserializeSourceFile(@Language("kotlin") sourceFileContent: String): CirTreeModule {
return deserializeModule {
source("test.kt", content = sourceFileContent)
}
}
private fun createModuleDescriptor(moduleRoot: File, module: Module): ModuleDescriptor {
check(Name.isValidIdentifier(module.name))
val configuration = KotlinTestUtils.newConfiguration()
configuration.put(CommonConfigurationKeys.MODULE_NAME, module.name)
val environment: KotlinCoreEnvironment = KotlinCoreEnvironment.createForTests(
parentDisposable = testRootDisposable,
initialConfiguration = configuration,
extensionConfigs = EnvironmentConfigFiles.METADATA_CONFIG_FILES
)
val psiFactory = KtPsiFactory(environment.project)
val psiFiles: List<KtFile> = moduleRoot.walkTopDown()
.filter { it.isFile }
.map { psiFactory.createFile(it.name, KtTestUtil.doLoadFile(it)) }
.toList()
return CommonResolverForModuleFactory.analyzeFiles(
files = psiFiles,
moduleName = Name.special("<${module.name}>"),
dependOnBuiltIns = true,
languageVersionSettings = environment.configuration.languageVersionSettings,
targetPlatform = CommonPlatforms.defaultCommonPlatform,
targetEnvironment = CompilerEnvironment,
dependenciesContainer = DependenciesContainerImpl(),
) { content ->
environment.createPackagePartProvider(content.moduleContentScope)
}.moduleDescriptor
}
private class DependenciesContainerImpl : CommonDependenciesContainer {
private object DefaultBuiltInsModuleInfo : ModuleInfo {
override val name get() = DefaultBuiltIns.Instance.builtInsModule.name
override fun dependencies() = listOf(this)
override fun dependencyOnBuiltIns() = ModuleInfo.DependencyOnBuiltIns.LAST
override val platform get() = CommonPlatforms.defaultCommonPlatform
override val analyzerServices get() = CommonPlatformAnalyzerServices
}
override val moduleInfos: List<ModuleInfo> get() = listOf(DefaultBuiltInsModuleInfo)
override val friendModuleInfos: List<ModuleInfo> get() = emptyList()
override val refinesModuleInfos: List<ModuleInfo> get() = emptyList()
override fun registerDependencyForAllModules(moduleInfo: ModuleInfo, descriptorForModule: ModuleDescriptorImpl) = Unit
override fun packageFragmentProviderForModuleInfo(moduleInfo: ModuleInfo): PackageFragmentProvider? = null
override fun moduleDescriptorForModuleInfo(moduleInfo: ModuleInfo): ModuleDescriptor {
check(moduleInfo == DefaultBuiltInsModuleInfo) { "Unknown module info $moduleInfo" }
return DefaultBuiltIns.Instance.builtInsModule
}
}
protected fun CirTreeModule.assertSinglePackage(): CirTreePackage {
return packages.singleOrNull()
?: kotlin.test.fail("Expected single package. Found ${packages.map { it.pkg.packageName }}")
}
protected fun CirTreeModule.assertSingleProperty(): CirTreeProperty {
return assertSinglePackage().properties.singleOrNull()
?: kotlin.test.fail("Expected single property. Found ${assertSinglePackage().properties.map { it.property.name }}")
}
protected fun CirTreeModule.assertSingleFunction(): CirTreeFunction {
return assertSinglePackage().functions.singleOrNull()
?: kotlin.test.fail("Expected single property. Found ${assertSinglePackage().functions.map { it.function.name }}")
}
protected fun CirTreeModule.assertSingleClass(): CirTreeClass {
return assertSinglePackage().classes.singleOrNull()
?: kotlin.test.fail("Expected single class. Found ${assertSinglePackage().classes.map { it.clazz.name }}")
}
protected fun CirTreeModule.assertSingleTypeAlias(): CirTreeTypeAlias {
return assertSinglePackage().typeAliases.singleOrNull()
?: kotlin.test.fail("Expected single type alias. Found ${assertSinglePackage().typeAliases.map { it.typeAlias.name }}")
}
}
@@ -0,0 +1,176 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.tree.deserializer
import org.jetbrains.kotlin.commonizer.cir.CirClassType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import kotlin.test.*
class CirTreeClassDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test simple class`() {
val module = deserializeSourceFile("class X")
val clazz = module.assertSingleClass().clazz
assertEquals(Visibilities.Public, clazz.visibility, "Expected class to be public")
assertNull(clazz.companion, "Expected class *not* having a companion")
assertFalse(clazz.isInner, "Expected class *not* being inner")
assertFalse(clazz.isCompanion, "Expected class *not* being companion")
assertFalse(clazz.isExternal, "Expected class *not* being external")
assertFalse(clazz.isValue, "Expected class *not* being value")
assertFalse(clazz.isData, "Expected class *not* being data class")
assertTrue(clazz.supertypes.isEmpty(), "Expected class not having any explicit supertypes")
assertEquals(Modality.FINAL, clazz.modality, "Expected class to be final")
assertEquals(ClassKind.CLASS, clazz.kind)
}
fun `test nested class`() {
val module = deserializeSourceFile(
"""
class Outer {
class Inner
}
"""
)
val pkg = module.assertSinglePackage()
val outerClass = pkg.classes.singleOrNull() ?: kotlin.test.fail("Expected single class in package")
assertEquals("Outer", outerClass.clazz.name.toStrippedString())
val innerClass = outerClass.classes.singleOrNull() ?: kotlin.test.fail("Expected single nested class 'Inner'")
assertFalse(innerClass.clazz.isInner, "Expected nested class to *not* be inner")
}
fun `test inner class`() {
val module = deserializeSourceFile(
"""
class Outer {
inner class Inner
}
"""
)
val pkg = module.assertSinglePackage()
val outerClass = pkg.classes.singleOrNull() ?: kotlin.test.fail("Expected single class in package")
assertEquals("Outer", outerClass.clazz.name.toStrippedString())
val innerClass = outerClass.classes.singleOrNull() ?: kotlin.test.fail("Expected single nested class 'Inner'")
assertTrue(innerClass.clazz.isInner, "Expected nested class to be inner class")
}
fun `test data class`() {
val module = deserializeSourceFile("data class X(val x: String)")
val clazz = module.assertSingleClass()
assertTrue(clazz.clazz.isData, "Expected is data class")
assertEquals(1, clazz.constructors.size, "Expected single constructor")
assertEquals(1, clazz.properties.size, "Expected single property")
}
fun `test companion`() {
val module = deserializeSourceFile(
"""
class Outer {
companion object {
val x: Int = 42
}
}
""".trimIndent()
)
val clazz = module.assertSingleClass()
val companion = clazz.classes.singleOrNull() ?: kotlin.test.fail("Expected single class in 'Outer'")
assertTrue(companion.clazz.isCompanion, "Expected companion being marked as companion")
assertEquals(1, companion.properties.size, "Expected exactly one property in companion")
}
fun `test object`() {
val module = deserializeSourceFile("object X")
val clazz = module.assertSingleClass()
assertEquals(ClassKind.OBJECT, clazz.clazz.kind, "Expected object class kind")
}
fun `test interface`() {
val module = deserializeSourceFile("interface X")
val clazz = module.assertSingleClass()
assertEquals(ClassKind.INTERFACE, clazz.clazz.kind)
}
fun `test supertypes`() {
val module = deserializeSourceFile(
"""
interface A
interface B: A
interface C: B
class X: C
""".trimIndent()
)
val pkg = module.assertSinglePackage()
val xClass = pkg.classes.singleOrNull { it.clazz.name.toStrippedString() == "X" } ?: kotlin.test.fail("Missing class 'X'")
val xSuperType = xClass.clazz.supertypes.singleOrNull() ?: kotlin.test.fail("Expected single supertype for 'X'")
val xClassSuperType = assertIs<CirClassType>(xSuperType, "Expected xSuperType to be class type")
assertEquals("/C", xClassSuperType.classifierId.toString())
}
fun `test abstract class`() {
val module = deserializeSourceFile("abstract class X")
val clazz = module.assertSingleClass()
assertEquals(Modality.ABSTRACT, clazz.clazz.modality)
}
fun `test open class`() {
val module = deserializeSourceFile("open class X")
val clazz = module.assertSingleClass()
assertEquals(Modality.OPEN, clazz.clazz.modality)
}
fun `test class with properties functions and nested classes`() {
val module = deserializeSourceFile(
"""
class X {
val myInt: Int = 42
val myFloat: Float = 42f
val myDouble: Double = 42.0
val myString = "hello"
fun myIntFunction(int: Int) = int
fun myStringFunction(string: String) = string
class MyInnerClass1
class MyInnerClass2
}
""".trimIndent()
)
val clazz = module.assertSingleClass()
fun assertContainsProperty(name: String) {
clazz.properties.singleOrNull { it.property.name.toStrippedString() == name }
?: kotlin.test.fail("Missing property '$name'")
}
fun assertContainsFunction(name: String) {
clazz.functions.singleOrNull { it.function.name.toStrippedString() == name }
?: kotlin.test.fail("Missing function '$name'")
}
fun assertContainsClass(name: String) {
clazz.classes.singleOrNull { it.clazz.name.toStrippedString() == name }
?: kotlin.test.fail("Missing class '$name'")
}
assertContainsProperty("myInt")
assertContainsProperty("myFloat")
assertContainsProperty("myDouble")
assertContainsProperty("myString")
assertContainsFunction("myIntFunction")
assertContainsFunction("myStringFunction")
assertContainsClass("MyInnerClass1")
assertContainsClass("MyInnerClass2")
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.tree.deserializer
import org.jetbrains.kotlin.commonizer.cir.CirClass
import org.jetbrains.kotlin.commonizer.cir.CirClassType
import org.jetbrains.kotlin.commonizer.cir.CirTypeParameterType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import kotlin.test.*
class CirTreeFunctionDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test simple function`() {
val module = deserializeSourceFile("fun x() = Unit")
val (_, function) = module.assertSingleFunction()
assertNull(function.containingClass, "Expected function to *not* have containing class")
assertEquals(Visibilities.Public, function.visibility, "Expected function to be public")
val returnType = function.returnType as? CirClassType ?: kotlin.test.fail("Expected return type being class")
assertFalse(returnType.isMarkedNullable, "Expected return type *not* being marked nullable")
assertEquals("kotlin/Unit", returnType.classifierId.toString())
assertEquals(Modality.FINAL, function.modality, "Expected function to be final")
assertNull(function.extensionReceiver, "Expected *no* extension receiver")
}
fun `test generic function`() {
val module = deserializeSourceFile("""fun <T: Any> T.isHappy(): Boolean = true""")
val (_, function) = module.assertSingleFunction()
val extensionReceiver = assertNotNull(function.extensionReceiver, "Expected function being extension receiver")
val extensionReceiverType = extensionReceiver.type as? CirTypeParameterType
?: kotlin.test.fail("Expected receiver type ${CirTypeParameterType::class.simpleName}")
assertFalse(extensionReceiverType.isMarkedNullable, "Expected extensionReceiverType *not* being marked nullable")
val typeParameter = function.typeParameters.singleOrNull()
?: kotlin.test.fail("Expected a single type parameter. Found ${function.typeParameters}")
assertFalse(typeParameter.isReified, "Expected type parameter *not* being reified")
val upperBound = assertIs<CirClassType>(
typeParameter.upperBounds.singleOrNull()
?: kotlin.test.fail("Expected a single upper bound. Found ${typeParameter.upperBounds}")
)
assertFalse(upperBound.isMarkedNullable, "Expected upper bound *not* being marked nullable")
assertEquals("kotlin/Any", upperBound.toString())
}
fun `test function with outer object`() {
val module = deserializeSourceFile(
"""
object Parent {
fun x(): String = "Hello, you're reading a test"
}
"""
)
val parent = module.assertSingleClass()
val function = parent.functions.singleOrNull()?.function
?: kotlin.test.fail("Expected single function in parent. Found ${parent.functions.map { it.function.name }}")
val containingClass = assertIs<CirClass>(kotlin.test.assertNotNull(function.containingClass))
assertEquals(ClassKind.OBJECT, containingClass.kind, "Expected containing class being object")
assertEquals("Parent", containingClass.name.toStrippedString())
}
}
@@ -0,0 +1,118 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.tree.deserializer
class CirTreePackageDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test package with multiple classes properties and functions`() {
val module = deserializeModule {
source(
"root.kt", """
typealias rootTypeAlias = Int
val rootProperty: String = "hello,"
fun rootFunction(): String = "it is me"
class RootClass
""".trimIndent()
)
source(
"pkg1.kt", """
package test.pkg1
typealias pkg1TypeAlias = Int
val pkg1Property: Int = 42
fun pkg1Function(): String = "answer"
class Pkg1
""".trimIndent()
)
source(
"pkg2.kt", """
package test.pkg2
typealias pkg2TypeAlias = Int
val pkg2Property: Int = 42
fun pkg2Function(): String = "answer"
class Pkg2
""".trimIndent()
)
}
val rootPackage = module.packages.singleOrNull { it.pkg.packageName.isRoot() }
?: kotlin.test.fail("Missing root package")
val pkg1 = module.packages.singleOrNull { it.pkg.packageName.toMetadataString() == "test/pkg1" }
?: kotlin.test.fail("Missing pkg1")
val pkg2 = module.packages.singleOrNull { it.pkg.packageName.toMetadataString() == "test/pkg2" }
?: kotlin.test.fail("Missing pkg2")
rootPackage.run {
kotlin.test.assertTrue(
typeAliases.any { it.typeAlias.name.toStrippedString() == "rootTypeAlias" },
"Expected 'rootTypeAlias'"
)
kotlin.test.assertTrue(
properties.any { it.property.name.toStrippedString() == "rootProperty" },
"Expected 'rootProperty'"
)
kotlin.test.assertTrue(
functions.any { it.function.name.toStrippedString() == "rootFunction" },
"Expected 'rootFunction'"
)
kotlin.test.assertTrue(
classes.any { it.clazz.name.toStrippedString() == "RootClass" },
"Expected 'RootClass'"
)
}
pkg1.run {
kotlin.test.assertTrue(
typeAliases.any { it.typeAlias.name.toStrippedString() == "pkg1TypeAlias" },
"Expected 'pkg1TypeAlias'"
)
kotlin.test.assertTrue(
properties.any { it.property.name.toStrippedString() == "pkg1Property" },
"Expected 'pkg1Property'"
)
kotlin.test.assertTrue(
functions.any { it.function.name.toStrippedString() == "pkg1Function" },
"Expected 'pkg1Function'"
)
kotlin.test.assertTrue(
classes.any { it.clazz.name.toStrippedString() == "Pkg1" },
"Expected 'Pkg1'"
)
}
pkg2.run {
kotlin.test.assertTrue(
typeAliases.any { it.typeAlias.name.toStrippedString() == "pkg2TypeAlias" },
"Expected 'pkg2TypeAlias'"
)
kotlin.test.assertTrue(
properties.any { it.property.name.toStrippedString() == "pkg2Property" },
"Expected 'pkg2Property'"
)
kotlin.test.assertTrue(
functions.any { it.function.name.toStrippedString() == "pkg2Function" },
"Expected 'pkg2Function'"
)
kotlin.test.assertTrue(
classes.any { it.clazz.name.toStrippedString() == "Pkg2" },
"Expected 'Pkg2'"
)
}
}
}
@@ -0,0 +1,83 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.commonizer.tree.deserializer
import org.jetbrains.kotlin.commonizer.cir.CirClassType
import org.jetbrains.kotlin.commonizer.cir.CirName
import org.jetbrains.kotlin.commonizer.cir.CirTypeParameterType
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
import org.jetbrains.kotlin.descriptors.Visibilities
import kotlin.test.*
class CirTreePropertyDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test simple val property`() {
val module = deserializeSourceFile("val x: Int = 42")
val (key, property) = module.assertSingleProperty()
assertEquals(PropertyApproximationKey(CirName.Companion.create("x"), null), key)
assertEquals("x", property.name.toStrippedString())
assertFalse(property.isConst, "Expected property to is *no* const")
assertNotNull(property.getter, "Expected property to have getter")
assertNull(property.setter, "Expected property to have *no* setter")
assertFalse(property.isLateInit, "Expected property to be *not* lateinit")
assertFalse(property.isVar, "Expected property to be *not* var")
assertEquals(Visibilities.Public, property.visibility, "Expected property to be public")
assertNull(property.extensionReceiver, "Expected property to *not* have extension receiver")
}
fun `test simple var property`() {
val module = deserializeSourceFile("var x: Int = 42")
val (_, property) = module.assertSingleProperty()
assertNotNull(property.getter, "Expected property has getter")
assertNotNull(property.setter, "Expected property has setter")
assertFalse(property.isLateInit, "Expected property to be not lateinit")
assertTrue(property.isVar, "Expected property to be var")
}
fun `test lateinit var property`() {
val module = deserializeSourceFile("lateinit var x: Int")
val (_, property) = module.assertSingleProperty()
assertNotNull(property.getter, "Expected property has getter")
assertNotNull(property.setter, "Expected property has setter")
assertTrue(property.isLateInit, "Expected property to be lateinit")
assertTrue(property.isVar, "Expected property to be var")
}
fun `test generic var property`() {
val module = deserializeSourceFile("var <T> T.x: T get() = this")
val (_, property) = module.assertSingleProperty()
assertNotNull(property.extensionReceiver, "Expected property has extension receiver")
assertTrue(
property.extensionReceiver?.type is CirTypeParameterType,
"Expected extension receiver being type of ${CirTypeParameterType::class.simpleName}"
)
}
fun `test multiple properties`() {
val module = deserializeSourceFile(
"""
val x: Int = 42
val y: Float = 42f
var z: String = "42"
var Any?.answer get() = if(this != null) 42 else null
""".trimIndent()
)
val pkg = module.assertSinglePackage()
assertEquals(4, pkg.properties.size, "Expected exactly 4 properties in package")
val answerProperty = pkg.properties.single { it.property.name.toStrippedString() == "answer" }
val answerReturnType = answerProperty.property.returnType as? CirClassType
?: kotlin.test.fail("Expected answer return type is class")
assertEquals("kotlin/Int", answerReturnType.classifierId.toString())
assertTrue(answerReturnType.isMarkedNullable, "Expected answer return type being marked nullable")
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("RemoveRedundantQualifierName")
package org.jetbrains.kotlin.commonizer.tree.deserializer
import org.jetbrains.kotlin.commonizer.cir.CirClassType
import org.jetbrains.kotlin.commonizer.cir.CirName
import org.jetbrains.kotlin.commonizer.cir.CirRegularTypeProjection
import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertIs
class CirTreeTypeAliasDeserializerTest : AbstractCirTreeDeserializerTest() {
fun `test simple type alias`() {
val module = deserializeSourceFile("typealias x = Int")
val typeAlias = module.assertSingleTypeAlias().typeAlias
assertEquals(CirName.create("x"), typeAlias.name, "Expected correct type alias name")
assertEquals("kotlin/Int", typeAlias.expandedType.toString())
assertEquals("kotlin/Int", typeAlias.underlyingType.toString())
}
fun `test transitive type alias`() {
val module = deserializeSourceFile(
"""
interface Map<K, V>
typealias IntMap<V> = Map<Int, V>
typealias IntStringMap = IntMap<String>
""".trimIndent()
)
val pkg = module.assertSinglePackage()
assertEquals(2, pkg.typeAliases.size, "Expected exactly 2 type aliases in package")
val intStringMapTypeAlias = pkg.typeAliases.singleOrNull { it.typeAlias.name.toStrippedString() == "IntStringMap" }
?: kotlin.test.fail("Missing 'IntStringMap' type alias")
val underlyingType = assertIs<CirTypeAliasType>(
intStringMapTypeAlias.typeAlias.underlyingType, "Expected underlying type to be type alias"
)
assertEquals("/IntMap", underlyingType.classifierId.toString())
val underlyingTypeArgument = underlyingType.arguments.singleOrNull()
?: kotlin.test.fail("Expected single argument on underlying type. Found ${underlyingType.arguments}}")
assertIs<CirRegularTypeProjection>(underlyingTypeArgument, "Expected regular type projection for underlying type")
assertEquals("kotlin/String", underlyingTypeArgument.type.toString())
val expandedType = assertIs<CirClassType>(intStringMapTypeAlias.typeAlias.expandedType)
assertFalse(expandedType.isMarkedNullable, "Expected expanded type to be *not* marked nullable")
kotlin.test.assertEquals("/Map", expandedType.classifierId.toString(), "Expected correct expanded type classifier")
kotlin.test.assertEquals(2, expandedType.arguments.size, "Expected two type arguments")
kotlin.test.assertEquals("kotlin/Int", expandedType.arguments[0].toString(), "Expected correct first type argument")
kotlin.test.assertEquals("kotlin/String", expandedType.arguments[1].toString(), "Expected correct second type argument")
}
}