[FIR] Add RawFirBuilder & DeclarationsConverter support
This commit is contained in:
committed by
TeamCityServer
parent
ee58df6b3c
commit
38079372e1
+83
-18
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
@@ -1041,6 +1038,7 @@ class DeclarationsConverter(
|
||||
val accessors = mutableListOf<LighterASTNode>()
|
||||
var propertyInitializer: FirExpression? = null
|
||||
var typeParameterList: LighterASTNode? = null
|
||||
var fieldDeclaration: LighterASTNode? = null
|
||||
property.forEachChildren {
|
||||
when (it.tokenType) {
|
||||
MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
@@ -1054,6 +1052,7 @@ class DeclarationsConverter(
|
||||
PROPERTY_ACCESSOR -> {
|
||||
accessors += it
|
||||
}
|
||||
BACKING_FIELD -> fieldDeclaration = it
|
||||
else -> if (it.isExpression()) propertyInitializer = expressionConverter.getAsFirExpression(it, "Should have initializer")
|
||||
}
|
||||
}
|
||||
@@ -1082,6 +1081,8 @@ class DeclarationsConverter(
|
||||
|
||||
typeParameterList?.let { firTypeParameters += convertTypeParameters(it, typeConstraints, symbol) }
|
||||
|
||||
backingField = fieldDeclaration.convertBackingField(symbol, modifiers)
|
||||
|
||||
if (isLocal) {
|
||||
this.isLocal = true
|
||||
val delegateBuilder = delegateExpression?.let {
|
||||
@@ -1130,21 +1131,24 @@ class DeclarationsConverter(
|
||||
isExternal = modifiers.hasExternal()
|
||||
}
|
||||
|
||||
val convertedAccessors = accessors.map { convertGetterOrSetter(it, returnType, propertyVisibility, symbol, modifiers) }
|
||||
val hasExplicitBackingField = backingField != null
|
||||
val convertedAccessors = accessors.map {
|
||||
convertGetterOrSetter(it, returnType, propertyVisibility, symbol, modifiers, hasExplicitBackingField)
|
||||
}
|
||||
this.getter = convertedAccessors.find { it.isGetter }
|
||||
?: FirDefaultPropertyGetter(
|
||||
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor),
|
||||
moduleData,
|
||||
FirDeclarationOrigin.Source,
|
||||
returnType,
|
||||
propertyVisibility, symbol,
|
||||
).also {
|
||||
it.status = defaultAccessorStatus()
|
||||
it.initContainingClassAttr()
|
||||
?: if (!hasExplicitBackingField) {
|
||||
FirDefaultPropertyGetter(
|
||||
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor), moduleData, FirDeclarationOrigin.Source, returnType, propertyVisibility, symbol,
|
||||
).also {
|
||||
it.status = defaultAccessorStatus()
|
||||
it.initContainingClassAttr()
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
// NOTE: We still need the setter even for a val property so we can report errors (e.g., VAL_WITH_SETTER).
|
||||
this.setter = convertedAccessors.find { it.isSetter }
|
||||
?: if (isVar) {
|
||||
?: if (isVar && !hasExplicitBackingField) {
|
||||
FirDefaultPropertySetter(
|
||||
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor),
|
||||
moduleData,
|
||||
@@ -1246,14 +1250,15 @@ class DeclarationsConverter(
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePropertyGetterOrSetter
|
||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePropertyComponent
|
||||
*/
|
||||
private fun convertGetterOrSetter(
|
||||
getterOrSetter: LighterASTNode,
|
||||
propertyTypeRef: FirTypeRef,
|
||||
propertyVisibility: Visibility,
|
||||
propertySymbol: FirPropertySymbol,
|
||||
propertyModifiers: Modifier
|
||||
propertyModifiers: Modifier,
|
||||
hasBackingField: Boolean,
|
||||
): FirPropertyAccessor {
|
||||
var modifiers = Modifier()
|
||||
var isGetter = true
|
||||
@@ -1292,7 +1297,11 @@ class DeclarationsConverter(
|
||||
isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal()
|
||||
}
|
||||
val sourceElement = getterOrSetter.toFirSourceElement()
|
||||
if (block == null && expression == null) {
|
||||
// If an explicit backing field is present,
|
||||
// the default accessors might not be compatible
|
||||
// with it. We should check the types first, and
|
||||
// only then see if we can create the default accessors.
|
||||
if (block == null && expression == null && !hasBackingField) {
|
||||
return FirDefaultPropertyAccessor
|
||||
.createGetterOrSetter(
|
||||
sourceElement,
|
||||
@@ -1340,6 +1349,62 @@ class DeclarationsConverter(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePropertyComponent
|
||||
*/
|
||||
private fun LighterASTNode?.convertBackingField(
|
||||
propertySymbol: FirPropertySymbol,
|
||||
propertyModifiers: Modifier,
|
||||
): FirBackingField? {
|
||||
var modifiers = Modifier()
|
||||
var returnType: FirTypeRef = implicitType
|
||||
var initializerExpression: LighterASTNode? = null
|
||||
this?.forEachChildren {
|
||||
when {
|
||||
it.tokenType == MODIFIER_LIST -> modifiers = convertModifierList(it)
|
||||
it.tokenType == TYPE_REFERENCE -> returnType = convertType(it)
|
||||
it.isExpression() -> initializerExpression = it
|
||||
}
|
||||
}
|
||||
val backingFieldInitializer: FirExpression = expressionConverter.getAsFirExpression(
|
||||
initializerExpression,
|
||||
"Should have initializer"
|
||||
)
|
||||
var componentVisibility = modifiers.getVisibility()
|
||||
if (componentVisibility == Visibilities.Unknown) {
|
||||
componentVisibility = Visibilities.Private
|
||||
}
|
||||
val status = obtainPropertyComponentStatus(componentVisibility, modifiers, propertyModifiers)
|
||||
val sourceElement = this?.toFirSourceElement()
|
||||
return if (this != null) {
|
||||
buildBackingField {
|
||||
source = sourceElement
|
||||
moduleData = baseModuleData
|
||||
origin = FirDeclarationOrigin.Source
|
||||
returnTypeRef = returnType
|
||||
symbol = FirPropertyFieldDeclarationSymbol()
|
||||
this.status = status
|
||||
annotations += modifiers.annotations
|
||||
this.propertySymbol = propertySymbol
|
||||
this.initializer = backingFieldInitializer
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun obtainPropertyComponentStatus(
|
||||
componentVisibility: Visibility,
|
||||
modifiers: Modifier,
|
||||
propertyModifiers: Modifier,
|
||||
): FirDeclarationStatus {
|
||||
// Downward propagation of `inline` and `external` modifiers (from property to its accessors)
|
||||
return FirDeclarationStatusImpl(componentVisibility, modifiers.getModality(isClassOrObject = false)).apply {
|
||||
isInline = propertyModifiers.hasInline() || modifiers.hasInline()
|
||||
isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal()
|
||||
}
|
||||
}
|
||||
|
||||
private fun obtainContractDescription(rawContractDescription: LighterASTNode): FirContractDescription? =
|
||||
buildRawContractDescription {
|
||||
source = rawContractDescription.toFirSourceElement()
|
||||
|
||||
@@ -18,10 +18,7 @@ import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||
import org.jetbrains.kotlin.fir.contracts.builder.buildRawContractDescription
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
@@ -370,6 +367,7 @@ open class RawFirBuilder(
|
||||
propertyTypeRef: FirTypeRef,
|
||||
propertySymbol: FirPropertySymbol,
|
||||
isGetter: Boolean,
|
||||
hasExplicitBackingField: Boolean,
|
||||
): FirPropertyAccessor? {
|
||||
val accessorVisibility =
|
||||
if (this?.visibility != null && this.visibility != Visibilities.Unknown) this.visibility else property.visibility
|
||||
@@ -426,7 +424,11 @@ open class RawFirBuilder(
|
||||
this@RawFirBuilder.context.firFunctionTargets.removeLast()
|
||||
}
|
||||
}
|
||||
isGetter || property.isVar -> {
|
||||
// If an explicit backing field is present,
|
||||
// the default accessors might not be compatible
|
||||
// with it. We should check the types first, and
|
||||
// only then see if we can create the default accessors.
|
||||
!hasExplicitBackingField && (isGetter || property.isVar) -> {
|
||||
// Default getter for val/var properties, and default setter for var properties.
|
||||
val propertySource =
|
||||
this?.toFirSourceElement() ?: property.toFirPsiSourceElement(FirFakeSourceElementKind.DefaultAccessor)
|
||||
@@ -455,6 +457,55 @@ open class RawFirBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
private fun obtainPropertyComponentStatus(
|
||||
componentVisibility: Visibility,
|
||||
declaration: KtDeclaration?,
|
||||
property: KtProperty,
|
||||
): FirDeclarationStatus {
|
||||
return FirDeclarationStatusImpl(componentVisibility, declaration?.modality).apply {
|
||||
isInline = property.hasModifier(INLINE_KEYWORD) ||
|
||||
declaration?.hasModifier(INLINE_KEYWORD) == true
|
||||
isExternal = property.hasModifier(EXTERNAL_KEYWORD) ||
|
||||
declaration?.hasModifier(EXTERNAL_KEYWORD) == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtBackingField?.toFirBackingField(
|
||||
property: KtProperty,
|
||||
propertySymbol: FirPropertySymbol,
|
||||
): FirBackingField? {
|
||||
val componentVisibility = if (this?.visibility != null && this.visibility != Visibilities.Unknown) {
|
||||
this.visibility
|
||||
} else {
|
||||
Visibilities.Private
|
||||
}
|
||||
val status = obtainPropertyComponentStatus(componentVisibility, this, property)
|
||||
val backingFieldInitializer = when (mode) {
|
||||
BodyBuildingMode.LAZY_BODIES -> buildLazyExpression {
|
||||
source = this@toFirBackingField?.initializer?.toFirSourceElement()
|
||||
}
|
||||
BodyBuildingMode.STUBS -> buildExpressionStub()
|
||||
else -> this@toFirBackingField?.initializer.toFirExpression("Should have initializer")
|
||||
}
|
||||
val returnType = this?.returnTypeReference.toFirOrImplicitType()
|
||||
val source = this?.toFirSourceElement()
|
||||
return if (this != null) {
|
||||
buildBackingField {
|
||||
this.source = source
|
||||
moduleData = baseModuleData
|
||||
origin = FirDeclarationOrigin.Source
|
||||
returnTypeRef = returnType
|
||||
this.status = status
|
||||
extractAnnotationsTo(this)
|
||||
symbol = FirPropertyFieldDeclarationSymbol()
|
||||
this.propertySymbol = propertySymbol
|
||||
this.initializer = backingFieldInitializer
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtParameter.toFirValueParameter(
|
||||
defaultTypeRef: FirTypeRef? = null,
|
||||
valueParameterDeclaration: ValueParameterDeclaration = ValueParameterDeclaration.OTHER
|
||||
@@ -1423,6 +1474,12 @@ open class RawFirBuilder(
|
||||
if (this@toFirProperty.isLocal) {
|
||||
isLocal = true
|
||||
symbol = FirPropertySymbol(propertyName)
|
||||
|
||||
backingField = this@toFirProperty.fieldDeclaration.toFirBackingField(
|
||||
this@toFirProperty,
|
||||
propertySymbol = symbol,
|
||||
)
|
||||
|
||||
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL).apply {
|
||||
isLateInit = hasModifier(LATEINIT_KEYWORD)
|
||||
}
|
||||
@@ -1455,17 +1512,25 @@ open class RawFirBuilder(
|
||||
dispatchReceiverType = currentDispatchReceiverType()
|
||||
extractTypeParametersTo(this, symbol)
|
||||
withCapturedTypeParameters(true, this.typeParameters) {
|
||||
backingField = this@toFirProperty.fieldDeclaration.toFirBackingField(
|
||||
this@toFirProperty,
|
||||
propertySymbol = symbol,
|
||||
)
|
||||
|
||||
val hasExplicitBackingField = backingField != null
|
||||
getter = this@toFirProperty.getter.toFirPropertyAccessor(
|
||||
this@toFirProperty,
|
||||
propertyType,
|
||||
propertySymbol = symbol,
|
||||
isGetter = true
|
||||
isGetter = true,
|
||||
hasExplicitBackingField,
|
||||
)
|
||||
setter = this@toFirProperty.setter.toFirPropertyAccessor(
|
||||
this@toFirProperty,
|
||||
propertyType,
|
||||
propertySymbol = symbol,
|
||||
isGetter = false
|
||||
isGetter = false,
|
||||
hasExplicitBackingField,
|
||||
)
|
||||
|
||||
status = FirDeclarationStatusImpl(visibility, modality).apply {
|
||||
@@ -2420,4 +2485,3 @@ enum class PsiHandlingMode {
|
||||
*/
|
||||
IDE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user