[Commonizer] Implement basic tests for CirTree deserializers
This commit is contained in:
+163
@@ -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 }}")
|
||||
}
|
||||
}
|
||||
+176
@@ -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")
|
||||
}
|
||||
}
|
||||
+70
@@ -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())
|
||||
}
|
||||
|
||||
}
|
||||
+118
@@ -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'"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+83
@@ -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")
|
||||
}
|
||||
}
|
||||
+62
@@ -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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user