[FIR] Add RawFirBuilder & DeclarationsConverter support

This commit is contained in:
Nikolay Lunyak
2021-08-05 11:45:04 +03:00
committed by TeamCityServer
parent ee58df6b3c
commit 38079372e1
2 changed files with 155 additions and 26 deletions
@@ -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;
}