[Commonizer] Property descriptors

This commit is contained in:
Dmitriy Dolovov
2019-08-05 17:08:52 +07:00
parent 0239229dfc
commit 7fee9d2f5a
54 changed files with 2800 additions and 0 deletions
+4
View File
@@ -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>
+52
View File
@@ -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())
}
}
@@ -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 }
@@ -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
}
}
}
}
@@ -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?>
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
}
@@ -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
}
}
@@ -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
}
@@ -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
}
@@ -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
@@ -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)
}
@@ -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 }
)
}
@@ -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()) }
@@ -0,0 +1,3 @@
package org.sample.one
val firstOrgSampleOne = 1
@@ -0,0 +1,3 @@
package org.sample.three
val firstOrgSampleThree = 1
@@ -0,0 +1,3 @@
package org.sample.two
val firstOrgSampleTwo = 1
@@ -0,0 +1,3 @@
// root package
val firstRoot = 1
@@ -0,0 +1,3 @@
package org.sample.one
val secondOrgSampleOne = 1
@@ -0,0 +1,3 @@
package org.sample.two
val secondOrgSampleTwo = 1
@@ -0,0 +1,3 @@
// root package
val secondRoot = 1
@@ -0,0 +1,3 @@
package org.sample.three
val thirdOrgSampleThree = 1
@@ -0,0 +1,3 @@
package org.sample.two
val thirdOrgSampleTwo = 1
@@ -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()
}
@@ -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
}
}
}
@@ -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())
}
}
@@ -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())
}
}
@@ -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()
}
}
@@ -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")
)
@@ -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()
}
@@ -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!!
@@ -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))
}
@@ -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()
}
@@ -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 }
)
+2
View File
@@ -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