diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 0b5471d01d5..22546b38a7c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -82,6 +82,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.UNSUPPORTED_SUSPEND_TEST) { firDiagnostic -> + UnsupportedSuspendTestImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.NEW_INFERENCE_ERROR) { firDiagnostic -> NewInferenceErrorImpl( firDiagnostic.a, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 87d4b9bfdb1..698ed11a8c7 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -103,6 +103,10 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val unsupportedFeature: Pair } + interface UnsupportedSuspendTest : KtFirDiagnostic { + override val diagnosticClass get() = UnsupportedSuspendTest::class + } + interface NewInferenceError : KtFirDiagnostic { override val diagnosticClass get() = NewInferenceError::class val error: String diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 43ab619b961..cf65e3833be 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -105,6 +105,11 @@ internal class UnsupportedFeatureImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.UnsupportedFeature +internal class UnsupportedSuspendTestImpl( + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.UnsupportedSuspendTest + internal class NewInferenceErrorImpl( override val error: String, firDiagnostic: KtPsiDiagnostic, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index fcf9929190f..8f672b06045 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -54,6 +54,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val UNSUPPORTED_FEATURE by error { parameter>("unsupportedFeature") } + val UNSUPPORTED_SUSPEND_TEST by error() val NEW_INFERENCE_ERROR by error { parameter("error") } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 79ca54221fb..7e2f195a328 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -119,6 +119,7 @@ object FirErrors { // Meta-errors val UNSUPPORTED by error1() val UNSUPPORTED_FEATURE by error1>() + val UNSUPPORTED_SUSPEND_TEST by error0() val NEW_INFERENCE_ERROR by error1() // Miscellaneous diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 856282ab972..b475c456f84 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -48,6 +48,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirFunctionParameterChecker, FirFunctionReturnChecker, FirInlineDeclarationChecker, + FirSuspendLimitationsChecker, ) override val simpleFunctionCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendLimitationsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendLimitationsChecker.kt new file mode 100644 index 00000000000..f9b087134c9 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendLimitationsChecker.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2020 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.fir.analysis.checkers.declaration + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.getModifier +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId +import org.jetbrains.kotlin.fir.declarations.utils.isSuspend +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.StandardClassIds + +object FirSuspendLimitationsChecker : FirFunctionChecker() { + override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isSuspend) { + return + } + + if (declaration.annotations.any { it.isKotlinTestAnnotation(context.session) }) { + declaration.getModifier(KtTokens.SUSPEND_KEYWORD)?.let { + reporter.reportOn(it.source, FirErrors.UNSUPPORTED_SUSPEND_TEST, context) + } + } + } + + private fun FirAnnotation.isKotlinTestAnnotation(session: FirSession): Boolean { + val nonExpandedType = annotationTypeRef.coneType as? ConeClassLikeType + return nonExpandedType?.lookupTag?.classId == StandardClassIds.Annotations.Test + || toAnnotationClassId(session) == StandardClassIds.Annotations.Test + } +} + + diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index e3afe17b6d9..02f24aa8a8d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -607,6 +607,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_SUSPEND_TEST import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED @@ -675,6 +676,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { // Meta-errors map.put(UNSUPPORTED, "Unsupported [{0}]", TO_STRING) map.put(UNSUPPORTED_FEATURE, "{0}", LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.UNSUPPORTED)) + map.put(UNSUPPORTED_SUSPEND_TEST, "'suspend' functions annotated with @kotlin.test.Test are unsupported") map.put(NEW_INFERENCE_ERROR, "New inference error [{0}]", STRING) // Miscellaneous diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.fir.kt deleted file mode 100644 index ccbbf46e955..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -// ALLOW_KOTLIN_PACKAGE -// 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/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt index 6d87662cbda..6fe994bc157 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendTest.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // ALLOW_KOTLIN_PACKAGE // SKIP_TXT // FILE: test.kt diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt index 6c83c62c844..223517cb0c3 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt @@ -21,6 +21,7 @@ object StandardClassIds { val BASE_ENUMS_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("enums")) val BASE_CONTRACTS_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("contracts")) val BASE_CONCURRENT_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("concurrent")) + val BASE_TEST_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("test")) val builtInsPackages = setOf( BASE_KOTLIN_PACKAGE, @@ -175,6 +176,8 @@ object StandardClassIds { val Volatile = "Volatile".concurrentId() + val Test = "Test".testId() + val RawTypeAnnotation = "RawType".internalIrId() val FlexibleNullability = "FlexibleNullability".internalIrId() val FlexibleMutability = "FlexibleMutability".internalIrId() @@ -268,6 +271,8 @@ private fun String.coroutinesId() = ClassId(StandardClassIds.BASE_COROUTINES_PAC private fun String.enumsId() = ClassId(StandardClassIds.BASE_ENUMS_PACKAGE, Name.identifier(this)) private fun String.concurrentId() = ClassId(StandardClassIds.BASE_CONCURRENT_PACKAGE, Name.identifier(this)) +private fun String.testId() = ClassId(StandardClassIds.BASE_TEST_PACKAGE, Name.identifier(this)) + private fun String.callableId(packageName: FqName) = CallableId(packageName, Name.identifier(this)) private fun String.callableId(classId: ClassId) = CallableId(classId, Name.identifier(this))