From bcf47ddc94380c8116525ced44c86385c4383d4e Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 22 Apr 2021 20:31:53 +0200 Subject: [PATCH] Move optional annotation utilities to module 'resolution' To avoid depending on a heavy module 'frontend' in parts of the compiler where checking for optional annotations is needed, such as in 'ir.serialization.common'. --- .../kotlin/codegen/AnnotationCodegen.java | 4 +- .../kotlin/codegen/PackageCodegenImpl.java | 6 +-- .../ExpectedActualDeclarationChecker.kt | 37 +------------------ .../checkers/OptionalExpectationChecker.kt | 3 +- .../OptionalExpectationUsageChecker.kt | 5 ++- .../common/lower/ExpectDeclarationRemover.kt | 4 +- .../backend/jvm/codegen/AnnotationCodegen.kt | 4 +- .../backend/jvm/codegen/irCodegenUtils.kt | 4 +- .../serialization/LegacyDescriptorUtils.kt | 8 ++-- .../multiplatform/OptionalAnnotationUtil.kt | 36 ++++++++++++++++++ .../OptionalExpectationInspection.kt | 6 +-- .../expectactual/ExpectActualUtils.kt | 4 +- .../js/KotlinJavascriptSerializationUtil.kt | 4 +- .../descriptors/LegacyDescriptorUtils.kt | 4 -- .../konan/lower/ExpectDeclarationsRemoving.kt | 8 +--- 15 files changed, 67 insertions(+), 70 deletions(-) create mode 100644 compiler/resolution/src/org/jetbrains/kotlin/resolve/multiplatform/OptionalAnnotationUtil.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java index c44172f262d..f9d75fe5b9a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java @@ -34,10 +34,10 @@ import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.AnnotationChecker; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; -import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker; import org.jetbrains.kotlin.resolve.constants.*; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt; +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil; import org.jetbrains.kotlin.types.FlexibleType; import org.jetbrains.kotlin.types.FlexibleTypesKt; import org.jetbrains.kotlin.types.KotlinType; @@ -376,7 +376,7 @@ public abstract class AnnotationCodegen { // We do not generate annotations whose classes are optional (annotated with `@OptionalExpectation`) because if an annotation entry // is resolved to the expected declaration, this means that annotation has no actual class, and thus should not be generated. // (Otherwise we would've resolved the entry to the actual annotation class.) - if (ExpectedActualDeclarationChecker.isOptionalAnnotationClass(classDescriptor)) { + if (OptionalAnnotationUtil.isOptionalAnnotationClass(classDescriptor)) { return null; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java index 0edd2925ec2..e86e37f487c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java @@ -35,9 +35,9 @@ import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStat import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.lazy.descriptors.PackageDescriptorUtilKt; +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil; import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments; import org.jetbrains.org.objectweb.asm.Type; @@ -91,8 +91,8 @@ public class PackageCodegenImpl implements PackageCodegen { if (declaration instanceof KtClassOrObject) { ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration); if (PsiUtilsKt.hasExpectModifier(declaration)) { - if (descriptor != null && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor)) { - assert ExpectedActualDeclarationChecker.isOptionalAnnotationClass(descriptor) : + if (descriptor != null && OptionalAnnotationUtil.shouldGenerateExpectClass(descriptor)) { + assert OptionalAnnotationUtil.isOptionalAnnotationClass(descriptor) : "Expect class should be generated only if it's an optional annotation: " + descriptor; state.getFactory().getPackagePartRegistry().getOptionalAnnotations().add(descriptor); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt index 41af0be9294..eeeea8681d4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExpectedActualDeclarationChecker.kt @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver.Compati import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver.Compatibility.Compatible import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver.Compatibility.Incompatible import org.jetbrains.kotlin.resolve.multiplatform.ModuleFilter +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil import org.jetbrains.kotlin.resolve.source.PsiSourceFile import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -171,7 +172,7 @@ class ExpectedActualDeclarationChecker( val compatibility = ExpectedActualResolver.findActualForExpected(descriptor, module, moduleVisibilityFilter) ?: return // Only strong incompatibilities, but this is an OptionalExpectation -- don't report it - if (compatibility.allStrongIncompatibilities() && isOptionalAnnotationClass(descriptor)) return + if (compatibility.allStrongIncompatibilities() && OptionalAnnotationUtil.isOptionalAnnotationClass(descriptor)) return // Only strong incompatibilities, or error won't be reported on actual: report NO_ACTUAL_FOR_EXPECT here if (compatibility.allStrongIncompatibilities() || @@ -389,41 +390,7 @@ class ExpectedActualDeclarationChecker( } companion object { - val OPTIONAL_EXPECTATION_FQ_NAME = FqName("kotlin.OptionalExpectation") - - @JvmStatic - fun isOptionalAnnotationClass(descriptor: DeclarationDescriptor): Boolean = - descriptor is ClassDescriptor && - descriptor.kind == ClassKind.ANNOTATION_CLASS && - descriptor.isExpect && - descriptor.annotations.hasAnnotation(OPTIONAL_EXPECTATION_FQ_NAME) - - // TODO: move to some other place which is accessible both from backend-common and js.serializer - @JvmStatic - fun shouldGenerateExpectClass(descriptor: ClassDescriptor): Boolean { - assert(descriptor.isExpect) { "Not an expected class: $descriptor" } - - if (isOptionalAnnotationClass(descriptor)) { - with(ExpectedActualResolver) { - return descriptor.findCompatibleActualForExpected(descriptor.module).isEmpty() - } - } - - return false - } - fun Map>.allStrongIncompatibilities(): Boolean = this.keys.all { it is Incompatible && it.kind == Compatibility.IncompatibilityKind.STRONG } - - private fun LinkedHashMap>.merge(other: Map>): LinkedHashMap> { - for ((key, newValue) in other) { - val oldValue = this[key] ?: emptyList() - this[key] = oldValue + newValue - } - - return this - } - - private fun ModuleInfo.unwrapModuleInfo(): List = if (this is CombinedModuleInfo) this.containedModules else listOf(this) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt index 8a03c699f33..df5ad2d85e3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationChecker.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil object OptionalExpectationChecker { fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, trace: BindingTrace) { @@ -34,6 +35,6 @@ object OptionalExpectationChecker { private fun getOptionalExpectationEntry(declaration: KtDeclaration, trace: BindingTrace): KtAnnotationEntry? = declaration.annotationEntries.find { entry -> val annotationDescriptor = trace.get(BindingContext.ANNOTATION, entry) - annotationDescriptor?.fqName == ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME + annotationDescriptor?.fqName == OptionalAnnotationUtil.OPTIONAL_EXPECTATION_FQ_NAME } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationUsageChecker.kt index dbba43206e8..9f864474b12 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/OptionalExpectationUsageChecker.kt @@ -8,14 +8,15 @@ package org.jetbrains.kotlin.resolve.checkers import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.descriptorUtil.platform -import org.jetbrains.kotlin.platform.isCommon +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource class OptionalExpectationUsageChecker : ClassifierUsageChecker { override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) { - if (!ExpectedActualDeclarationChecker.isOptionalAnnotationClass(targetDescriptor)) return + if (!OptionalAnnotationUtil.isOptionalAnnotationClass(targetDescriptor)) return if (!element.isUsageAsAnnotationOrImport()) { context.trace.report(Errors.OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY.on(element)) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationRemover.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationRemover.kt index 61d8533a150..81a35b05151 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationRemover.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ExpectDeclarationRemover.kt @@ -20,9 +20,9 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil // `doRemove` means should expect-declaration be removed from IR @OptIn(ObsoleteDescriptorBasedAPI::class) @@ -70,7 +70,7 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va private fun isOptionalAnnotationClass(klass: IrClass): Boolean { return klass.kind == ClassKind.ANNOTATION_CLASS && klass.isExpect && - klass.annotations.hasAnnotation(ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME) + klass.annotations.hasAnnotation(OptionalAnnotationUtil.OPTIONAL_EXPECTATION_FQ_NAME) } private fun tryCopyDefaultArguments(declaration: IrValueParameter) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt index 9c6a3b39b04..041d7f1b1b2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt @@ -40,7 +40,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.org.objectweb.asm.* @@ -480,4 +480,4 @@ private fun loadAnnotationTargets(targetEntry: IrConstructorCall): Set internal val DeclarationDescriptor.isExpectMember: Boolean get() = this is MemberDescriptor && this.isExpect - -internal val DeclarationDescriptor.isSerializableExpectClass: Boolean - get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt index 26aaac98218..658777744c9 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt @@ -23,9 +23,9 @@ import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid -import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver +import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil /** * This pass removes all declarations with `isExpect == true`. @@ -71,11 +71,7 @@ internal class ExpectToActualDefaultValueCopier(private val irModule: IrModuleFr val index = declaration.index assert(function.valueParameters[index] == declaration) - if (function is IrConstructor && - ExpectedActualDeclarationChecker.isOptionalAnnotationClass( - function.descriptor.constructedClass - ) - ) { + if (function is IrConstructor && OptionalAnnotationUtil.isOptionalAnnotationClass(function.descriptor.constructedClass)) { return }