From 9d09b9605fe5a32a40a84718aebeab6ca6234ab8 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 14 Sep 2021 15:17:03 +0300 Subject: [PATCH] [FIR] Cleanup and reorganize utils in :compiler:fir:java --- .../jetbrains/kotlin/fir/java/JavaUtils.kt | 261 ++---------------- .../fir/java/enhancement/javaTypeUtils.kt | 14 +- .../kotlin/fir/java/javaAnnotationsMapping.kt | 232 ++++++++++++++++ .../{DescriptorUtils.kt => SignatureUtils.kt} | 0 .../builtins/jvm/JavaToKotlinClassMap.kt | 19 +- 5 files changed, 274 insertions(+), 252 deletions(-) create mode 100644 compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt rename compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/{DescriptorUtils.kt => SignatureUtils.kt} (100%) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt index ef7fc0d7c0a..ec5d410a179 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt @@ -7,37 +7,24 @@ package org.jetbrains.kotlin.fir.java import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.fir.* -import org.jetbrains.kotlin.fir.declarations.FirConstructor -import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind -import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.expressions.builder.* -import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter -import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference -import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference -import org.jetbrains.kotlin.fir.resolve.bindSymbolToLookupTag -import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError -import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols -import org.jetbrains.kotlin.fir.resolve.symbolProvider +import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall +import org.jetbrains.kotlin.fir.expressions.FirConstExpression +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList +import org.jetbrains.kotlin.fir.expressions.builder.buildArrayOfCall +import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression +import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression +import org.jetbrains.kotlin.fir.lookupTracker +import org.jetbrains.kotlin.fir.recordTypeResolveAsLookup import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.expectedConeType -import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl -import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef -import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl -import org.jetbrains.kotlin.load.java.structure.* -import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.StandardClassIds -import org.jetbrains.kotlin.name.StandardClassIds.Annotations -import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames +import org.jetbrains.kotlin.fir.types.createArrayType +import org.jetbrains.kotlin.load.java.structure.JavaClass +import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner import org.jetbrains.kotlin.types.ConstantValueKind -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull -import java.util.* internal val JavaModifierListOwner.modality: Modality get() = when { @@ -62,215 +49,6 @@ internal val JavaClass.classKind: ClassKind else -> ClassKind.CLASS } -private fun buildEnumCall(session: FirSession, classId: ClassId?, entryName: Name?) = - buildFunctionCall { - val calleeReference = if (classId != null && entryName != null) { - session.symbolProvider.getClassDeclaredPropertySymbols(classId, entryName) - .firstOrNull()?.let { propertySymbol -> - buildResolvedNamedReference { - name = entryName - resolvedSymbol = propertySymbol - } - } - } else { - null - } - this.calleeReference = calleeReference - ?: buildErrorNamedReference { - diagnostic = ConeSimpleDiagnostic("Strange Java enum value: $classId.$entryName", DiagnosticKind.Java) - } - } - -private val JAVA_TARGETS_TO_KOTLIN = mapOf( - "TYPE" to EnumSet.of(AnnotationTarget.CLASS, AnnotationTarget.FILE), - "ANNOTATION_TYPE" to EnumSet.of(AnnotationTarget.ANNOTATION_CLASS), - "TYPE_PARAMETER" to EnumSet.of(AnnotationTarget.TYPE_PARAMETER), - "FIELD" to EnumSet.of(AnnotationTarget.FIELD), - "LOCAL_VARIABLE" to EnumSet.of(AnnotationTarget.LOCAL_VARIABLE), - "PARAMETER" to EnumSet.of(AnnotationTarget.VALUE_PARAMETER), - "CONSTRUCTOR" to EnumSet.of(AnnotationTarget.CONSTRUCTOR), - "METHOD" to EnumSet.of(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER), - "TYPE_USE" to EnumSet.of(AnnotationTarget.TYPE) -) - -private fun List.mapJavaTargetArguments(session: FirSession): FirExpression? { - return buildVarargArgumentsExpression { - val resultSet = EnumSet.noneOf(AnnotationTarget::class.java) - for (target in this@mapJavaTargetArguments) { - if (target !is JavaEnumValueAnnotationArgument) return null - resultSet.addAll(JAVA_TARGETS_TO_KOTLIN[target.entryName?.asString()] ?: continue) - } - val classId = StandardClassIds.AnnotationTarget - resultSet.mapTo(arguments) { buildEnumCall(session, classId, Name.identifier(it.name)) } - varargElementType = buildResolvedTypeRef { - type = ConeClassLikeTypeImpl( - ConeClassLikeLookupTagImpl(classId), - emptyArray(), - isNullable = false, - ConeAttributes.Empty - ).createOutArrayType() - } - } -} - -private val JAVA_RETENTION_TO_KOTLIN = mapOf( - "RUNTIME" to AnnotationRetention.RUNTIME, - "CLASS" to AnnotationRetention.BINARY, - "SOURCE" to AnnotationRetention.SOURCE -) - -private fun JavaAnnotationArgument.mapJavaRetentionArgument(session: FirSession): FirExpression? = - JAVA_RETENTION_TO_KOTLIN[(this as? JavaEnumValueAnnotationArgument)?.entryName?.asString()]?.let { - buildEnumCall(session, StandardClassIds.AnnotationRetention, Name.identifier(it.name)) - } - -private fun fillAnnotationArgumentMapping( - session: FirSession, - javaTypeParameterStack: JavaTypeParameterStack, - lookupTag: ConeClassLikeLookupTagImpl, - annotationArguments: Collection, - destination: MutableMap -) { - if (annotationArguments.isEmpty()) return - - val annotationClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(lookupTag.classId).also { - lookupTag.bindSymbolToLookupTag(session, it) - } - val annotationConstructor = (annotationClassSymbol?.fir as FirRegularClass?) - ?.declarations - ?.firstIsInstanceOrNull() - annotationArguments.associateTo(destination) { argument -> - val name = argument.name ?: ParameterNames.value - val parameter = annotationConstructor?.valueParameters?.find { it.name == name } - name to argument.toFirExpression(session, javaTypeParameterStack, parameter?.returnTypeRef) - } -} - -internal fun Iterable.convertAnnotationsToFir( - session: FirSession, javaTypeParameterStack: JavaTypeParameterStack -): List = map { it.toFirAnnotationCall(session, javaTypeParameterStack) } - -internal fun JavaAnnotationOwner.convertAnnotationsToFir( - session: FirSession, javaTypeParameterStack: JavaTypeParameterStack -): List = annotations.convertAnnotationsToFir(session, javaTypeParameterStack) - -internal fun MutableList.addFromJava( - session: FirSession, - javaAnnotationOwner: JavaAnnotationOwner, - javaTypeParameterStack: JavaTypeParameterStack -) { - javaAnnotationOwner.annotations.mapTo(this) { it.toFirAnnotationCall(session, javaTypeParameterStack) } -} - -private fun JavaAnnotation.toFirAnnotationCall( - session: FirSession, javaTypeParameterStack: JavaTypeParameterStack -): FirAnnotation { - return buildAnnotation { - val lookupTag = when (classId) { - Annotations.Java.Target -> Annotations.Target - Annotations.Java.Retention -> Annotations.Retention - Annotations.Java.Documented -> Annotations.MustBeDocumented - Annotations.Java.Deprecated -> Annotations.Deprecated - else -> classId - }?.let(::ConeClassLikeLookupTagImpl) - annotationTypeRef = if (lookupTag != null) { - buildResolvedTypeRef { - type = ConeClassLikeTypeImpl(lookupTag, emptyArray(), isNullable = false) - } - } else { - buildErrorTypeRef { diagnostic = ConeUnresolvedReferenceError() } - } - - argumentMapping = buildAnnotationArgumentMapping { - when (classId) { - Annotations.Java.Target -> { - when (val argument = arguments.firstOrNull()) { - is JavaArrayAnnotationArgument -> argument.getElements().mapJavaTargetArguments(session) - is JavaEnumValueAnnotationArgument -> listOf(argument).mapJavaTargetArguments(session) - else -> null - }?.let { - mapping[ParameterNames.targetAllowedTargets] = it - } - } - Annotations.Java.Retention -> { - arguments.firstOrNull()?.mapJavaRetentionArgument(session)?.let { - mapping[ParameterNames.retentionValue] = it - } - } - Annotations.Java.Deprecated -> { - mapping[ParameterNames.deprecatedMessage] = buildConstExpression( - source = null, - ConstantValueKind.String, - "Deprecated in Java" - ).setProperType(session) - } - else -> { - fillAnnotationArgumentMapping(session, javaTypeParameterStack, lookupTag!!, arguments, mapping) - } - } - } - } -} - -internal fun JavaValueParameter.toFirValueParameter( - session: FirSession, moduleData: FirModuleData, index: Int, javaTypeParameterStack: JavaTypeParameterStack -): FirValueParameter { - return buildJavaValueParameter { - source = (this@toFirValueParameter as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement() - this.moduleData = moduleData - name = this@toFirValueParameter.name ?: Name.identifier("p$index") - returnTypeRef = type.toFirJavaTypeRef(session, javaTypeParameterStack) - isVararg = this@toFirValueParameter.isVararg - annotationBuilder = { convertAnnotationsToFir(session, javaTypeParameterStack) } - } -} - -internal fun JavaAnnotationArgument.toFirExpression( - session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, expectedTypeRef: FirTypeRef? -): FirExpression { - return when (this) { - is JavaLiteralAnnotationArgument -> value.createConstantOrError(session) - is JavaArrayAnnotationArgument -> buildArrayOfCall { - val argumentTypeRef = expectedTypeRef?.let { - typeRef = it - buildResolvedTypeRef { - type = it.coneTypeSafe()?.lowerBoundIfFlexible()?.arrayElementType() - ?: ConeClassErrorType(ConeSimpleDiagnostic("expected type is not array type")) - } - } - argumentList = buildArgumentList { - getElements().mapTo(arguments) { it.toFirExpression(session, javaTypeParameterStack, argumentTypeRef) } - } - } - is JavaEnumValueAnnotationArgument -> buildEnumCall(session, enumClassId, entryName) - is JavaClassObjectAnnotationArgument -> buildGetClassCall { - argumentList = buildUnaryArgumentList( - buildClassReferenceExpression { - classTypeRef = getReferencedType().toFirResolvedTypeRef(session, javaTypeParameterStack) - } - ) - } - is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall(session, javaTypeParameterStack) - else -> buildErrorExpression { - diagnostic = ConeSimpleDiagnostic("Unknown JavaAnnotationArgument: ${this::class.java}", DiagnosticKind.Java) - } - } -} - -// TODO: use kind here -private fun List.createArrayOfCall(session: FirSession, @Suppress("UNUSED_PARAMETER") kind: ConstantValueKind): FirArrayOfCall { - return buildArrayOfCall { - argumentList = buildArgumentList { - for (element in this@createArrayOfCall) { - arguments += element.createConstantOrError(session) - } - } - typeRef = buildResolvedTypeRef { - type = kind.expectedConeType(session).createArrayType() - } - } -} - internal fun Any?.createConstantOrError(session: FirSession): FirExpression { return createConstantIfAny(session) ?: buildErrorExpression { diagnostic = ConeSimpleDiagnostic("Unknown value in JavaLiteralAnnotationArgument: $this", DiagnosticKind.Java) @@ -302,6 +80,19 @@ internal fun Any?.createConstantIfAny(session: FirSession): FirExpression? { } } +private fun List.createArrayOfCall(session: FirSession, kind: ConstantValueKind): FirArrayOfCall { + return buildArrayOfCall { + argumentList = buildArgumentList { + for (element in this@createArrayOfCall) { + arguments += element.createConstantOrError(session) + } + } + typeRef = buildResolvedTypeRef { + type = kind.expectedConeType(session).createArrayType() + } + } +} + private fun FirConstExpression<*>.setProperType(session: FirSession): FirConstExpression<*> { val typeRef = buildResolvedTypeRef { type = kind.expectedConeType(session) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt index 087aeaf937c..0aa8db23ac8 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt @@ -79,22 +79,12 @@ private fun ConeKotlinType.enhanceConeKotlinType( } } -private val KOTLIN_COLLECTIONS = FqName("kotlin.collections") - -private val KOTLIN_COLLECTIONS_PREFIX_LENGTH = KOTLIN_COLLECTIONS.asString().length + 1 - internal fun ClassId.readOnlyToMutable(): ClassId? { - val mutableFqName = JavaToKotlinClassMap.readOnlyToMutable(asSingleFqName().toUnsafe()) - return mutableFqName?.let { - ClassId(KOTLIN_COLLECTIONS, FqName(it.asString().substring(KOTLIN_COLLECTIONS_PREFIX_LENGTH)), false) - } + return JavaToKotlinClassMap.readOnlyToMutable(this) } private fun ClassId.mutableToReadOnly(): ClassId? { - val readOnlyFqName = JavaToKotlinClassMap.mutableToReadOnly(asSingleFqName().toUnsafe()) - return readOnlyFqName?.let { - ClassId(KOTLIN_COLLECTIONS, FqName(it.asString().substring(KOTLIN_COLLECTIONS_PREFIX_LENGTH)), false) - } + return JavaToKotlinClassMap.mutableToReadOnly(this) } private fun ConeKotlinType.enhanceInflexibleType( diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt new file mode 100644 index 00000000000..c54e541e793 --- /dev/null +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt @@ -0,0 +1,232 @@ +/* + * 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.fir.java + +import org.jetbrains.kotlin.fir.FirModuleData +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirConstructor +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.buildUnaryArgumentList +import org.jetbrains.kotlin.fir.expressions.builder.* +import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter +import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference +import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference +import org.jetbrains.kotlin.fir.resolve.bindSymbolToLookupTag +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError +import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols +import org.jetbrains.kotlin.fir.resolve.symbolProvider +import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl +import org.jetbrains.kotlin.fir.toFirPsiSourceElement +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef +import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef +import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl +import org.jetbrains.kotlin.load.java.structure.* +import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import java.util.* + +internal fun Iterable.convertAnnotationsToFir( + session: FirSession, javaTypeParameterStack: JavaTypeParameterStack +): List = map { it.toFirAnnotationCall(session, javaTypeParameterStack) } + +internal fun JavaAnnotationOwner.convertAnnotationsToFir( + session: FirSession, javaTypeParameterStack: JavaTypeParameterStack +): List = annotations.convertAnnotationsToFir(session, javaTypeParameterStack) + +internal fun MutableList.addFromJava( + session: FirSession, + javaAnnotationOwner: JavaAnnotationOwner, + javaTypeParameterStack: JavaTypeParameterStack +) { + javaAnnotationOwner.annotations.mapTo(this) { it.toFirAnnotationCall(session, javaTypeParameterStack) } +} + +internal fun JavaValueParameter.toFirValueParameter( + session: FirSession, moduleData: FirModuleData, index: Int, javaTypeParameterStack: JavaTypeParameterStack +): FirValueParameter { + return buildJavaValueParameter { + source = (this@toFirValueParameter as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement() + this.moduleData = moduleData + name = this@toFirValueParameter.name ?: Name.identifier("p$index") + returnTypeRef = type.toFirJavaTypeRef(session, javaTypeParameterStack) + isVararg = this@toFirValueParameter.isVararg + annotationBuilder = { convertAnnotationsToFir(session, javaTypeParameterStack) } + } +} + +internal fun JavaAnnotationArgument.toFirExpression( + session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, expectedTypeRef: FirTypeRef? +): FirExpression { + return when (this) { + is JavaLiteralAnnotationArgument -> value.createConstantOrError(session) + is JavaArrayAnnotationArgument -> buildArrayOfCall { + val argumentTypeRef = expectedTypeRef?.let { + typeRef = it + buildResolvedTypeRef { + type = it.coneTypeSafe()?.lowerBoundIfFlexible()?.arrayElementType() + ?: ConeClassErrorType(ConeSimpleDiagnostic("expected type is not array type")) + } + } + argumentList = buildArgumentList { + getElements().mapTo(arguments) { it.toFirExpression(session, javaTypeParameterStack, argumentTypeRef) } + } + } + is JavaEnumValueAnnotationArgument -> buildEnumCall(session, enumClassId, entryName) + is JavaClassObjectAnnotationArgument -> buildGetClassCall { + argumentList = buildUnaryArgumentList( + buildClassReferenceExpression { + classTypeRef = getReferencedType().toFirResolvedTypeRef(session, javaTypeParameterStack) + } + ) + } + is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall(session, javaTypeParameterStack) + else -> buildErrorExpression { + diagnostic = ConeSimpleDiagnostic("Unknown JavaAnnotationArgument: ${this::class.java}", DiagnosticKind.Java) + } + } +} + +private val JAVA_RETENTION_TO_KOTLIN: Map = mapOf( + "RUNTIME" to AnnotationRetention.RUNTIME, + "CLASS" to AnnotationRetention.BINARY, + "SOURCE" to AnnotationRetention.SOURCE +) + +private val JAVA_TARGETS_TO_KOTLIN = mapOf( + "TYPE" to EnumSet.of(AnnotationTarget.CLASS, AnnotationTarget.FILE), + "ANNOTATION_TYPE" to EnumSet.of(AnnotationTarget.ANNOTATION_CLASS), + "TYPE_PARAMETER" to EnumSet.of(AnnotationTarget.TYPE_PARAMETER), + "FIELD" to EnumSet.of(AnnotationTarget.FIELD), + "LOCAL_VARIABLE" to EnumSet.of(AnnotationTarget.LOCAL_VARIABLE), + "PARAMETER" to EnumSet.of(AnnotationTarget.VALUE_PARAMETER), + "CONSTRUCTOR" to EnumSet.of(AnnotationTarget.CONSTRUCTOR), + "METHOD" to EnumSet.of(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER), + "TYPE_USE" to EnumSet.of(AnnotationTarget.TYPE) +) + +private fun buildEnumCall(session: FirSession, classId: ClassId?, entryName: Name?): FirFunctionCall { + return buildFunctionCall { + val calleeReference = if (classId != null && entryName != null) { + session.symbolProvider.getClassDeclaredPropertySymbols(classId, entryName) + .firstOrNull()?.let { propertySymbol -> + buildResolvedNamedReference { + name = entryName + resolvedSymbol = propertySymbol + } + } + } else { + null + } + this.calleeReference = calleeReference ?: buildErrorNamedReference { + diagnostic = ConeSimpleDiagnostic("Strange Java enum value: $classId.$entryName", DiagnosticKind.Java) + } + } +} + +private fun List.mapJavaTargetArguments(session: FirSession): FirExpression? { + return buildVarargArgumentsExpression { + val resultSet = EnumSet.noneOf(AnnotationTarget::class.java) + for (target in this@mapJavaTargetArguments) { + if (target !is JavaEnumValueAnnotationArgument) return null + resultSet.addAll(JAVA_TARGETS_TO_KOTLIN[target.entryName?.asString()] ?: continue) + } + val classId = StandardClassIds.AnnotationTarget + resultSet.mapTo(arguments) { buildEnumCall(session, classId, Name.identifier(it.name)) } + varargElementType = buildResolvedTypeRef { + type = ConeClassLikeTypeImpl( + ConeClassLikeLookupTagImpl(classId), + emptyArray(), + isNullable = false, + ConeAttributes.Empty + ).createOutArrayType() + } + } +} + +private fun JavaAnnotationArgument.mapJavaRetentionArgument(session: FirSession): FirExpression? { + return JAVA_RETENTION_TO_KOTLIN[(this as? JavaEnumValueAnnotationArgument)?.entryName?.asString()]?.let { + buildEnumCall(session, StandardClassIds.AnnotationRetention, Name.identifier(it.name)) + } +} + +private fun fillAnnotationArgumentMapping( + session: FirSession, + javaTypeParameterStack: JavaTypeParameterStack, + lookupTag: ConeClassLikeLookupTagImpl, + annotationArguments: Collection, + destination: MutableMap +) { + if (annotationArguments.isEmpty()) return + + val annotationClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(lookupTag.classId).also { + lookupTag.bindSymbolToLookupTag(session, it) + } + val annotationConstructor = (annotationClassSymbol?.fir as FirRegularClass?) + ?.declarations + ?.firstIsInstanceOrNull() + annotationArguments.associateTo(destination) { argument -> + val name = argument.name ?: StandardClassIds.Annotations.ParameterNames.value + val parameter = annotationConstructor?.valueParameters?.find { it.name == name } + name to argument.toFirExpression(session, javaTypeParameterStack, parameter?.returnTypeRef) + } +} + +private fun JavaAnnotation.toFirAnnotationCall( + session: FirSession, javaTypeParameterStack: JavaTypeParameterStack +): FirAnnotation { + return buildAnnotation { + val lookupTag = when (classId) { + StandardClassIds.Annotations.Java.Target -> StandardClassIds.Annotations.Target + StandardClassIds.Annotations.Java.Retention -> StandardClassIds.Annotations.Retention + StandardClassIds.Annotations.Java.Documented -> StandardClassIds.Annotations.MustBeDocumented + StandardClassIds.Annotations.Java.Deprecated -> StandardClassIds.Annotations.Deprecated + else -> classId + }?.let(::ConeClassLikeLookupTagImpl) + annotationTypeRef = if (lookupTag != null) { + buildResolvedTypeRef { + type = ConeClassLikeTypeImpl(lookupTag, emptyArray(), isNullable = false) + } + } else { + buildErrorTypeRef { diagnostic = ConeUnresolvedReferenceError() } + } + + argumentMapping = buildAnnotationArgumentMapping { + when (classId) { + StandardClassIds.Annotations.Java.Target -> { + when (val argument = arguments.firstOrNull()) { + is JavaArrayAnnotationArgument -> argument.getElements().mapJavaTargetArguments(session) + is JavaEnumValueAnnotationArgument -> listOf(argument).mapJavaTargetArguments(session) + else -> null + }?.let { + mapping[StandardClassIds.Annotations.ParameterNames.targetAllowedTargets] = it + } + } + StandardClassIds.Annotations.Java.Retention -> { + arguments.firstOrNull()?.mapJavaRetentionArgument(session)?.let { + mapping[StandardClassIds.Annotations.ParameterNames.retentionValue] = it + } + } + StandardClassIds.Annotations.Java.Deprecated -> { + mapping[StandardClassIds.Annotations.ParameterNames.deprecatedMessage] = + "Deprecated in Java".createConstantOrError(session) + } + else -> { + fillAnnotationArgumentMapping(session, javaTypeParameterStack, lookupTag!!, arguments, mapping) + } + } + } + } +} diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/DescriptorUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/SignatureUtils.kt similarity index 100% rename from compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/DescriptorUtils.kt rename to compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/SignatureUtils.kt diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt index b1c9ad96338..a93138c98a6 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/builtins/jvm/JavaToKotlinClassMap.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity import org.jetbrains.kotlin.builtins.functions.FunctionClassKind import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType -import java.util.* object JavaToKotlinClassMap { private val NUMBERED_FUNCTION_PREFIX: String = @@ -26,8 +25,8 @@ object JavaToKotlinClassMap { private val FUNCTION_N_CLASS_ID: ClassId = ClassId.topLevel(FqName("kotlin.jvm.functions.FunctionN")) val FUNCTION_N_FQ_NAME: FqName = FUNCTION_N_CLASS_ID.asSingleFqName() - private val K_FUNCTION_CLASS_ID: ClassId = ClassId.topLevel(FqName("kotlin.reflect.KFunction")) - private val K_CLASS_CLASS_ID: ClassId = ClassId.topLevel(FqName("kotlin.reflect.KClass")) + private val K_FUNCTION_CLASS_ID: ClassId = StandardClassIds.KFunction + private val K_CLASS_CLASS_ID: ClassId = StandardClassIds.KClass private val CLASS_CLASS_ID: ClassId = classId(Class::class.java) private val javaToKotlin = HashMap() @@ -36,6 +35,9 @@ object JavaToKotlinClassMap { private val mutableToReadOnly = HashMap() private val readOnlyToMutable = HashMap() + private val mutableToReadOnlyClassId = HashMap() + private val readOnlyToMutableClassId = HashMap() + // describes mapping for a java class that has separate readOnly and mutable equivalents in Kotlin data class PlatformMutabilityMapping( val javaClass: ClassId, @@ -161,6 +163,9 @@ object JavaToKotlinClassMap { add(javaClassId, readOnlyClassId) addKotlinToJava(mutableClassId.asSingleFqName(), javaClassId) + mutableToReadOnlyClassId[mutableClassId] = readOnlyClassId + readOnlyToMutableClassId[readOnlyClassId] = mutableClassId + val readOnlyFqName = readOnlyClassId.asSingleFqName() val mutableFqName = mutableClassId.asSingleFqName() mutableToReadOnly[mutableClassId.asSingleFqName().toUnsafe()] = readOnlyFqName @@ -191,13 +196,17 @@ object JavaToKotlinClassMap { fun isJavaPlatformClass(fqName: FqName): Boolean = mapJavaToKotlin(fqName) != null fun mutableToReadOnly(fqNameUnsafe: FqNameUnsafe?): FqName? = mutableToReadOnly[fqNameUnsafe] - fun readOnlyToMutable(fqNameUnsafe: FqNameUnsafe?): FqName? = readOnlyToMutable[fqNameUnsafe] - fun isMutable(fqNameUnsafe: FqNameUnsafe?): Boolean = mutableToReadOnly.containsKey(fqNameUnsafe) + fun mutableToReadOnly(classId: ClassId): ClassId? = mutableToReadOnlyClassId[classId] + fun readOnlyToMutable(classId: ClassId): ClassId? = readOnlyToMutableClassId[classId] + fun isMutable(fqNameUnsafe: FqNameUnsafe?): Boolean = mutableToReadOnly.containsKey(fqNameUnsafe) fun isReadOnly(fqNameUnsafe: FqNameUnsafe?): Boolean = readOnlyToMutable.containsKey(fqNameUnsafe) + fun isMutable(classId: ClassId?): Boolean = readOnlyToMutableClassId.containsKey(classId) + fun isReadOnly(classId: ClassId?): Boolean = readOnlyToMutableClassId.containsKey(classId) + private fun classId(clazz: Class<*>): ClassId { assert(!clazz.isPrimitive && !clazz.isArray) { "Invalid class: $clazz" } val outer = clazz.declaringClass