[FIR] Cleanup and reorganize utils in :compiler:fir:java
This commit is contained in:
committed by
teamcityserver
parent
7a347b11e3
commit
9d09b9605f
@@ -7,37 +7,24 @@ package org.jetbrains.kotlin.fir.java
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.fir.*
|
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.ConeSimpleDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
import org.jetbrains.kotlin.fir.expressions.builder.buildArrayOfCall
|
||||||
import org.jetbrains.kotlin.fir.resolve.bindSymbolToLookupTag
|
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError
|
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols
|
import org.jetbrains.kotlin.fir.lookupTracker
|
||||||
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
import org.jetbrains.kotlin.fir.recordTypeResolveAsLookup
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.expectedConeType
|
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.builder.buildResolvedTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
import org.jetbrains.kotlin.fir.types.createArrayType
|
||||||
import org.jetbrains.kotlin.load.java.structure.*
|
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl
|
import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner
|
||||||
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.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
internal val JavaModifierListOwner.modality: Modality
|
internal val JavaModifierListOwner.modality: Modality
|
||||||
get() = when {
|
get() = when {
|
||||||
@@ -62,215 +49,6 @@ internal val JavaClass.classKind: ClassKind
|
|||||||
else -> ClassKind.CLASS
|
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 {
|
internal fun Any?.createConstantOrError(session: FirSession): FirExpression {
|
||||||
return createConstantIfAny(session) ?: buildErrorExpression {
|
return createConstantIfAny(session) ?: buildErrorExpression {
|
||||||
diagnostic = ConeSimpleDiagnostic("Unknown value in JavaLiteralAnnotationArgument: $this", DiagnosticKind.Java)
|
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<*> {
|
private fun FirConstExpression<*>.setProperType(session: FirSession): FirConstExpression<*> {
|
||||||
val typeRef = buildResolvedTypeRef {
|
val typeRef = buildResolvedTypeRef {
|
||||||
type = kind.expectedConeType(session)
|
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? {
|
internal fun ClassId.readOnlyToMutable(): ClassId? {
|
||||||
val mutableFqName = JavaToKotlinClassMap.readOnlyToMutable(asSingleFqName().toUnsafe())
|
return JavaToKotlinClassMap.readOnlyToMutable(this)
|
||||||
return mutableFqName?.let {
|
|
||||||
ClassId(KOTLIN_COLLECTIONS, FqName(it.asString().substring(KOTLIN_COLLECTIONS_PREFIX_LENGTH)), false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ClassId.mutableToReadOnly(): ClassId? {
|
private fun ClassId.mutableToReadOnly(): ClassId? {
|
||||||
val readOnlyFqName = JavaToKotlinClassMap.mutableToReadOnly(asSingleFqName().toUnsafe())
|
return JavaToKotlinClassMap.mutableToReadOnly(this)
|
||||||
return readOnlyFqName?.let {
|
|
||||||
ClassId(KOTLIN_COLLECTIONS, FqName(it.asString().substring(KOTLIN_COLLECTIONS_PREFIX_LENGTH)), false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConeKotlinType.enhanceInflexibleType(
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-5
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
|
|||||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||||
import org.jetbrains.kotlin.name.*
|
import org.jetbrains.kotlin.name.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
object JavaToKotlinClassMap {
|
object JavaToKotlinClassMap {
|
||||||
private val NUMBERED_FUNCTION_PREFIX: String =
|
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"))
|
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()
|
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_FUNCTION_CLASS_ID: ClassId = StandardClassIds.KFunction
|
||||||
private val K_CLASS_CLASS_ID: ClassId = ClassId.topLevel(FqName("kotlin.reflect.KClass"))
|
private val K_CLASS_CLASS_ID: ClassId = StandardClassIds.KClass
|
||||||
private val CLASS_CLASS_ID: ClassId = classId(Class::class.java)
|
private val CLASS_CLASS_ID: ClassId = classId(Class::class.java)
|
||||||
|
|
||||||
private val javaToKotlin = HashMap<FqNameUnsafe, ClassId>()
|
private val javaToKotlin = HashMap<FqNameUnsafe, ClassId>()
|
||||||
@@ -36,6 +35,9 @@ object JavaToKotlinClassMap {
|
|||||||
private val mutableToReadOnly = HashMap<FqNameUnsafe, FqName>()
|
private val mutableToReadOnly = HashMap<FqNameUnsafe, FqName>()
|
||||||
private val readOnlyToMutable = 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
|
// describes mapping for a java class that has separate readOnly and mutable equivalents in Kotlin
|
||||||
data class PlatformMutabilityMapping(
|
data class PlatformMutabilityMapping(
|
||||||
val javaClass: ClassId,
|
val javaClass: ClassId,
|
||||||
@@ -161,6 +163,9 @@ object JavaToKotlinClassMap {
|
|||||||
add(javaClassId, readOnlyClassId)
|
add(javaClassId, readOnlyClassId)
|
||||||
addKotlinToJava(mutableClassId.asSingleFqName(), javaClassId)
|
addKotlinToJava(mutableClassId.asSingleFqName(), javaClassId)
|
||||||
|
|
||||||
|
mutableToReadOnlyClassId[mutableClassId] = readOnlyClassId
|
||||||
|
readOnlyToMutableClassId[readOnlyClassId] = mutableClassId
|
||||||
|
|
||||||
val readOnlyFqName = readOnlyClassId.asSingleFqName()
|
val readOnlyFqName = readOnlyClassId.asSingleFqName()
|
||||||
val mutableFqName = mutableClassId.asSingleFqName()
|
val mutableFqName = mutableClassId.asSingleFqName()
|
||||||
mutableToReadOnly[mutableClassId.asSingleFqName().toUnsafe()] = readOnlyFqName
|
mutableToReadOnly[mutableClassId.asSingleFqName().toUnsafe()] = readOnlyFqName
|
||||||
@@ -191,13 +196,17 @@ object JavaToKotlinClassMap {
|
|||||||
fun isJavaPlatformClass(fqName: FqName): Boolean = mapJavaToKotlin(fqName) != null
|
fun isJavaPlatformClass(fqName: FqName): Boolean = mapJavaToKotlin(fqName) != null
|
||||||
|
|
||||||
fun mutableToReadOnly(fqNameUnsafe: FqNameUnsafe?): FqName? = mutableToReadOnly[fqNameUnsafe]
|
fun mutableToReadOnly(fqNameUnsafe: FqNameUnsafe?): FqName? = mutableToReadOnly[fqNameUnsafe]
|
||||||
|
|
||||||
fun readOnlyToMutable(fqNameUnsafe: FqNameUnsafe?): FqName? = readOnlyToMutable[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 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 {
|
private fun classId(clazz: Class<*>): ClassId {
|
||||||
assert(!clazz.isPrimitive && !clazz.isArray) { "Invalid class: $clazz" }
|
assert(!clazz.isPrimitive && !clazz.isArray) { "Invalid class: $clazz" }
|
||||||
val outer = clazz.declaringClass
|
val outer = clazz.declaringClass
|
||||||
|
|||||||
Reference in New Issue
Block a user