[FIR] Cleanup and reorganize utils in :compiler:fir:java

This commit is contained in:
Dmitriy Novozhilov
2021-09-14 15:17:03 +03:00
committed by teamcityserver
parent 7a347b11e3
commit 9d09b9605f
5 changed files with 274 additions and 252 deletions
@@ -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<JavaAnnotationArgument>.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<JavaAnnotationArgument>,
destination: MutableMap<Name, FirExpression>
) {
if (annotationArguments.isEmpty()) return
val annotationClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(lookupTag.classId).also {
lookupTag.bindSymbolToLookupTag(session, it)
}
val annotationConstructor = (annotationClassSymbol?.fir as FirRegularClass?)
?.declarations
?.firstIsInstanceOrNull<FirConstructor>()
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<JavaAnnotation>.convertAnnotationsToFir(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack
): List<FirAnnotation> = map { it.toFirAnnotationCall(session, javaTypeParameterStack) }
internal fun JavaAnnotationOwner.convertAnnotationsToFir(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack
): List<FirAnnotation> = annotations.convertAnnotationsToFir(session, javaTypeParameterStack)
internal fun MutableList<FirAnnotation>.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<ConeKotlinType>()?.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 <T> List<T>.createArrayOfCall(session: FirSession, @Suppress("UNUSED_PARAMETER") kind: ConstantValueKind<T>): 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 <T> List<T>.createArrayOfCall(session: FirSession, kind: ConstantValueKind<T>): 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)
@@ -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(
@@ -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<JavaAnnotation>.convertAnnotationsToFir(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack
): List<FirAnnotation> = map { it.toFirAnnotationCall(session, javaTypeParameterStack) }
internal fun JavaAnnotationOwner.convertAnnotationsToFir(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack
): List<FirAnnotation> = annotations.convertAnnotationsToFir(session, javaTypeParameterStack)
internal fun MutableList<FirAnnotation>.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<ConeKotlinType>()?.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<String, AnnotationRetention> = 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<JavaAnnotationArgument>.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<JavaAnnotationArgument>,
destination: MutableMap<Name, FirExpression>
) {
if (annotationArguments.isEmpty()) return
val annotationClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(lookupTag.classId).also {
lookupTag.bindSymbolToLookupTag(session, it)
}
val annotationConstructor = (annotationClassSymbol?.fir as FirRegularClass?)
?.declarations
?.firstIsInstanceOrNull<FirConstructor>()
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)
}
}
}
}
}
@@ -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<FqNameUnsafe, ClassId>()
@@ -36,6 +35,9 @@ object JavaToKotlinClassMap {
private val mutableToReadOnly = HashMap<FqNameUnsafe, FqName>()
private val readOnlyToMutable = HashMap<FqNameUnsafe, FqName>()
private val mutableToReadOnlyClassId = HashMap<ClassId, ClassId>()
private val readOnlyToMutableClassId = HashMap<ClassId, ClassId>()
// 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