[Commonizer] Property descriptors
This commit is contained in:
Generated
+4
@@ -1,6 +1,10 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="dmitriy.dolovov">
|
||||
<words>
|
||||
<w>commonization</w>
|
||||
<w>commonize</w>
|
||||
<w>commonized</w>
|
||||
<w>commonizer</w>
|
||||
<w>konan</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":core:util.runtime"))
|
||||
compileOnly(project(":core:descriptors"))
|
||||
|
||||
compile(kotlinStdlib())
|
||||
|
||||
testCompile(commonDep("junit:junit"))
|
||||
testCompile(projectTests(":compiler:tests-common"))
|
||||
|
||||
testCompile(intellijCoreDep()) { includeJars("intellij-core") }
|
||||
testCompile(intellijDep()) {
|
||||
includeJars(
|
||||
"openapi",
|
||||
"jps-model",
|
||||
"extensions",
|
||||
"util",
|
||||
"platform-api",
|
||||
"platform-impl",
|
||||
"idea",
|
||||
"idea_rt",
|
||||
"guava",
|
||||
"trove4j",
|
||||
"picocontainer",
|
||||
"asm-all",
|
||||
"log4j",
|
||||
"jdom",
|
||||
"streamex",
|
||||
"bootstrap",
|
||||
rootProject = rootProject
|
||||
)
|
||||
isTransitive = false
|
||||
}
|
||||
|
||||
Platform[192].orHigher {
|
||||
testCompile(intellijDep()) { includeJars("platform-util-ui", "platform-concurrency", "platform-objectSerializer") }
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
projectTest(parallel = true) {
|
||||
dependsOn(":dist")
|
||||
workingDir = rootDir
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
// N.B. TargetPlatform/SimplePlatform are non exhaustive enough to address both target platforms such as
|
||||
// JVM, JS and concrete Kotlin/Native targets, e.g. macos_x64, ios_x64, linux_x64.
|
||||
sealed class TargetId
|
||||
|
||||
data class ConcreteTargetId(val name: String) : TargetId()
|
||||
|
||||
data class CommonTargetId(val targets: Set<TargetId>) : TargetId() {
|
||||
init {
|
||||
require(targets.isNotEmpty())
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.builder
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
internal class CommonizedMemberScope : MemberScopeImpl() {
|
||||
private val members = ArrayList<DeclarationDescriptor>()
|
||||
|
||||
operator fun plusAssign(member: DeclarationDescriptor) {
|
||||
this.members += member
|
||||
}
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? =
|
||||
members.filteredBy<ClassifierDescriptor>(name).firstOrNull()
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
|
||||
members.filteredBy<PropertyDescriptor>(name).toList()
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> =
|
||||
members.filteredBy<SimpleFunctionDescriptor>(name).toList()
|
||||
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> = members.filter { kindFilter.accepts(it) && nameFilter(it.name) }
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(this::class.java.simpleName, " {")
|
||||
p.pushIndent()
|
||||
|
||||
p.println("declarations = $members")
|
||||
|
||||
p.popIndent()
|
||||
p.println("}")
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun createArray(size: Int) = Array(size) { CommonizedMemberScope() }
|
||||
|
||||
operator fun Array<CommonizedMemberScope>.plusAssign(members: List<DeclarationDescriptor?>) {
|
||||
members.forEachIndexed { index, member ->
|
||||
this[index] += member ?: return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : DeclarationDescriptor> List<*>.filteredBy(name: Name): Sequence<T> =
|
||||
this.asSequence().filterIsInstance<T>().filter { it.name == name }
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.builder
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class CommonizedPackageFragmentProvider : PackageFragmentProvider {
|
||||
private val packageFragments = ArrayList<PackageFragmentDescriptor>()
|
||||
|
||||
operator fun plusAssign(packageFragment: PackageFragmentDescriptor) {
|
||||
this.packageFragments += packageFragment
|
||||
}
|
||||
|
||||
override fun getPackageFragments(fqName: FqName): List<PackageFragmentDescriptor> =
|
||||
packageFragments.filter { it.fqName == fqName }
|
||||
|
||||
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> =
|
||||
packageFragments.asSequence()
|
||||
.map { it.fqName }
|
||||
.filter { !it.isRoot && it.parent() == fqName }
|
||||
.toList()
|
||||
|
||||
companion object {
|
||||
fun createArray(size: Int) = Array(size) { CommonizedPackageFragmentProvider() }
|
||||
|
||||
operator fun Array<CommonizedPackageFragmentProvider>.plusAssign(packageFragments: List<PackageFragmentDescriptor?>) {
|
||||
packageFragments.forEachIndexed { index, packageFragment ->
|
||||
this[index] += packageFragment ?: return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.builder
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.TargetId
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.builder.CommonizedMemberScope.Companion.plusAssign
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.builder.CommonizedPackageFragmentProvider.Companion.plusAssign
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
internal class DeclarationsBuilderVisitor(
|
||||
private val storageManager: StorageManager,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val collector: (TargetId, Collection<ModuleDescriptor>) -> Unit
|
||||
) : NodeVisitor<List<DeclarationDescriptor?>, List<DeclarationDescriptor?>> {
|
||||
override fun visitRootNode(node: RootNode, data: List<DeclarationDescriptor?>): List<DeclarationDescriptor?> {
|
||||
val allTargets = (node.target + node.common).map { it.targetId }
|
||||
|
||||
val modulesByTargets = HashMap<TargetId, MutableList<ModuleDescriptorImpl>>()
|
||||
|
||||
// collect module descriptors:
|
||||
for (moduleNode in node.modules) {
|
||||
val modules = moduleNode.accept(this, noContainingDeclarations()).asListContaining<ModuleDescriptorImpl>()
|
||||
modules.forEachIndexed { index, module ->
|
||||
val target = allTargets[index]
|
||||
modulesByTargets.computeIfAbsent(target) { mutableListOf() }.addIfNotNull(module)
|
||||
}
|
||||
}
|
||||
|
||||
// set cross-module dependencies:
|
||||
modulesByTargets.values.forEach { modulesSameTarget ->
|
||||
for (module in modulesSameTarget)
|
||||
module.setDependencies(modulesSameTarget)
|
||||
}
|
||||
|
||||
// return result (preserve platforms order):
|
||||
for (target in allTargets) {
|
||||
collector(target, modulesByTargets[target]!!)
|
||||
}
|
||||
|
||||
return noReturningDeclarations()
|
||||
}
|
||||
|
||||
override fun visitModuleNode(node: ModuleNode, data: List<DeclarationDescriptor?>): List<ModuleDescriptorImpl?> {
|
||||
// build module descriptors:
|
||||
val moduleDescriptorsGroup = CommonizedGroup<ModuleDescriptorImpl>(node.dimension)
|
||||
node.buildDescriptors(moduleDescriptorsGroup, storageManager, builtIns)
|
||||
val moduleDescriptors = moduleDescriptorsGroup.toList()
|
||||
|
||||
// build package fragments:
|
||||
val packageFragmentProviders = CommonizedPackageFragmentProvider.createArray(node.dimension)
|
||||
for (packageNode in node.packages) {
|
||||
val packageFragments = packageNode.accept(this, moduleDescriptors).asListContaining<PackageFragmentDescriptor>()
|
||||
packageFragmentProviders += packageFragments
|
||||
}
|
||||
|
||||
// initialize module descriptors:
|
||||
moduleDescriptors.asListContaining<ModuleDescriptorImpl>().forEachIndexed { index, moduleDescriptor ->
|
||||
moduleDescriptor?.initialize(packageFragmentProviders[index])
|
||||
}
|
||||
|
||||
return moduleDescriptors
|
||||
}
|
||||
|
||||
override fun visitPackageNode(node: PackageNode, data: List<DeclarationDescriptor?>): List<PackageFragmentDescriptor?> {
|
||||
val containingDeclarations = data.asListContaining<ModuleDescriptorImpl>()
|
||||
|
||||
// build package fragments:
|
||||
val packageFragmentsGroup = CommonizedGroup<CommonizedPackageFragmentDescriptor>(node.dimension)
|
||||
node.buildDescriptors(packageFragmentsGroup, containingDeclarations)
|
||||
val packageFragments = packageFragmentsGroup.toList()
|
||||
|
||||
// build package members:
|
||||
val packageMemberScopes = CommonizedMemberScope.createArray(node.dimension)
|
||||
for (propertyNode in node.properties) {
|
||||
packageMemberScopes += propertyNode.accept(this, packageFragments)
|
||||
}
|
||||
|
||||
// initialize package fragments:
|
||||
packageFragments.forEachIndexed { index, packageFragment ->
|
||||
packageFragment?.initialize(packageMemberScopes[index])
|
||||
}
|
||||
|
||||
return packageFragments
|
||||
}
|
||||
|
||||
override fun visitPropertyNode(node: PropertyNode, data: List<DeclarationDescriptor?>): List<PropertyDescriptor?> {
|
||||
val propertyDescriptorsGroup = CommonizedGroup<PropertyDescriptor>(node.dimension)
|
||||
node.buildDescriptors(propertyDescriptorsGroup, data, storageManager)
|
||||
|
||||
return propertyDescriptorsGroup.toList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
inline fun <reified T : DeclarationDescriptor> noContainingDeclarations() = emptyList<T?>()
|
||||
inline fun <reified T : DeclarationDescriptor> noReturningDeclarations() = emptyList<T?>()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private inline fun <reified T : DeclarationDescriptor> List<DeclarationDescriptor?>.asListContaining(): List<T?> =
|
||||
this as List<T?>
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.builder
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Module
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.ModuleNode
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.indexOfCommon
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal fun ModuleNode.buildDescriptors(
|
||||
output: CommonizedGroup<ModuleDescriptorImpl>,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns
|
||||
) {
|
||||
target.forEachIndexed { index, module ->
|
||||
module?.buildDescriptor(output, index, storageManager, builtIns)
|
||||
}
|
||||
|
||||
common?.buildDescriptor(output, indexOfCommon, storageManager, builtIns)
|
||||
}
|
||||
|
||||
private fun Module.buildDescriptor(
|
||||
output: CommonizedGroup<ModuleDescriptorImpl>,
|
||||
index: Int,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns
|
||||
) {
|
||||
val moduleDescriptor = ModuleDescriptorImpl(
|
||||
moduleName = name,
|
||||
storageManager = storageManager,
|
||||
builtIns = builtIns,
|
||||
capabilities = emptyMap() // TODO: specify capabilities
|
||||
)
|
||||
|
||||
output[index] = moduleDescriptor
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.builder
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Package
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.PackageNode
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.indexOfCommon
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
|
||||
internal fun PackageNode.buildDescriptors(
|
||||
output: CommonizedGroup<CommonizedPackageFragmentDescriptor>,
|
||||
modules: List<ModuleDescriptorImpl?>
|
||||
) {
|
||||
target.forEachIndexed { index, pkg ->
|
||||
pkg?.buildDescriptor(output, index, modules)
|
||||
}
|
||||
|
||||
common?.buildDescriptor(output, indexOfCommon, modules)
|
||||
}
|
||||
|
||||
private fun Package.buildDescriptor(
|
||||
output: CommonizedGroup<CommonizedPackageFragmentDescriptor>,
|
||||
index: Int,
|
||||
modules: List<ModuleDescriptorImpl?>
|
||||
) {
|
||||
val module = modules[index] ?: error("No containing declaration for package $this")
|
||||
val packageFragment = CommonizedPackageFragmentDescriptor(module, fqName)
|
||||
output[index] = packageFragment
|
||||
}
|
||||
|
||||
internal class CommonizedPackageFragmentDescriptor(
|
||||
module: ModuleDescriptor,
|
||||
fqName: FqName
|
||||
) : PackageFragmentDescriptorImpl(module, fqName) {
|
||||
private lateinit var memberScope: MemberScope
|
||||
|
||||
fun initialize(memberScope: MemberScope) {
|
||||
this.memberScope = memberScope
|
||||
}
|
||||
|
||||
override fun getMemberScope() = memberScope
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.builder
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Property
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.PropertyNode
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.indexOfCommon
|
||||
import org.jetbrains.kotlin.descriptors.impl.FieldDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal fun PropertyNode.buildDescriptors(
|
||||
output: CommonizedGroup<PropertyDescriptor>,
|
||||
containingDeclarations: List<DeclarationDescriptor?>,
|
||||
storageManager: StorageManager
|
||||
) {
|
||||
val isCommonized = common != null
|
||||
|
||||
target.forEachIndexed { index, property ->
|
||||
property?.buildDescriptor(output, index, containingDeclarations, storageManager, isActual = isCommonized)
|
||||
}
|
||||
|
||||
common?.buildDescriptor(output, indexOfCommon, containingDeclarations, storageManager, isExpect = isCommonized)
|
||||
}
|
||||
|
||||
private fun Property.buildDescriptor(
|
||||
output: CommonizedGroup<PropertyDescriptor>,
|
||||
index: Int,
|
||||
containingDeclarations: List<DeclarationDescriptor?>,
|
||||
storageManager: StorageManager,
|
||||
isExpect: Boolean = false,
|
||||
isActual: Boolean = false
|
||||
) {
|
||||
val containingDeclaration = containingDeclarations[index] ?: error("No containing declaration for property $this")
|
||||
|
||||
val propertyDescriptor = PropertyDescriptorImpl.create(
|
||||
containingDeclaration,
|
||||
annotations,
|
||||
modality,
|
||||
visibility,
|
||||
isVar,
|
||||
name,
|
||||
kind,
|
||||
SourceElement.NO_SOURCE,
|
||||
lateInit,
|
||||
isConst,
|
||||
isExpect,
|
||||
isActual,
|
||||
isExternal,
|
||||
isDelegate
|
||||
)
|
||||
|
||||
val extensionReceiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
propertyDescriptor,
|
||||
extensionReceiverType,
|
||||
Annotations.EMPTY
|
||||
)
|
||||
|
||||
val dispatchReceiverDescriptor = DescriptorUtils.getDispatchReceiverParameterIfNeeded(containingDeclaration)
|
||||
|
||||
propertyDescriptor.setType(
|
||||
type,
|
||||
emptyList(), // TODO: support type parameters
|
||||
dispatchReceiverDescriptor,
|
||||
extensionReceiverDescriptor
|
||||
)
|
||||
|
||||
val getterDescriptor = getter?.let { getter ->
|
||||
DescriptorFactory.createGetter(
|
||||
propertyDescriptor,
|
||||
getter.annotations,
|
||||
getter.isDefault,
|
||||
getter.isExternal,
|
||||
getter.isInline
|
||||
).apply {
|
||||
initialize(null) // use return type from the property descriptor
|
||||
}
|
||||
}
|
||||
|
||||
val setterDescriptor = setter?.let { setter ->
|
||||
DescriptorFactory.createSetter(
|
||||
propertyDescriptor,
|
||||
setter.annotations,
|
||||
setter.parameterAnnotations,
|
||||
setter.isDefault,
|
||||
setter.isExternal,
|
||||
setter.isInline,
|
||||
setter.visibility,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
}
|
||||
|
||||
val backingField = backingFieldAnnotations?.let { FieldDescriptorImpl(it, propertyDescriptor) }
|
||||
val delegateField = delegateFieldAnnotations?.let { FieldDescriptorImpl(it, propertyDescriptor) }
|
||||
|
||||
propertyDescriptor.initialize(
|
||||
getterDescriptor,
|
||||
setterDescriptor,
|
||||
backingField,
|
||||
delegateField
|
||||
)
|
||||
|
||||
compileTimeInitializer?.let { constantValue ->
|
||||
propertyDescriptor.setCompileTimeInitializer(storageManager.createNullableLazyValue { constantValue })
|
||||
}
|
||||
|
||||
output[index] = propertyDescriptor
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
// Fixed-size list that represents a commonized group of same-rank elements
|
||||
internal class CommonizedGroup<T : Any>(
|
||||
val size: Int,
|
||||
initialize: (Int) -> T?
|
||||
) {
|
||||
constructor(elements: List<T?>) : this(elements.size, elements::get)
|
||||
|
||||
constructor(size: Int) : this(size, { null })
|
||||
|
||||
// array constructor requires concrete type which is known only at the call site,
|
||||
// so let's use `Any?` instead if `T` here
|
||||
private val elements = Array<Any?>(size, initialize)
|
||||
|
||||
operator fun get(index: Int): T? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return elements[index] as T?
|
||||
}
|
||||
|
||||
operator fun set(index: Int, value: T) {
|
||||
val oldValue = this[index]
|
||||
check(oldValue == null) { "$oldValue can not be overwritten with $value at index $index" }
|
||||
|
||||
elements[index] = value
|
||||
}
|
||||
|
||||
fun toList(): List<T?> = object : AbstractList<T?>() {
|
||||
override val size
|
||||
get() = this@CommonizedGroup.size
|
||||
|
||||
override fun get(index: Int): T? = this@CommonizedGroup[index]
|
||||
}
|
||||
}
|
||||
|
||||
internal class CommonizedGroupMap<K, V : Any>(val size: Int) : Iterable<Map.Entry<K, CommonizedGroup<V>>> {
|
||||
private val wrapped: MutableMap<K, CommonizedGroup<V>> = HashMap()
|
||||
|
||||
operator fun get(key: K): CommonizedGroup<V> = wrapped.getOrPut(key) { CommonizedGroup(size) }
|
||||
|
||||
override fun iterator(): Iterator<Map.Entry<K, CommonizedGroup<V>>> = wrapped.iterator()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
interface Commonizer<T, R> {
|
||||
val result: R
|
||||
fun commonizeWith(next: T): Boolean
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
interface ExtensionReceiverCommonizer : Commonizer<ReceiverParameterDescriptor?, UnwrappedType?> {
|
||||
companion object {
|
||||
fun default(): ExtensionReceiverCommonizer = DefaultExtensionReceiverCommonizer()
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultExtensionReceiverCommonizer : ExtensionReceiverCommonizer {
|
||||
private enum class State {
|
||||
EMPTY,
|
||||
ERROR,
|
||||
WITH_RECEIVER,
|
||||
WITHOUT_RECEIVER
|
||||
}
|
||||
|
||||
private var state = State.EMPTY
|
||||
private var receiverType: TypeCommonizer? = null
|
||||
|
||||
override val result: UnwrappedType?
|
||||
get() = when (state) {
|
||||
State.EMPTY, State.ERROR -> error("Receiver parameter type can't be commonized")
|
||||
State.WITH_RECEIVER -> receiverType!!.result
|
||||
State.WITHOUT_RECEIVER -> null // null receiverType means there is no extension receiver
|
||||
}
|
||||
|
||||
override fun commonizeWith(next: ReceiverParameterDescriptor?): Boolean {
|
||||
state = when (state) {
|
||||
State.ERROR -> State.ERROR
|
||||
State.EMPTY -> next?.let {
|
||||
receiverType = TypeCommonizer.default()
|
||||
doCommonizeWith(next)
|
||||
} ?: State.WITHOUT_RECEIVER
|
||||
State.WITH_RECEIVER -> next?.let(::doCommonizeWith) ?: State.ERROR
|
||||
State.WITHOUT_RECEIVER -> next?.let { State.ERROR } ?: State.WITHOUT_RECEIVER
|
||||
}
|
||||
|
||||
return state != State.ERROR
|
||||
}
|
||||
|
||||
private fun doCommonizeWith(receiverParameter: ReceiverParameterDescriptor) =
|
||||
if (receiverType!!.commonizeWith(receiverParameter.type)) State.WITH_RECEIVER else State.ERROR
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
|
||||
interface ModalityCommonizer : Commonizer<Modality, Modality> {
|
||||
companion object {
|
||||
fun default(): ModalityCommonizer = DefaultModalityCommonizer()
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultModalityCommonizer : ModalityCommonizer {
|
||||
private enum class State {
|
||||
EMPTY {
|
||||
override fun getNext(modality: Modality) = when (modality) {
|
||||
Modality.ABSTRACT -> CAN_HAVE_ONLY_ABSTRACT
|
||||
Modality.SEALED -> CAN_HAVE_ONLY_SEALED
|
||||
Modality.FINAL -> HAS_FINAL
|
||||
Modality.OPEN -> HAS_OPEN
|
||||
}
|
||||
},
|
||||
ERROR {
|
||||
override fun getNext(modality: Modality) = ERROR
|
||||
},
|
||||
CAN_HAVE_ONLY_SEALED {
|
||||
override fun getNext(modality: Modality) = if (modality == Modality.SEALED) this else ERROR
|
||||
},
|
||||
CAN_HAVE_ONLY_ABSTRACT {
|
||||
override fun getNext(modality: Modality) = if (modality == Modality.ABSTRACT) this else ERROR
|
||||
},
|
||||
HAS_FINAL {
|
||||
override fun getNext(modality: Modality) = when (modality) {
|
||||
Modality.FINAL -> this
|
||||
Modality.OPEN -> HAS_FINAL_AND_OPEN
|
||||
else -> ERROR
|
||||
}
|
||||
},
|
||||
HAS_OPEN {
|
||||
override fun getNext(modality: Modality) = when (modality) {
|
||||
Modality.FINAL -> HAS_FINAL_AND_OPEN
|
||||
Modality.OPEN -> this
|
||||
else -> ERROR
|
||||
}
|
||||
},
|
||||
HAS_FINAL_AND_OPEN {
|
||||
override fun getNext(modality: Modality) = when (modality) {
|
||||
Modality.FINAL, Modality.OPEN -> this
|
||||
else -> ERROR
|
||||
}
|
||||
};
|
||||
|
||||
abstract fun getNext(modality: Modality): State
|
||||
}
|
||||
|
||||
private var state = State.EMPTY
|
||||
|
||||
override val result: Modality
|
||||
get() = when (state) {
|
||||
State.CAN_HAVE_ONLY_SEALED -> Modality.SEALED
|
||||
State.CAN_HAVE_ONLY_ABSTRACT -> Modality.ABSTRACT
|
||||
State.HAS_FINAL, State.HAS_FINAL_AND_OPEN -> Modality.FINAL
|
||||
State.HAS_OPEN -> Modality.OPEN
|
||||
else -> error("Modality can't be commonized")
|
||||
}
|
||||
|
||||
override fun commonizeWith(next: Modality): Boolean {
|
||||
state = state.getNext(next)
|
||||
return state != State.ERROR
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.CommonProperty
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Property
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class PropertyCommonizer : Commonizer<PropertyDescriptor, Property> {
|
||||
private enum class State {
|
||||
EMPTY,
|
||||
ERROR,
|
||||
IN_PROGRESS
|
||||
}
|
||||
|
||||
private var name: Name? = null
|
||||
// TODO: visibility - what if virtual declaration?
|
||||
private val visibility = VisibilityCommonizer.lowering()
|
||||
private val modality = ModalityCommonizer.default()
|
||||
private val returnType = TypeCommonizer.default()
|
||||
private val setter = PropertySetterCommonizer.default()
|
||||
private val extensionReceiver = ExtensionReceiverCommonizer.default()
|
||||
|
||||
private var state = State.EMPTY
|
||||
|
||||
override val result: Property
|
||||
get() = when (state) {
|
||||
State.EMPTY, State.ERROR -> error("Can't commonize property")
|
||||
State.IN_PROGRESS -> CommonProperty(
|
||||
name = name!!,
|
||||
visibility = visibility.result,
|
||||
modality = modality.result,
|
||||
type = returnType.result,
|
||||
setter = setter.result,
|
||||
extensionReceiverType = extensionReceiver.result
|
||||
)
|
||||
}
|
||||
|
||||
override fun commonizeWith(next: PropertyDescriptor): Boolean {
|
||||
if (state == State.ERROR)
|
||||
return false
|
||||
|
||||
if (name == null)
|
||||
name = next.name
|
||||
|
||||
val result = canBeCommonized(next)
|
||||
&& visibility.commonizeWith(next.visibility)
|
||||
&& modality.commonizeWith(next.modality)
|
||||
&& returnType.commonizeWith(next.type)
|
||||
&& setter.commonizeWith(next.setter)
|
||||
&& extensionReceiver.commonizeWith(next.extensionReceiverParameter)
|
||||
|
||||
// TODO: type parameters (for properties???)
|
||||
|
||||
state = if (!result) State.ERROR else State.IN_PROGRESS
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun canBeCommonized(property: PropertyDescriptor) = when {
|
||||
property.isConst -> false // expect property can't be const because expect can't have initializer
|
||||
property.isLateInit -> false // expect property can't be lateinit
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Setter
|
||||
|
||||
interface PropertySetterCommonizer : Commonizer<PropertySetterDescriptor?, Setter?> {
|
||||
companion object {
|
||||
fun default(): PropertySetterCommonizer = DefaultPropertySetterCommonizer()
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultPropertySetterCommonizer : PropertySetterCommonizer {
|
||||
private enum class State {
|
||||
EMPTY,
|
||||
ERROR,
|
||||
WITH_SETTER,
|
||||
WITHOUT_SETTER
|
||||
}
|
||||
|
||||
private var state = State.EMPTY
|
||||
private var setterVisibility: VisibilityCommonizer? = null
|
||||
|
||||
override val result: Setter?
|
||||
get() = when (state) {
|
||||
State.EMPTY, State.ERROR -> error("Property setter can't be commonized")
|
||||
State.WITH_SETTER -> Setter.createDefaultNoAnnotations(setterVisibility!!.result)
|
||||
State.WITHOUT_SETTER -> null // null visibility means there is no setter
|
||||
}
|
||||
|
||||
override fun commonizeWith(next: PropertySetterDescriptor?): Boolean {
|
||||
state = when (state) {
|
||||
State.ERROR -> State.ERROR
|
||||
State.EMPTY -> next?.let {
|
||||
setterVisibility = VisibilityCommonizer.lowering()
|
||||
doCommonizeWith(next)
|
||||
} ?: State.WITHOUT_SETTER
|
||||
State.WITH_SETTER -> next?.let(::doCommonizeWith) ?: State.ERROR
|
||||
State.WITHOUT_SETTER -> next?.let { State.ERROR } ?: State.WITHOUT_SETTER
|
||||
}
|
||||
|
||||
return state != State.ERROR
|
||||
}
|
||||
|
||||
private fun doCommonizeWith(setter: PropertySetterDescriptor) =
|
||||
if (setterVisibility!!.commonizeWith(setter.visibility)) State.WITH_SETTER else State.ERROR
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.isClassType
|
||||
|
||||
interface TypeCommonizer : Commonizer<KotlinType, UnwrappedType> {
|
||||
companion object {
|
||||
fun default(): TypeCommonizer = DefaultTypeCommonizer()
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultTypeCommonizer : TypeCommonizer {
|
||||
private enum class State {
|
||||
EMPTY,
|
||||
ERROR,
|
||||
IN_PROGRESS
|
||||
}
|
||||
|
||||
private var state = State.EMPTY
|
||||
private var temp: UnwrappedType? = null
|
||||
|
||||
override val result: UnwrappedType
|
||||
get() = when (state) {
|
||||
State.EMPTY, State.ERROR -> error("Can't commonize type")
|
||||
State.IN_PROGRESS -> temp!!
|
||||
}
|
||||
|
||||
override fun commonizeWith(next: KotlinType): Boolean {
|
||||
state = when (state) {
|
||||
State.ERROR -> State.ERROR
|
||||
State.EMPTY -> {
|
||||
temp = next.unwrap()
|
||||
State.IN_PROGRESS
|
||||
}
|
||||
// TODO: maybe cache type comparison results?
|
||||
State.IN_PROGRESS -> {
|
||||
if (!areTypesEqual(temp!!, next.unwrap())) State.ERROR else State.IN_PROGRESS
|
||||
}
|
||||
}
|
||||
|
||||
return state != State.ERROR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See also [AbstractStrictEqualityTypeChecker].
|
||||
*/
|
||||
internal fun areTypesEqual(a: UnwrappedType, b: UnwrappedType): Boolean = when {
|
||||
a === b -> true
|
||||
a is SimpleType -> (b is SimpleType) && areSimpleTypesEqual(a, b)
|
||||
a is FlexibleType -> (b is FlexibleType)
|
||||
&& areSimpleTypesEqual(a.lowerBound, b.lowerBound) && areSimpleTypesEqual(a.upperBound, b.upperBound)
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun areSimpleTypesEqual(a: SimpleType, b: SimpleType): Boolean = areAbbreviatedTypesEqual(
|
||||
a = a.getAbbreviation() ?: a,
|
||||
aExpanded = a,
|
||||
b = b.getAbbreviation() ?: b,
|
||||
bExpandedType = b
|
||||
)
|
||||
|
||||
private fun areAbbreviatedTypesEqual(a: SimpleType, aExpanded: SimpleType, b: SimpleType, bExpandedType: SimpleType): Boolean {
|
||||
if (a.arguments.size != b.arguments.size
|
||||
|| a.isMarkedNullable != b.isMarkedNullable
|
||||
|| a.isDefinitelyNotNullType != b.isDefinitelyNotNullType
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
val aDescriptor = requireNotNull(a.constructor.declarationDescriptor, a::nonNullDescriptorExpectedErrorMessage)
|
||||
val bDescriptor = requireNotNull(b.constructor.declarationDescriptor, b::nonNullDescriptorExpectedErrorMessage)
|
||||
|
||||
val aFqName = aDescriptor.fqNameSafe
|
||||
val bFqName = bDescriptor.fqNameSafe
|
||||
|
||||
if (aFqName.isUnderStandardKotlinPackages || bFqName.isUnderStandardKotlinPackages) {
|
||||
// make sure that FQ names of abbreviated types (e.g. representing type aliases) are equal
|
||||
return aFqName == bFqName
|
||||
// if classes are from the standard Kotlin packages, compare them only by type constructors
|
||||
// effectively, this includes 1) comparison of FQ names and 2) number of type constructor parameters
|
||||
// see org.jetbrains.kotlin.types.AbstractClassTypeConstructor.equals() for details
|
||||
&& aExpanded.constructor == bExpandedType.constructor
|
||||
}
|
||||
|
||||
val descriptorsCanBeCommonized = when (aDescriptor) {
|
||||
is TypeAliasDescriptor -> (bDescriptor is TypeAliasDescriptor) && canBeCommonized(aDescriptor, bDescriptor)
|
||||
is ClassDescriptor -> (bDescriptor is ClassDescriptor) && canBeCommonized(aDescriptor, bDescriptor)
|
||||
else -> false
|
||||
}
|
||||
|
||||
if (!descriptorsCanBeCommonized)
|
||||
return false
|
||||
|
||||
if (a.arguments === b.arguments)
|
||||
return true
|
||||
|
||||
for (i in 0 until a.arguments.size) {
|
||||
val aArg = a.arguments[i]
|
||||
val bArg = b.arguments[i]
|
||||
|
||||
if (aArg.isStarProjection != bArg.isStarProjection)
|
||||
return false
|
||||
|
||||
if (!aArg.isStarProjection) {
|
||||
if (aArg.projectionKind != bArg.projectionKind)
|
||||
return false
|
||||
|
||||
if (!areTypesEqual(aArg.type.unwrap(), bArg.type.unwrap()))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun SimpleType.nonNullDescriptorExpectedErrorMessage() =
|
||||
"${TypeCommonizer::class} couldn't obtain non-null descriptor from: $this, ${this::class}"
|
||||
|
||||
private val standardKotlinPackages = setOf(
|
||||
KotlinBuiltIns.BUILT_INS_PACKAGE_NAME,
|
||||
Name.identifier("kotlinx")
|
||||
)
|
||||
|
||||
private val FqName.isUnderStandardKotlinPackages: Boolean
|
||||
get() = pathSegments().firstOrNull() in standardKotlinPackages
|
||||
|
||||
// TODO: extract this method to class commonizer
|
||||
private fun canBeCommonized(a: ClassDescriptor, b: ClassDescriptor) = when {
|
||||
a.kind != b.kind -> false
|
||||
!areFqNamesEqual(a, b) -> false
|
||||
// TODO: compare class descriptors (visibility, modifiers, etc)
|
||||
else -> true
|
||||
}
|
||||
|
||||
// TODO: extract this method to type alias commonizer
|
||||
private fun canBeCommonized(a: TypeAliasDescriptor, b: TypeAliasDescriptor): Boolean {
|
||||
if (!areFqNamesEqual(a, b))
|
||||
return false
|
||||
|
||||
val aUnderlyingType = a.underlyingType
|
||||
val bUnderlyingType = b.underlyingType
|
||||
|
||||
if (aUnderlyingType.arguments.isNotEmpty() || bUnderlyingType.arguments.isNotEmpty())
|
||||
return false // type aliases with functional types at the right-hand side can't be commonized
|
||||
|
||||
if (!aUnderlyingType.isClassType || !bUnderlyingType.isClassType)
|
||||
return false // right-hand side could have only classes
|
||||
|
||||
return areTypesEqual(aUnderlyingType, bUnderlyingType)
|
||||
}
|
||||
|
||||
private fun <T : ClassifierDescriptor> areFqNamesEqual(d1: T, d2: T): Boolean {
|
||||
val p1 = d1.parentsWithSelf.iterator()
|
||||
val p2 = d2.parentsWithSelf.iterator()
|
||||
|
||||
while (p1.hasNext() && p2.hasNext()) {
|
||||
val n1 = p1.next()
|
||||
val n2 = p2.next()
|
||||
|
||||
when (n1) {
|
||||
is ModuleDescriptor -> return n2 is ModuleDescriptor
|
||||
is PackageFragmentDescriptor -> return (n2 is PackageFragmentDescriptor) && n1.fqName == n2.fqName
|
||||
else -> if (n1.name != n2.name) return false
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
|
||||
abstract class VisibilityCommonizer : Commonizer<Visibility, Visibility> {
|
||||
|
||||
companion object {
|
||||
fun lowering(): VisibilityCommonizer = LoweringVisibilityCommonizer()
|
||||
fun equalizing(): VisibilityCommonizer = EqualizingVisibilityCommonizer()
|
||||
}
|
||||
|
||||
private var temp: Visibility? = null
|
||||
|
||||
override val result: Visibility
|
||||
get() {
|
||||
return temp?.takeIf { it != Visibilities.UNKNOWN } ?: error("Visibility can't be commonized")
|
||||
}
|
||||
|
||||
override fun commonizeWith(next: Visibility): Boolean {
|
||||
if (temp == Visibilities.UNKNOWN)
|
||||
return false
|
||||
|
||||
if (Visibilities.isPrivate(next)) {
|
||||
temp = Visibilities.UNKNOWN
|
||||
return false
|
||||
}
|
||||
|
||||
temp = temp?.let { temp -> getNext(temp, next) } ?: next
|
||||
|
||||
return temp != Visibilities.UNKNOWN
|
||||
}
|
||||
|
||||
protected abstract fun getNext(current: Visibility, next: Visibility): Visibility
|
||||
}
|
||||
|
||||
private class LoweringVisibilityCommonizer : VisibilityCommonizer() {
|
||||
override fun getNext(current: Visibility, next: Visibility): Visibility {
|
||||
val comparisonResult: Int = Visibilities.compare(current, next)
|
||||
?: return Visibilities.UNKNOWN // two visibilities that can't be compared against each one, ex: protected vs internal
|
||||
|
||||
return if (comparisonResult <= 0) current else next
|
||||
}
|
||||
}
|
||||
|
||||
private class EqualizingVisibilityCommonizer : VisibilityCommonizer() {
|
||||
override fun getNext(current: Visibility, next: Visibility) =
|
||||
if (Visibilities.compare(current, next) == 0) current else Visibilities.UNKNOWN
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.builder.DeclarationsBuilderVisitor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.mergeRoots
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
|
||||
class CommonizationSession {
|
||||
// TODO: add progress tracker
|
||||
// TODO: add logger
|
||||
}
|
||||
|
||||
class CommonizationParameters {
|
||||
private val modulesByTargets = LinkedHashMap<ConcreteTargetId, Collection<ModuleDescriptor>>()
|
||||
|
||||
fun addTarget(targetName: String, modules: Collection<ModuleDescriptor>): CommonizationParameters {
|
||||
val targetId = ConcreteTargetId(targetName)
|
||||
require(targetId !in modulesByTargets) {
|
||||
"Target $targetId is already added"
|
||||
}
|
||||
|
||||
val modulesWithUniqueNames = modules.groupingBy { it.name }.eachCount()
|
||||
require(modulesWithUniqueNames.size == modules.size) {
|
||||
"Modules with duplicated names found: ${modulesWithUniqueNames.filter { it.value > 1 }}"
|
||||
}
|
||||
|
||||
modulesByTargets[targetId] = modules
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
// get them as ordered immutable collection (List) for further processing
|
||||
fun getModulesByTargets(): List<Pair<ConcreteTargetId, Collection<ModuleDescriptor>>> =
|
||||
modulesByTargets.map { it.key to it.value }
|
||||
|
||||
fun hasIntersection(): Boolean {
|
||||
if (modulesByTargets.size < 2)
|
||||
return false
|
||||
|
||||
return modulesByTargets.flatMap { it.value }
|
||||
.groupingBy { it.name }
|
||||
.eachCount()
|
||||
.any { it.value == modulesByTargets.size }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CommonizationResult
|
||||
|
||||
object NothingToCommonize : CommonizationResult()
|
||||
|
||||
class CommonizationPerformed(
|
||||
val commonModules: Collection<ModuleDescriptor>,
|
||||
val modulesByTargets: Map<String, Collection<ModuleDescriptor>>
|
||||
) : CommonizationResult()
|
||||
|
||||
fun runCommonization(parameters: CommonizationParameters): CommonizationResult {
|
||||
if (!parameters.hasIntersection())
|
||||
return NothingToCommonize
|
||||
|
||||
val mergedTree = mergeRoots(parameters.getModulesByTargets())
|
||||
|
||||
val storageManager = LockBasedStorageManager("Declaration descriptors commonization")
|
||||
|
||||
var commonModules: Collection<ModuleDescriptor>? = null
|
||||
val otherModulesByTargets = LinkedHashMap<String, Collection<ModuleDescriptor>>()
|
||||
|
||||
val visitor = DeclarationsBuilderVisitor(storageManager, DefaultBuiltIns.Instance) { targetId, commonizedModules ->
|
||||
when (targetId) {
|
||||
is CommonTargetId -> {
|
||||
check(commonModules == null)
|
||||
commonModules = commonizedModules
|
||||
}
|
||||
is ConcreteTargetId -> {
|
||||
val targetName = targetId.name
|
||||
check(targetName !in otherModulesByTargets)
|
||||
otherModulesByTargets[targetName] = commonizedModules
|
||||
}
|
||||
}
|
||||
}
|
||||
mergedTree.accept(visitor, DeclarationsBuilderVisitor.noContainingDeclarations())
|
||||
|
||||
return CommonizationPerformed(commonModules!!, otherModulesByTargets)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.ir
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
data class Module(
|
||||
val name: Name
|
||||
) : Declaration
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.ir
|
||||
|
||||
interface NodeVisitor<R, T> {
|
||||
fun visitRootNode(node: RootNode, data: T): R
|
||||
fun visitModuleNode(node: ModuleNode, data: T): R
|
||||
fun visitPackageNode(node: PackageNode, data: T): R
|
||||
fun visitPropertyNode(node: PropertyNode, data: T): R
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.ir
|
||||
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
data class Package(
|
||||
val fqName: FqName
|
||||
) : Declaration
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Getter.Companion.toGetter
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Setter.Companion.toSetter
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
|
||||
interface Property : Declaration {
|
||||
val annotations: Annotations
|
||||
val name: Name
|
||||
val visibility: Visibility
|
||||
val modality: Modality
|
||||
val isVar: Boolean
|
||||
val kind: CallableMemberDescriptor.Kind
|
||||
val type: UnwrappedType
|
||||
val lateInit: Boolean
|
||||
val isConst: Boolean
|
||||
val isExternal: Boolean
|
||||
val isDelegate: Boolean
|
||||
val getter: Getter?
|
||||
val setter: Setter?
|
||||
val extensionReceiverType: UnwrappedType?
|
||||
val backingFieldAnnotations: Annotations? // null assumes no backing field
|
||||
val delegateFieldAnnotations: Annotations? // null assumes no backing field
|
||||
val compileTimeInitializer: ConstantValue<*>?
|
||||
}
|
||||
|
||||
data class CommonProperty(
|
||||
override val name: Name,
|
||||
override val visibility: Visibility,
|
||||
override val modality: Modality,
|
||||
override val type: UnwrappedType,
|
||||
override val setter: Setter?,
|
||||
override val extensionReceiverType: UnwrappedType?
|
||||
) : Property {
|
||||
override val annotations get() = Annotations.EMPTY
|
||||
override val isVar: Boolean get() = setter != null
|
||||
override val kind get() = CallableMemberDescriptor.Kind.DECLARATION
|
||||
override val lateInit: Boolean get() = false
|
||||
override val isConst: Boolean get() = false
|
||||
override val isExternal: Boolean get() = false
|
||||
override val isDelegate: Boolean get() = false
|
||||
override val getter: Getter get() = Getter.DEFAULT_NO_ANNOTATIONS
|
||||
override val backingFieldAnnotations: Annotations? get() = null
|
||||
override val delegateFieldAnnotations: Annotations? get() = null
|
||||
override val compileTimeInitializer: ConstantValue<*>? get() = null
|
||||
}
|
||||
|
||||
data class TargetProperty(private val descriptor: PropertyDescriptor) : Property {
|
||||
override val annotations: Annotations get() = descriptor.annotations
|
||||
override val name: Name get() = descriptor.name
|
||||
override val visibility: Visibility get() = descriptor.visibility
|
||||
override val modality: Modality get() = descriptor.modality
|
||||
override val isVar: Boolean get() = descriptor.isVar
|
||||
override val kind: CallableMemberDescriptor.Kind get() = descriptor.kind
|
||||
override val type: UnwrappedType get() = descriptor.type.unwrap()
|
||||
override val lateInit: Boolean get() = descriptor.isLateInit
|
||||
override val isConst: Boolean get() = descriptor.isConst
|
||||
override val isExternal: Boolean get() = descriptor.isExternal
|
||||
@Suppress("DEPRECATION")
|
||||
override val isDelegate: Boolean get() = descriptor.isDelegated
|
||||
override val getter: Getter? get() = descriptor.getter?.toGetter()
|
||||
override val setter: Setter? get() = descriptor.setter?.toSetter()
|
||||
override val extensionReceiverType: UnwrappedType? get() = descriptor.extensionReceiverParameter?.type?.unwrap()
|
||||
override val backingFieldAnnotations: Annotations? get() = descriptor.backingField?.annotations
|
||||
override val delegateFieldAnnotations: Annotations? get() = descriptor.delegateField?.annotations
|
||||
override val compileTimeInitializer: ConstantValue<*>? get() = descriptor.compileTimeInitializer
|
||||
}
|
||||
|
||||
interface PropertyAccessor {
|
||||
val annotations: Annotations
|
||||
val isDefault: Boolean
|
||||
val isExternal: Boolean
|
||||
val isInline: Boolean
|
||||
}
|
||||
|
||||
data class Getter(
|
||||
override val annotations: Annotations,
|
||||
override val isDefault: Boolean,
|
||||
override val isExternal: Boolean,
|
||||
override val isInline: Boolean
|
||||
) : PropertyAccessor {
|
||||
companion object {
|
||||
val DEFAULT_NO_ANNOTATIONS = Getter(Annotations.EMPTY, isDefault = true, isExternal = false, isInline = false)
|
||||
|
||||
fun PropertyGetterDescriptor.toGetter() =
|
||||
if (isDefault && annotations.isEmpty())
|
||||
DEFAULT_NO_ANNOTATIONS
|
||||
else
|
||||
Getter(annotations, isDefault, isExternal, isInline)
|
||||
}
|
||||
}
|
||||
|
||||
data class Setter(
|
||||
override val annotations: Annotations,
|
||||
val parameterAnnotations: Annotations,
|
||||
val visibility: Visibility,
|
||||
override val isDefault: Boolean,
|
||||
override val isExternal: Boolean,
|
||||
override val isInline: Boolean
|
||||
) : PropertyAccessor {
|
||||
companion object {
|
||||
fun createDefaultNoAnnotations(visibility: Visibility) = Setter(
|
||||
Annotations.EMPTY,
|
||||
Annotations.EMPTY,
|
||||
visibility,
|
||||
isDefault = true,
|
||||
isExternal = false,
|
||||
isInline = false
|
||||
)
|
||||
|
||||
fun PropertySetterDescriptor.toSetter() = Setter(
|
||||
annotations,
|
||||
valueParameters.single().annotations,
|
||||
visibility,
|
||||
isDefault,
|
||||
isExternal,
|
||||
isInline
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.TargetId
|
||||
|
||||
data class Root(val targetId: TargetId) : Declaration
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.*
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroup
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.core.Commonizer
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.core.PropertyCommonizer
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.firstNonNull
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
|
||||
internal fun buildRootNode(targets: List<ConcreteTargetId>): RootNode = RootNode(
|
||||
targets.map { Root(it) },
|
||||
Root(CommonTargetId(targets.toSet()))
|
||||
)
|
||||
|
||||
internal fun buildModuleNode(modules: List<ModuleDescriptor?>): ModuleNode = buildNode(
|
||||
modules,
|
||||
{ Module(it.name) },
|
||||
{ Module(it.firstNonNull().name) },
|
||||
::ModuleNode
|
||||
)
|
||||
|
||||
internal fun buildPackageNode(packageFqName: FqName, packageMemberScopes: List<MemberScope?>): PackageNode = buildNode(
|
||||
packageMemberScopes,
|
||||
{ Package(packageFqName) },
|
||||
{ Package(packageFqName) },
|
||||
::PackageNode
|
||||
)
|
||||
|
||||
internal fun buildPropertyNode(properties: List<PropertyDescriptor?>): PropertyNode = buildNode(
|
||||
properties,
|
||||
{ TargetProperty(it) },
|
||||
{ commonize(it, PropertyCommonizer()) },
|
||||
::PropertyNode
|
||||
)
|
||||
|
||||
private fun <T : Any, D : Declaration, N : Node<D>> buildNode(
|
||||
descriptors: List<T?>,
|
||||
targetDeclarationProducer: (T) -> D,
|
||||
commonDeclarationProducer: (List<T?>) -> D?,
|
||||
nodeProducer: (List<D?>, D?) -> N
|
||||
): N {
|
||||
val target = CommonizedGroup<D>(descriptors.size)
|
||||
var canHaveCommon = descriptors.size > 1
|
||||
|
||||
descriptors.forEachIndexed { index, descriptor ->
|
||||
if (descriptor != null)
|
||||
target[index] = targetDeclarationProducer(descriptor)
|
||||
else
|
||||
canHaveCommon = false
|
||||
}
|
||||
|
||||
val common = if (canHaveCommon) commonDeclarationProducer(descriptors) else null
|
||||
|
||||
return nodeProducer(target.toList(), common)
|
||||
}
|
||||
|
||||
private fun <T : Any, R : Declaration> commonize(descriptors: List<T?>, commonizer: Commonizer<T, R>): R? {
|
||||
for (item in descriptors) {
|
||||
if (item == null || !commonizer.commonizeWith(item))
|
||||
return null
|
||||
}
|
||||
|
||||
return commonizer.result
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.ir
|
||||
|
||||
interface Declaration
|
||||
|
||||
interface Node<D : Declaration> {
|
||||
val target: List<D?>
|
||||
val common: D?
|
||||
|
||||
fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T): R
|
||||
}
|
||||
|
||||
class RootNode(
|
||||
override val target: List<Root>,
|
||||
override val common: Root
|
||||
) : Node<Root> {
|
||||
val modules: MutableList<ModuleNode> = ArrayList()
|
||||
|
||||
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T): R =
|
||||
visitor.visitRootNode(this, data)
|
||||
}
|
||||
|
||||
class ModuleNode(
|
||||
override val target: List<Module?>,
|
||||
override val common: Module?
|
||||
) : Node<Module> {
|
||||
val packages: MutableList<PackageNode> = ArrayList()
|
||||
|
||||
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T) =
|
||||
visitor.visitModuleNode(this, data)
|
||||
}
|
||||
|
||||
class PackageNode(
|
||||
override val target: List<Package?>,
|
||||
override val common: Package?
|
||||
) : Node<Package> {
|
||||
val properties: MutableList<PropertyNode> = ArrayList()
|
||||
|
||||
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T) =
|
||||
visitor.visitPackageNode(this, data)
|
||||
}
|
||||
|
||||
class PropertyNode(
|
||||
override val target: List<Property?>,
|
||||
override val common: Property?
|
||||
) : Node<Property> {
|
||||
override fun <R, T> accept(visitor: NodeVisitor<R, T>, data: T) =
|
||||
visitor.visitPropertyNode(this, data)
|
||||
}
|
||||
|
||||
internal val <D : Declaration> Node<D>.indexOfCommon: Int
|
||||
get() = target.size
|
||||
|
||||
internal val <D : Declaration> Node<D>.dimension: Int
|
||||
get() = target.size + 1
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.mergedtree
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.ModuleNode
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.buildModuleNode
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.toList
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.scopes.ChainedMemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.utils.alwaysTrue
|
||||
|
||||
internal fun mergeModules(modules: List<ModuleDescriptor?>): ModuleNode {
|
||||
val node = buildModuleNode(modules)
|
||||
|
||||
val packageMemberScopesMap = CommonizedGroupMap<FqName, MemberScope>(modules.size)
|
||||
|
||||
modules.forEachIndexed { index, module ->
|
||||
module?.collectNonEmptyPackageMemberScopes { packageFqName, memberScope ->
|
||||
packageMemberScopesMap[packageFqName][index] = memberScope
|
||||
}
|
||||
}
|
||||
|
||||
for ((packageFqName, packageMemberScopesGroup) in packageMemberScopesMap) {
|
||||
node.packages += mergePackages(packageFqName, packageMemberScopesGroup.toList())
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
// collects member scopes for every non-empty package provided by this module
|
||||
private fun ModuleDescriptor.collectNonEmptyPackageMemberScopes(collector: (FqName, MemberScope) -> Unit) {
|
||||
// we don's need to process fragments from other modules which are the dependencies of this module, so
|
||||
// let's use the appropriate package fragment provider
|
||||
val packageFragmentProvider = (this as ModuleDescriptorImpl).packageFragmentProviderForModuleContentWithoutDependencies
|
||||
|
||||
fun recurse(packageFqName: FqName) {
|
||||
val ownPackageFragments = packageFragmentProvider.getPackageFragments(packageFqName)
|
||||
val ownPackageMemberScopes = ownPackageFragments.asSequence()
|
||||
.map { it.getMemberScope() }
|
||||
.filter { it != MemberScope.Empty }
|
||||
.toList(ownPackageFragments.size)
|
||||
|
||||
if (ownPackageMemberScopes.isNotEmpty()) {
|
||||
// don't include subpackages into chained member scope
|
||||
val memberScope = ChainedMemberScope.create(
|
||||
"package member scope for $packageFqName in $name",
|
||||
ownPackageMemberScopes
|
||||
)
|
||||
collector(packageFqName, memberScope)
|
||||
}
|
||||
|
||||
packageFragmentProvider.getSubPackagesOf(packageFqName, alwaysTrue()).map { recurse(it) }
|
||||
}
|
||||
|
||||
recurse(FqName.ROOT)
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.mergedtree
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.PackageNode
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.buildPackageNode
|
||||
|
||||
internal fun mergePackages(
|
||||
packageFqName: FqName,
|
||||
packageMemberScopes: List<MemberScope?>
|
||||
): PackageNode {
|
||||
val node = buildPackageNode(packageFqName, packageMemberScopes)
|
||||
|
||||
val propertiesMap = CommonizedGroupMap<PropertyKey, PropertyDescriptor>(packageMemberScopes.size)
|
||||
|
||||
packageMemberScopes.forEachIndexed { index, memberScope ->
|
||||
memberScope?.collectProperties { propertyKey, property ->
|
||||
propertiesMap[propertyKey][index] = property
|
||||
}
|
||||
}
|
||||
|
||||
for ((_, propertiesGroup) in propertiesMap) {
|
||||
node.properties += mergeProperties(propertiesGroup.toList())
|
||||
}
|
||||
|
||||
// FIXME: traverse the rest - functions, classes, typealiases
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
private fun MemberScope.collectProperties(collector: (PropertyKey, PropertyDescriptor) -> Unit) {
|
||||
getContributedDescriptors(DescriptorKindFilter.VARIABLES).asSequence()
|
||||
.filterIsInstance<PropertyDescriptor>()
|
||||
.forEach { property ->
|
||||
collector(PropertyKey(property), property)
|
||||
}
|
||||
}
|
||||
|
||||
private data class PropertyKey(
|
||||
val name: Name,
|
||||
val extensionReceiverParameterFqName: FqName?
|
||||
) {
|
||||
constructor(property: PropertyDescriptor) : this(
|
||||
property.name,
|
||||
property.extensionReceiverParameter?.run { type.constructor.declarationDescriptor!!.fqNameSafe }
|
||||
)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.mergedtree
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.buildPropertyNode
|
||||
|
||||
internal fun mergeProperties(properties: List<PropertyDescriptor?>) = buildPropertyNode(properties)
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.mergedtree
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizedGroupMap
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ConcreteTargetId
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.RootNode
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.buildRootNode
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal fun mergeRoots(modulesByTargets: List<Pair<ConcreteTargetId, Collection<ModuleDescriptor>>>): RootNode {
|
||||
val node = buildRootNode(modulesByTargets.map { it.first })
|
||||
|
||||
val modulesMap = CommonizedGroupMap<Name, ModuleDescriptor>(modulesByTargets.size)
|
||||
|
||||
modulesByTargets.forEachIndexed { index, (_, modules) ->
|
||||
for (module in modules) {
|
||||
modulesMap[module.name][index] = module
|
||||
}
|
||||
}
|
||||
|
||||
for ((_, modulesGroup) in modulesMap) {
|
||||
node.modules += mergeModules(modulesGroup.toList())
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.isCommon
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
internal fun <T> Sequence<T>.toList(expectedCapacity: Int): List<T> {
|
||||
val result = ArrayList<T>(expectedCapacity)
|
||||
toCollection(result)
|
||||
return result
|
||||
}
|
||||
|
||||
internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>()
|
||||
|
||||
internal fun List<TargetPlatform>.asCommonPlatform() =
|
||||
TargetPlatform(flatMap(TargetPlatform::componentPlatforms).toSet()).also { check(it.isCommon()) }
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package org.sample.one
|
||||
|
||||
val firstOrgSampleOne = 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package org.sample.three
|
||||
|
||||
val firstOrgSampleThree = 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package org.sample.two
|
||||
|
||||
val firstOrgSampleTwo = 1
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// root package
|
||||
|
||||
val firstRoot = 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package org.sample.one
|
||||
|
||||
val secondOrgSampleOne = 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package org.sample.two
|
||||
|
||||
val secondOrgSampleTwo = 1
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// root package
|
||||
|
||||
val secondRoot = 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package org.sample.three
|
||||
|
||||
val thirdOrgSampleThree = 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package org.sample.two
|
||||
|
||||
val thirdOrgSampleTwo = 1
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// root package
|
||||
|
||||
val thirdRoot = 1
|
||||
@@ -0,0 +1,21 @@
|
||||
// root package
|
||||
|
||||
val foo = 1
|
||||
|
||||
val bar = 42
|
||||
val String.bar get() = this
|
||||
val Int.bar get() = this
|
||||
|
||||
var baz = "baz"
|
||||
var bazWithSetter = "baz"
|
||||
set
|
||||
var bazWithCustomSetter = "baz"
|
||||
set(value) {
|
||||
field = value.toLowerCase()
|
||||
}
|
||||
var bazWithSetterWithInternalVisibility = "baz"
|
||||
internal set
|
||||
var bazWithCustomSetterWithInternalVisibility = "baz"
|
||||
internal set(value) {
|
||||
field = value.toLowerCase()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// root package
|
||||
|
||||
val foo = 1
|
||||
|
||||
val bar = 42
|
||||
val String.bar get() = this
|
||||
val Int.bar get() = this
|
||||
|
||||
var baz = "baz"
|
||||
var bazWithSetter = "baz"
|
||||
set
|
||||
var bazWithCustomSetter = "baz"
|
||||
set(value) {
|
||||
field = value.toLowerCase()
|
||||
}
|
||||
var bazWithSetterWithInternalVisibility = "baz"
|
||||
internal set
|
||||
var bazWithCustomSetterWithInternalVisibility = "baz"
|
||||
internal set(value) {
|
||||
field = value.toLowerCase()
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
import com.intellij.testFramework.PlatformTestUtil.lowercaseFirstLetter
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils.*
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import java.io.File
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
|
||||
companion object {
|
||||
init {
|
||||
System.setProperty("java.awt.headless", "true")
|
||||
}
|
||||
|
||||
fun List<ModuleDescriptor>.eachModuleAsTarget() = CommonizationParameters().also {
|
||||
forEachIndexed { index, module ->
|
||||
it.addTarget("target_$index", listOf(module))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun assertIsDirectory(file: File) {
|
||||
assertTrue("Not a directory: $file", file.isDirectory)
|
||||
}
|
||||
|
||||
protected fun createEnvironment(bareModuleName: String): KotlinCoreEnvironment {
|
||||
check(Name.isValidIdentifier(bareModuleName))
|
||||
val configuration = newConfiguration()
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, bareModuleName)
|
||||
|
||||
return KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.METADATA_CONFIG_FILES)
|
||||
}
|
||||
|
||||
protected val KotlinCoreEnvironment.moduleName: Name
|
||||
get() {
|
||||
val bareModuleName = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
||||
return Name.special("<$bareModuleName>")
|
||||
}
|
||||
|
||||
protected val testDataDir: File
|
||||
get() {
|
||||
val testCaseDir = lowercaseFirstLetter(
|
||||
this::class.java.simpleName.substringBefore("FromSources").substringBefore("Test"),
|
||||
true
|
||||
)
|
||||
val testDir = testDirectoryName
|
||||
|
||||
return File(getHomeDirectory())
|
||||
.resolve("konan/commonizer/testData")
|
||||
.resolve(testCaseDir)
|
||||
.resolve(testDir)
|
||||
.also(::assertIsDirectory)
|
||||
}
|
||||
|
||||
protected val sourceModuleRoots: List<File>
|
||||
get() {
|
||||
val testDataDir = testDataDir
|
||||
val roots = testDataDir.listFiles()?.toList()
|
||||
|
||||
if (roots.isNullOrEmpty())
|
||||
error("No source module roots found in $testDataDir")
|
||||
|
||||
roots.forEach(::assertIsDirectory)
|
||||
|
||||
return roots
|
||||
}
|
||||
|
||||
protected val sourceModuleDescriptors: List<ModuleDescriptor>
|
||||
get() {
|
||||
return sourceModuleRoots.map { root ->
|
||||
val environment = createEnvironment(root.parentFile.name)
|
||||
val psiFactory = KtPsiFactory(environment.project)
|
||||
|
||||
val psiFiles = root.walkTopDown()
|
||||
.filter { it.isFile }
|
||||
.map { psiFactory.createFile(it.name, doLoadFile(it)) }
|
||||
.toList()
|
||||
|
||||
CommonResolverForModuleFactory.analyzeFiles(
|
||||
files = psiFiles,
|
||||
moduleName = environment.moduleName,
|
||||
dependOnBuiltIns = true,
|
||||
languageVersionSettings = environment.configuration.languageVersionSettings
|
||||
) { content ->
|
||||
environment.createPackagePartProvider(content.moduleContentScope)
|
||||
}.moduleDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.AbstractCommonizationFromSourcesTest.Companion.eachModuleAsTarget
|
||||
|
||||
class BasicCommonizerFacadeTest {
|
||||
|
||||
@Test
|
||||
fun nothingToCommonize0() {
|
||||
val modules = listOf<ModuleDescriptor>()
|
||||
|
||||
val result = runCommonization(modules.eachModuleAsTarget())
|
||||
|
||||
assertEquals(NothingToCommonize, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nothingToCommonize1() {
|
||||
val modules = listOf(
|
||||
mockEmptyModule("<foo>")
|
||||
)
|
||||
|
||||
val result = runCommonization(modules.eachModuleAsTarget())
|
||||
|
||||
assertEquals(NothingToCommonize, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nothingToCommonize2() {
|
||||
val modules = listOf(
|
||||
mockEmptyModule("<foo>"),
|
||||
mockEmptyModule("<foo>")
|
||||
)
|
||||
|
||||
val result = runCommonization(modules.eachModuleAsTarget())
|
||||
|
||||
assertTrue(result is CommonizationPerformed)
|
||||
require(result is CommonizationPerformed) // to enforce Kotlin contracts
|
||||
|
||||
assertSingleModuleForTarget("<foo>", result.commonModules)
|
||||
|
||||
assertEquals(2, result.modulesByTargets.size)
|
||||
for (modulesSamePlatform in result.modulesByTargets.values) {
|
||||
assertSingleModuleForTarget("<foo>", modulesSamePlatform)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mismatchedModules() {
|
||||
val modules = listOf(
|
||||
mockEmptyModule("<foo>"),
|
||||
mockEmptyModule("<foo>"),
|
||||
mockEmptyModule("<bar>")
|
||||
)
|
||||
|
||||
val result = runCommonization(modules.eachModuleAsTarget())
|
||||
|
||||
assertEquals(NothingToCommonize, result)
|
||||
}
|
||||
|
||||
private fun assertSingleModuleForTarget(
|
||||
@Suppress("SameParameterValue") expectedModuleName: String,
|
||||
modules: Collection<ModuleDescriptor>
|
||||
) {
|
||||
assertEquals(1, modules.size)
|
||||
assertEquals(expectedModuleName, modules.single().name.asString())
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
class PropertyCommonizationFromSourcesTest : AbstractCommonizationFromSourcesTest() {
|
||||
fun testMatchingPackages() {
|
||||
val modules = sourceModuleDescriptors
|
||||
val result = runCommonization(modules.eachModuleAsTarget())
|
||||
|
||||
println(result)
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
fun testSample() {
|
||||
val modules = sourceModuleDescriptors
|
||||
runCommonization(modules.eachModuleAsTarget())
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
|
||||
abstract class AbstractCommonizerTest<T, R> {
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun failOnNoVariantsSubmitted() {
|
||||
createCommonizer().result
|
||||
fail()
|
||||
}
|
||||
|
||||
protected abstract fun createCommonizer(): Commonizer<T, R>
|
||||
|
||||
protected open fun isEqual(a: R?, b: R?): Boolean = a == b
|
||||
|
||||
protected fun doTestSuccess(expected: R, vararg variants: T) {
|
||||
check(variants.isNotEmpty())
|
||||
|
||||
val commonized = createCommonizer().apply {
|
||||
variants.forEach {
|
||||
assertTrue(commonizeWith(it))
|
||||
}
|
||||
}
|
||||
|
||||
val actual = commonized.result
|
||||
if (!isEqual(expected, actual)) fail("Expected: $expected\nActual: $actual")
|
||||
}
|
||||
|
||||
// should fail on the last variant
|
||||
protected fun doTestFailure(vararg variants: T) {
|
||||
check(variants.isNotEmpty())
|
||||
|
||||
val commonized = createCommonizer().apply {
|
||||
variants.forEachIndexed { index, variant ->
|
||||
val result = commonizeWith(variant)
|
||||
if (index == variants.size - 1) assertFalse(result) else assertTrue(result)
|
||||
}
|
||||
}
|
||||
|
||||
commonized.result
|
||||
fail()
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mockClassType
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mockProperty
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.junit.Test
|
||||
|
||||
@TypeRefinement
|
||||
class DefaultExtensionReceiverCommonizerTest : AbstractCommonizerTest<ReceiverParameterDescriptor?, UnwrappedType?>() {
|
||||
|
||||
@Test
|
||||
fun nullReceiver() = doTestSuccess(
|
||||
null,
|
||||
mock().extensionReceiverParameter,
|
||||
mock().extensionReceiverParameter,
|
||||
mock().extensionReceiverParameter
|
||||
)
|
||||
|
||||
@Test
|
||||
fun sameReceiver() = doTestSuccess(
|
||||
mockClassType("kotlin.String").unwrap(),
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun differentReceivers() = doTestFailure(
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = "kotlin.Int").extensionReceiverParameter
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun nullAndNonNullReceivers1() = doTestFailure(
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = null).extensionReceiverParameter
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun nullAndNonNullReceivers2() = doTestFailure(
|
||||
mock(receiverTypeFqName = null).extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = null).extensionReceiverParameter,
|
||||
mock(receiverTypeFqName = "kotlin.String").extensionReceiverParameter
|
||||
)
|
||||
|
||||
override fun createCommonizer() = ExtensionReceiverCommonizer.default()
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
private fun mock(name: String = "myLength", receiverTypeFqName: String? = null) = mockProperty(
|
||||
name = name,
|
||||
setterVisibility = null,
|
||||
extensionReceiverType = receiverTypeFqName?.let { mockClassType(receiverTypeFqName) },
|
||||
returnType = mockClassType("kotlin.Int")
|
||||
)
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Modality.*
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultModalityCommonizerTest : AbstractCommonizerTest<Modality, Modality>() {
|
||||
|
||||
@Test
|
||||
fun onlyFinal() = doTestSuccess(FINAL, FINAL, FINAL, FINAL)
|
||||
|
||||
@Test
|
||||
fun onlyOpen() = doTestSuccess(OPEN, OPEN, OPEN, OPEN)
|
||||
|
||||
@Test
|
||||
fun onlySealed() = doTestSuccess(SEALED, SEALED, SEALED, SEALED)
|
||||
|
||||
@Test
|
||||
fun onlyAbstract() = doTestSuccess(ABSTRACT, ABSTRACT, ABSTRACT, ABSTRACT)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun sealedAndAbstract() = doTestFailure(SEALED, ABSTRACT)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun sealedAndFinal() = doTestFailure(SEALED, FINAL)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun abstractAndFinal() = doTestFailure(ABSTRACT, FINAL)
|
||||
|
||||
@Test
|
||||
fun finalAndOpen() = doTestSuccess(FINAL, FINAL, OPEN, FINAL)
|
||||
|
||||
@Test
|
||||
fun openAndFinal() = doTestSuccess(FINAL, OPEN, OPEN, FINAL)
|
||||
|
||||
override fun createCommonizer() = ModalityCommonizer.default()
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities.*
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.ir.Setter
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mockClassType
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mockProperty
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultPropertySetterCommonizerTest : AbstractCommonizerTest<PropertySetterDescriptor?, Setter?>() {
|
||||
|
||||
@Test
|
||||
fun absentOnly() = super.doTestSuccess(null, null, null, null)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun absentAndPublic() = doTestFailure(null, null, null, PUBLIC)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun publicAndAbsent() = doTestFailure(PUBLIC, PUBLIC, PUBLIC, null)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun protectedAndAbsent() = doTestFailure(PROTECTED, PROTECTED, null)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun absentAndInternal() = doTestFailure(null, null, INTERNAL)
|
||||
|
||||
@Test
|
||||
fun publicOnly() = doTestSuccess(PUBLIC, PUBLIC, PUBLIC, PUBLIC)
|
||||
|
||||
@Test
|
||||
fun protectedOnly() = doTestSuccess(PROTECTED, PROTECTED, PROTECTED, PROTECTED)
|
||||
|
||||
@Test
|
||||
fun internalOnly() = doTestSuccess(INTERNAL, INTERNAL, INTERNAL, INTERNAL)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun privateOnly() = doTestFailure(PRIVATE)
|
||||
|
||||
@Test
|
||||
fun publicAndProtected() = doTestSuccess(PROTECTED, PUBLIC, PROTECTED, PUBLIC)
|
||||
|
||||
@Test
|
||||
fun publicAndInternal() = doTestSuccess(INTERNAL, PUBLIC, INTERNAL, PUBLIC)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun protectedAndInternal() = doTestFailure(PUBLIC, INTERNAL, PROTECTED)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun publicAndPrivate() = doTestFailure(PUBLIC, INTERNAL, PRIVATE)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun somethingUnexpected() = doTestFailure(PUBLIC, LOCAL)
|
||||
|
||||
private fun doTestSuccess(expected: Visibility?, vararg variants: Visibility?) =
|
||||
super.doTestSuccess(
|
||||
expected?.let { Setter.createDefaultNoAnnotations(expected) },
|
||||
*variants.map { it?.let(Visibility::toMockProperty) }.toTypedArray()
|
||||
)
|
||||
|
||||
private fun doTestFailure(vararg variants: Visibility?) =
|
||||
super.doTestFailure(
|
||||
*variants.map { it?.let(Visibility::toMockProperty) }.toTypedArray()
|
||||
)
|
||||
|
||||
override fun createCommonizer() = PropertySetterCommonizer.default()
|
||||
}
|
||||
|
||||
|
||||
@UseExperimental(TypeRefinement::class)
|
||||
private fun Visibility.toMockProperty() = mockProperty(
|
||||
name = "myProperty",
|
||||
setterVisibility = this,
|
||||
extensionReceiverType = null,
|
||||
returnType = mockClassType("kotlin.String").unwrap()
|
||||
).setter!!
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mockClassType
|
||||
import org.jetbrains.kotlin.descriptors.commonizer.mockTAType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import org.junit.Test
|
||||
|
||||
// TODO: add tests for type parameters
|
||||
@TypeRefinement
|
||||
class DefaultTypeCommonizerTest : AbstractCommonizerTest<KotlinType, UnwrappedType>() {
|
||||
|
||||
@Test
|
||||
fun classTypesInKotlinPackageWithSameName() = doTestSuccess(
|
||||
mockClassType("kotlin.collections.List").unwrap(),
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("kotlin.collections.List")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinPackageWithDifferentNames1() = doTestFailure(
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("kotlin.fictitiousPackageName.List")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinPackageWithDifferentNames2() = doTestFailure(
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("kotlin.collections.Set")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinPackageWithDifferentNames3() = doTestFailure(
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("kotlin.collections.List"),
|
||||
mockClassType("org.sample.Foo")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun classTypesInKotlinxPackageWithSameName() = doTestSuccess(
|
||||
mockClassType("kotlinx.cinterop.CPointer").unwrap(),
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("kotlinx.cinterop.CPointer")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinxPackageWithDifferentNames1() = doTestFailure(
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("kotlinx.fictitiousPackageName.CPointer")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinxPackageWithDifferentNames2() = doTestFailure(
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("kotlinx.cinterop.ObjCObject")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinxPackageWithDifferentNames3() = doTestFailure(
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("kotlinx.cinterop.CPointer"),
|
||||
mockClassType("org.sample.Foo")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun classTypesInUserPackageWithSameName() = doTestSuccess(
|
||||
mockClassType("org.sample.Foo").unwrap(),
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("org.sample.Foo")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInUserPackageWithDifferentNames1() = doTestFailure(
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("org.fictitiousPackageName.Foo")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInUserPackageWithDifferentNames2() = doTestFailure(
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("org.sample.Bar")
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInUserPackageWithDifferentNames3() = doTestFailure(
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("org.sample.Foo"),
|
||||
mockClassType("kotlin.String")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun classTypesInKotlinPackageWithSameNullability1() = doTestSuccess(
|
||||
mockClassType("kotlin.collections.List").unwrap(),
|
||||
mockClassType("kotlin.collections.List", nullable = false),
|
||||
mockClassType("kotlin.collections.List", nullable = false),
|
||||
mockClassType("kotlin.collections.List", nullable = false)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun classTypesInKotlinPackageWithSameNullability2() = doTestSuccess(
|
||||
mockClassType("kotlin.collections.List", nullable = true).unwrap(),
|
||||
mockClassType("kotlin.collections.List", nullable = true),
|
||||
mockClassType("kotlin.collections.List", nullable = true),
|
||||
mockClassType("kotlin.collections.List", nullable = true)
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinPackageWithDifferentNullability1() = doTestFailure(
|
||||
mockClassType("kotlin.collections.List", nullable = false),
|
||||
mockClassType("kotlin.collections.List", nullable = false),
|
||||
mockClassType("kotlin.collections.List", nullable = true)
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInKotlinPackageWithDifferentNullability2() = doTestFailure(
|
||||
mockClassType("kotlin.collections.List", nullable = true),
|
||||
mockClassType("kotlin.collections.List", nullable = true),
|
||||
mockClassType("kotlin.collections.List", nullable = false)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun classTypesInUserPackageWithSameNullability1() = doTestSuccess(
|
||||
mockClassType("org.sample.Foo").unwrap(),
|
||||
mockClassType("org.sample.Foo", nullable = false),
|
||||
mockClassType("org.sample.Foo", nullable = false),
|
||||
mockClassType("org.sample.Foo", nullable = false)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun classTypesInUserPackageWithSameNullability2() = doTestSuccess(
|
||||
mockClassType("org.sample.Foo", nullable = true).unwrap(),
|
||||
mockClassType("org.sample.Foo", nullable = true),
|
||||
mockClassType("org.sample.Foo", nullable = true),
|
||||
mockClassType("org.sample.Foo", nullable = true)
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInUserPackageWithDifferentNullability1() = doTestFailure(
|
||||
mockClassType("org.sample.Foo", nullable = false),
|
||||
mockClassType("org.sample.Foo", nullable = false),
|
||||
mockClassType("org.sample.Foo", nullable = true)
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun classTypesInUserPackageWithDifferentNullability2() = doTestFailure(
|
||||
mockClassType("org.sample.Foo", nullable = true),
|
||||
mockClassType("org.sample.Foo", nullable = true),
|
||||
mockClassType("org.sample.Foo", nullable = false)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInKotlinPackageWithSameNameAndClass() = doTestSuccess(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") }.unwrap(),
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInKotlinPackageWithDifferentNames() = doTestFailure(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.FictitiousTypeAlias") { mockClassType("kotlin.sequences.SequenceScope") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInKotlinPackageWithDifferentClasses() = doTestFailure(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.FictitiousClass") }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInKotlinxPackageWithSameNameAndClass() = doTestSuccess(
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") }.unwrap(),
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") },
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") },
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInKotlinxPackageWithDifferentNames() = doTestFailure(
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") },
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") },
|
||||
mockTAType("kotlinx.cinterop.FictitiousTypeAlias") { mockClassType("kotlinx.cinterop.CPointer") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInKotlinxPackageWithDifferentClasses() = doTestFailure(
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") },
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.CPointer") },
|
||||
mockTAType("kotlinx.cinterop.CArrayPointer") { mockClassType("kotlinx.cinterop.FictitiousClass") }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun multilevelTATypesInKotlinPackageWithSameNameAndRightHandSideClass() = doTestSuccess(
|
||||
// that's OK as long as the fully expanded right-hand side is the same class
|
||||
mockTAType("kotlin.FictitiousTypeAlias") {
|
||||
mockClassType("kotlin.FictitiousClass")
|
||||
}.unwrap(),
|
||||
|
||||
mockTAType("kotlin.FictitiousTypeAlias") {
|
||||
mockClassType("kotlin.FictitiousClass")
|
||||
},
|
||||
|
||||
mockTAType("kotlin.FictitiousTypeAlias") {
|
||||
mockTAType("kotlin.FictitiousTypeAliasL2") {
|
||||
mockClassType("kotlin.FictitiousClass")
|
||||
}
|
||||
},
|
||||
|
||||
mockTAType("kotlin.FictitiousTypeAlias") {
|
||||
mockTAType("kotlin.FictitiousTypeAliasL2") {
|
||||
mockTAType("kotlin.FictitiousTypeAliasL3") {
|
||||
mockClassType("kotlin.FictitiousClass")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInUserPackageWithSameNameAndClass() = doTestSuccess(
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") }.unwrap(),
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInUserPackageWithDifferentNames() = doTestFailure(
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.BarAlias") { mockClassType("org.sample.Foo") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInUserPackageWithDifferentClasses() = doTestFailure(
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Bar") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun multilevelTATypesInUserPackageWithSameNameAndRightHandSideClass() = doTestFailure(
|
||||
mockTAType("org.sample.FooAlias") {
|
||||
mockClassType("org.sample.Foo")
|
||||
},
|
||||
|
||||
mockTAType("org.sample.FooAlias") {
|
||||
mockTAType("org.sample.FooAliasL2") {
|
||||
mockClassType("org.sample.Foo")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInKotlinPackageWithSameNullability1() = doTestSuccess(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") }.unwrap(),
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = false) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = false) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = false) { mockClassType("kotlin.sequences.SequenceScope") }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInKotlinPackageWithSameNullability2() = doTestSuccess(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = true) { mockClassType("kotlin.sequences.SequenceScope") }.unwrap(),
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = true) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = true) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = true) { mockClassType("kotlin.sequences.SequenceScope") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInKotlinPackageWithDifferentNullability1() = doTestFailure(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = false) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = false) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = true) { mockClassType("kotlin.sequences.SequenceScope") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInKotlinPackageWithDifferentNullability2() = doTestFailure(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = true) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = true) { mockClassType("kotlin.sequences.SequenceScope") },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder", nullable = false) { mockClassType("kotlin.sequences.SequenceScope") }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInKotlinPackageWithDifferentNullability3() = doTestSuccess(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") }.unwrap(),
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope", nullable = false) },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope", nullable = false) },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope", nullable = true) }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInKotlinPackageWithDifferentNullability4() = doTestSuccess(
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope") }.unwrap(),
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope", nullable = true) },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope", nullable = true) },
|
||||
mockTAType("kotlin.sequences.SequenceBuilder") { mockClassType("kotlin.sequences.SequenceScope", nullable = false) }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInUserPackageWithSameNullability1() = doTestSuccess(
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo") }.unwrap(),
|
||||
mockTAType("org.sample.FooAlias", nullable = false) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = false) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = false) { mockClassType("org.sample.Foo") }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun taTypesInUserPackageWithSameNullability2() = doTestSuccess(
|
||||
mockTAType("org.sample.FooAlias", nullable = true) { mockClassType("org.sample.Foo") }.unwrap(),
|
||||
mockTAType("org.sample.FooAlias", nullable = true) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = true) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = true) { mockClassType("org.sample.Foo") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInUserPackageWithDifferentNullability1() = doTestFailure(
|
||||
mockTAType("org.sample.FooAlias", nullable = false) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = false) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = true) { mockClassType("org.sample.Foo") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInUserPackageWithDifferentNullability2() = doTestFailure(
|
||||
mockTAType("org.sample.FooAlias", nullable = true) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = true) { mockClassType("org.sample.Foo") },
|
||||
mockTAType("org.sample.FooAlias", nullable = false) { mockClassType("org.sample.Foo") }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInUserPackageWithDifferentNullability3() = doTestFailure(
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = false) },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = false) },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = true) }
|
||||
)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun taTypesInUserPackageWithDifferentNullability4() = doTestFailure(
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = true) },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = true) },
|
||||
mockTAType("org.sample.FooAlias") { mockClassType("org.sample.Foo", nullable = false) }
|
||||
)
|
||||
|
||||
override fun createCommonizer() = TypeCommonizer.default()
|
||||
override fun isEqual(a: UnwrappedType?, b: UnwrappedType?) = (a === b) || (a != null && b != null && areTypesEqual(a, b))
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities.*
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.junit.Test
|
||||
|
||||
class EqualizingVisibilityCommonizerTest : AbstractCommonizerTest<Visibility, Visibility>() {
|
||||
|
||||
@Test
|
||||
fun publicOnly() = doTestSuccess(PUBLIC, PUBLIC, PUBLIC, PUBLIC)
|
||||
|
||||
@Test
|
||||
fun protectedOnly() = doTestSuccess(PROTECTED, PROTECTED, PROTECTED, PROTECTED)
|
||||
|
||||
@Test
|
||||
fun internalOnly() = doTestSuccess(INTERNAL, INTERNAL, INTERNAL, INTERNAL)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun privateOnly() = doTestFailure(PRIVATE)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun publicAndProtected() = doTestFailure(PROTECTED, PROTECTED, PROTECTED, PUBLIC)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun publicAndInternal() = doTestFailure(INTERNAL, INTERNAL, INTERNAL, PUBLIC)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun protectedAndInternal() = doTestFailure(PROTECTED, PROTECTED, PROTECTED, INTERNAL)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun publicAndPrivate() = doTestFailure(PUBLIC, PUBLIC, PRIVATE)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun somethingUnexpected() = doTestFailure(PUBLIC, LOCAL)
|
||||
|
||||
override fun createCommonizer() = VisibilityCommonizer.equalizing()
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer.core
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities.*
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.junit.Test
|
||||
|
||||
class LoweringVisibilityCommonizerTest : AbstractCommonizerTest<Visibility, Visibility>() {
|
||||
|
||||
@Test
|
||||
fun publicOnly() = doTestSuccess(PUBLIC, PUBLIC, PUBLIC, PUBLIC)
|
||||
|
||||
@Test
|
||||
fun protectedOnly() = doTestSuccess(PROTECTED, PROTECTED, PROTECTED, PROTECTED)
|
||||
|
||||
@Test
|
||||
fun internalOnly() = doTestSuccess(INTERNAL, INTERNAL, INTERNAL, INTERNAL)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun privateOnly() = doTestFailure(PRIVATE)
|
||||
|
||||
@Test
|
||||
fun publicAndProtected() = doTestSuccess(PROTECTED, PUBLIC, PROTECTED, PUBLIC)
|
||||
|
||||
@Test
|
||||
fun publicAndInternal() = doTestSuccess(INTERNAL, PUBLIC, INTERNAL, PUBLIC)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun protectedAndInternal() = doTestFailure(PUBLIC, INTERNAL, PROTECTED)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun publicAndPrivate() = doTestFailure(PUBLIC, INTERNAL, PRIVATE)
|
||||
|
||||
@Test(expected = IllegalStateException::class)
|
||||
fun somethingUnexpected() = doTestFailure(PUBLIC, LOCAL)
|
||||
|
||||
override fun createCommonizer() = VisibilityCommonizer.lowering()
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.parentOrNull
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
|
||||
import org.jetbrains.kotlin.types.refinement.TypeRefinement
|
||||
import kotlin.random.Random
|
||||
|
||||
// expected special name for module
|
||||
internal fun mockEmptyModule(moduleName: String): ModuleDescriptor {
|
||||
val module = KotlinTestUtils.createEmptyModule(moduleName)
|
||||
module.initialize(PackageFragmentProvider.Empty)
|
||||
return module
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
internal fun mockClassType(
|
||||
fqName: String,
|
||||
nullable: Boolean = false
|
||||
): KotlinType = LazyWrappedType(LockBasedStorageManager.NO_LOCKS) {
|
||||
val classFqName = FqName(fqName)
|
||||
|
||||
val classTypeConstructor = object : AbstractClassTypeConstructor(LockBasedStorageManager.NO_LOCKS) {
|
||||
lateinit var classDescriptor: ClassDescriptor
|
||||
override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||
override fun computeSupertypes(): List<KotlinType> = emptyList()
|
||||
override fun isDenotable() = true
|
||||
override fun getDeclarationDescriptor() = classDescriptor
|
||||
override val supertypeLoopChecker = SupertypeLoopChecker.EMPTY
|
||||
override fun toString() = "class type constructor ${declarationDescriptor.name}"
|
||||
}
|
||||
|
||||
val classDescriptor = object : ClassDescriptorBase(
|
||||
/*storageManager =*/ LockBasedStorageManager.NO_LOCKS,
|
||||
/*containingDeclaration =*/ createPackageFragmentForClassifier(classFqName),
|
||||
/*name =*/ classFqName.shortName(),
|
||||
/*source =*/ SourceElement.NO_SOURCE,
|
||||
/*isExternal =*/ false
|
||||
) {
|
||||
override fun getStaticScope() = MemberScope.Empty
|
||||
override fun getConstructors(): List<ClassConstructorDescriptor> = emptyList()
|
||||
override fun getCompanionObjectDescriptor(): ClassDescriptor? = null
|
||||
override fun getKind() = ClassKind.CLASS
|
||||
override fun getModality() = Modality.FINAL
|
||||
override fun getVisibility() = Visibilities.PUBLIC
|
||||
override fun isCompanionObject() = false
|
||||
override fun isData() = false
|
||||
override fun isInline() = false
|
||||
override fun getUnsubstitutedPrimaryConstructor(): ClassConstructorDescriptor? = null
|
||||
override fun isExpect() = false
|
||||
override fun getUnsubstitutedMemberScope(kotlinTypeRefiner: KotlinTypeRefiner) = MemberScope.Empty
|
||||
override fun isActual() = false
|
||||
override fun getSealedSubclasses(): List<ClassDescriptor> = emptyList()
|
||||
override fun getTypeConstructor() = classTypeConstructor
|
||||
override fun isInner() = false
|
||||
override fun getDeclaredTypeParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||
override val annotations = Annotations.EMPTY
|
||||
override fun toString() = "class descriptor $name"
|
||||
}
|
||||
|
||||
classTypeConstructor.classDescriptor = classDescriptor
|
||||
|
||||
createSimpleType(classTypeConstructor, nullable)
|
||||
}
|
||||
|
||||
@TypeRefinement
|
||||
internal fun mockTAType(
|
||||
fqName: String,
|
||||
nullable: Boolean = false,
|
||||
rightHandSideTypeProvider: () -> KotlinType
|
||||
): KotlinType = LazyWrappedType(LockBasedStorageManager.NO_LOCKS) {
|
||||
val typeAliasFqName = FqName(fqName)
|
||||
|
||||
val rightHandSideType = rightHandSideTypeProvider().lowerIfFlexible()
|
||||
|
||||
val typeAliasDescriptor = object : AbstractTypeAliasDescriptor(
|
||||
containingDeclaration = createPackageFragmentForClassifier(typeAliasFqName),
|
||||
annotations = Annotations.EMPTY,
|
||||
name = typeAliasFqName.shortName(),
|
||||
sourceElement = SourceElement.NO_SOURCE,
|
||||
visibilityImpl = Visibilities.PUBLIC
|
||||
) {
|
||||
private val myDefaultType by lazy { createSimpleType(typeConstructor, nullable) }
|
||||
override val storageManager = LockBasedStorageManager.NO_LOCKS
|
||||
override fun getTypeConstructorTypeParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||
override val underlyingType by lazy { rightHandSideType.getAbbreviation() ?: rightHandSideType }
|
||||
override fun getDefaultType() = myDefaultType
|
||||
override val classDescriptor get() = expandedType.constructor.declarationDescriptor as ClassDescriptor?
|
||||
override val constructors: Collection<TypeAliasConstructorDescriptor> = emptyList()
|
||||
override fun substitute(substitutor: TypeSubstitutor) = this
|
||||
override val expandedType by lazy { rightHandSideType }
|
||||
}
|
||||
|
||||
(rightHandSideType.getAbbreviatedType()?.expandedType ?: rightHandSideType).withAbbreviation(typeAliasDescriptor.defaultType)
|
||||
}
|
||||
|
||||
internal fun mockProperty(
|
||||
name: String,
|
||||
setterVisibility: Visibility?,
|
||||
extensionReceiverType: KotlinType?,
|
||||
returnType: KotlinType
|
||||
): PropertyDescriptor {
|
||||
val propertyName = Name.identifier(name)
|
||||
|
||||
val containingDeclaration = object : DeclarationDescriptorImpl(Annotations.EMPTY, Name.special("<fake containing declaration>")) {
|
||||
override fun getContainingDeclaration() = error("not supported")
|
||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D) = error("not supported")
|
||||
}
|
||||
|
||||
val propertyDescriptor = PropertyDescriptorImpl.create(
|
||||
/*containingDeclaration =*/ containingDeclaration,
|
||||
/*annotations =*/ Annotations.EMPTY,
|
||||
/*modality =*/ Modality.FINAL,
|
||||
/*visibility =*/ Visibilities.PUBLIC,
|
||||
/*isVar =*/ setterVisibility != null,
|
||||
/*name =*/ propertyName,
|
||||
/*kind =*/ CallableMemberDescriptor.Kind.DECLARATION,
|
||||
/*source =*/ SourceElement.NO_SOURCE,
|
||||
/*lateInit =*/ false,
|
||||
/*isConst =*/ false,
|
||||
/*isExpect =*/ false,
|
||||
/*isActual =*/ false,
|
||||
/*isExternal =*/ false,
|
||||
/*isDelegated =*/ false
|
||||
)
|
||||
|
||||
val extensionReceiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
|
||||
/*owner =*/ propertyDescriptor,
|
||||
/*receiverParameterType =*/ extensionReceiverType,
|
||||
/*annotations =*/ Annotations.EMPTY
|
||||
)
|
||||
|
||||
val dispatchReceiverDescriptor = DescriptorUtils.getDispatchReceiverParameterIfNeeded(containingDeclaration)
|
||||
|
||||
propertyDescriptor.setType(
|
||||
/*outType =*/ returnType,
|
||||
/*typeParameters =*/ emptyList(),
|
||||
/*dispatchReceiverParameter =*/ dispatchReceiverDescriptor,
|
||||
/*extensionReceiverParameter =*/ extensionReceiverDescriptor
|
||||
)
|
||||
|
||||
val getter = DescriptorFactory.createDefaultGetter(
|
||||
/*propertyDescriptor =*/ propertyDescriptor,
|
||||
/*annotations =*/ Annotations.EMPTY
|
||||
).apply {
|
||||
initialize(null) // use return type from the property descriptor
|
||||
}
|
||||
|
||||
val setter = setterVisibility?.let {
|
||||
DescriptorFactory.createSetter(
|
||||
/*propertyDescriptor =*/ propertyDescriptor,
|
||||
/*annotations =*/ Annotations.EMPTY,
|
||||
/*parameterAnnotations =*/ Annotations.EMPTY,
|
||||
/*isDefault =*/ false,
|
||||
/*isExternal =*/ false,
|
||||
/*isInline =*/ false,
|
||||
/*visibility =*/ setterVisibility,
|
||||
/*sourceElement =*/ SourceElement.NO_SOURCE
|
||||
)
|
||||
}
|
||||
|
||||
propertyDescriptor.initialize(getter, setter)
|
||||
|
||||
return propertyDescriptor
|
||||
}
|
||||
|
||||
//private fun mockTypeParameterType(
|
||||
// name: String,
|
||||
// containingDeclaration: DeclarationDescriptor,
|
||||
// definitelyNotNull: Boolean = false
|
||||
//): KotlinType {
|
||||
// val typeParameterName = Name.identifier(name)
|
||||
//
|
||||
// val typeParameterDescriptor = TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||
// /*containingDeclaration =*/ containingDeclaration,
|
||||
// /*annotations =*/ Annotations.EMPTY,
|
||||
// /*reified =*/ false,
|
||||
// /*variance =*/ Variance.INVARIANT,
|
||||
// /*name =*/ typeParameterName,
|
||||
// /*index =*/ 0
|
||||
// )
|
||||
//
|
||||
// val simpleType = createSimpleType(typeParameterDescriptor.typeConstructor, false)
|
||||
//
|
||||
// return if (definitelyNotNull)
|
||||
// simpleType.makeSimpleTypeDefinitelyNotNullOrNotNull().also { check(it.isDefinitelyNotNullType) }
|
||||
// else
|
||||
// simpleType
|
||||
//}
|
||||
|
||||
private fun createPackageFragmentForClassifier(classifierFqName: FqName): PackageFragmentDescriptor =
|
||||
object : PackageFragmentDescriptor {
|
||||
private val module: ModuleDescriptor by lazy { mockEmptyModule("<module4_${classifierFqName.shortName()}_x${Random.nextInt()}>") }
|
||||
override fun getContainingDeclaration(): ModuleDescriptor = module
|
||||
override val fqName = classifierFqName.parentOrNull() ?: FqName.ROOT
|
||||
override fun getMemberScope() = MemberScope.Empty
|
||||
override fun getOriginal() = this
|
||||
override fun getName() = fqName.shortNameOrSpecial()
|
||||
override fun getSource() = SourceElement.NO_SOURCE
|
||||
override val annotations = Annotations.EMPTY
|
||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R = error("not supported")
|
||||
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) = error("not supported")
|
||||
override fun toString() = "package $name"
|
||||
}
|
||||
|
||||
private fun createSimpleType(typeConstructor: TypeConstructor, nullable: Boolean): SimpleType =
|
||||
KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
annotations = Annotations.EMPTY,
|
||||
constructor = typeConstructor,
|
||||
arguments = emptyList(),
|
||||
nullable = nullable,
|
||||
memberScope = MemberScope.Empty,
|
||||
refinedTypeFactory = { null }
|
||||
)
|
||||
@@ -83,6 +83,7 @@ include ":kotlin-build-common",
|
||||
":js:js.tests",
|
||||
":kotlin-native:kotlin-native-utils",
|
||||
":kotlin-native:kotlin-native-library-reader",
|
||||
":kotlin-native:commonizer",
|
||||
":jps-plugin",
|
||||
":kotlin-jps-plugin",
|
||||
":core:descriptors",
|
||||
@@ -337,6 +338,7 @@ project(':kotlin-util-io').projectDir = "$rootDir/compiler/util-io" as File
|
||||
project(':kotlin-util-klib').projectDir = "$rootDir/compiler/util-klib" as File
|
||||
project(':kotlin-native:kotlin-native-utils').projectDir = "$rootDir/konan/utils" as File
|
||||
project(':kotlin-native:kotlin-native-library-reader').projectDir = "$rootDir/konan/library-reader" as File
|
||||
project(':kotlin-native:commonizer').projectDir = "$rootDir/konan/commonizer" as File
|
||||
project(':kotlin-jps-plugin').projectDir = "$rootDir/prepare/jps-plugin" as File
|
||||
project(':idea:idea-android-output-parser').projectDir = "$rootDir/idea/idea-android/idea-android-output-parser" as File
|
||||
project(':plugins:android-extensions-compiler').projectDir = "$rootDir/plugins/android-extensions/android-extensions-compiler" as File
|
||||
|
||||
Reference in New Issue
Block a user