Instantiation of annotations for JVM IR with the corresponding feature flag

Seperate checker for platforms that do not support this language feature yet

Synthetic implementations of annotations are generated on-demand with proper 
equals, hashCode, and annotationType methods

#KT-47699 Fixed
This commit is contained in:
Leonid Startsev
2021-07-21 10:23:51 +00:00
committed by Space
parent 4bc521249b
commit ce0a3a57df
59 changed files with 1589 additions and 64 deletions
@@ -1103,6 +1103,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt"); runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt");
} }
@Test
@TestMetadata("ConstructorCallAllowed.kt")
public void testConstructorCallAllowed() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt");
}
@Test @Test
@TestMetadata("DanglingMixed.kt") @TestMetadata("DanglingMixed.kt")
public void testDanglingMixed() throws Exception { public void testDanglingMixed() throws Exception {
@@ -1103,6 +1103,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt"); runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt");
} }
@Test
@TestMetadata("ConstructorCallAllowed.kt")
public void testConstructorCallAllowed() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt");
}
@Test @Test
@TestMetadata("DanglingMixed.kt") @TestMetadata("DanglingMixed.kt")
public void testDanglingMixed() throws Exception { public void testDanglingMixed() throws Exception {
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -380,6 +380,76 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
} }
} }
@Nested
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
public class Instances {
@Test
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationEnclosingName.kt")
public void testAnnotationEnclosingName() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationEnclosingName.kt");
}
@Test
@TestMetadata("annotationEqHc.kt")
public void testAnnotationEqHc() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationEqHc.kt");
}
@Test
@TestMetadata("annotationInstances.kt")
public void testAnnotationInstances() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationInstances.kt");
}
@Test
@TestMetadata("annotationInstancesEmptyDefault.kt")
public void testAnnotationInstancesEmptyDefault() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationInstancesEmptyDefault.kt");
}
@Test
@TestMetadata("annotationToString.kt")
public void testAnnotationToString() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
}
@Test
@TestMetadata("annotationType.kt")
public void testAnnotationType() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationType.kt");
}
@Test
@TestMetadata("javaAnnotation.kt")
public void testJavaAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt");
}
@Test
@TestMetadata("multifileEqHc.kt")
public void testMultifileEqHc() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/multifileEqHc.kt");
}
@Test
@TestMetadata("multimoduleInlining.kt")
public void testMultimoduleInlining() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/multimoduleInlining.kt");
}
@Test
@TestMetadata("multiplatformInstantiation.kt")
public void testMultiplatformInstantiation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/multiplatformInstantiation.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -25,6 +25,28 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
} }
@Nested
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
public class Annotations {
@Test
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationInstanceInlining.kt")
public void testAnnotationInstanceInlining() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/annotationInstanceInlining.kt");
}
@Test
@TestMetadata("instanceInAnonymousClass.kt")
public void testInstanceInAnonymousClass() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/instanceInAnonymousClass.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
package org.jetbrains.kotlin.resolve.calls package org.jetbrains.kotlin.resolve.calls
@@ -238,7 +227,8 @@ class CallExpressionResolver(
if (functionDescriptor is ConstructorDescriptor) { if (functionDescriptor is ConstructorDescriptor) {
val constructedClass = functionDescriptor.constructedClass val constructedClass = functionDescriptor.constructedClass
if (DescriptorUtils.isAnnotationClass(constructedClass) && !canInstantiateAnnotationClass(callExpression, context.trace)) { if (DescriptorUtils.isAnnotationClass(constructedClass) && !canInstantiateAnnotationClass(callExpression, context.trace)) {
context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression)) val supported = context.languageVersionSettings.supportsFeature(LanguageFeature.InstantiationOfAnnotationClasses) && constructedClass.declaredTypeParameters.isEmpty()
if (!supported) context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression))
} }
if (DescriptorUtils.isEnumClass(constructedClass)) { if (DescriptorUtils.isEnumClass(constructedClass)) {
context.trace.report(ENUM_CLASS_CONSTRUCTOR_CALL.on(callExpression)) context.trace.report(ENUM_CLASS_CONSTRUCTOR_CALL.on(callExpression))
@@ -515,7 +505,7 @@ class CallExpressionResolver(
companion object { companion object {
private fun canInstantiateAnnotationClass(expression: KtCallExpression, trace: BindingTrace): Boolean { fun canInstantiateAnnotationClass(expression: KtCallExpression, trace: BindingTrace): Boolean {
//noinspection unchecked //noinspection unchecked
var parent: PsiElement? = PsiTreeUtil.getParentOfType(expression, KtValueArgument::class.java, KtParameter::class.java) var parent: PsiElement? = PsiTreeUtil.getParentOfType(expression, KtValueArgument::class.java, KtParameter::class.java)
if (parent is KtValueArgument) { if (parent is KtValueArgument) {
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
/**
* Additional checker that prohibits usage of LanguageFeature.InstantiationOfAnnotationClasses on backends
* that do not support this feature yet
*/
object InstantiationOfAnnotationClassesCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.InstantiationOfAnnotationClasses)) return
val calledDescriptor = resolvedCall.resultingDescriptor as? ConstructorDescriptor ?: return
val constructedClass = calledDescriptor.constructedClass
val expression = resolvedCall.call.callElement as? KtCallExpression ?: return
if (DescriptorUtils.isAnnotationClass(constructedClass) && !CallExpressionResolver.canInstantiateAnnotationClass(
expression,
context.trace
)
) {
val supported = constructedClass.declaredTypeParameters.isEmpty()
if (supported) {
context.trace.report(Errors.ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(expression))
} else {
// already reported in CallExpressionResolver.getCallExpressionTypeInfoWithoutFinalTypeCheck
}
}
}
}
@@ -0,0 +1,208 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isKClass
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
val ANNOTATION_IMPLEMENTATION = object : IrDeclarationOriginImpl("ANNOTATION_IMPLEMENTATION", isSynthetic = true) {}
class AnnotationImplementationLowering(
val transformer: (IrFile) -> AnnotationImplementationTransformer
) : FileLoweringPass {
override fun lower(irFile: IrFile) {
val tf = transformer(irFile)
irFile.transformChildrenVoid(tf)
tf.implementations.values.forEach {
val parentClass = it.parent as IrDeclarationContainer
parentClass.declarations += it
}
}
}
open class AnnotationImplementationTransformer(val context: BackendContext, val irFile: IrFile) : IrElementTransformerVoidWithContext() {
internal val implementations: MutableMap<IrClass, IrClass> = mutableMapOf()
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
val constructedClass = expression.type.classOrNull?.owner ?: return expression
if (!constructedClass.isAnnotationClass) return expression
if (constructedClass.typeParameters.isNotEmpty()) return expression // Not supported yet
val implClass = implementations.getOrPut(constructedClass) { createAnnotationImplementation(constructedClass) }
val ctor = implClass.constructors.single()
val newCall = IrConstructorCallImpl.fromSymbolOwner(
expression.startOffset,
expression.endOffset,
implClass.defaultType,
ctor.symbol,
)
newCall.copyTypeAndValueArgumentsFrom(expression)
newCall.transformChildrenVoid() // for annotations in annotations
return newCall
}
private fun createAnnotationImplementation(annotationClass: IrClass): IrClass {
val localDeclarationParent = currentClass?.scope?.getLocalDeclarationParent() as? IrClass
val parentFqName = annotationClass.fqNameWhenAvailable!!.asString().replace('.', '_')
val wrapperName = Name.identifier("annotationImpl\$$parentFqName$0")
val subclass = context.irFactory.buildClass {
name = wrapperName
origin = ANNOTATION_IMPLEMENTATION
// It can be seen from inline functions and multiple classes within one file
// JavaDescriptorVisibilities.PACKAGE_VISIBILITY also can be used here, like in SAM, but that's not a big difference
// since declaration is synthetic anyway
visibility = DescriptorVisibilities.INTERNAL
}.apply {
parent = localDeclarationParent ?: irFile
createImplicitParameterDeclarationWithWrappedDescriptor()
superTypes = listOf(annotationClass.defaultType)
}
val ctor = subclass.addConstructor {
visibility = DescriptorVisibilities.PUBLIC
}
val (originalProps, implementationProps) = implementAnnotationProperties(subclass, annotationClass, ctor)
implementEqualsAndHashCode(annotationClass, subclass, originalProps, implementationProps)
implementPlatformSpecificParts(annotationClass, subclass)
return subclass
}
fun implementAnnotationProperties(implClass: IrClass, annotationClass: IrClass, generatedConstructor: IrConstructor): Pair<List<IrProperty>, List<IrProperty>> {
val ctorBody = context.irFactory.createBlockBody(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(
IrDelegatingConstructorCallImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, context.irBuiltIns.anyClass.constructors.single(),
typeArgumentsCount = 0, valueArgumentsCount = 0
)
)
)
generatedConstructor.body = ctorBody
val properties = annotationClass.getAnnotationProperties()
return properties to properties.map { property ->
val propType = property.getter!!.returnType
val propName = property.name
val field = context.irFactory.buildField {
name = propName
type = propType
origin = ANNOTATION_IMPLEMENTATION
isFinal = true
visibility = DescriptorVisibilities.PRIVATE
}.also { it.parent = implClass }
val parameter = generatedConstructor.addValueParameter(propName.asString(), propType)
// VALUE_FROM_PARAMETER
val originalParameter = ((property.backingField?.initializer?.expression as? IrGetValue)?.symbol?.owner as? IrValueParameter)
if (originalParameter?.defaultValue != null) {
parameter.defaultValue = originalParameter.defaultValue!!.deepCopyWithVariables().also { it.transformChildrenVoid() }
}
ctorBody.statements += IrSetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, field.symbol,
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, implClass.thisReceiver!!.symbol),
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.symbol),
context.irBuiltIns.unitType,
)
val prop = implClass.addProperty {
name = propName
isVar = false
origin = ANNOTATION_IMPLEMENTATION
}.apply {
backingField = field
parent = implClass
}
prop.addGetter {
name = propName // Annotation value getter should be named 'x', not 'getX'
returnType = propType.kClassToJClassIfNeeded() // On JVM, annotation store j.l.Class even if declared with KClass
origin = ANNOTATION_IMPLEMENTATION
visibility = DescriptorVisibilities.PUBLIC
modality = Modality.FINAL
}.apply {
dispatchReceiverParameter = implClass.thisReceiver!!.copyTo(this)
body = context.createIrBuilder(symbol).irBlockBody {
var value: IrExpression = irGetField(irGet(dispatchReceiverParameter!!), field)
if (propType.isKClass()) value = this.kClassExprToJClassIfNeeded(value)
+irReturn(value)
}
}
prop
}
}
fun IrClass.getAnnotationProperties(): List<IrProperty> {
// For some weird reason, annotations defined in other IrFiles, do not have IrProperties in declarations.
// (although annotations imported from Java do have)
val props = declarations.filterIsInstance<IrProperty>()
if (props.isNotEmpty()) return props
return declarations.filterIsInstance<IrSimpleFunction>().filter { it.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR }
.mapNotNull { it.correspondingPropertySymbol?.owner }
}
open fun IrType.kClassToJClassIfNeeded(): IrType = this
open fun IrBuilderWithScope.kClassExprToJClassIfNeeded(irExpression: IrExpression): IrExpression = irExpression
open fun generatedEquals(irBuilder: IrBlockBodyBuilder, type: IrType, arg1: IrExpression, arg2: IrExpression): IrExpression =
irBuilder.irEquals(arg1, arg2)
@Suppress("UNUSED_VARIABLE")
fun implementEqualsAndHashCode(annotationClass: IrClass, implClass: IrClass, originalProps: List<IrProperty>, childProps: List<IrProperty>) {
val creator = MethodsFromAnyGeneratorForLowerings(context, implClass, ANNOTATION_IMPLEMENTATION)
val generator =
creator.LoweringDataClassMemberGenerator(
nameForToString = "@" + annotationClass.fqNameWhenAvailable!!.asString(),
typeForEquals = annotationClass.defaultType
) { type, a, b ->
generatedEquals(this, type, a, b)
}
// Manual implementation of equals is required for two reasons:
// 1. `other` should be casted to interface instead of implementation
// 2. Properties should be retrieved using getters without accessing backing fields
// (DataClassMembersGenerator typically tries to access fields)
val eqFun = creator.createEqualsMethodDeclaration()
generator.generateEqualsUsingGetters(eqFun, annotationClass.defaultType, originalProps)
val hcFun = creator.createHashCodeMethodDeclaration()
generator.generateHashCodeMethod(hcFun, childProps)
val toStringFun = creator.createToStringMethodDeclaration()
generator.generateToStringMethod(toStringFun, childProps)
}
open fun implementPlatformSpecificParts(annotationClass: IrClass, implClass: IrClass) {}
}
@@ -0,0 +1,127 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.kotlin.ir.util.DataClassMembersGenerator
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
class MethodsFromAnyGeneratorForLowerings(val context: BackendContext, val irClass: IrClass, val origin: IrDeclarationOrigin) {
fun createToStringMethodDeclaration(): IrSimpleFunction = irClass.addFunction("toString", context.irBuiltIns.stringType).apply {
overriddenSymbols = irClass.collectOverridenSymbols { it.isToString() }
}
fun createHashCodeMethodDeclaration(): IrSimpleFunction = irClass.addFunction("hashCode", context.irBuiltIns.intType).apply {
overriddenSymbols = irClass.collectOverridenSymbols { it.isHashCode() }
}
fun createEqualsMethodDeclaration(): IrSimpleFunction = irClass.addFunction("equals", context.irBuiltIns.booleanType).apply {
overriddenSymbols = irClass.collectOverridenSymbols { it.isEquals(context) }
addValueParameter("other", context.irBuiltIns.anyNType)
}
inner class LoweringDataClassMemberGenerator(
val nameForToString: String,
val typeForEquals: IrType,
val selectEquals: IrBlockBodyBuilder.(IrType, IrExpression, IrExpression) -> IrExpression,
) :
DataClassMembersGenerator(
IrLoweringContext(context),
context.ir.symbols.externalSymbolTable,
irClass,
origin
) {
override fun declareSimpleFunction(startOffset: Int, endOffset: Int, functionDescriptor: FunctionDescriptor): IrFunction {
error("Descriptor API shouldn't be used in lowerings")
}
override fun generateSyntheticFunctionParameterDeclarations(irFunction: IrFunction) {
// no-op — irFunction from lowering should already have necessary parameters
}
override fun getProperty(parameter: ValueParameterDescriptor?, irValueParameter: IrValueParameter?): IrProperty? {
error("Descriptor API shouldn't be used in lowerings")
}
override fun transform(typeParameterDescriptor: TypeParameterDescriptor): IrType {
error("Descriptor API shouldn't be used in lowerings")
}
override val intPlusSymbol: IrSimpleFunctionSymbol =
context.irBuiltIns.intClass.functions.single { it.owner.name.asString() == "plus" && it.owner.valueParameters[0].type == context.irBuiltIns.intType }
override val intTimesSymbol: IrSimpleFunctionSymbol =
context.irBuiltIns.intClass.functions.single { it.owner.name.asString() == "times" && it.owner.valueParameters[0].type == context.irBuiltIns.intType }
override fun getHashCodeFunctionInfo(type: IrType): HashCodeFunctionInfo {
val symbol = if (type.isArray() || type.isPrimitiveArray()) {
context.irBuiltIns.dataClassArrayMemberHashCodeSymbol
} else {
context.irBuiltIns.anyClass.functions.single { it.owner.name.asString() == "hashCode" }
}
return object : HashCodeFunctionInfo {
override val symbol: IrSimpleFunctionSymbol = symbol
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>) {}
}
}
override fun IrClass.classNameForToString(): String = nameForToString
fun generateEqualsUsingGetters(equalsFun: IrSimpleFunction, typeForEquals: IrType, properties: List<IrProperty>) = equalsFun.apply {
body = this@MethodsFromAnyGeneratorForLowerings.context.createIrBuilder(symbol).irBlockBody {
val irType = typeForEquals
fun irOther() = irGet(valueParameters[0])
fun irThis() = irGet(dispatchReceiverParameter!!)
fun IrProperty.get(receiver: IrExpression) = irCall(getter!!).apply {
dispatchReceiver = receiver
}
+irIfThenReturnFalse(irNotIs(irOther(), irType))
val otherWithCast = irTemporary(irAs(irOther(), irType), "other_with_cast")
for (property in properties) {
val arg1 = property.get(irThis())
val arg2 = property.get(irGet(irType, otherWithCast.symbol))
+irIfThenReturnFalse(irNot(selectEquals(property.getter?.returnType ?: property.backingField!!.type, arg1, arg2)))
}
+irReturnTrue()
}
}
}
companion object {
fun IrFunction.isToString(): Boolean =
name.asString() == "toString" && extensionReceiverParameter == null && valueParameters.isEmpty()
fun IrFunction.isHashCode() =
name.asString() == "hashCode" && extensionReceiverParameter == null && valueParameters.isEmpty()
fun IrFunction.isEquals(context: BackendContext) =
name.asString() == "equals" &&
extensionReceiverParameter == null &&
valueParameters.singleOrNull()?.type == context.irBuiltIns.anyNType
fun IrClass.collectOverridenSymbols(predicate: (IrFunction) -> Boolean): List<IrSimpleFunctionSymbol> =
superTypes.mapNotNull { it.getClass()?.functions?.singleOrNull(predicate)?.symbol }
}
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.ir.addFakeOverrides import org.jetbrains.kotlin.backend.common.ir.addFakeOverrides
import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.MethodsFromAnyGeneratorForLowerings.Companion.isHashCode
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.DescriptorVisibility
@@ -273,8 +274,9 @@ class SamEqualsHashCodeMethodsGenerator(
fun generate() { fun generate() {
generateGetFunctionDelegate() generateGetFunctionDelegate()
generateEquals() val anyGenerator = MethodsFromAnyGeneratorForLowerings(context, klass, IrDeclarationOrigin.SYNTHETIC_GENERATED_SAM_IMPLEMENTATION)
generateHashCode() generateEquals(anyGenerator)
generateHashCode(anyGenerator)
} }
private fun generateGetFunctionDelegate() { private fun generateGetFunctionDelegate() {
@@ -286,17 +288,9 @@ class SamEqualsHashCodeMethodsGenerator(
} }
} }
private fun generateEquals() { private fun generateEquals(anyGenerator: MethodsFromAnyGeneratorForLowerings) {
klass.addFunction("equals", builtIns.booleanType).apply { anyGenerator.createEqualsMethodDeclaration().apply {
overriddenSymbols = klass.superTypes.mapNotNull { val other = valueParameters[0]
it.getClass()?.functions?.singleOrNull {
it.name.asString() == "equals" &&
it.extensionReceiverParameter == null &&
it.valueParameters.singleOrNull()?.type == builtIns.anyNType
}?.symbol
}
val other = addValueParameter("other", builtIns.anyNType)
body = context.createIrBuilder(symbol).run { body = context.createIrBuilder(symbol).run {
irExprBody( irExprBody(
irIfThenElse( irIfThenElse(
@@ -322,16 +316,9 @@ class SamEqualsHashCodeMethodsGenerator(
} }
} }
private fun generateHashCode() { private fun generateHashCode(anyGenerator: MethodsFromAnyGeneratorForLowerings) {
klass.addFunction("hashCode", builtIns.intType).apply { anyGenerator.createHashCodeMethodDeclaration().apply {
val hashCode = context.irBuiltIns.functionClass.owner.functions.single{ it.isHashCode() }.symbol
fun isHashCode(function: IrSimpleFunction) =
function.name.asString() == "hashCode" && function.extensionReceiverParameter == null && function.valueParameters.isEmpty()
overriddenSymbols = klass.superTypes.mapNotNull {
it.getClass()?.functions?.singleOrNull(::isHashCode)?.symbol
}
val hashCode = context.irBuiltIns.functionClass.owner.functions.single(::isHashCode).symbol
body = context.createIrBuilder(symbol).run { body = context.createIrBuilder(symbol).run {
irExprBody( irExprBody(
irCall(hashCode).also { irCall(hashCode).also {
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -324,6 +324,7 @@ private val jvmFilePhases = listOf(
inventNamesForLocalClassesPhase, inventNamesForLocalClassesPhase,
kCallableNamePropertyPhase, kCallableNamePropertyPhase,
annotationPhase, annotationPhase,
annotationImplementationPhase,
polymorphicSignaturePhase, polymorphicSignaturePhase,
varargPhase, varargPhase,
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -802,19 +802,30 @@ class JvmSymbols(
} }
} }
private fun IrClass.addArraysEqualsFunction(arrayType: IrSimpleType) {
addFunction("equals", irBuiltIns.booleanType, isStatic = true).apply {
addValueParameter("a", arrayType)
addValueParameter("b", arrayType)
}
}
val arraysClass: IrClassSymbol = val arraysClass: IrClassSymbol =
createClass(FqName("java.util.Arrays")) { irClass -> createClass(FqName("java.util.Arrays")) { irClass ->
irClass.addArraysCopyOfFunction(booleanArrayType) for (type in listOf(
irClass.addArraysCopyOfFunction(byteArrayType) booleanArrayType,
irClass.addArraysCopyOfFunction(charArrayType) byteArrayType,
irClass.addArraysCopyOfFunction(shortArrayType) charArrayType,
irClass.addArraysCopyOfFunction(intArrayType) shortArrayType,
irClass.addArraysCopyOfFunction(longArrayType) intArrayType,
irClass.addArraysCopyOfFunction(floatArrayType) longArrayType,
irClass.addArraysCopyOfFunction(doubleArrayType) floatArrayType,
doubleArrayType,
// public static <T> T[] copyOf(T[] original, int newLength) arrayOfAnyNType
irClass.addArraysCopyOfFunction(arrayOfAnyNType) )) {
irClass.addArraysCopyOfFunction(type)
irClass.addArraysEqualsFunction(type)
}
} }
fun getArraysCopyOfFunction(arrayType: IrSimpleType): IrSimpleFunctionSymbol { fun getArraysCopyOfFunction(arrayType: IrSimpleType): IrSimpleFunctionSymbol {
@@ -0,0 +1,86 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.lower.ANNOTATION_IMPLEMENTATION
import org.jetbrains.kotlin.backend.common.lower.AnnotationImplementationLowering
import org.jetbrains.kotlin.backend.common.lower.AnnotationImplementationTransformer
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering.Companion.javaClassReference
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.findDeclaration
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
import org.jetbrains.kotlin.ir.util.render
internal val annotationImplementationPhase = makeIrFilePhase<JvmBackendContext>(
{ ctxt -> AnnotationImplementationLowering { JvmAnnotationImplementationTransformer(ctxt, it) } },
name = "AnnotationImplementation",
description = "Create synthetic annotations implementations and use them in annotations constructor calls"
)
class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext, file: IrFile) :
AnnotationImplementationTransformer(jvmContext, file) {
override fun IrType.kClassToJClassIfNeeded(): IrType = when {
this.isKClass() -> jvmContext.ir.symbols.javaLangClass.starProjectedType
this.isKClassArray() -> jvmContext.irBuiltIns.arrayClass.typeWith(
jvmContext.ir.symbols.javaLangClass.starProjectedType
)
else -> this
}
private fun IrType.isKClassArray() =
this is IrSimpleType && isArray() && arguments.single().typeOrNull?.isKClass() == true
override fun IrBuilderWithScope.kClassExprToJClassIfNeeded(irExpression: IrExpression): IrExpression {
with(this) {
return irGet(
jvmContext.ir.symbols.javaLangClass.starProjectedType,
null,
jvmContext.ir.symbols.kClassJava.owner.getter!!.symbol
).apply {
extensionReceiver = irExpression
}
}
}
override fun generatedEquals(irBuilder: IrBlockBodyBuilder, type: IrType, arg1: IrExpression, arg2: IrExpression): IrExpression {
return if (type.isArray() || type.isPrimitiveArray()) {
val targetType = if (type.isPrimitiveArray()) type else jvmContext.ir.symbols.arrayOfAnyNType
val requiredSymbol = jvmContext.ir.symbols.arraysClass.owner.findDeclaration<IrFunction> {
it.name.asString() == "equals" && it.valueParameters.size == 2 && it.valueParameters.first().type == targetType
}
requireNotNull(requiredSymbol) { "Can't find Arrays.equals method for type ${targetType.render()}" }
irBuilder.irCall(
requiredSymbol.symbol
).apply {
putValueArgument(0, arg1)
putValueArgument(1, arg2)
}
} else super.generatedEquals(irBuilder, type, arg1, arg2)
}
override fun implementPlatformSpecificParts(annotationClass: IrClass, implClass: IrClass) {
implClass.addFunction(
name = "annotationType",
returnType = jvmContext.ir.symbols.javaLangClass.starProjectedType,
origin = ANNOTATION_IMPLEMENTATION,
isStatic = false
).apply {
body = jvmContext.createIrBuilder(symbol).irBlockBody {
+irReturn(javaClassReference(annotationClass.defaultType, jvmContext))
}
}
}
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -16,9 +16,7 @@ import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.mapTypeParameters import org.jetbrains.kotlin.ir.expressions.mapTypeParameters
import org.jetbrains.kotlin.ir.expressions.mapValueParameters import org.jetbrains.kotlin.ir.expressions.mapValueParameters
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
@@ -34,7 +32,7 @@ import org.jetbrains.kotlin.name.Name
@OptIn(ObsoleteDescriptorBasedAPI::class) @OptIn(ObsoleteDescriptorBasedAPI::class)
abstract class DataClassMembersGenerator( abstract class DataClassMembersGenerator(
val context: IrGeneratorContext, val context: IrGeneratorContext,
val symbolTable: SymbolTable, val symbolTable: ReferenceSymbolTable,
val irClass: IrClass, val irClass: IrClass,
val origin: IrDeclarationOrigin val origin: IrDeclarationOrigin
) { ) {
@@ -43,11 +41,24 @@ abstract class DataClassMembersGenerator(
inline fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T = inline fun <T : IrDeclaration> T.buildWithScope(builder: (T) -> Unit): T =
also { irDeclaration -> also { irDeclaration ->
symbolTable.withScope(irDeclaration) { symbolTable.withReferenceScope(irDeclaration) {
builder(irDeclaration) builder(irDeclaration)
} }
} }
private val intClass = context.builtIns.int
private val intType = context.builtIns.intType
open val intTimesSymbol: IrSimpleFunctionSymbol =
intClass.unsubstitutedMemberScope.findFirstFunction("times") {
KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, intType)
}.let { symbolTable.referenceSimpleFunction(it) }
open val intPlusSymbol: IrSimpleFunctionSymbol =
intClass.unsubstitutedMemberScope.findFirstFunction("plus") {
KotlinTypeChecker.DEFAULT.equalTypes(it.valueParameters[0].type, intType)
}.let { symbolTable.referenceSimpleFunction(it) }
private inner class MemberFunctionBuilder( private inner class MemberFunctionBuilder(
startOffset: Int = UNDEFINED_OFFSET, startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET,
@@ -206,7 +217,7 @@ abstract class DataClassMembersGenerator(
fun generateToStringMethodBody(properties: List<IrProperty>) { fun generateToStringMethodBody(properties: List<IrProperty>) {
val irConcat = irConcat() val irConcat = irConcat()
irConcat.addArgument(irString(irClass.name.asString() + "(")) irConcat.addArgument(irString(irClass.classNameForToString() + "("))
var first = true var first = true
for (property in properties) { for (property in properties) {
if (!first) irConcat.addArgument(irString(", ")) if (!first) irConcat.addArgument(irString(", "))
@@ -362,4 +373,6 @@ abstract class DataClassMembersGenerator(
generateToStringMethodBody(properties) generateToStringMethodBody(properties)
} }
} }
open fun IrClass.classNameForToString(): String = irClass.name.asString()
} }
@@ -0,0 +1,53 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
// FILE: a.kt
package test
annotation class A1
annotation class A2
fun interface I {
fun run(): A1
}
// FILE: test.kt
package test
class E {
fun insideClass(): A1 = A1()
fun insideLammbda(): A1 = run { A1() }
fun insideSAM(): I = I { A1() }
}
class G {
// test that we can reuse instance in different classes from same file
fun insideClassAgain(): A1 = A1()
}
fun outsideClass(): A2 = A2()
fun test(instance: Any, parent: String, fqa: String) {
val clz = instance.javaClass
assert(clz.getName().startsWith(parent))
assert(clz.getName().contains(fqa))
assert(clz.getEnclosingMethod() == null)
assert(clz.getEnclosingClass().getName() == parent)
// SAM treated as anonymous because of Origin or something else, see ClassCodegen#IrClass.isAnonymousInnerClass
// assert(clz.getDeclaringClass() == null)
}
fun box(): String {
test(E().insideClass(), "test.E", "test_A1")
test(E().insideLammbda(), "test.E", "test_A1")
test(E().insideSAM().run(), "test.E", "test_A1")
test(G().insideClassAgain(), "test.E", "test_A1")
test(outsideClass(), "test.TestKt", "test_A2")
return "OK"
}
@@ -0,0 +1,30 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
import kotlin.reflect.KClass
annotation class Bar(val i:Int, val s: String, val f: Float)
annotation class Foo(
val int: Int,
val s: String,
val arr: Array<String>,
val arr2: IntArray,
val kClass: KClass<*>,
val bar: Bar
)
data class BarLike(val i:Int, val s: String, val f: Float)
fun box(): String {
val foo1 = Foo(42, "foo", arrayOf("a", "b"), intArrayOf(1,2), Bar::class, Bar(10, "bar", Float.NaN))
val foo2 = Foo(42, "foo", arrayOf("a", "b"), intArrayOf(1,2), Bar::class, Bar(10, "bar", Float.NaN))
if (foo1 != foo2) return "Failed equals"
val barlike = BarLike(10, "bar", Float.NaN)
if (barlike.hashCode() != foo1.bar.hashCode()) return "Failed HC1"
if (barlike.hashCode() != foo2.bar.hashCode()) return "Failed HC2"
return "OK"
}
@@ -0,0 +1,70 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
// note: taken from ../parameters.kt and ../parametersWithPrimitiveValues.kt
import kotlin.reflect.KClass
import kotlin.test.assertEquals
enum class E { E0 }
annotation class Empty
annotation class A(
val b: Byte,
val s: Short,
val i: Int,
val f: Float,
val d: Double,
val l: Long,
val c: Char,
val bool: Boolean
)
@Retention(AnnotationRetention.RUNTIME)
annotation class Anno(
val s: String,
val i: Int,
val f: Double,
val u: UInt,
val e: E,
val a: A,
val k: KClass<*>,
val arr: Array<String>,
val intArr: IntArray,
val arrOfE: Array<E>,
val arrOfA: Array<Empty>,
val arrOfK: Array<KClass<*>>
)
fun box(): String {
val anno = Anno(
"OK", 42, 2.718281828, 43u, E.E0,
A(1, 1, 1, 1.0.toFloat(), 1.0, 1, 'c', true),
A::class, emptyArray(), intArrayOf(1, 2), arrayOf(E.E0), arrayOf(Empty()), arrayOf(E::class, Empty::class)
)
assertEquals(anno.s, "OK")
assertEquals(anno.i, 42)
assert(anno.f > 2.0 && anno.f < 3.0)
assertEquals(anno.u, 43u)
assertEquals(anno.e, E.E0)
assert(anno.a is A)
assert(anno.k == A::class)
assert(anno.arr.isEmpty())
assert(anno.intArr.contentEquals(intArrayOf(1, 2)))
assert(anno.arrOfE.contentEquals(arrayOf(E.E0)))
assert(anno.arrOfA.size == 1)
// assert(anno.arrOfK.size == 2) TODO(KT-47703): Array<KClass> to Array<j.l.Class> conversion
val ann = anno.a
assertEquals(ann.b, 1.toByte())
assertEquals(ann.s, 1.toShort())
assertEquals(ann.i, 1)
assertEquals(ann.f, 1.toFloat())
assertEquals(ann.d, 1.0)
assertEquals(ann.l, 1.toLong())
assertEquals(ann.c, 'c')
assert(ann.bool)
return "OK"
}
@@ -0,0 +1,38 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
package test
import kotlin.reflect.KClass
enum class E { A, B }
annotation class A()
annotation class B(val a: A = A())
annotation class C(
val i: Int = 42,
val b: B = B(),
val kClass: KClass<*> = B::class,
val e: E = E.B,
val aS: Array<String> = arrayOf("a", "b"),
val aI: IntArray = intArrayOf(1, 2)
)
annotation class Partial(
val i: Int = 42,
val s: String = "foo",
val e: E = E.A
)
fun box(): String {
val c = C()
assert(c.toString() == "@test.C(i=42, b=@test.B(a=@test.A()), kClass=interface test.B (Kotlin reflection is not available), e=B, aS=[a, b], aI=[1, 2])")
val p = Partial(e = E.B, s = "bar")
assert(p.toString() == "@test.Partial(i=42, s=bar, e=B)")
return "OK"
}
@@ -0,0 +1,50 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
package test
import kotlin.reflect.KClass
enum class E { E0 }
annotation class Empty
annotation class A(
val b: Byte,
val s: Short,
val i: Int,
val f: Float,
val d: Double,
val l: Long,
val c: Char,
val bool: Boolean
)
@Retention(AnnotationRetention.RUNTIME)
annotation class Anno(
val s: String,
val i: Int,
val f: Double,
val u: UInt,
val e: E,
val a: A,
val k: KClass<*>,
val arr: Array<String>,
val intArr: IntArray,
val arrOfE: Array<E>,
val arrOfA: Array<Empty>,
)
fun box(): String {
val anno = Anno(
"OK", 42, 2.718281828, 43u, E.E0,
A(1, 1, 1, 1.0.toFloat(), 1.0, 1, 'c', true),
A::class, emptyArray(), intArrayOf(1, 2), arrayOf(E.E0), arrayOf(Empty())
)
val s = anno.toString()
val target = "@test.Anno(s=OK, i=42, f=2.718281828, u=43, e=E0, a=@test.A(b=1, s=1, i=1, f=1.0, d=1.0, l=1, c=c, bool=true), " +
"k=interface test.A (Kotlin reflection is not available), arr=[], intArr=[1, 2], arrOfE=[E0], arrOfA=[@test.Empty()])"
return if (s == target) "OK" else "FAILED, got string $s"
}
@@ -0,0 +1,18 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
annotation class Foo(
val int: Int,
)
fun box(): String {
val foo = Foo(42)
val jClass = (foo as java.lang.annotation.Annotation).annotationType()
val kClass = foo.annotationClass
if (kClass != Foo::class) return "FAIL $kClass"
if (jClass != Foo::class.java) return "FAIL $jClass"
return "OK"
}
@@ -0,0 +1,44 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
// FILE: A.java
public @interface A {}
// FILE: B.java
public @interface B {
String value();
}
// FILE: C.java
public @interface C {
int[] v1();
String v2();
}
// FILE: D.java
public @interface D {
String value() default "hello";
}
// FILE: b.kt
fun box(): String {
val a = A()
val b = B("OK")
assert(b.value == "OK")
val c = C(v2 = "v2", v1 = intArrayOf(1))
assert(c.v2 == "v2")
// TODO(KT-47702): Looks like we have to force users either to pass default java parameters explicitly
// or hack LazyJavaClassDescriptor/JavaPropertyDescriptor to load annotation param default value,
// because it is not stored currently anywhere.
// val d = D()
val d = D("OK").value
return d
}
@@ -0,0 +1,26 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
// FILE: a.kt
package a
annotation class A(val i: Int)
fun createInOtherFile(): A = A(10)
// FILE: b.kt
import a.*
fun here(): A = A(10)
fun box(): String {
if (here() != createInOtherFile()) return "Fail equals"
if (here().hashCode() != createInOtherFile().hashCode()) return "Fail hashCode"
if (here().toString() != createInOtherFile().toString()) return "Fail toString"
return "OK"
}
@@ -0,0 +1,42 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// IGNORE_DEXING
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
// MODULE: lib
// FILE: lib.kt
package a
annotation class A(val i: Int)
inline fun foo(i: Int): A = A(i)
inline fun bar(f: () -> Int): A = A(f())
// MODULE: app(lib)
// FILE: app.kt
package test
import a.*
class C {
fun one(): A = foo(1)
fun two(): A = bar { 2 }
}
fun box(): String {
val one = C().one()
val two = C().two()
assert(one.i == 1)
assert(two.i == 2)
// Just like SAM wrappers, annotation implementation classes should be copied from inline functions
// into current module to avoid compatibility problems when inline fun implementation in origin module
// has changed (e.g. do not instantiate annotation anymore)
assert(one.javaClass.getEnclosingClass().getName() == "test.C")
assert(two.javaClass.getEnclosingClass().getName() == "test.C")
return "OK"
}
@@ -0,0 +1,30 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses +MultiPlatformProjects
// MODULE: lib
// FILE: common.kt
expect annotation class A(val value: String)
fun createCommon(): A = A("OK")
// FILE: platform.kt
actual annotation class A(actual val value: String)
fun createPlatform(): A = A("OK")
// MODULE: main(lib)
// FILE: main.kt
fun createApp(): A = A("OK")
fun box(): String {
if (createApp().value != "OK") return "FAIL app"
if (createCommon().value != "OK") return "FAIL common"
if (createPlatform().value != "OK") return "FAIL platform"
return "OK"
}
@@ -0,0 +1,41 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_MULTI_MODULE_OLD_AGAINST_IR, JVM_MULTI_MODULE_IR_AGAINST_OLD
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
// IGNORE_DEXING
// TODO: D8 fails with AssertionError and does not print reason, need further investigation
// FILE: 1.kt
package a
annotation class A(val i: Int)
inline fun foo(i: Int): A = A(i)
inline fun bar(f: () -> Int): A = A(f())
// FILE: 2.kt
import a.*
class C {
fun one(): A {
return foo(1)
}
}
fun two(): A {
return bar { 2 }
}
fun box(): String {
val one = C().one()
assert(one.i == 1)
val two = two()
assert(two.i == 2)
// During cross-module inlining, anonymous classes are copied
// println(one.javaClass.getName().startsWith("a._1Kt"))
return "OK"
}
@@ -0,0 +1,35 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_MULTI_MODULE_OLD_AGAINST_IR, JVM_MULTI_MODULE_IR_AGAINST_OLD
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
// IGNORE_DEXING
// TODO: D8 fails with AssertionError and does not print reason, need further investigation
// FILE: 1.kt
package a
annotation class A(val i: String)
interface I {
fun g(): A
}
inline fun foo(i: String): I = object : I {
override fun g(): A {
return A(i)
}
}
// FILE: 2.kt
import a.*
class C() {
fun one(): A = foo("OK").g()
}
fun box(): String {
return C().one().i
}
@@ -0,0 +1,11 @@
// WITH_RUNTIME
// IGNORE_BACKEND: JVM
// !LANGUAGE: +InstantiationOfAnnotationClasses
annotation class Foo(val int: Int)
annotation class Bar
fun box() {
val foo = Foo(42)
}
@@ -0,0 +1,32 @@
@kotlin.Metadata
public synthetic final class AnnotationCtorCallGenerateSyntheticKt$annotationImpl$Foo$0 {
// source: 'annotationCtorCallGenerateSynthetic.kt'
private synthetic final field int: int
public method <init>(p0: int): void
public synthetic final method annotationType(): java.lang.Class
public final method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public final method hashCode(): int
public synthetic final method int(): int
public final @org.jetbrains.annotations.NotNull method toString(): java.lang.String
public synthetic inner class AnnotationCtorCallGenerateSyntheticKt$annotationImpl$Foo$0
}
@kotlin.Metadata
public final class AnnotationCtorCallGenerateSyntheticKt {
// source: 'annotationCtorCallGenerateSynthetic.kt'
public final static method box(): void
public synthetic inner class AnnotationCtorCallGenerateSyntheticKt$annotationImpl$Foo$0
}
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class Bar {
// source: 'annotationCtorCallGenerateSynthetic.kt'
}
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class Foo {
// source: 'annotationCtorCallGenerateSynthetic.kt'
public abstract method int(): int
}
@@ -0,0 +1,10 @@
// WITH_RUNTIME
// !LANGUAGE: +InstantiationOfAnnotationClasses
annotation class Foo(val bar: Bar)
annotation class Bar
@Foo(Bar())
fun box() {
}
@@ -0,0 +1,18 @@
@kotlin.Metadata
public final class AnnotationCtorCallNoSyntheticKt {
// source: 'annotationCtorCallNoSynthetic.kt'
public final static @Foo method box(): void
}
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class Bar {
// source: 'annotationCtorCallNoSynthetic.kt'
}
@java.lang.annotation.Retention
@kotlin.Metadata
public annotation class Foo {
// source: 'annotationCtorCallNoSynthetic.kt'
public abstract method bar(): Bar
}
@@ -0,0 +1,21 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// WITH_RUNTIME
// SKIP_TXT
// !LANGUAGE: +InstantiationOfAnnotationClasses
// FILE: test.kt
import kotlin.reflect.KClass
annotation class A
annotation class B(val int: Int)
annotation class C(val int: Int = 42)
annotation class G<T: Any>(val int: KClass<T>)
fun box() {
val a = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>A()<!>
val b = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>B(4)<!>
val c = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>C()<!>
val foo = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>G(Int::class)<!>
}
@@ -0,0 +1,18 @@
// WITH_RUNTIME
// SKIP_TXT
// !LANGUAGE: +InstantiationOfAnnotationClasses
import kotlin.reflect.KClass
annotation class A
annotation class B(val int: Int)
annotation class C(val int: Int = 42)
annotation class G<T: Any>(val int: KClass<T>)
fun box() {
val a = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>A()<!>
val b = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>B(4)<!>
val c = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>C()<!>
val foo = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>G(Int::class)<!>
}
@@ -0,0 +1,18 @@
// WITH_RUNTIME
// SKIP_TXT
// !LANGUAGE: +InstantiationOfAnnotationClasses
import kotlin.reflect.KClass
annotation class A
annotation class B(val int: Int)
annotation class C(val int: Int = 42)
annotation class G<T: Any>(val int: KClass<T>)
fun box() {
val a = A()
val b = B(4)
val c = C()
val foo = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>G(Int::class)<!>
}
@@ -0,0 +1,19 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// WITH_RUNTIME
// SKIP_TXT
// !LANGUAGE: +InstantiationOfAnnotationClasses
import kotlin.reflect.KClass
annotation class A
annotation class B(val int: Int)
annotation class C(val int: Int = 42)
annotation class G<T: Any>(val int: KClass<T>)
fun box() {
val a = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>A()<!>
val b = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>B(4)<!>
val c = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>C()<!>
val foo = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>G(Int::class)<!>
}
@@ -1103,6 +1103,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt"); runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt");
} }
@Test
@TestMetadata("ConstructorCallAllowed.kt")
public void testConstructorCallAllowed() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt");
}
@Test @Test
@TestMetadata("DanglingInScript.kts") @TestMetadata("DanglingInScript.kts")
public void testDanglingInScript() throws Exception { public void testDanglingInScript() throws Exception {
@@ -24,6 +24,12 @@ public class DiagnosticsNativeTestGenerated extends AbstractDiagnosticsNativeTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/nativeTests"), Pattern.compile("^(.+)\\.kt$"), null, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/nativeTests"), Pattern.compile("^(.+)\\.kt$"), null, true);
} }
@Test
@TestMetadata("annotationConstructorCallNative.kt")
public void testAnnotationConstructorCallNative() throws Exception {
runTest("compiler/testData/diagnostics/nativeTests/annotationConstructorCallNative.kt");
}
@Test @Test
@TestMetadata("sharedImmutable.kt") @TestMetadata("sharedImmutable.kt")
public void testSharedImmutable() throws Exception { public void testSharedImmutable() throws Exception {
@@ -24,6 +24,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib"), Pattern.compile("^(.+)\\.kt$"), null, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib"), Pattern.compile("^(.+)\\.kt$"), null, true);
} }
@Test
@TestMetadata("annotationConstructorCallJs.kt")
public void testAnnotationConstructorCallJs() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/annotationConstructorCallJs.kt");
}
@Test @Test
@TestMetadata("funConstructorCallJS.kt") @TestMetadata("funConstructorCallJS.kt")
public void testFunConstructorCallJS() throws Exception { public void testFunConstructorCallJS() throws Exception {
@@ -380,6 +380,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
} }
} }
@Nested
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
public class Instances {
@Test
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -25,6 +25,16 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
} }
@Nested
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
public class Annotations {
@Test
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -316,6 +316,18 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
} }
@Test
@TestMetadata("annotationCtorCallGenerateSynthetic.kt")
public void testAnnotationCtorCallGenerateSynthetic() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/annotations/annotationCtorCallGenerateSynthetic.kt");
}
@Test
@TestMetadata("annotationCtorCallNoSynthetic.kt")
public void testAnnotationCtorCallNoSynthetic() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/annotations/annotationCtorCallNoSynthetic.kt");
}
@Test @Test
@TestMetadata("annotationsOnDelegatedMembers.kt") @TestMetadata("annotationsOnDelegatedMembers.kt")
public void testAnnotationsOnDelegatedMembers() throws Exception { public void testAnnotationsOnDelegatedMembers() throws Exception {
@@ -25,6 +25,16 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
} }
@Nested
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
public class Annotations {
@Test
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -380,6 +380,76 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
} }
} }
@Nested
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
public class Instances {
@Test
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationEnclosingName.kt")
public void testAnnotationEnclosingName() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationEnclosingName.kt");
}
@Test
@TestMetadata("annotationEqHc.kt")
public void testAnnotationEqHc() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationEqHc.kt");
}
@Test
@TestMetadata("annotationInstances.kt")
public void testAnnotationInstances() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationInstances.kt");
}
@Test
@TestMetadata("annotationInstancesEmptyDefault.kt")
public void testAnnotationInstancesEmptyDefault() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationInstancesEmptyDefault.kt");
}
@Test
@TestMetadata("annotationToString.kt")
public void testAnnotationToString() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationToString.kt");
}
@Test
@TestMetadata("annotationType.kt")
public void testAnnotationType() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/annotationType.kt");
}
@Test
@TestMetadata("javaAnnotation.kt")
public void testJavaAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt");
}
@Test
@TestMetadata("multifileEqHc.kt")
public void testMultifileEqHc() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/multifileEqHc.kt");
}
@Test
@TestMetadata("multimoduleInlining.kt")
public void testMultimoduleInlining() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/multimoduleInlining.kt");
}
@Test
@TestMetadata("multiplatformInstantiation.kt")
public void testMultiplatformInstantiation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/instances/multiplatformInstantiation.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -25,6 +25,28 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
} }
@Nested
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
public class Annotations {
@Test
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationInstanceInlining.kt")
public void testAnnotationInstanceInlining() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/annotationInstanceInlining.kt");
}
@Test
@TestMetadata("instanceInAnonymousClass.kt")
public void testInstanceInAnonymousClass() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/instanceInAnonymousClass.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -316,6 +316,18 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
} }
@Test
@TestMetadata("annotationCtorCallGenerateSynthetic.kt")
public void testAnnotationCtorCallGenerateSynthetic() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/annotations/annotationCtorCallGenerateSynthetic.kt");
}
@Test
@TestMetadata("annotationCtorCallNoSynthetic.kt")
public void testAnnotationCtorCallNoSynthetic() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/annotations/annotationCtorCallNoSynthetic.kt");
}
@Test @Test
@TestMetadata("annotationsOnDelegatedMembers.kt") @TestMetadata("annotationsOnDelegatedMembers.kt")
public void testAnnotationsOnDelegatedMembers() throws Exception { public void testAnnotationsOnDelegatedMembers() throws Exception {
@@ -25,6 +25,28 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
} }
@Nested
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
public class Annotations {
@Test
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationInstanceInlining.kt")
public void testAnnotationInstanceInlining() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/annotationInstanceInlining.kt");
}
@Test
@TestMetadata("instanceInAnonymousClass.kt")
public void testInstanceInAnonymousClass() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/instanceInAnonymousClass.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -25,6 +25,28 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_IR_AGAINST_OLD, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_IR_AGAINST_OLD, true);
} }
@Nested
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
public class Annotations {
@Test
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_IR_AGAINST_OLD, true);
}
@Test
@TestMetadata("annotationInstanceInlining.kt")
public void testAnnotationInstanceInlining() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/annotationInstanceInlining.kt");
}
@Test
@TestMetadata("instanceInAnonymousClass.kt")
public void testInstanceInAnonymousClass() throws Exception {
runTest("compiler/testData/codegen/boxInline/annotations/instanceInAnonymousClass.kt");
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -25,6 +25,16 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_OLD_AGAINST_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_OLD_AGAINST_IR, true);
} }
@Nested
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
public class Annotations {
@Test
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_OLD_AGAINST_IR, true);
}
}
@Nested @Nested
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -335,6 +335,19 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
} }
} }
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Instances extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -220,6 +220,8 @@ enum class LanguageFeature(
ProhibitNonExhaustiveWhenOnAlgebraicTypes(KOTLIN_1_7, kind = BUG_FIX), ProhibitNonExhaustiveWhenOnAlgebraicTypes(KOTLIN_1_7, kind = BUG_FIX),
InstantiationOfAnnotationClasses(KOTLIN_1_6),
// Temporarily disabled, see KT-27084/KT-22379 // Temporarily disabled, see KT-27084/KT-22379
SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX), SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX),
@@ -1103,6 +1103,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt"); runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCall.kt");
} }
@Test
@TestMetadata("ConstructorCallAllowed.kt")
public void testConstructorCallAllowed() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt");
}
@Test @Test
@TestMetadata("DanglingMixed.kt") @TestMetadata("DanglingMixed.kt")
public void testDanglingMixed() throws Exception { public void testDanglingMixed() throws Exception {
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.js.analyze.JsNativeDiagnosticSuppressor
import org.jetbrains.kotlin.js.naming.NameSuggestion import org.jetbrains.kotlin.js.naming.NameSuggestion
import org.jetbrains.kotlin.js.resolve.diagnostics.* import org.jetbrains.kotlin.js.resolve.diagnostics.*
import org.jetbrains.kotlin.resolve.PlatformConfiguratorBase import org.jetbrains.kotlin.resolve.PlatformConfiguratorBase
import org.jetbrains.kotlin.resolve.calls.checkers.InstantiationOfAnnotationClassesCallChecker
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.deprecation.CoroutineCompatibilitySupport import org.jetbrains.kotlin.resolve.deprecation.CoroutineCompatibilitySupport
import org.jetbrains.kotlin.types.DynamicTypesAllowed import org.jetbrains.kotlin.types.DynamicTypesAllowed
@@ -29,9 +30,10 @@ object JsPlatformConfigurator : PlatformConfiguratorBase(
JsExportDeclarationChecker JsExportDeclarationChecker
), ),
additionalCallCheckers = listOf( additionalCallCheckers = listOf(
JsModuleCallChecker, JsModuleCallChecker,
JsDynamicCallChecker, JsDynamicCallChecker,
JsDefinedExternallyCallChecker, JsDefinedExternallyCallChecker,
InstantiationOfAnnotationClassesCallChecker
), ),
identifierChecker = JsIdentifierChecker identifierChecker = JsIdentifierChecker
) { ) {
@@ -80,6 +80,19 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
} }
} }
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Instances extends AbstractIrJsCodegenBoxES6Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
}
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -30,6 +30,19 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
} }
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Annotations extends AbstractIrJsCodegenInlineES6Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath);
}
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -80,6 +80,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
} }
} }
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Instances extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -30,6 +30,19 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
} }
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Annotations extends AbstractIrJsCodegenInlineTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -80,6 +80,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
} }
} }
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Instances extends AbstractJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -30,6 +30,19 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
} }
@TestMetadata("compiler/testData/codegen/boxInline/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Annotations extends AbstractJsCodegenInlineTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInAnnotations() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/annotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject") @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -75,6 +75,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
} }
} }
@TestMetadata("compiler/testData/codegen/box/annotations/instances")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Instances extends AbstractIrCodegenBoxWasmTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
}
public void testAllFilesPresentInInstances() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/instances"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping") @TestMetadata("compiler/testData/codegen/box/annotations/kClassMapping")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.PlatformConfiguratorBase import org.jetbrains.kotlin.resolve.PlatformConfiguratorBase
import org.jetbrains.kotlin.resolve.calls.checkers.InstantiationOfAnnotationClassesCallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.TypeOfChecker import org.jetbrains.kotlin.resolve.calls.checkers.TypeOfChecker
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.inline.ReasonableInlineRule import org.jetbrains.kotlin.resolve.inline.ReasonableInlineRule
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.resolve.konan.diagnostics.NativeTopLevelSingletonChe
object NativePlatformConfigurator : PlatformConfiguratorBase( object NativePlatformConfigurator : PlatformConfiguratorBase(
additionalCallCheckers = listOf( additionalCallCheckers = listOf(
SuperCallWithDefaultArgumentsChecker(), SuperCallWithDefaultArgumentsChecker(),
InstantiationOfAnnotationClassesCallChecker
), ),
additionalDeclarationCheckers = listOf( additionalDeclarationCheckers = listOf(
NativeThrowsChecker, NativeSharedImmutableChecker, NativeThrowsChecker, NativeSharedImmutableChecker,