org.jetbrains.kotlin.fir.java.FirJavaFacade.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2024 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 com.intellij.psi.PsiMethod
import com.intellij.psi.util.JavaPsiRecordUtil
import org.jetbrains.kotlin.*
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildConstructedClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.builder.buildEnumEntry
import org.jetbrains.kotlin.fir.declarations.builder.buildOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.sourceElement
import org.jetbrains.kotlin.fir.extensions.FirStatusTransformerExtension
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.statusTransformerExtensions
import org.jetbrains.kotlin.fir.java.declarations.*
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
import org.jetbrains.kotlin.name.*
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
class FirJavaFacadeForSource(
session: FirSession,
private val sourceModuleData: FirModuleData,
classFinder: JavaClassFinder
) : FirJavaFacade(session, sourceModuleData.session.builtinTypes, classFinder) {
override fun getModuleDataForClass(javaClass: JavaClass): FirModuleData {
return sourceModuleData
}
}
@ThreadSafeMutableState
abstract class FirJavaFacade(
private val session: FirSession,
private val builtinTypes: BuiltinTypes,
private val classFinder: JavaClassFinder
) {
companion object {
val VALUE_METHOD_NAME: Name = Name.identifier("value")
private const val PACKAGE_INFO_CLASS_NAME = "package-info"
}
private val packageCache = session.firCachesFactory.createCache { fqName: FqName ->
val knownClassNames: Set? = knownClassNamesInPackage(fqName)
classFinder.findPackage(
fqName,
mayHaveAnnotations = if (knownClassNames != null) PACKAGE_INFO_CLASS_NAME in knownClassNames else true
)
}
private val knownClassNamesInPackage = session.firCachesFactory.createCache(classFinder::knownClassNamesInPackage)
private val parentClassTypeParameterStackCache = mutableMapOf()
private val parentClassEffectiveVisibilityCache = mutableMapOf()
private val statusExtensions = session.extensionService.statusTransformerExtensions
private val classTypeParameterBoundsResolveLock = ReentrantLock()
internal fun withClassTypeParameterBoundsResolveLock(f: () -> Unit) {
// TODO: KT-68587
classTypeParameterBoundsResolveLock.withLock(f)
}
fun findClass(classId: ClassId, knownContent: ByteArray? = null): JavaClass? =
classFinder.findClass(JavaClassFinder.Request(classId, knownContent))?.takeUnless(JavaClass::hasMetadataAnnotation)
fun getPackage(fqName: FqName): FqName? =
packageCache.getValue(fqName)?.fqName
fun hasTopLevelClassOf(classId: ClassId): Boolean {
val knownNames = knownClassNamesInPackage(classId.packageFqName) ?: return true
return classId.relativeClassName.topLevelName() in knownNames
}
fun knownClassNamesInPackage(packageFqName: FqName): Set? {
// Avoid filling the cache with `null`s and accessing the cache if `knownClassNamesInPackage` cannot be calculated anyway.
if (!classFinder.canComputeKnownClassNamesInPackage()) return null
return knownClassNamesInPackage.getValue(packageFqName)
}
abstract fun getModuleDataForClass(javaClass: JavaClass): FirModuleData
private fun JavaTypeParameter.toFirTypeParameter(
javaTypeParameterStack: MutableJavaTypeParameterStack,
containingDeclarationSymbol: FirBasedSymbol<*>,
moduleData: FirModuleData,
source: KtSourceElement?,
): FirTypeParameter {
return buildJavaTypeParameter {
this.moduleData = moduleData
origin = javaOrigin(isFromSource)
name = [email protected]
symbol = FirTypeParameterSymbol()
javaTypeParameterStack.addParameter(this@toFirTypeParameter, symbol)
this.containingDeclarationSymbol = containingDeclarationSymbol
for (upperBound in [email protected]) {
bounds += upperBound.toFirJavaTypeRef(session, source)
}
if (bounds.isEmpty()) {
bounds += buildResolvedTypeRef {
coneType = ConeFlexibleType(builtinTypes.anyType.coneType, builtinTypes.nullableAnyType.coneType)
}
}
}.apply {
// TODO: should be lazy (in case annotations refer to the containing class)
setAnnotationsFromJava(session, source, this@toFirTypeParameter)
}
}
private fun List.convertTypeParameters(
stack: MutableJavaTypeParameterStack,
containingDeclarationSymbol: FirBasedSymbol<*>,
moduleData: FirModuleData,
source: KtSourceElement?,
): List {
return map { it.toFirTypeParameter(stack, containingDeclarationSymbol, moduleData, source) }
}
private class ValueParametersForAnnotationConstructor {
val valueParameters: MutableMap = linkedMapOf()
var valueParameterForValue: Pair? = null
inline fun forEach(block: (JavaMethod, FirJavaValueParameter) -> Unit) {
valueParameterForValue?.let { (javaMethod, firJavaValueParameter) -> block(javaMethod, firJavaValueParameter) }
valueParameters.forEach { (javaMethod, firJavaValueParameter) -> block(javaMethod, firJavaValueParameter) }
}
}
fun convertJavaClassToFir(
classSymbol: FirRegularClassSymbol,
parentClassSymbol: FirRegularClassSymbol?,
javaClass: JavaClass,
): FirJavaClass {
val classId = classSymbol.classId
val javaTypeParameterStack = MutableJavaTypeParameterStack()
if (parentClassSymbol != null) {
val parentStack = parentClassTypeParameterStackCache[parentClassSymbol]
?: (parentClassSymbol.fir as? FirJavaClass)?.javaTypeParameterStack
if (parentStack != null) {
javaTypeParameterStack.addStack(parentStack)
}
}
parentClassTypeParameterStackCache[classSymbol] = javaTypeParameterStack
val firJavaClass = createFirJavaClass(javaClass, classSymbol, parentClassSymbol, classId, javaTypeParameterStack)
parentClassTypeParameterStackCache.remove(classSymbol)
parentClassEffectiveVisibilityCache.remove(classSymbol)
/**
* This is where the problems begin. We need to enhance nullability of super types and type parameter bounds,
* for which we need the annotations of this class as they may specify default nullability.
* However, all three - annotations, type parameter bounds, and supertypes - can refer to other classes,
* which will cause the type parameter bounds and supertypes of *those* classes to get enhanced first,
* but they may refer back to this class again - which, thanks to the magic of symbol resolver caches,
* will be observed in a state where we've not done the enhancement yet. For those cases, we must publish
* at least unenhanced resolved types,
* or else FIR may crash upon encountering a [org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef]
* where [FirResolvedTypeRef] is expected.
*
* 1. (will happen lazily in [FirJavaClass.annotations]]) Resolve annotations
* 2. Enhance type parameter bounds in [FirJavaTypeParameter] - may refer to each other, take default nullability from annotations
* 3. (will happen lazily in [FirJavaClass.superTypeRefs]) Enhance super types - may refer to type parameter bounds, take default nullability from annotations
*/
val enhancement = FirSignatureEnhancement(firJavaClass, session) { emptyList() }
val fakeSource = classSymbol.source?.fakeElement(KtFakeSourceElementKind.Enhancement)
enhancement.performBoundsResolutionForClassTypeParameters(this, firJavaClass, fakeSource)
updateStatuses(firJavaClass, parentClassSymbol)
return firJavaClass
}
private fun updateStatuses(firJavaClass: FirJavaClass, parentClassSymbol: FirRegularClassSymbol?) {
if (statusExtensions.isEmpty()) return
val classSymbol = firJavaClass.symbol
val visitor = object : FirVisitorVoid() {
override fun visitElement(element: FirElement) {}
override fun visitRegularClass(regularClass: FirRegularClass) {
regularClass.applyExtensionTransformers {
transformStatus(it, regularClass, parentClassSymbol, isLocal = false)
}
regularClass.acceptChildren(this)
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
simpleFunction.applyExtensionTransformers {
transformStatus(it, simpleFunction, classSymbol, isLocal = false)
}
}
override fun visitField(field: FirField) {
field.applyExtensionTransformers {
transformStatus(it, field, classSymbol, isLocal = false)
}
}
override fun visitConstructor(constructor: FirConstructor) {
constructor.applyExtensionTransformers {
transformStatus(it, constructor, classSymbol, isLocal = false)
}
}
}
firJavaClass.accept(visitor)
}
private fun createFirJavaClass(
javaClass: JavaClass,
classSymbol: FirRegularClassSymbol,
parentClassSymbol: FirRegularClassSymbol?,
classId: ClassId,
javaTypeParameterStack: MutableJavaTypeParameterStack,
): FirJavaClass {
val valueParametersForAnnotationConstructor = ValueParametersForAnnotationConstructor()
val classIsAnnotation = javaClass.classKind == ClassKind.ANNOTATION_CLASS
val moduleData = getModuleDataForClass(javaClass)
val fakeSource = javaClass.toSourceElement()?.fakeElement(KtFakeSourceElementKind.Enhancement)
return buildJavaClass {
resolvePhase = FirResolvePhase.BODY_RESOLVE
javaAnnotations += javaClass.annotations
isDeprecatedInJavaDoc = javaClass.isDeprecatedInJavaDoc
source = javaClass.toSourceElement()
this.moduleData = moduleData
symbol = classSymbol
name = javaClass.name
isFromSource = javaClass.isFromSource
val visibility = javaClass.visibility
[email protected] = visibility
classKind = javaClass.classKind
modality = javaClass.modality
this.isTopLevel = classId.outerClassId == null
isStatic = javaClass.isStatic
javaPackage = packageCache.getValue(classSymbol.classId.packageFqName)
this.javaTypeParameterStack = javaTypeParameterStack
existingNestedClassifierNames += javaClass.innerClassNames
scopeProvider = JavaScopeProvider
val selfEffectiveVisibility = visibility.toEffectiveVisibility(parentClassSymbol?.toLookupTag(), forClass = true)
val parentEffectiveVisibility = parentClassSymbol?.let {
parentClassEffectiveVisibilityCache[it] ?: it.fir.effectiveVisibility
} ?: EffectiveVisibility.Public
val effectiveVisibility = parentEffectiveVisibility.lowerBound(selfEffectiveVisibility, session.typeContext)
parentClassEffectiveVisibilityCache[classSymbol] = effectiveVisibility
val classTypeParameters = javaClass.typeParameters.convertTypeParameters(
javaTypeParameterStack, classSymbol, moduleData, fakeSource
)
typeParameters += classTypeParameters
if (!isStatic && parentClassSymbol != null) {
typeParameters += parentClassSymbol.fir.typeParameters.map {
buildOuterClassTypeParameterRef { symbol = it.symbol }
}
}
javaClass.supertypes.mapTo(superTypeRefs) { it.toFirJavaTypeRef(session, fakeSource) }
if (superTypeRefs.isEmpty()) {
superTypeRefs.add(
buildResolvedTypeRef {
coneType = StandardClassIds.Any.constructClassLikeType(emptyArray(), isNullable = false)
}
)
}
val dispatchReceiver = classId.defaultType(typeParameters.map { it.symbol })
status = FirResolvedDeclarationStatusImpl(
visibility,
modality!!,
effectiveVisibility
).apply {
this.isInner = !isTopLevel && [email protected]
isFun = classKind == ClassKind.INTERFACE
}
// TODO: may be we can process fields & methods later.
// However, they should be built up to override resolve stage
for (javaField in javaClass.fields) {
declarations += convertJavaFieldToFir(javaField, classId, javaTypeParameterStack, dispatchReceiver, moduleData)
}
for (javaMethod in javaClass.methods) {
if (javaMethod.isObjectMethodInInterface()) continue
val firJavaMethod = convertJavaMethodToFir(
javaClass,
javaMethod,
classId,
javaTypeParameterStack,
dispatchReceiver,
moduleData,
)
declarations += firJavaMethod
if (classIsAnnotation) {
val parameterForAnnotationConstructor =
convertJavaAnnotationMethodToValueParameter(javaMethod, firJavaMethod, moduleData)
if (javaMethod.name == VALUE_METHOD_NAME) {
valueParametersForAnnotationConstructor.valueParameterForValue = javaMethod to parameterForAnnotationConstructor
} else {
valueParametersForAnnotationConstructor.valueParameters[javaMethod] = parameterForAnnotationConstructor
}
}
}
val javaClassDeclaredConstructors = javaClass.constructors
val constructorId = CallableId(classId.packageFqName, classId.relativeClassName, classId.shortClassName)
if (javaClassDeclaredConstructors.isEmpty()
&& javaClass.classKind == ClassKind.CLASS
&& !javaClass.isRecord
&& javaClass.hasDefaultConstructor()
) {
declarations += convertJavaConstructorToFir(
javaConstructor = null,
constructorId,
javaClass,
ownerClassBuilder = this,
classTypeParameters,
javaTypeParameterStack,
parentClassSymbol,
moduleData,
)
}
for (javaConstructor in javaClassDeclaredConstructors) {
declarations += convertJavaConstructorToFir(
javaConstructor,
constructorId,
javaClass,
ownerClassBuilder = this,
classTypeParameters,
javaTypeParameterStack,
parentClassSymbol,
moduleData,
)
}
if (classKind == ClassKind.ENUM_CLASS) {
generateValuesFunction(
moduleData,
classId.packageFqName,
classId.relativeClassName
)
generateValueOfFunction(moduleData, classId.packageFqName, classId.relativeClassName)
generateEntriesGetter(moduleData, classId.packageFqName, classId.relativeClassName)
}
if (classIsAnnotation) {
declarations +=
buildConstructorForAnnotationClass(
javaClass,
constructorId = constructorId,
ownerClassBuilder = this,
valueParametersForAnnotationConstructor = valueParametersForAnnotationConstructor,
moduleData = moduleData,
)
}
// There is no need to generated synthetic declarations for java record from binary dependencies
// because they are actually present in .class files
if (javaClass.isRecord && javaClass.isFromSource) {
createDeclarationsForJavaRecord(
javaClass,
classId,
moduleData,
dispatchReceiver,
classTypeParameters,
declarations
)
}
}.apply {
if (modality == Modality.SEALED) {
val permittedTypes = javaClass.permittedTypes
setSealedClassInheritors {
permittedTypes.mapNotNullTo(mutableListOf()) { classifierType ->
val classifier = classifierType.classifier as? JavaClass
classifier?.let { JavaToKotlinClassMap.mapJavaToKotlin(it.fqName!!) ?: it.classId }
}
}
}
if (classIsAnnotation) {
val javaTypeParameterStackSnapshot = javaTypeParameterStack.snapshot()
// Cannot load these until the symbol is bound because they may be self-referential.
valueParametersForAnnotationConstructor.forEach { javaMethod, firValueParameter ->
javaMethod.annotationParameterDefaultValue?.let { javaDefaultValue ->
firValueParameter.lazyDefaultValue = lazy {
javaDefaultValue.toFirExpression(
session, javaTypeParameterStackSnapshot, firValueParameter.returnTypeRef, fakeSource
)
}
}
}
}
if (javaClass.isRecord) {
this.isJavaRecord = true
}
if (javaClass is BinaryJavaClass) {
sourceElement = JavaBinarySourceElement(javaClass)
}
}
}
private fun createDeclarationsForJavaRecord(
javaClass: JavaClass,
classId: ClassId,
moduleData: FirModuleData,
classType: ConeClassLikeType,
classTypeParameters: List,
destination: MutableList
) {
val functionsByName = destination.filterIsInstance().groupBy { it.name }
for (recordComponent in javaClass.recordComponents) {
val name = recordComponent.name
if (functionsByName[name].orEmpty().any { it.valueParameters.isEmpty() }) continue
val componentId = CallableId(classId, name)
destination += buildJavaMethod {
this.moduleData = moduleData
source = recordComponent.toSourceElement(KtFakeSourceElementKind.JavaRecordComponentFunction)
symbol = FirNamedFunctionSymbol(componentId)
this.name = name
isFromSource = recordComponent.isFromSource
returnTypeRef = recordComponent.type.toFirJavaTypeRef(session, source)
annotationBuilder = { emptyList() }
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.FINAL,
EffectiveVisibility.Public
)
dispatchReceiverType = classType
}.apply {
isJavaRecordComponent = true
}
}
/**
* It is possible that JavaClass already has a synthetic primary constructor ([LightRecordCanonicalConstructor]) or a
* canonical constructor ([JavaPsiRecordUtil.isCanonicalConstructor]).
* Such behavior depends on a platform version and psi providers
* (e.g., in IntelliJ plugin Java class can have additional declarations)
*/
if (destination.none { it is FirJavaConstructor && it.isPrimary }) {
destination += buildJavaConstructor {
source = javaClass.toSourceElement(KtFakeSourceElementKind.ImplicitJavaRecordConstructor)
this.moduleData = moduleData
isFromSource = javaClass.isFromSource
val constructorId = CallableId(classId, classId.shortClassName)
symbol = FirConstructorSymbol(constructorId)
status = FirResolvedDeclarationStatusImpl(
Visibilities.Public,
Modality.FINAL,
EffectiveVisibility.Public
)
isPrimary = true
returnTypeRef = classType.toFirResolvedTypeRef()
dispatchReceiverType = null
typeParameters += classTypeParameters.toRefs()
annotationBuilder = { emptyList() }
javaClass.recordComponents.mapTo(valueParameters) { component ->
buildJavaValueParameter {
containingFunctionSymbol = [email protected]
source = component.toSourceElement(KtFakeSourceElementKind.ImplicitRecordConstructorParameter)
this.moduleData = moduleData
isFromSource = component.isFromSource
returnTypeRef = component.type.toFirJavaTypeRef(session, source)
name = component.name
isVararg = component.isVararg
annotationBuilder = { emptyList() }
}
}
}.apply {
containingClassForStaticMemberAttr = classType.lookupTag
}
}
}
private fun convertJavaFieldToFir(
javaField: JavaField,
classId: ClassId,
javaTypeParameterStack: MutableJavaTypeParameterStack,
dispatchReceiver: ConeClassLikeType,
moduleData: FirModuleData,
): FirDeclaration {
val fieldName = javaField.name
val fieldId = CallableId(classId.packageFqName, classId.relativeClassName, fieldName)
val returnType = javaField.type
val fakeSource = javaField.toSourceElement()?.fakeElement(KtFakeSourceElementKind.Enhancement)
return when {
javaField.isEnumEntry -> buildEnumEntry {
source = javaField.toSourceElement()
this.moduleData = moduleData
symbol = FirEnumEntrySymbol(fieldId)
name = fieldName
status = FirResolvedDeclarationStatusImpl(
javaField.visibility,
javaField.modality,
javaField.visibility.toEffectiveVisibility(dispatchReceiver.lookupTag)
).apply {
isStatic = javaField.isStatic
}
returnTypeRef = returnType.toFirJavaTypeRef(session, fakeSource)
.resolveIfJavaType(session, javaTypeParameterStack, fakeSource, mode = FirJavaTypeConversionMode.ANNOTATION_MEMBER)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
origin = javaOrigin(javaField.isFromSource)
}.apply {
containingClassForStaticMemberAttr = classId.toLookupTag()
// TODO: check if this works properly with annotations that take the enum class as an argument
setAnnotationsFromJava(session, fakeSource, javaField)
}
else -> buildJavaField {
source = javaField.toSourceElement()
this.moduleData = moduleData
symbol = FirFieldSymbol(fieldId)
name = fieldName
isFromSource = javaField.isFromSource
status = FirResolvedDeclarationStatusImpl(
javaField.visibility,
javaField.modality,
javaField.visibility.toEffectiveVisibility(dispatchReceiver.lookupTag)
).apply {
isStatic = javaField.isStatic
}
returnTypeRef = returnType.toFirJavaTypeRef(session, fakeSource)
isVar = !javaField.isFinal
annotationBuilder = { javaField.convertAnnotationsToFir(session, fakeSource) }
lazyInitializer = lazy {
// NB: null should be converted to null
javaField.initializerValue?.createConstantIfAny(session)
}
lazyHasConstantInitializer = lazy {
javaField.hasConstantNotNullInitializer
}
if (!javaField.isStatic) {
dispatchReceiverType = dispatchReceiver
}
}.apply {
if (javaField.isStatic) {
containingClassForStaticMemberAttr = classId.toLookupTag()
}
}
}
}
private fun convertJavaMethodToFir(
containingClass: JavaClass,
javaMethod: JavaMethod,
classId: ClassId,
javaTypeParameterStack: MutableJavaTypeParameterStack,
dispatchReceiver: ConeClassLikeType,
moduleData: FirModuleData,
): FirJavaMethod {
val methodName = javaMethod.name
val methodId = CallableId(classId.packageFqName, classId.relativeClassName, methodName)
val methodSymbol = FirNamedFunctionSymbol(methodId)
val returnType = javaMethod.returnType
return buildJavaMethod {
this.moduleData = moduleData
source = javaMethod.toSourceElement()
symbol = methodSymbol
name = methodName
isFromSource = javaMethod.isFromSource
val fakeSource = source?.fakeElement(KtFakeSourceElementKind.Enhancement)
returnTypeRef = returnType.toFirJavaTypeRef(session, fakeSource)
isStatic = javaMethod.isStatic
typeParameters += javaMethod.typeParameters.convertTypeParameters(javaTypeParameterStack, methodSymbol, moduleData, fakeSource)
for ((index, valueParameter) in javaMethod.valueParameters.withIndex()) {
valueParameters += valueParameter.toFirValueParameter(session, methodSymbol, moduleData, index)
}
annotationBuilder = { javaMethod.convertAnnotationsToFir(session, fakeSource) }
status = FirResolvedDeclarationStatusImpl(
javaMethod.visibility,
javaMethod.modality,
javaMethod.visibility.toEffectiveVisibility(dispatchReceiver.lookupTag)
).apply {
isStatic = javaMethod.isStatic
hasStableParameterNames = false
}
if (!javaMethod.isStatic) {
dispatchReceiverType = dispatchReceiver
}
}.apply {
if (javaMethod.isStatic) {
containingClassForStaticMemberAttr = classId.toLookupTag()
}
if (containingClass.isRecord && valueParameters.isEmpty() && containingClass.recordComponents.any { it.name == methodName }) {
isJavaRecordComponent = true
}
}
}
private fun convertJavaAnnotationMethodToValueParameter(
javaMethod: JavaMethod,
firJavaMethod: FirJavaMethod,
moduleData: FirModuleData,
): FirJavaValueParameter =
buildJavaValueParameter {
source = javaMethod.toSourceElement(KtFakeSourceElementKind.ImplicitJavaAnnotationConstructor)
this.moduleData = moduleData
isFromSource = javaMethod.isFromSource
returnTypeRef = firJavaMethod.returnTypeRef
containingFunctionSymbol = firJavaMethod.symbol
name = javaMethod.name
isVararg = javaMethod.returnType is JavaArrayType && javaMethod.name == VALUE_METHOD_NAME
annotationBuilder = { emptyList() }
}
private fun convertJavaConstructorToFir(
javaConstructor: JavaConstructor?,
constructorId: CallableId,
javaClass: JavaClass,
ownerClassBuilder: FirJavaClassBuilder,
classTypeParameters: List,
javaTypeParameterStack: MutableJavaTypeParameterStack,
outerClassSymbol: FirRegularClassSymbol?,
moduleData: FirModuleData,
): FirJavaConstructor {
val constructorSymbol = FirConstructorSymbol(constructorId)
return buildJavaConstructor {
source = javaConstructor?.toSourceElement() ?: javaClass.toSourceElement(KtFakeSourceElementKind.ImplicitConstructor)
this.moduleData = moduleData
isFromSource = javaClass.isFromSource
symbol = constructorSymbol
isInner = javaClass.outerClass != null && !javaClass.isStatic
val isThisInner = this.isInner
val visibility = javaConstructor?.visibility ?: ownerClassBuilder.visibility
status = FirResolvedDeclarationStatusImpl(
visibility,
Modality.FINAL,
visibility.toEffectiveVisibility(ownerClassBuilder.symbol)
).apply {
isInner = isThisInner
hasStableParameterNames = false
}
// TODO get rid of dependency on PSI KT-63046
isPrimary = javaConstructor == null || source?.psi.let { it is PsiMethod && JavaPsiRecordUtil.isCanonicalConstructor(it) }
returnTypeRef = buildResolvedTypeRef {
coneType = ownerClassBuilder.buildSelfTypeRef()
}
dispatchReceiverType = if (isThisInner) outerClassSymbol?.defaultType() else null
typeParameters += classTypeParameters.toRefs()
val fakeSource = source?.fakeElement(KtFakeSourceElementKind.Enhancement)
if (javaConstructor != null) {
this.typeParameters += javaConstructor.typeParameters.convertTypeParameters(
javaTypeParameterStack, constructorSymbol, moduleData, fakeSource
)
annotationBuilder = { javaConstructor.convertAnnotationsToFir(session, fakeSource) }
for ((index, valueParameter) in javaConstructor.valueParameters.withIndex()) {
valueParameters += valueParameter.toFirValueParameter(session, constructorSymbol, moduleData, index)
}
} else {
annotationBuilder = { emptyList() }
}
}.apply {
containingClassForStaticMemberAttr = ownerClassBuilder.symbol.toLookupTag()
}
}
private fun buildConstructorForAnnotationClass(
javaClass: JavaClass,
constructorId: CallableId,
ownerClassBuilder: FirJavaClassBuilder,
valueParametersForAnnotationConstructor: ValueParametersForAnnotationConstructor,
moduleData: FirModuleData,
): FirJavaConstructor {
return buildJavaConstructor {
source = javaClass.toSourceElement(KtFakeSourceElementKind.ImplicitConstructor)
this.moduleData = moduleData
isFromSource = javaClass.isFromSource
symbol = FirConstructorSymbol(constructorId)
status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL, EffectiveVisibility.Public)
returnTypeRef = buildResolvedTypeRef {
coneType = ownerClassBuilder.buildSelfTypeRef()
}
valueParametersForAnnotationConstructor.forEach { _, firValueParameter -> valueParameters += firValueParameter }
isInner = false
isPrimary = true
annotationBuilder = { emptyList() }
}.apply {
containingClassForStaticMemberAttr = ownerClassBuilder.symbol.toLookupTag()
}
}
private fun FirJavaClassBuilder.buildSelfTypeRef(): ConeKotlinType = symbol.constructType(
typeParameters.map {
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), isNullable = false)
}.toTypedArray(),
isNullable = false,
)
private fun FqName.topLevelName() =
asString().substringBefore(".")
private fun JavaElement.toSourceElement(sourceElementKind: KtSourceElementKind = KtRealSourceElementKind): KtSourceElement? {
return (this as? JavaElementImpl<*>)?.psi?.toKtPsiSourceElement(sourceElementKind)
}
private fun List.toRefs(): List {
return this.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } }
}
private inline fun FirMemberDeclaration.applyExtensionTransformers(
operation: FirStatusTransformerExtension.(FirDeclarationStatus) -> FirDeclarationStatus
) {
val declaration = this
val oldStatus = declaration.status as FirResolvedDeclarationStatusImpl
val newStatus = statusExtensions.fold(status) { acc, it ->
if (it.needTransformStatus(declaration)) {
it.operation(acc)
} else {
acc
}
} as FirDeclarationStatusImpl
if (newStatus === oldStatus) return
val resolvedStatus = newStatus.resolved(
newStatus.visibility,
newStatus.modality ?: oldStatus.modality,
oldStatus.effectiveVisibility
)
replaceStatus(resolvedStatus)
}
}