diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index be7f77e120d..989102d1a2e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -116,7 +116,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( DynamicReceiverChecker, DelegationChecker(), KClassWithIncorrectTypeArgumentChecker, - SuspendOperatorsCheckers, + SuspendLimitationsChecker, InlineClassDeclarationChecker, PropertiesWithBackingFieldsInsideInlineClass(), AnnotationClassTargetAndRetentionChecker(), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendOperatorsCheckers.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendLimitationsChecker.kt similarity index 61% rename from compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendOperatorsCheckers.kt rename to compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendLimitationsChecker.kt index 6ccafb73066..0e39ac2fc0d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendOperatorsCheckers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendLimitationsChecker.kt @@ -18,12 +18,17 @@ package org.jetbrains.kotlin.resolve.checkers import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.abbreviationFqName import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull +import org.jetbrains.kotlin.types.getAbbreviation import org.jetbrains.kotlin.util.OperatorNameConventions -object SuspendOperatorsCheckers : DeclarationChecker { +object SuspendLimitationsChecker : DeclarationChecker { private val UNSUPPORTED_OPERATOR_NAMES = setOf( OperatorNameConventions.CONTAINS, OperatorNameConventions.GET, OperatorNameConventions.SET, @@ -31,11 +36,22 @@ object SuspendOperatorsCheckers : DeclarationChecker { ) override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { - if (descriptor is FunctionDescriptor && descriptor.isSuspend && descriptor.isOperator && - descriptor.name in UNSUPPORTED_OPERATOR_NAMES) { + if (descriptor !is FunctionDescriptor || !descriptor.isSuspend) return + + if (descriptor.isOperator && descriptor.name in UNSUPPORTED_OPERATOR_NAMES) { declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD)?.let { context.trace.report(Errors.UNSUPPORTED.on(it, "suspend operator \"${descriptor.name}\"")) } } + + if (descriptor.annotations.any(AnnotationDescriptor::isKotlinTestAnnotation)) { + declaration.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD)?.let { + context.trace.report(Errors.UNSUPPORTED.on(it, "suspend test functions")) + } + } } } + +private val KOTLIN_TEST_TEST_FQNAME = FqName("kotlin.test.Test") +private fun AnnotationDescriptor.isKotlinTestAnnotation() = + fqName == KOTLIN_TEST_TEST_FQNAME || abbreviationFqName == KOTLIN_TEST_TEST_FQNAME diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt new file mode 100644 index 00000000000..d9576cc6a03 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt @@ -0,0 +1,20 @@ +// SKIP_TXT +// FILE: test.kt + +package kotlin.test + +annotation class IrrelevantClass + +public typealias Test = IrrelevantClass + +// FILE: main.kt + +import kotlin.test.Test + +class A { + @Test + suspend fun test() {} +} + +@Test +suspend fun test() {} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 35500e56318..b157919a0a2 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -1653,6 +1653,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt"); } + @TestMetadata("suspendTest.kt") + public void testSuspendTest() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt"); + } + @TestMetadata("suspesionInDefaultValue.kt") public void testSuspesionInDefaultValue() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index ab41d80d7ea..1ce86b18fe6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -1653,6 +1653,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendOverridability.kt"); } + @TestMetadata("suspendTest.kt") + public void testSuspendTest() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt"); + } + @TestMetadata("suspesionInDefaultValue.kt") public void testSuspesionInDefaultValue() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspesionInDefaultValue.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt index bab0babc6f3..b6dec08742d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt @@ -18,21 +18,24 @@ package org.jetbrains.kotlin.descriptors.annotations import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.getAbbreviation interface AnnotationDescriptor { val type: KotlinType val fqName: FqName? - get() = annotationClass?.takeUnless(ErrorUtils::isError)?.fqNameUnsafe?.takeIf(FqNameUnsafe::isSafe)?.toSafe() + get() = annotationClass?.takeUnless(ErrorUtils::isError)?.fqNameOrNull() val allValueArguments: Map> val source: SourceElement } + +val AnnotationDescriptor.abbreviationFqName: FqName? + get() = type.getAbbreviation()?.constructor?.declarationDescriptor?.fqNameOrNull() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index b5eb1990371..dbe64eedfe8 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -221,7 +221,7 @@ val DeclarationDescriptor.parents: Sequence val CallableMemberDescriptor.propertyIfAccessor: CallableMemberDescriptor get() = if (this is PropertyAccessorDescriptor) correspondingProperty else this -fun CallableDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.takeIf { it.isSafe }?.toSafe() +fun DeclarationDescriptor.fqNameOrNull(): FqName? = fqNameUnsafe.takeIf { it.isSafe }?.toSafe() fun CallableMemberDescriptor.firstOverridden( useOriginal: Boolean = false,