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 3b2115e2bcf..aa17db39e76 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 @@ -3464,6 +3464,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION) { firDiagnostic -> + ActualTypealiasToSpecialAnnotationImpl( + firDiagnostic.a, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION) { firDiagnostic -> InitializerRequiredForDestructuringDeclarationImpl( firDiagnostic as KtPsiDiagnostic, 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 e5db667f0ee..697aff3202c 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 @@ -2420,6 +2420,11 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ExpectActualOptInAnnotation::class } + interface ActualTypealiasToSpecialAnnotation : KtFirDiagnostic { + override val diagnosticClass get() = ActualTypealiasToSpecialAnnotation::class + val typealiasedClassId: ClassId + } + interface InitializerRequiredForDestructuringDeclaration : KtFirDiagnostic { override val diagnosticClass get() = InitializerRequiredForDestructuringDeclaration::class } 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 8dd466e85fd..353ef7c8c44 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 @@ -2918,6 +2918,12 @@ internal class ExpectActualOptInAnnotationImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.ExpectActualOptInAnnotation +internal class ActualTypealiasToSpecialAnnotationImpl( + override val typealiasedClassId: ClassId, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.ActualTypealiasToSpecialAnnotation + internal class InitializerRequiredForDestructuringDeclarationImpl( firDiagnostic: KtPsiDiagnostic, token: KtLifetimeToken, diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java index 079a5719dae..2b66b475c74 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java @@ -20,6 +20,12 @@ import java.util.regex.Pattern; @TestMetadata("compiler/testData/diagnostics/tests/multiplatform") @TestDataPath("$PROJECT_ROOT") public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends AbstractFirLightTreeWithActualizerDiagnosticsTest { + @Test + @TestMetadata("actualTypealiasToSpecialAnnotation.kt") + public void testActualTypealiasToSpecialAnnotation() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasToSpecialAnnotation.kt"); + } + @Test public void testAllFilesPresentInMultiplatform() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true); diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java index 52f510d0f5b..8c2a5393ae3 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java @@ -20,6 +20,12 @@ import java.util.regex.Pattern; @TestMetadata("compiler/testData/diagnostics/tests/multiplatform") @TestDataPath("$PROJECT_ROOT") public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFirPsiWithActualizerDiagnosticsTest { + @Test + @TestMetadata("actualTypealiasToSpecialAnnotation.kt") + public void testActualTypealiasToSpecialAnnotation() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasToSpecialAnnotation.kt"); + } + @Test public void testAllFilesPresentInMultiplatform() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true); 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 0bc71fd4dcd..b8756cdc6dc 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 @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.* import org.jetbrains.kotlin.fir.declarations.FirFunction +import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* @@ -1176,6 +1177,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val NOT_A_MULTIPLATFORM_COMPILATION by error() val EXPECT_ACTUAL_OPT_IN_ANNOTATION by error(PositioningStrategy.EXPECT_ACTUAL_MODIFIER) + + val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error(PositioningStrategy.TYPEALIAS_TYPE_REFERENCE) { + parameter("typealiasedClassId") + } } val DESTRUCTING_DECLARATION by object : DiagnosticGroup("Destructuring declaration") { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt index 0c4109ac1da..e7713d947c6 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt @@ -114,6 +114,7 @@ enum class PositioningStrategy(private val strategy: String? = null) { INLINE_FUN_MODIFIER, CALL_ELEMENT_WITH_DOT, EXPECT_ACTUAL_MODIFIER, + TYPEALIAS_TYPE_REFERENCE, ; val expressionToCreate get() = "SourceElementPositioningStrategies.${strategy ?: name}" 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 da5a5c60870..05fcf0420f4 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 @@ -627,6 +627,7 @@ object FirErrors { val ACTUAL_MISSING by error0(SourceElementPositioningStrategies.ACTUAL_DECLARATION_NAME) val NOT_A_MULTIPLATFORM_COMPILATION by error0() val EXPECT_ACTUAL_OPT_IN_ANNOTATION by error0(SourceElementPositioningStrategies.EXPECT_ACTUAL_MODIFIER) + val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error1(SourceElementPositioningStrategies.TYPEALIAS_TYPE_REFERENCE) // Destructuring declaration val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0() 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 d1bba9c7371..fd0f19515af 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 @@ -159,6 +159,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { get() = setOf( FirTopLevelTypeAliasChecker, FirActualTypeAliasChecker, + FirActualTypealiasToSpecialAnnotationChecker, ) override val anonymousFunctionCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualTypealiasToSpecialAnnotationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualTypealiasToSpecialAnnotationChecker.kt new file mode 100644 index 00000000000..e6b2f879188 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualTypealiasToSpecialAnnotationChecker.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2023 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.descriptors.ClassKind +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.classKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirTypeAlias +import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType +import org.jetbrains.kotlin.fir.declarations.utils.isActual +import org.jetbrains.kotlin.fir.types.toSymbol +import org.jetbrains.kotlin.resolve.calls.mpp.ActualTypealiasToSpecialAnnotationUtils.isAnnotationProhibitedInActualTypeAlias + +internal object FirActualTypealiasToSpecialAnnotationChecker : FirTypeAliasChecker() { + override fun check(declaration: FirTypeAlias, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isActual) return + val typealiasedClassSymbol = declaration.expandedConeType?.toSymbol(context.session) ?: return + if (typealiasedClassSymbol.classKind != ClassKind.ANNOTATION_CLASS) { + return + } + val classId = typealiasedClassSymbol.classId + if (isAnnotationProhibitedInActualTypeAlias(classId)) { + reporter.reportOn(declaration.source, FirErrors.ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION, classId, context) + } + } +} \ No newline at end of file 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 f932f33841e..5eeb4e5cfce 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 @@ -54,6 +54,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_NOT_TO_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION @@ -1847,6 +1848,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(ACTUAL_MISSING, "Declaration must be marked with 'actual'") map.put(NOT_A_MULTIPLATFORM_COMPILATION, "'expect' and 'actual' declarations can be used only in multiplatform projects. Learn more about Kotlin Multiplatform: https://kotl.in/multiplatform-setup") map.put(EXPECT_ACTUAL_OPT_IN_ANNOTATION, "Opt-in annotations are prohibited to be `expect` or `actual`. Instead, declare annotation once in common sources.") + map.put( + ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION, + "`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.", + TO_STRING + ) // Destructuring declaration map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration") diff --git a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt index be4df6fedb3..035b21709e9 100644 --- a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt @@ -1208,6 +1208,17 @@ object LightTreePositioningStrategies { } } + val TYPEALIAS_TYPE_REFERENCE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { + override fun mark( + node: LighterASTNode, + startOffset: Int, + endOffset: Int, + tree: FlyweightCapableTreeStructure + ): List { + val nodeToMark = tree.findChildByType(node, KtNodeTypes.TYPE_REFERENCE) ?: node + return markElement(nodeToMark, startOffset, endOffset, tree, node) + } + } } fun KtSourceElement.hasValOrVar(): Boolean = diff --git a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index bcace455a68..991ec4fbc0c 100644 --- a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -1031,6 +1031,13 @@ object PositioningStrategies { } } + @JvmField + val TYPEALIAS_TYPE_REFERENCE = object : PositioningStrategy() { + override fun mark(element: KtTypeAlias): List { + return markElement(element.getTypeReference() ?: element) + } + } + /** * @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for * diagnostics on super and unresolved references. For example, with the following, only the part inside the parentheses should be diff --git a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/SourceElementPositioningStrategies.kt b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/SourceElementPositioningStrategies.kt index b66fbef7302..a41fe84e286 100644 --- a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/SourceElementPositioningStrategies.kt +++ b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/SourceElementPositioningStrategies.kt @@ -384,4 +384,9 @@ object SourceElementPositioningStrategies { LightTreePositioningStrategies.CALL_ELEMENT_WITH_DOT, PositioningStrategies.CALL_ELEMENT_WITH_DOT ) + + val TYPEALIAS_TYPE_REFERENCE = SourceElementPositioningStrategy( + LightTreePositioningStrategies.TYPEALIAS_TYPE_REFERENCE, + PositioningStrategies.TYPEALIAS_TYPE_REFERENCE, + ) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index f7cf9724741..77bedf06920 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.lexer.KtKeywordToken; import org.jetbrains.kotlin.lexer.KtModifierKeywordToken; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement; +import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; @@ -837,6 +838,8 @@ public interface Errors { DiagnosticFactory0 OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 NOT_A_MULTIPLATFORM_COMPILATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 EXPECT_ACTUAL_OPT_IN_ANNOTATION = DiagnosticFactory0.create(ERROR, EXPECT_ACTUAL_MODIFIER); + DiagnosticFactory1 ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION = + DiagnosticFactory1.create(ERROR, TYPEALIAS_TYPE_REFERENCE); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 5cf817607e4..3415c94628c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -393,6 +393,9 @@ public class DefaultErrorMessages { MAP.put(OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE, "Declaration annotated with '@OptionalExpectation' can only be used in common module sources"); MAP.put(NOT_A_MULTIPLATFORM_COMPILATION, "'expect' and 'actual' declarations can be used only in multiplatform projects. Learn more about Kotlin Multiplatform: https://kotl.in/multiplatform-setup"); MAP.put(EXPECT_ACTUAL_OPT_IN_ANNOTATION, "Opt-in annotations are prohibited to be `expect` or `actual`. Instead, declare annotation once in common sources."); + MAP.put(ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION, + "`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.", + TO_STRING); MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties"); MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index 190187d1119..db44360537f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -58,6 +58,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( DataObjectContentChecker, EnumEntriesRedeclarationChecker, VolatileAnnotationChecker, + ActualTypealiasToSpecialAnnotationChecker, ) private val DEFAULT_CALL_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualTypealiasToSpecialAnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualTypealiasToSpecialAnnotationChecker.kt new file mode 100644 index 00000000000..4dc3f6afb77 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualTypealiasToSpecialAnnotationChecker.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2023 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.checkers + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtTypeAlias +import org.jetbrains.kotlin.resolve.calls.mpp.ActualTypealiasToSpecialAnnotationUtils.isAnnotationProhibitedInActualTypeAlias +import org.jetbrains.kotlin.resolve.descriptorUtil.classId + +internal object ActualTypealiasToSpecialAnnotationChecker : DeclarationChecker { + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (declaration !is KtTypeAlias || descriptor !is TypeAliasDescriptor || !descriptor.isActual) { + return + } + val classDescriptor = descriptor.classDescriptor ?: return + if (classDescriptor.kind != ClassKind.ANNOTATION_CLASS) { + return + } + val classId = classDescriptor.classId ?: return + if (isAnnotationProhibitedInActualTypeAlias(classId)) { + context.trace.report(Errors.ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION.on(declaration, classId)) + } + } +} \ No newline at end of file diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ActualTypealiasToSpecialAnnotationUtils.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ActualTypealiasToSpecialAnnotationUtils.kt new file mode 100644 index 00000000000..847e493177e --- /dev/null +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/ActualTypealiasToSpecialAnnotationUtils.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2023 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.mpp + +import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.name.ClassId + +object ActualTypealiasToSpecialAnnotationUtils { + /** + * Type aliases may be useful to commonize some platform-specific annotations, e.g. [kotlin.jvm.Synchronized]. + * We cannot universally determine at compile time whether annotation is accessible in common code. + * Instead, we prohibit certain package names because we are sure that annotations from them + * are visible in common and there is no point to typealias them. + */ + private val FORBIDDEN_PACKAGES = setOf( + StandardNames.ANNOTATION_PACKAGE_FQ_NAME, + StandardNames.BUILT_INS_PACKAGE_FQ_NAME, + StandardNames.KOTLIN_INTERNAL_FQ_NAME, + ) + + fun isAnnotationProhibitedInActualTypeAlias(classId: ClassId): Boolean { + return classId.packageFqName in FORBIDDEN_PACKAGES + } +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/actualTypealiasToSpecialAnnotation.kt b/compiler/testData/diagnostics/tests/multiplatform/actualTypealiasToSpecialAnnotation.kt new file mode 100644 index 00000000000..15ea0204e0f --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/actualTypealiasToSpecialAnnotation.kt @@ -0,0 +1,28 @@ +// FIR_IDENTICAL +// WITH_STDLIB +// MODULE: m1-common +// FILE: common.kt +expect annotation class TypealiasToKotlinPkg + +internal expect annotation class TypealiasToInternalPkg + +expect annotation class TypealiasToAnnotationPkg + +expect annotation class TypealiasToPlatformPkg + +expect enum class TypealiasNotToAnnotation + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt +actual typealias TypealiasToKotlinPkg = kotlin.Deprecated + +@Suppress("INVISIBLE_REFERENCE") +internal actual typealias TypealiasToInternalPkg = kotlin.internal.RequireKotlin + +actual typealias TypealiasToAnnotationPkg = kotlin.annotation.Target + +actual typealias TypealiasToPlatformPkg = kotlin.jvm.Synchronized + +typealias NonActualTypealias = kotlin.Deprecated + +actual typealias TypealiasNotToAnnotation = kotlin.DeprecationLevel diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index b8446fb3c51..1db952e3deb 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -22529,6 +22529,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { @TestMetadata("compiler/testData/diagnostics/tests/multiplatform") @TestDataPath("$PROJECT_ROOT") public class Multiplatform { + @Test + @TestMetadata("actualTypealiasToSpecialAnnotation.kt") + public void testActualTypealiasToSpecialAnnotation() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/actualTypealiasToSpecialAnnotation.kt"); + } + @Test public void testAllFilesPresentInMultiplatform() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);