[Commonizer] Property descriptor tests

This commit is contained in:
Dmitriy Dolovov
2019-09-02 16:49:52 +07:00
parent 7fee9d2f5a
commit 6a20a14f6e
77 changed files with 923 additions and 125 deletions
@@ -62,8 +62,8 @@ private fun Property.buildDescriptor(
val extensionReceiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
propertyDescriptor,
extensionReceiverType,
Annotations.EMPTY
extensionReceiver?.type,
extensionReceiver?.annotations ?: Annotations.EMPTY
)
val dispatchReceiverDescriptor = DescriptorUtils.getDispatchReceiverParameterIfNeeded(containingDeclaration)
@@ -7,6 +7,7 @@ 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.ExtensionReceiver
import org.jetbrains.kotlin.descriptors.commonizer.ir.Property
import org.jetbrains.kotlin.name.Name
@@ -36,7 +37,7 @@ class PropertyCommonizer : Commonizer<PropertyDescriptor, Property> {
modality = modality.result,
type = returnType.result,
setter = setter.result,
extensionReceiverType = extensionReceiver.result
extensionReceiver = extensionReceiver.result?.let { ExtensionReceiver.createNoAnnotations(it) }
)
}
@@ -36,7 +36,7 @@ private class DefaultPropertySetterCommonizer : PropertySetterCommonizer {
state = when (state) {
State.ERROR -> State.ERROR
State.EMPTY -> next?.let {
setterVisibility = VisibilityCommonizer.lowering()
setterVisibility = VisibilityCommonizer.equalizing()
doCommonizeWith(next)
} ?: State.WITHOUT_SETTER
State.WITH_SETTER -> next?.let(::doCommonizeWith) ?: State.ERROR
@@ -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.ir
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.types.UnwrappedType
data class ExtensionReceiver(
val annotations: Annotations,
val type: UnwrappedType
) {
companion object {
fun createNoAnnotations(type: UnwrappedType) = ExtensionReceiver(Annotations.EMPTY, type)
fun ReceiverParameterDescriptor.toReceiver() = ExtensionReceiver(annotations, type.unwrap())
}
}
@@ -11,6 +11,7 @@ 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.descriptors.commonizer.ir.ExtensionReceiver.Companion.toReceiver
import org.jetbrains.kotlin.resolve.constants.ConstantValue
interface Property : Declaration {
@@ -27,7 +28,7 @@ interface Property : Declaration {
val isDelegate: Boolean
val getter: Getter?
val setter: Setter?
val extensionReceiverType: UnwrappedType?
val extensionReceiver: ExtensionReceiver?
val backingFieldAnnotations: Annotations? // null assumes no backing field
val delegateFieldAnnotations: Annotations? // null assumes no backing field
val compileTimeInitializer: ConstantValue<*>?
@@ -39,7 +40,7 @@ data class CommonProperty(
override val modality: Modality,
override val type: UnwrappedType,
override val setter: Setter?,
override val extensionReceiverType: UnwrappedType?
override val extensionReceiver: ExtensionReceiver?
) : Property {
override val annotations get() = Annotations.EMPTY
override val isVar: Boolean get() = setter != null
@@ -69,7 +70,7 @@ data class TargetProperty(private val descriptor: PropertyDescriptor) : Property
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 extensionReceiver: ExtensionReceiver? get() = descriptor.extensionReceiverParameter?.toReceiver()
override val backingFieldAnnotations: Annotations? get() = descriptor.backingField?.annotations
override val delegateFieldAnnotations: Annotations? get() = descriptor.delegateField?.annotations
override val compileTimeInitializer: ConstantValue<*>? get() = descriptor.compileTimeInitializer
@@ -112,7 +113,7 @@ data class Setter(
Annotations.EMPTY,
Annotations.EMPTY,
visibility,
isDefault = true,
isDefault = visibility == Visibilities.PUBLIC,
isExternal = false,
isInline = false
)
@@ -35,7 +35,7 @@ internal fun mergeModules(modules: List<ModuleDescriptor?>): ModuleNode {
}
// collects member scopes for every non-empty package provided by this module
private fun ModuleDescriptor.collectNonEmptyPackageMemberScopes(collector: (FqName, MemberScope) -> Unit) {
internal 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
@@ -38,7 +38,7 @@ internal fun mergePackages(
return node
}
private fun MemberScope.collectProperties(collector: (PropertyKey, PropertyDescriptor) -> Unit) {
internal fun MemberScope.collectProperties(collector: (PropertyKey, PropertyDescriptor) -> Unit) {
getContributedDescriptors(DescriptorKindFilter.VARIABLES).asSequence()
.filterIsInstance<PropertyDescriptor>()
.forEach { property ->
@@ -46,7 +46,7 @@ private fun MemberScope.collectProperties(collector: (PropertyKey, PropertyDescr
}
}
private data class PropertyKey(
internal data class PropertyKey(
val name: Name,
val extensionReceiverParameterFqName: FqName?
) {
@@ -5,8 +5,6 @@
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> {
@@ -16,6 +14,3 @@ internal fun <T> Sequence<T>.toList(expectedCapacity: Int): List<T> {
}
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,7 @@
expect var propertyWithoutBackingField: Double
expect val propertyWithBackingField: Double
expect val propertyWithDelegateField: Int
expect val String.propertyWithExtensionReceiver: Int
@@ -0,0 +1,22 @@
import kotlin.annotation.AnnotationTarget.*
@Target(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, FIELD, VALUE_PARAMETER)
@Repeatable
annotation class Foo(val text: String)
@property:Foo("property")
@get:Foo("getter")
@set:Foo("setter")
@setparam:Foo("parameter")
actual var propertyWithoutBackingField
get() = 3.14
set(value) = Unit
@field:Foo("field")
actual val propertyWithBackingField = 3.14
@delegate:Foo("field")
actual val propertyWithDelegateField: Int by lazy { 42 }
actual val @receiver:Foo("receiver") String.propertyWithExtensionReceiver: Int
get() = length
@@ -0,0 +1,19 @@
import kotlin.annotation.AnnotationTarget.*
@Target(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, FIELD, VALUE_PARAMETER)
@Repeatable
annotation class Bar(val text: String)
@Bar("property")
actual var propertyWithoutBackingField
@Bar("getter") get() = 3.14
@Bar("setter") set(@Bar("parameter") value) = Unit
@field:Bar("field")
actual val propertyWithBackingField = 3.14
@delegate:Bar("field")
actual val propertyWithDelegateField: Int by lazy { 42 }
actual val @receiver:Bar("receiver") String.propertyWithExtensionReceiver: Int
get() = length
@@ -0,0 +1,19 @@
import kotlin.annotation.AnnotationTarget.*
@Target(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, FIELD, VALUE_PARAMETER)
@Repeatable
annotation class Foo(val text: String)
@Foo("property")
var propertyWithoutBackingField
@Foo("getter") get() = 3.14
@Foo("setter") set(@Foo("parameter") value) = Unit
@field:Foo("field")
val propertyWithBackingField = 3.14
@delegate:Foo("field")
val propertyWithDelegateField: Int by lazy { 42 }
val @receiver:Foo("receiver") String.propertyWithExtensionReceiver: Int
get() = length
@@ -0,0 +1,19 @@
import kotlin.annotation.AnnotationTarget.*
@Target(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, FIELD, VALUE_PARAMETER)
@Repeatable
annotation class Bar(val text: String)
@Bar("property")
var propertyWithoutBackingField
@Bar("getter") get() = 3.14
@Bar("setter") set(@Bar("parameter") value) = Unit
@field:Bar("field")
val propertyWithBackingField = 3.14
@delegate:Bar("field")
val propertyWithDelegateField: Int by lazy { 42 }
val @receiver:Bar("receiver") String.propertyWithExtensionReceiver: Int
get() = length
@@ -0,0 +1,8 @@
class Planet(val name: String, val diameter: Double)
expect val intProperty: Int
expect val Int.intProperty: Int
expect val Short.intProperty: Int
expect val Long.intProperty: Int
expect val String.intProperty: Int
expect val Planet.intProperty: Int
@@ -0,0 +1,11 @@
class Planet(val name: String, val diameter: Double)
actual val intProperty get() = 42
actual val Int.intProperty get() = this
actual val Short.intProperty get() = toInt()
actual val Long.intProperty get() = toInt()
actual val String.intProperty get() = length
actual val Planet.intProperty get() = diameter.toInt()
val String.mismatchedProperty1 get() = 42
val mismatchedProperty2 get() = 42
@@ -0,0 +1,11 @@
class Planet(val name: String, val diameter: Double)
actual val intProperty get() = 42
actual val Int.intProperty get() = this
actual val Short.intProperty get() = toInt()
actual val Long.intProperty get() = toInt()
actual val String.intProperty get() = length
actual val Planet.intProperty get() = diameter.toInt()
val mismatchedProperty1 get() = 42
val Double.mismatchedProperty2 get() = 42
@@ -0,0 +1,11 @@
class Planet(val name: String, val diameter: Double)
val intProperty get() = 42
val Int.intProperty get() = this
val Short.intProperty get() = toInt()
val Long.intProperty get() = toInt()
val String.intProperty get() = length
val Planet.intProperty get() = diameter.toInt()
val String.mismatchedProperty1 get() = 42
val mismatchedProperty2 get() = 42
@@ -0,0 +1,11 @@
class Planet(val name: String, val diameter: Double)
val intProperty get() = 42
val Int.intProperty get() = this
val Short.intProperty get() = toInt()
val Long.intProperty get() = toInt()
val String.intProperty get() = length
val Planet.intProperty get() = diameter.toInt()
val mismatchedProperty1 get() = 42
val Double.mismatchedProperty2 get() = 42
@@ -1,3 +0,0 @@
package org.sample.one
val firstOrgSampleOne = 1
@@ -1,3 +0,0 @@
package org.sample.three
val firstOrgSampleThree = 1
@@ -1,3 +0,0 @@
package org.sample.two
val firstOrgSampleTwo = 1
@@ -1,3 +0,0 @@
// root package
val firstRoot = 1
@@ -1,3 +0,0 @@
package org.sample.one
val secondOrgSampleOne = 1
@@ -1,3 +0,0 @@
package org.sample.two
val secondOrgSampleTwo = 1
@@ -1,3 +0,0 @@
// root package
val secondRoot = 1
@@ -1,3 +0,0 @@
package org.sample.three
val thirdOrgSampleThree = 1
@@ -1,3 +0,0 @@
package org.sample.two
val thirdOrgSampleTwo = 1
@@ -1,3 +0,0 @@
// root package
val thirdRoot = 1
@@ -0,0 +1,3 @@
package org.sample.two
expect val qux: Int
@@ -0,0 +1 @@
expect val foo: Int
@@ -0,0 +1,3 @@
package org.sample
val bar = 1
@@ -0,0 +1,3 @@
package org.sample.one
val baz = 1
@@ -0,0 +1,3 @@
package org.sample.two
actual val qux = 1
@@ -0,0 +1,5 @@
actual val foo = 1
val jsSpecificProperty = 42
val jsAndJvmSpecificProperty = 42 * 2
val jsAndNativeSpecificProperty = 42 * 3
@@ -0,0 +1,3 @@
package org.sample
val bar = 1
@@ -0,0 +1,3 @@
package org.sample.two
actual val qux = 1
@@ -0,0 +1,5 @@
actual val foo = 1
val jvmSpecificProperty = 42
val jsAndJvmSpecificProperty = 42 * 2
val jvmAndNativeSpecificProperty = 42 * 4
@@ -0,0 +1,3 @@
package org.sample.one
val baz = 1
@@ -0,0 +1,3 @@
package org.sample.two
actual val qux = 1
@@ -0,0 +1,5 @@
actual val foo = 1
val nativeSpecificProperty = 42
val jsAndNativeSpecificProperty = 42 * 3
val jvmAndNativeSpecificProperty = 42 * 4
@@ -0,0 +1,3 @@
package org.sample
val bar = 1
@@ -0,0 +1,3 @@
package org.sample.one
val baz = 1
@@ -0,0 +1,3 @@
package org.sample.two
val qux = 1
@@ -0,0 +1,5 @@
val foo = 1
val jsSpecificProperty = 42
val jsAndJvmSpecificProperty = 42 * 2
val jsAndNativeSpecificProperty = 42 * 3
@@ -0,0 +1,3 @@
package org.sample
val bar = 1
@@ -0,0 +1,3 @@
package org.sample.two
val qux = 1
@@ -0,0 +1,5 @@
val foo = 1
val jvmSpecificProperty = 42
val jsAndJvmSpecificProperty = 42 * 2
val jvmAndNativeSpecificProperty = 42 * 4
@@ -0,0 +1,3 @@
package org.sample.one
val baz = 1
@@ -0,0 +1,3 @@
package org.sample.two
val qux = 1
@@ -0,0 +1,5 @@
val foo = 1
val nativeSpecificProperty = 42
val jsAndNativeSpecificProperty = 42 * 3
val jvmAndNativeSpecificProperty = 42 * 4
@@ -0,0 +1,15 @@
class Planet(val name: String, val diameter: Double)
expect val propertyWithInferredType1: Int
expect val propertyWithInferredType2: String
expect val propertyWithInferredType3: String
expect val propertyWithInferredType4: Nothing?
expect val propertyWithInferredType5: Planet
typealias C = Planet
expect val property1: Int
expect val property2: String
expect val property3: Planet
expect val property6: Planet
expect val property7: C
@@ -0,0 +1,24 @@
class Planet(val name: String, val diameter: Double)
actual val propertyWithInferredType1 = 1
actual val propertyWithInferredType2 = "hello"
actual val propertyWithInferredType3 = 42.toString()
actual val propertyWithInferredType4 = null
actual val propertyWithInferredType5 = Planet("Earth", 12742)
typealias A = Planet
typealias C = Planet
actual val property1 = 1
actual val property2 = "hello"
actual val property3 = Planet("Earth", 12742)
val property4 = A("Earth", 12742)
val property5 = A("Earth", 12742)
actual val property6 = Planet("Earth", 12742)
actual val property7 = C("Earth", 12742)
val propertyWithMismatchedType1: Int = 1
val propertyWithMismatchedType2: Int = 1
val propertyWithMismatchedType3: Int = 1
val propertyWithMismatchedType4: Int = 1
val propertyWithMismatchedType5: Int = 1
@@ -0,0 +1,24 @@
class Planet(val name: String, val diameter: Double)
actual val propertyWithInferredType1 get() = 1
actual val propertyWithInferredType2 get() = "hello"
actual val propertyWithInferredType3 get() = 42.toString()
actual val propertyWithInferredType4 get() = null
actual val propertyWithInferredType5 get() = Planet("Earth", 12742)
typealias B = Planet
typealias C = Planet
actual val property1 = 1
actual val property2 = "hello"
actual val property3 = Planet("Earth", 12742)
val property4: B = Planet("Earth", 12742)
val property5: Planet = A("Earth", 12742)
actual val property6: Planet = A("Earth", 12742)
actual val property7: C = Planet("Earth", 12742)
val propertyWithMismatchedType1: Long = 1
val propertyWithMismatchedType2: Short = 1
val propertyWithMismatchedType3: Number = 1
val propertyWithMismatchedType4: Comparable<Int> = 1
val propertyWithMismatchedType5: String = 1.toString()
@@ -0,0 +1,24 @@
class Planet(val name: String, val diameter: Double)
val propertyWithInferredType1 = 1
val propertyWithInferredType2 = "hello"
val propertyWithInferredType3 = 42.toString()
val propertyWithInferredType4 = null
val propertyWithInferredType5 = Planet("Earth", 12742)
typealias A = Planet
typealias C = Planet
val property1 = 1 // with inferred type
val property2 = "hello" // with inferred type
val property3 = Planet("Earth", 12742) // with inferred type
val property4 = A("Earth", 12742) // with inferred type
val property5 = A("Earth", 12742) // with inferred type
val property6 = Planet("Earth", 12742) // with inferred type
val property7 = C("Earth", 12742) // with inferred type
val propertyWithMismatchedType1: Int = 1
val propertyWithMismatchedType2: Int = 1
val propertyWithMismatchedType3: Int = 1
val propertyWithMismatchedType4: Int = 1
val propertyWithMismatchedType5: Int = 1
@@ -0,0 +1,24 @@
class Planet(val name: String, val diameter: Double)
val propertyWithInferredType1 get() = 1
val propertyWithInferredType2 get() = "hello"
val propertyWithInferredType3 get() = 42.toString()
val propertyWithInferredType4 get() = null
val propertyWithInferredType5 get() = Planet("Earth", 12742)
typealias B = Planet
typealias C = Planet
val property1: Int = 1 // with explicit type
val property2: String = "hello" // with explicit type
val property3: Planet = Planet("Earth", 12742) // with explicit type
val property4: B = Planet("Earth", 12742) // with explicit type
val property5: Planet = A("Earth", 12742) // with explicit type
val property6: Planet = A("Earth", 12742) // with explicit type
val property7: C = Planet("Earth", 12742) // with explicit type
val propertyWithMismatchedType1: Long = 1
val propertyWithMismatchedType2: Short = 1
val propertyWithMismatchedType3: Number = 1
val propertyWithMismatchedType4: Comparable<Int> = 1
val propertyWithMismatchedType5: String = 1.toString()
@@ -1,21 +0,0 @@
// 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()
}
@@ -1,21 +0,0 @@
// 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,16 @@
expect var defaultSetter1: Int
expect var defaultSetter2: Int
expect var defaultSetter3: Int
expect var setterWithoutBackingField1: Int
expect var setterWithoutBackingField2: Int
expect var setterWithDelegation1: Int
expect var setterWithDelegation2: Int
expect var defaultSetteCustomVisibility1: Int
expect var defaultSetteCustomVisibility3 = 42
internal set
expect val propertyWithoutSetter: Int
expect var propertyWithSetter: Int
@@ -0,0 +1,30 @@
actual var defaultSetter1 = 42
actual var defaultSetter2 = 42
set
actual var defaultSetter3 = 42
set
actual var setterWithoutBackingField1
get() = 42
set(value) = Unit
actual var setterWithoutBackingField2
get() = 42
set(value) = Unit
actual var setterWithDelegation1: Int by mutableMapOf("setterWithDelegation1" to 42)
actual var setterWithDelegation2: Int by mutableMapOf("setterWithDelegation2" to 42)
actual var defaultSetteCustomVisibility1 = 42
public set
var defaultSetteCustomVisibility2 = 42
internal set
actual var defaultSetteCustomVisibility3 = 42
internal set
var defaultSetteCustomVisibility4 = 42
private set
var defaultSetteCustomVisibility5 = 42
private set
actual val propertyWithoutSetter = 42
var propertyMaybeSetter = 42
actual var propertyWithSetter = 42
@@ -0,0 +1,27 @@
actual var defaultSetter1 = 42
actual var defaultSetter2 = 42
actual var defaultSetter3 = 42
set
actual var setterWithoutBackingField1
get() = 42
set(value) = Unit
actual var setterWithoutBackingField2 = 42
actual var setterWithDelegation1: Int by mutableMapOf("setterWithDelegation1" to 42)
actual var setterWithDelegation2 = 42
actual var defaultSetteCustomVisibility1 = 42
public set
var defaultSetteCustomVisibility2 = 42
public set
actual var defaultSetteCustomVisibility3 = 42
internal set
var defaultSetteCustomVisibility4 = 42
internal set
var defaultSetteCustomVisibility5 = 42
private set
actual val propertyWithoutSetter = 42
val propertyMaybeSetter = 42
actual var propertyWithSetter = 42
@@ -0,0 +1,30 @@
var defaultSetter1 = 42
var defaultSetter2 = 42
set
var defaultSetter3 = 42
set
var setterWithoutBackingField1
get() = 42
set(value) = Unit
var setterWithoutBackingField2
get() = 42
set(value) = Unit
var setterWithDelegation1: Int by mutableMapOf("setterWithDelegation1" to 42)
var setterWithDelegation2: Int by mutableMapOf("setterWithDelegation2" to 42)
var defaultSetteCustomVisibility1 = 42
public set
var defaultSetteCustomVisibility2 = 42
internal set
var defaultSetteCustomVisibility3 = 42
internal set
var defaultSetteCustomVisibility4 = 42
private set
var defaultSetteCustomVisibility5 = 42
private set
val propertyWithoutSetter = 42
var propertyMaybeSetter = 42
var propertyWithSetter = 42
@@ -0,0 +1,31 @@
var defaultSetter1 = 42
var defaultSetter2 = 42 // intentionally commented setter declaration
// set
var defaultSetter3 = 42
set
var setterWithoutBackingField1
get() = 42
set(value) = Unit
var setterWithoutBackingField2 = 42 // intentionally left as with backing field
var setterWithDelegation1: Int by mutableMapOf("setterWithDelegation1" to 42)
var setterWithDelegation2 = 42 // intentionally left without delegation
var defaultSetteCustomVisibility1 = 42
public set
var defaultSetteCustomVisibility2 = 42
// internal set
public set // intentionally used public visibility
var defaultSetteCustomVisibility3 = 42
internal set
var defaultSetteCustomVisibility4 = 42
// private set
internal set // intentionally used internal visibility
var defaultSetteCustomVisibility5 = 42
private set
val propertyWithoutSetter = 42
//var propertyMaybeSetter = 42
val propertyMaybeSetter = 42 // fixed to be a property without setter
var propertyWithSetter = 42
@@ -0,0 +1,7 @@
expect val delegatedProperty1: Int
expect val delegatedProperty2: Int
expect val delegatedProperty3: Int
expect val delegatedProperty4: Int
expect val inlineProperty1: Int
expect val inlineProperty2: Int
@@ -0,0 +1,13 @@
const val constProperty1 = 42
const val constProperty2 = 42
actual val delegatedProperty1: Int by lazy { 42 }
actual val delegatedProperty2: Int by lazy { 42 }
actual val delegatedProperty3: Int by mapOf("delegatedProperty3" to 42)
actual val delegatedProperty4: Int by mapOf("delegatedProperty4" to 42)
lateinit var lateinitProperty1: String
lateinit var lateinitProperty2: String
actual inline val inlineProperty1 get() = 42
actual inline val inlineProperty2 get() = 42
@@ -0,0 +1,13 @@
const val constProperty1 = 42
val constProperty2 = 42 // intentionally left as non-const
actual val delegatedProperty1: Int by lazy { 42 }
actual val delegatedProperty2 = 42 // intentionally left as non-delegated
actual val delegatedProperty3: Int by mapOf("delegatedProperty3" to 42)
actual val delegatedProperty4 = 42 // intentionally left as non-delegated
lateinit var lateinitProperty1: String
var lateinitProperty2 = "hello" // intentionally left as non-lateinit
actual inline val inlineProperty1 get() = 42
actual val inlineProperty2 = 42 // intentionally left as non-inline
@@ -0,0 +1,13 @@
const val constProperty1 = 42
const val constProperty2 = 42
val delegatedProperty1: Int by lazy { 42 }
val delegatedProperty2: Int by lazy { 42 }
val delegatedProperty3: Int by mapOf("delegatedProperty3" to 42)
val delegatedProperty4: Int by mapOf("delegatedProperty4" to 42)
lateinit var lateinitProperty1: String
lateinit var lateinitProperty2: String
inline val inlineProperty1 get() = 42
inline val inlineProperty2 get() = 42
@@ -0,0 +1,13 @@
const val constProperty1 = 42
val constProperty2 = 42 // intentionally left as non-const
val delegatedProperty1: Int by lazy { 42 }
val delegatedProperty2 = 42 // intentionally left as non-delegated
val delegatedProperty3: Int by mapOf("delegatedProperty3" to 42)
val delegatedProperty4 = 42 // intentionally left as non-delegated
lateinit var lateinitProperty1: String
var lateinitProperty2 = "hello" // intentionally left as non-lateinit
inline val inlineProperty1 get() = 42
val inlineProperty2 = 42 // intentionally left as non-inline
@@ -0,0 +1,2 @@
expect public val publicProperty: Int
expect internal val internalProperty: Int
@@ -0,0 +1,3 @@
actual public val publicProperty = 1
actual internal val internalProperty = 1
private val privateProperty = 1
@@ -0,0 +1,3 @@
actual public val publicProperty = 1
actual internal val internalProperty = 1
private val privateProperty = 1
@@ -0,0 +1,3 @@
public val publicProperty = 1
internal val internalProperty = 1
private val privateProperty = 1
@@ -0,0 +1,3 @@
public val publicProperty = 1
internal val internalProperty = 1
private val privateProperty = 1
@@ -17,7 +17,9 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.test.KotlinTestUtils.*
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import java.io.File
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
@Suppress("MemberVisibilityCanBePrivate")
abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
companion object {
@@ -25,17 +27,17 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
System.setProperty("java.awt.headless", "true")
}
fun List<ModuleDescriptor>.eachModuleAsTarget() = CommonizationParameters().also {
forEachIndexed { index, module ->
it.addTarget("target_$index", listOf(module))
fun Collection<ModuleDescriptor>.eachModuleAsTarget() = mapIndexed { index, moduleDescriptor ->
"target_$index" to moduleDescriptor
}.toMap().toCommonizationParameters()
fun Map<String, ModuleDescriptor>.toCommonizationParameters() = CommonizationParameters().also {
forEach { (targetName, moduleDescriptor) ->
it.addTarget(targetName, listOf(moduleDescriptor))
}
}
}
fun assertIsDirectory(file: File) {
assertTrue("Not a directory: $file", file.isDirectory)
}
protected fun createEnvironment(bareModuleName: String): KotlinCoreEnvironment {
check(Name.isValidIdentifier(bareModuleName))
val configuration = newConfiguration()
@@ -65,31 +67,46 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
.also(::assertIsDirectory)
}
protected val sourceModuleRoots: List<File>
protected val sourceModuleRoots: Pair<Set<File>, Set<File>>
get() {
val testDataDir = testDataDir
val roots = testDataDir.listFiles()?.toList()
if (roots.isNullOrEmpty())
error("No source module roots found in $testDataDir")
val originalRoots = testDataDir
.resolve("original")
.also(::assertIsDirectory)
.listFiles()
?.toSet()
?.also { it.forEach(::assertIsDirectory) }
roots.forEach(::assertIsDirectory)
val commonizedRoots = testDataDir
.resolve("commonized")
.also(::assertIsDirectory)
.listFiles()
?.toSet()
?.also { it.forEach(::assertIsDirectory) }
return roots
check(
!originalRoots.isNullOrEmpty() && !commonizedRoots.isNullOrEmpty()
&& (originalRoots.map { it.name } + "common").toSet() == commonizedRoots.map { it.name }.toSet()
) {
"Source module misconfiguration in $testDataDir"
}
return originalRoots to commonizedRoots
}
protected val sourceModuleDescriptors: List<ModuleDescriptor>
protected val sourceModuleDescriptors: Pair<Map<String, ModuleDescriptor>, Map<String, ModuleDescriptor>>
get() {
return sourceModuleRoots.map { root ->
val environment = createEnvironment(root.parentFile.name)
fun analyzeTarget(targetRoot: File): Pair<String, ModuleDescriptor> {
val environment = createEnvironment(targetRoot.parentFile.parentFile.name)
val psiFactory = KtPsiFactory(environment.project)
val psiFiles = root.walkTopDown()
val psiFiles = targetRoot.walkTopDown()
.filter { it.isFile }
.map { psiFactory.createFile(it.name, doLoadFile(it)) }
.toList()
CommonResolverForModuleFactory.analyzeFiles(
val moduleDescriptor = CommonResolverForModuleFactory.analyzeFiles(
files = psiFiles,
moduleName = environment.moduleName,
dependOnBuiltIns = true,
@@ -97,6 +114,32 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
) { content ->
environment.createPackagePartProvider(content.moduleContentScope)
}.moduleDescriptor
return targetRoot.name to moduleDescriptor
}
return sourceModuleRoots.first.map(::analyzeTarget).toMap() to sourceModuleRoots.second.map(::analyzeTarget).toMap()
}
protected fun doTestSuccessfulCommonization() {
val (originalModules, commonizedModules) = sourceModuleDescriptors
val result = runCommonization(originalModules.toCommonizationParameters())
assertCommonizationPerformed(result)
val commonModuleAsExpected = commonizedModules.getValue("common")
val commonModuleByCommonizer = result.commonModules.single()
assertModulesAreEqual(commonModuleAsExpected, commonModuleByCommonizer, "\"common\" target")
val concreteTargetNames = commonizedModules.keys - "common"
assertEquals(concreteTargetNames, result.modulesByTargets.keys)
for (targetName in concreteTargetNames) {
val targetModuleAsExpected = commonizedModules.getValue(targetName)
val targetModuleByCommonizer = result.modulesByTargets.getValue(targetName).single()
assertModulesAreEqual(targetModuleAsExpected, targetModuleByCommonizer, "\"$targetName\" target")
}
}
}
@@ -9,7 +9,9 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.junit.Assert.*
import org.junit.Test
import org.jetbrains.kotlin.descriptors.commonizer.AbstractCommonizationFromSourcesTest.Companion.eachModuleAsTarget
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
class BasicCommonizerFacadeTest {
@Test
@@ -41,8 +43,7 @@ class BasicCommonizerFacadeTest {
val result = runCommonization(modules.eachModuleAsTarget())
assertTrue(result is CommonizationPerformed)
require(result is CommonizationPerformed) // to enforce Kotlin contracts
assertCommonizationPerformed(result)
assertSingleModuleForTarget("<foo>", result.commonModules)
@@ -5,18 +5,26 @@
package org.jetbrains.kotlin.descriptors.commonizer
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
class PropertyCommonizationFromSourcesTest : AbstractCommonizationFromSourcesTest() {
fun testMatchingPackages() {
val modules = sourceModuleDescriptors
val result = runCommonization(modules.eachModuleAsTarget())
println(result)
fun testMismatchedPackages() = doTestSuccessfulCommonization()
// TODO: implement
}
fun testReturnTypes() = doTestSuccessfulCommonization()
fun testVisibility() = doTestSuccessfulCommonization()
fun testSpecificProperties() = doTestSuccessfulCommonization()
fun testExtensionReceivers() = doTestSuccessfulCommonization()
fun testSetters() = doTestSuccessfulCommonization()
fun testAnnotations() = doTestSuccessfulCommonization()
// TODO: test modality (possible only inside classes)
// TODO: test virtual val visibility commonization (possible only inside classes)
fun testSample() {
val modules = sourceModuleDescriptors
runCommonization(modules.eachModuleAsTarget())
}
}
@@ -0,0 +1,268 @@
/*
* 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 junit.framework.TestCase.fail
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.PropertyKey
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.collectNonEmptyPackageMemberScopes
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.collectProperties
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import java.io.File
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.reflect.KCallable
fun assertIsDirectory(file: File) {
if (!file.isDirectory)
fail("Not a directory: $file")
}
@ExperimentalContracts
fun assertCommonizationPerformed(result: CommonizationResult) {
contract {
returns() implies (result is CommonizationPerformed)
}
if (result !is CommonizationPerformed)
fail("$result is not instance of ${CommonizationPerformed::class}")
}
@ExperimentalContracts
fun assertModulesAreEqual(expected: ModuleDescriptor, actual: ModuleDescriptor, designatorMessage: String) {
val visitor = ComparingDeclarationsVisitor(designatorMessage)
val context = visitor.Context(actual)
expected.accept(visitor, context)
}
@ExperimentalContracts
private class ComparingDeclarationsVisitor(
val designatorMessage: String
) : DeclarationDescriptorVisitor<Unit, ComparingDeclarationsVisitor.Context> {
inner class Context private constructor(
private val actual: DeclarationDescriptor?,
private val path: List<String>
) {
constructor(actual: DeclarationDescriptor?) : this(actual, listOf(actual.toString()))
fun nextLevel(nextActual: DeclarationDescriptor?) = Context(nextActual, path + nextActual.toString())
fun nextLevel(customPathElement: String) = Context(actual, path + customPathElement)
inline fun <reified T> getActualAs() = actual as T
override fun toString() =
"""
|Context: ${this@ComparingDeclarationsVisitor.designatorMessage}
|Path: ${path.joinToString(separator = " ->\n\t")}"
""".trimMargin()
}
override fun visitModuleDeclaration(expected: ModuleDescriptor, context: Context) {
val actual = context.getActualAs<ModuleDescriptor>()
context.assertEquals(expected.name, actual.name, "module names")
fun collectPackageMemberScopes(module: ModuleDescriptor): Map<FqName, MemberScope> = mutableMapOf<FqName, MemberScope>().also {
module.collectNonEmptyPackageMemberScopes { packageFqName, memberScope ->
if (memberScope.getContributedDescriptors().isNotEmpty())
it[packageFqName] = memberScope
}
}
val expectedPackageMemberScopes = collectPackageMemberScopes(expected)
val actualPackageMemberScopes = collectPackageMemberScopes(actual)
context.assertEquals(expectedPackageMemberScopes.keys, actualPackageMemberScopes.keys, "sets of packages")
for (packageFqName in expectedPackageMemberScopes.keys) {
val expectedMemberScope = expectedPackageMemberScopes.getValue(packageFqName)
val actualMemberScope = actualPackageMemberScopes.getValue(packageFqName)
visitMemberScopes(expectedMemberScope, actualMemberScope, context.nextLevel("package member scope [$packageFqName]"))
}
}
override fun visitPackageViewDescriptor(expected: PackageViewDescriptor, context: Context) =
fail("Comparison of package views not supported")
override fun visitPackageFragmentDescriptor(expected: PackageFragmentDescriptor, context: Context) =
fail("Comparison of package fragments not supported")
fun visitMemberScopes(expected: MemberScope, actual: MemberScope, context: Context) {
fun collectProperties(memberScope: MemberScope): Map<PropertyKey, PropertyDescriptor> =
mutableMapOf<PropertyKey, PropertyDescriptor>().also {
memberScope.collectProperties { propertyKey, property ->
it[propertyKey] = property
}
}
val expectedProperties = collectProperties(expected)
val actualProperties = collectProperties(actual)
context.assertEquals(expectedProperties.keys, actualProperties.keys, "sets of properties")
expectedProperties.forEach { (propertyKey, expectedProperty) ->
val actualProperty = actualProperties.getValue(propertyKey)
expectedProperty.accept(this, context.nextLevel(actualProperty))
}
// FIXME: traverse the rest - functions, classes, typealiases
}
override fun visitVariableDescriptor(expected: VariableDescriptor, context: Context) {
TODO("not implemented")
}
override fun visitFunctionDescriptor(expected: FunctionDescriptor, context: Context) {
TODO("not implemented")
}
override fun visitTypeParameterDescriptor(expected: TypeParameterDescriptor, context: Context) {
TODO("not implemented")
}
override fun visitClassDescriptor(expected: ClassDescriptor, context: Context) {
TODO("not implemented")
}
override fun visitTypeAliasDescriptor(expected: TypeAliasDescriptor, context: Context) {
TODO("not implemented")
}
override fun visitConstructorDescriptor(expected: ConstructorDescriptor, context: Context) {
TODO("not implemented")
}
override fun visitPropertyDescriptor(expected: PropertyDescriptor, context: Context) {
val actual = context.getActualAs<PropertyDescriptor>()
visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Property annotations"))
context.assertFieldsEqual(expected::getName, actual::getName)
context.assertFieldsEqual(expected::getVisibility, actual::getVisibility)
context.assertFieldsEqual(expected::getModality, actual::getModality)
context.assertFieldsEqual(expected::isVar, actual::isVar)
context.assertFieldsEqual(expected::getKind, actual::getKind)
context.assertFieldsEqual(expected::isLateInit, actual::isLateInit)
context.assertFieldsEqual(expected::isConst, actual::isConst)
context.assertFieldsEqual(expected::isExternal, actual::isExternal)
context.assertFieldsEqual(expected::isExpect, actual::isExpect)
context.assertFieldsEqual(expected::isActual, actual::isActual)
context.assertFieldsEqual(expected::isDelegated, actual::isDelegated)
visitAnnotations(
expected.delegateField?.annotations,
actual.delegateField?.annotations,
context.nextLevel("Property delegate field annotations")
)
visitAnnotations(
expected.backingField?.annotations,
actual.backingField?.annotations,
context.nextLevel("Property backing field annotations")
)
context.assertEquals(expected.compileTimeInitializer != null, actual.compileTimeInitializer != null, "compile-time initializers")
visitType(expected.type, actual.type, context.nextLevel("Property type"))
visitPropertyGetterDescriptor(expected.getter, context.nextLevel(actual.getter))
visitPropertySetterDescriptor(expected.setter, context.nextLevel(actual.setter))
visitReceiverParameterDescriptor(expected.extensionReceiverParameter, context.nextLevel(actual.extensionReceiverParameter))
visitReceiverParameterDescriptor(expected.dispatchReceiverParameter, context.nextLevel(actual.dispatchReceiverParameter))
}
override fun visitValueParameterDescriptor(expected: ValueParameterDescriptor, context: Context) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun visitPropertyGetterDescriptor(expected: PropertyGetterDescriptor?, context: Context) {
val actual = context.getActualAs<PropertyGetterDescriptor?>()
if (expected === actual) return
check(actual != null && expected != null)
visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Property getter annotations"))
context.assertFieldsEqual(expected::isDefault, actual::isDefault)
context.assertFieldsEqual(expected::isExternal, actual::isExternal)
context.assertFieldsEqual(expected::isInline, actual::isInline)
}
override fun visitPropertySetterDescriptor(expected: PropertySetterDescriptor?, context: Context) {
val actual = context.getActualAs<PropertySetterDescriptor?>()
if (expected === actual) return
check(actual != null && expected != null)
visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Property setter annotations"))
context.assertFieldsEqual(expected::isDefault, actual::isDefault)
context.assertFieldsEqual(expected::isExternal, actual::isExternal)
context.assertFieldsEqual(expected::isInline, actual::isInline)
context.assertFieldsEqual(expected::getVisibility, actual::getVisibility)
visitAnnotations(
expected.valueParameters.single().annotations,
actual.valueParameters.single().annotations,
context.nextLevel("Property setter value parameter annotations")
)
}
override fun visitReceiverParameterDescriptor(expected: ReceiverParameterDescriptor?, context: Context) {
val actual = context.getActualAs<ReceiverParameterDescriptor?>()
if (expected === actual) return
check(actual != null && expected != null)
visitType(expected.type, actual.type, context.nextLevel("Receiver parameter type"))
visitAnnotations(expected.annotations, actual.annotations, context.nextLevel("Receiver parameter annotations"))
}
override fun visitScriptDescriptor(expected: ScriptDescriptor, context: Context) =
fail("Comparison of script descriptors not supported")
private fun visitAnnotations(expected: Annotations?, actual: Annotations?, context: Context) {
if (expected === actual) return
val expectedAnnotationFqNames = (expected ?: Annotations.EMPTY).map { it.fqName }.toSet()
val actualAnnotationFqNames = (actual ?: Annotations.EMPTY).map { it.fqName }.toSet()
context.assertEquals(expectedAnnotationFqNames, actualAnnotationFqNames, "annotations")
}
private fun visitType(expected: KotlinType, actual: KotlinType, context: Context) {
if (expected === actual) return
val expectedUnwrapped = expected.unwrap()
val actualUnwrapped = actual.unwrap()
if (expectedUnwrapped === actualUnwrapped) return
val expectedFqName = expectedUnwrapped.constructor.declarationDescriptor!!.fqNameSafe
val actualFqName = actualUnwrapped.constructor.declarationDescriptor!!.fqNameSafe
context.assertEquals(expectedFqName, actualFqName, "type FQN")
}
private fun <T> Context.assertEquals(expected: T?, actual: T?, subject: String) {
if (expected != actual)
fail(
buildString {
append("Comparing $subject:\n")
append("$expected is not equal to $actual\n")
append(this@assertEquals.toString())
}
)
}
private fun <T> Context.assertFieldsEqual(expected: KCallable<T>, actual: KCallable<T>) {
val expectedValue = expected.call()
val actualValue = actual.call()
assertEquals(expectedValue, actualValue, "fields \"$expected\"")
}
}
@@ -43,17 +43,17 @@ class DefaultPropertySetterCommonizerTest : AbstractCommonizerTest<PropertySette
@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 publicAndProtected() = doTestFailure(PUBLIC, PUBLIC, PROTECTED)
@Test(expected = IllegalStateException::class)
fun protectedAndInternal() = doTestFailure(PUBLIC, INTERNAL, PROTECTED)
fun publicAndInternal() = doTestFailure(PUBLIC, PUBLIC, INTERNAL)
@Test(expected = IllegalStateException::class)
fun publicAndPrivate() = doTestFailure(PUBLIC, INTERNAL, PRIVATE)
fun protectedAndInternal() = doTestFailure(PROTECTED, PROTECTED, INTERNAL)
@Test(expected = IllegalStateException::class)
fun publicAndPrivate() = doTestFailure(PUBLIC, PUBLIC, PRIVATE)
@Test(expected = IllegalStateException::class)
fun somethingUnexpected() = doTestFailure(PUBLIC, LOCAL)