Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.fir.lightTree.converter.DeclarationsConverter.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2020 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.lightTree.converter
import com.intellij.lang.LighterASTNode
import com.intellij.psi.TokenType
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.builder.Context
import org.jetbrains.kotlin.fir.builder.extractContractDescriptionIfPossible
import org.jetbrains.kotlin.fir.builder.generateAccessorsByDelegate
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.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.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
import org.jetbrains.kotlin.fir.lightTree.fir.*
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.TypeModifier
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.TypeParameterModifier
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.TypeProjectionModifier
import org.jetbrains.kotlin.fir.references.builder.buildImplicitThisReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirQualifierPartImpl
import org.jetbrains.kotlin.fir.types.impl.FirTypeArgumentListImpl
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class DeclarationsConverter(
session: FirSession,
private val baseScopeProvider: FirScopeProvider,
private val stubMode: Boolean,
tree: FlyweightCapableTreeStructure,
offset: Int = 0,
context: Context = Context()
) : BaseConverter(session, tree, offset, context) {
private val expressionConverter = ExpressionsConverter(session, stubMode, tree, this, offset + 1, context)
/**
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile]
* [org.jetbrains.kotlin.parsing.KotlinParsing.parsePreamble]
*/
fun convertFile(file: LighterASTNode, fileName: String = ""): FirFile {
if (file.tokenType != KT_FILE) {
//TODO throw error
throw Exception()
}
val fileAnnotationList = mutableListOf()
val importList = mutableListOf()
val firDeclarationList = mutableListOf()
context.packageFqName = FqName.ROOT
file.forEachChildren {
when (it.tokenType) {
FILE_ANNOTATION_LIST -> fileAnnotationList += convertFileAnnotationList(it)
PACKAGE_DIRECTIVE -> context.packageFqName = convertPackageName(it)
IMPORT_LIST -> importList += convertImportDirectives(it)
CLASS -> firDeclarationList += convertClass(it)
FUN -> firDeclarationList += convertFunctionDeclaration(it)
PROPERTY -> firDeclarationList += convertPropertyDeclaration(it)
TYPEALIAS -> firDeclarationList += convertTypeAlias(it)
OBJECT_DECLARATION -> firDeclarationList += convertClass(it)
}
}
return buildFile {
source = file.toFirSourceElement()
origin = FirDeclarationOrigin.Source
session = baseSession
name = fileName
packageFqName = context.packageFqName
annotations += fileAnnotationList
imports += importList
declarations += firDeclarationList
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlockExpression
*/
fun convertBlockExpression(block: LighterASTNode): FirBlock {
return convertBlockExpressionWithoutBuilding(block).build()
}
fun convertBlockExpressionWithoutBuilding(block: LighterASTNode): FirBlockBuilder {
val firStatements = block.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
CLASS, OBJECT_DECLARATION -> container += convertClass(node) as FirStatement
FUN -> container += convertFunctionDeclaration(node) as FirStatement
PROPERTY -> container += convertPropertyDeclaration(node) as FirStatement
DESTRUCTURING_DECLARATION -> container += convertDestructingDeclaration(node).toFirDestructingDeclaration(baseSession)
TYPEALIAS -> container += convertTypeAlias(node) as FirStatement
CLASS_INITIALIZER -> container += convertAnonymousInitializer(node) as FirStatement
else -> if (node.isExpression()) container += expressionConverter.getAsFirExpression(node)
}
}
return FirBlockBuilder().apply {
source = block.toFirSourceElement()
firStatements.forEach { firStatement ->
if (firStatement !is FirBlock || firStatement.annotations.isNotEmpty()) {
statements += firStatement
} else {
statements += firStatement.statements
}
}
}
}
/***** PREAMBLE *****/
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePackageName
*/
private fun convertPackageName(packageNode: LighterASTNode): FqName {
var packageName: FqName = FqName.ROOT
packageNode.forEachChildren {
when (it.tokenType) {
//TODO separate logic for both expression types
DOT_QUALIFIED_EXPRESSION, REFERENCE_EXPRESSION -> packageName = FqName(it.getAsStringWithoutBacktick())
}
}
return packageName
}
private fun convertImportAlias(importAlias: LighterASTNode): String? {
importAlias.forEachChildren {
when (it.tokenType) {
IDENTIFIER -> return it.asText
}
}
return null
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseImportDirective
*/
private fun convertImportDirective(importDirective: LighterASTNode): FirImport {
var importedFqName: FqName? = null
var isAllUnder = false
var aliasName: String? = null
importDirective.forEachChildren {
when (it.tokenType) {
DOT_QUALIFIED_EXPRESSION, REFERENCE_EXPRESSION -> importedFqName = FqName(it.asText)
MUL -> isAllUnder = true
IMPORT_ALIAS -> aliasName = convertImportAlias(it)
}
}
return buildImport {
source = importDirective.toFirSourceElement()
this.importedFqName = importedFqName
this.isAllUnder = isAllUnder
this.aliasName = aliasName?.let { Name.identifier(it) }
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseImportDirectives
*/
private fun convertImportDirectives(importList: LighterASTNode): List {
return importList.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
IMPORT_DIRECTIVE -> container += convertImportDirective(node)
}
}
}
/***** MODIFIERS *****/
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseModifierList
*/
private fun convertModifierList(modifiers: LighterASTNode, isInClass: Boolean = false): Modifier {
val modifier = Modifier()
modifiers.forEachChildren {
when (it.tokenType) {
ANNOTATION -> modifier.annotations += convertAnnotation(it)
ANNOTATION_ENTRY -> modifier.annotations += convertAnnotationEntry(it)
is KtModifierKeywordToken -> modifier.addModifier(it, isInClass)
}
}
return modifier
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeModifierList
*/
private fun convertTypeModifierList(modifiers: LighterASTNode): TypeModifier {
val typeModifierList = TypeModifier()
modifiers.forEachChildren {
when (it.tokenType) {
ANNOTATION -> typeModifierList.annotations += convertAnnotation(it)
ANNOTATION_ENTRY -> typeModifierList.annotations += convertAnnotationEntry(it)
is KtModifierKeywordToken -> typeModifierList.addModifier(it)
}
}
return typeModifierList
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeArgumentModifierList
*/
private fun convertTypeArgumentModifierList(modifiers: LighterASTNode): TypeProjectionModifier {
val typeArgumentModifierList = TypeProjectionModifier()
modifiers.forEachChildren {
when (it.tokenType) {
ANNOTATION -> typeArgumentModifierList.annotations += convertAnnotation(it)
ANNOTATION_ENTRY -> typeArgumentModifierList.annotations += convertAnnotationEntry(it)
is KtModifierKeywordToken -> typeArgumentModifierList.addModifier(it)
}
}
return typeArgumentModifierList
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeArgumentModifierList
*/
private fun convertTypeParameterModifiers(modifiers: LighterASTNode): TypeParameterModifier {
val modifier = TypeParameterModifier()
modifiers.forEachChildren {
when (it.tokenType) {
ANNOTATION -> modifier.annotations += convertAnnotation(it)
ANNOTATION_ENTRY -> modifier.annotations += convertAnnotationEntry(it)
is KtModifierKeywordToken -> modifier.addModifier(it)
}
}
return modifier
}
/***** ANNOTATIONS *****/
/**
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFileAnnotationList]
*/
private fun convertFileAnnotationList(fileAnnotationList: LighterASTNode): List {
return fileAnnotationList.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
ANNOTATION -> container += convertAnnotation(node)
ANNOTATION_ENTRY -> container += convertAnnotationEntry(node)
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseAnnotationOrList
*/
fun convertAnnotation(annotationNode: LighterASTNode): List {
var annotationTarget: AnnotationUseSiteTarget? = null
return annotationNode.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
ANNOTATION_TARGET -> annotationTarget = convertAnnotationTarget(node)
ANNOTATION_ENTRY -> container += convertAnnotationEntry(node, annotationTarget)
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseAnnotationTarget
*/
private fun convertAnnotationTarget(annotationUseSiteTarget: LighterASTNode): AnnotationUseSiteTarget {
lateinit var annotationTarget: AnnotationUseSiteTarget
annotationUseSiteTarget.forEachChildren {
when (it.tokenType) {
FIELD_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.FIELD
FILE_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.FILE
PROPERTY_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY
GET_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY_GETTER
SET_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY_SETTER
RECEIVER_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.RECEIVER
PARAM_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER
SETPARAM_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.SETTER_PARAMETER
DELEGATE_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
}
}
return annotationTarget
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseAnnotation
* can be treated as unescapedAnnotation
*/
fun convertAnnotationEntry(
unescapedAnnotation: LighterASTNode,
defaultAnnotationUseSiteTarget: AnnotationUseSiteTarget? = null
): FirAnnotationCall {
var annotationUseSiteTarget: AnnotationUseSiteTarget? = null
lateinit var constructorCalleePair: Pair>
unescapedAnnotation.forEachChildren {
when (it.tokenType) {
ANNOTATION_TARGET -> annotationUseSiteTarget = convertAnnotationTarget(it)
CONSTRUCTOR_CALLEE -> constructorCalleePair = convertConstructorInvocation(unescapedAnnotation)
}
}
val name = (constructorCalleePair.first as? FirUserTypeRef)?.qualifier?.last()?.name ?: Name.special("")
return buildAnnotationCall {
source = unescapedAnnotation.toFirSourceElement()
useSiteTarget = annotationUseSiteTarget ?: defaultAnnotationUseSiteTarget
annotationTypeRef = constructorCalleePair.first
calleeReference = buildSimpleNamedReference {
source = [email protected]
this.name = name
}
extractArgumentsFrom(constructorCalleePair.second, stubMode)
}
}
private fun LighterASTNode.hasValueParameters(): Boolean {
return getChildNodesByType(VALUE_PARAMETER_LIST).let {
it.isNotEmpty() && it.first().getChildNodesByType(VALUE_PARAMETER).isNotEmpty()
}
}
/***** DECLARATIONS *****/
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseClassOrObject
*/
private fun convertClass(classNode: LighterASTNode): FirDeclaration {
var modifiers = Modifier()
var classKind: ClassKind = ClassKind.CLASS //TODO
var identifier: String? = null
val firTypeParameters = mutableListOf()
var primaryConstructor: LighterASTNode? = null
val typeConstraints = mutableListOf()
var classBody: LighterASTNode? = null
var superTypeList: LighterASTNode? = null
var typeParameterList: LighterASTNode? = null
classNode.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it, isInClass = true)
CLASS_KEYWORD -> classKind = ClassKind.CLASS
INTERFACE_KEYWORD -> classKind = ClassKind.INTERFACE
OBJECT_KEYWORD -> classKind = ClassKind.OBJECT
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> typeParameterList = it
PRIMARY_CONSTRUCTOR -> primaryConstructor = it
SUPER_TYPE_LIST -> superTypeList = it
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
CLASS_BODY -> classBody = it
}
}
typeParameterList?.let { firTypeParameters += convertTypeParameters(it, typeConstraints) }
if (classKind == ClassKind.CLASS) {
classKind = when {
modifiers.isEnum() -> ClassKind.ENUM_CLASS
modifiers.isAnnotation() -> ClassKind.ANNOTATION_CLASS
else -> classKind
}
}
val className = identifier.nameAsSafeName(if (modifiers.isCompanion()) "Companion" else "")
val isLocal = isClassLocal(classNode) { getParent() }
return withChildClassName(className, isLocal) {
withCapturedTypeParameters {
val status = FirDeclarationStatusImpl(
if (isLocal) Visibilities.Local else modifiers.getVisibility(),
modifiers.getModality()
).apply {
isExpect = modifiers.hasExpect()
isActual = modifiers.hasActual()
isInner = modifiers.isInner()
isCompanion = modifiers.isCompanion() && classKind == ClassKind.OBJECT
isData = modifiers.isDataClass()
isInline = modifiers.isInlineClass()
isFun = modifiers.isFunctionalInterface()
}
buildRegularClass {
source = classNode.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
name = className
this.status = status
this.classKind = classKind
scopeProvider = baseScopeProvider
symbol = FirRegularClassSymbol(context.currentClassId)
annotations += modifiers.annotations
typeParameters += firTypeParameters
if (!status.isInner) clearCapturedTypeParameters()
typeParameters += context.capturedTypeParameters.map { buildOuterClassTypeParameterRef { symbol = it } }
addCapturedTypeParameters(firTypeParameters)
val selfType = classNode.toDelegatedSelfType(this)
val delegationSpecifiers = superTypeList?.let { convertDelegationSpecifiers(it, symbol, selfType) }
var delegatedSuperTypeRef: FirTypeRef? = delegationSpecifiers?.delegatedSuperTypeRef
val delegatedConstructorSource: FirLightSourceElement? = delegationSpecifiers?.delegatedConstructorSource
delegationSpecifiers?.delegateFields?.map { declarations += it }
val superTypeCallEntry = delegationSpecifiers?.delegatedConstructorArguments.orEmpty()
val superTypeRefs = mutableListOf()
delegationSpecifiers?.let { superTypeRefs += it.superTypesRef }
when {
modifiers.isEnum() && (classKind == ClassKind.ENUM_CLASS) -> {
delegatedSuperTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
implicitEnumType.type.lookupTag,
arrayOf(selfType.type),
isNullable = false
)
}
superTypeRefs += delegatedSuperTypeRef
}
modifiers.isAnnotation() && (classKind == ClassKind.ANNOTATION_CLASS) -> {
superTypeRefs += implicitAnnotationType
delegatedSuperTypeRef = implicitAnyType
}
}
superTypeRefs.ifEmpty {
superTypeRefs += implicitAnyType
delegatedSuperTypeRef = implicitAnyType
}
this.superTypeRefs += superTypeRefs
val secondaryConstructors = classBody.getChildNodesByType(SECONDARY_CONSTRUCTOR)
val classWrapper = ClassWrapper(
className, modifiers, classKind, this,
hasPrimaryConstructor = primaryConstructor != null,
hasSecondaryConstructor = secondaryConstructors.isNotEmpty(),
hasDefaultConstructor = if (primaryConstructor != null) !primaryConstructor!!.hasValueParameters()
else secondaryConstructors.isEmpty() || secondaryConstructors.any { !it.hasValueParameters() },
delegatedSelfTypeRef = selfType,
delegatedSuperTypeRef = delegatedSuperTypeRef ?: buildImplicitTypeRef(),
superTypeCallEntry = superTypeCallEntry
)
//parse primary constructor
val primaryConstructorWrapper = convertPrimaryConstructor(
primaryConstructor, selfType.source, classWrapper, delegatedConstructorSource,
delegationSpecifiers?.primaryConstructorBody
)
val firPrimaryConstructor = primaryConstructorWrapper?.firConstructor
firPrimaryConstructor?.let { declarations += it }
val properties = mutableListOf()
if (primaryConstructor != null && firPrimaryConstructor != null) {
//parse properties
properties += primaryConstructorWrapper.valueParameters
.filter { it.hasValOrVar() }
.map { it.toFirProperty(baseSession, callableIdForName(it.firValueParameter.name), classWrapper.hasExpect()) }
addDeclarations(properties)
}
//parse declarations
classBody?.let {
addDeclarations(convertClassBody(it, classWrapper))
}
//parse data class
if (modifiers.isDataClass() && firPrimaryConstructor != null) {
val zippedParameters = properties.map { it.source?.lightNode!! to it }
DataClassMembersGenerator(
baseSession,
classNode,
this,
zippedParameters,
context.packageFqName,
context.className,
createClassTypeRefWithSourceKind = { firPrimaryConstructor.returnTypeRef },
createParameterTypeRefWithSourceKind = { property, _ -> property.returnTypeRef },
).generate()
}
if (modifiers.isEnum()) {
generateValuesFunction(baseSession, context.packageFqName, context.className, modifiers.hasExpect())
generateValueOfFunction(baseSession, context.packageFqName, context.className, modifiers.hasExpect())
}
}
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseObjectLiteral
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitObjectLiteralExpression
*/
fun convertObjectLiteral(objectLiteral: LighterASTNode): FirElement {
return withChildClassName(ANONYMOUS_OBJECT_NAME) {
buildAnonymousObject {
source = objectLiteral.toFirSourceElement()
origin = FirDeclarationOrigin.Source
session = baseSession
classKind = ClassKind.OBJECT
scopeProvider = baseScopeProvider
symbol = FirAnonymousObjectSymbol()
typeParameters += context.capturedTypeParameters.map { buildOuterClassTypeParameterRef { this.symbol = it } }
val delegatedSelfType = objectLiteral.toDelegatedSelfType(this)
var modifiers = Modifier()
var primaryConstructor: LighterASTNode? = null
val superTypeRefs = mutableListOf()
val superTypeCallEntry = mutableListOf()
var delegatedSuperTypeRef: FirTypeRef? = null
var classBody: LighterASTNode? = null
var delegatedConstructorSource: FirLightSourceElement? = null
var delegateFields: List? = null
var primaryConstructorBody: FirBlock? = null
objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first().forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
PRIMARY_CONSTRUCTOR -> primaryConstructor = it
SUPER_TYPE_LIST -> convertDelegationSpecifiers(it, symbol, delegatedSelfType).let {
delegatedSuperTypeRef = it.delegatedSuperTypeRef
superTypeRefs += it.superTypesRef
superTypeCallEntry += it.delegatedConstructorArguments
delegatedConstructorSource = it.delegatedConstructorSource
delegateFields = it.delegateFields
primaryConstructorBody = it.primaryConstructorBody
}
CLASS_BODY -> classBody = it
}
}
superTypeRefs.ifEmpty {
superTypeRefs += implicitAnyType
delegatedSuperTypeRef = implicitAnyType
}
val delegatedSuperType = delegatedSuperTypeRef ?: buildImplicitTypeRef()
annotations += modifiers.annotations
this.superTypeRefs += superTypeRefs
typeRef = delegatedSelfType
delegateFields?.map { this.declarations += it }
val classWrapper = ClassWrapper(
SpecialNames.NO_NAME_PROVIDED, modifiers, ClassKind.OBJECT, this,
hasPrimaryConstructor = false,
hasSecondaryConstructor = classBody.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(),
hasDefaultConstructor = false,
delegatedSelfTypeRef = delegatedSelfType,
delegatedSuperTypeRef = delegatedSuperType,
superTypeCallEntry = superTypeCallEntry
)
//parse primary constructor
convertPrimaryConstructor(primaryConstructor, typeRef.source, classWrapper, delegatedConstructorSource, primaryConstructorBody)
?.let { this.declarations += it.firConstructor }
//parse declarations
classBody?.let {
this.declarations += convertClassBody(it, classWrapper)
}
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseEnumEntry
*/
private fun convertEnumEntry(enumEntry: LighterASTNode, classWrapper: ClassWrapper): FirEnumEntry {
var modifiers = Modifier()
lateinit var identifier: String
val enumSuperTypeCallEntry = mutableListOf()
var classBodyNode: LighterASTNode? = null
enumEntry.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.asText
INITIALIZER_LIST -> enumSuperTypeCallEntry += convertInitializerList(it)
CLASS_BODY -> classBodyNode = it
}
}
val enumEntryName = identifier.nameAsSafeName()
return buildEnumEntry {
source = enumEntry.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = classWrapper.delegatedSelfTypeRef
name = enumEntryName
symbol = FirVariableSymbol(CallableId(context.currentClassId, enumEntryName))
status = FirDeclarationStatusImpl(Visibilities.Public, Modality.FINAL).apply {
isStatic = true
isExpect = classWrapper.hasExpect()
}
if (classWrapper.hasDefaultConstructor && enumEntry.getChildNodeByType(INITIALIZER_LIST) == null &&
modifiers.annotations.isEmpty() && classBodyNode == null
) {
return@buildEnumEntry
}
annotations += modifiers.annotations
initializer = withChildClassName(enumEntryName) {
buildAnonymousObject {
source = [email protected]
session = baseSession
origin = FirDeclarationOrigin.Source
classKind = ClassKind.ENUM_ENTRY
scopeProvider = baseScopeProvider
symbol = FirAnonymousObjectSymbol()
annotations += modifiers.annotations
val enumClassWrapper = ClassWrapper(
enumEntryName, modifiers, ClassKind.ENUM_ENTRY, this,
hasPrimaryConstructor = true,
hasSecondaryConstructor = classBodyNode.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(),
hasDefaultConstructor = false,
delegatedSelfTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
[email protected] (),
emptyArray(),
isNullable = false
)
},
delegatedSuperTypeRef = classWrapper.delegatedSelfTypeRef,
superTypeCallEntry = enumSuperTypeCallEntry
)
superTypeRefs += enumClassWrapper.delegatedSuperTypeRef
convertPrimaryConstructor(null, null, enumClassWrapper, null)?.let { declarations += it.firConstructor }
classBodyNode?.also { declarations += convertClassBody(it, enumClassWrapper) }
}
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseEnumEntry
*/
private fun convertInitializerList(initializerList: LighterASTNode): List {
val firValueArguments = mutableListOf()
initializerList.forEachChildren {
when (it.tokenType) {
SUPER_TYPE_CALL_ENTRY -> convertConstructorInvocation(it).apply {
firValueArguments += second
}
}
}
return firValueArguments
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseClassBody
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseEnumClassBody
*/
private fun convertClassBody(classBody: LighterASTNode, classWrapper: ClassWrapper): List {
return classBody.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
ENUM_ENTRY -> container += convertEnumEntry(node, classWrapper)
CLASS -> container += convertClass(node)
FUN -> container += convertFunctionDeclaration(node, classWrapper)
PROPERTY -> container += convertPropertyDeclaration(node, classWrapper)
TYPEALIAS -> container += convertTypeAlias(node)
OBJECT_DECLARATION -> container += convertClass(node)
CLASS_INITIALIZER -> container += convertAnonymousInitializer(node) //anonymousInitializer
SECONDARY_CONSTRUCTOR -> container += convertSecondaryConstructor(node, classWrapper)
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseClassOrObject
* primaryConstructor branch
*/
private fun convertPrimaryConstructor(
primaryConstructor: LighterASTNode?,
selfTypeSource: FirSourceElement?,
classWrapper: ClassWrapper,
delegatedConstructorSource: FirLightSourceElement?,
body: FirBlock? = null
): PrimaryConstructor? {
if (primaryConstructor == null && !classWrapper.isEnumEntry() && classWrapper.hasSecondaryConstructor) return null
if (classWrapper.isInterface()) return null
var modifiers = Modifier()
val valueParameters = mutableListOf()
primaryConstructor?.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
VALUE_PARAMETER_LIST -> valueParameters += convertValueParameters(it)
}
}
val defaultVisibility = classWrapper.defaultConstructorVisibility()
val firDelegatedCall = buildDelegatedConstructorCall {
source = delegatedConstructorSource ?: selfTypeSource?.fakeElement(FirFakeSourceElementKind.DelegatingConstructorCall)
constructedTypeRef = classWrapper.delegatedSuperTypeRef.copyWithNewSourceKind(FirFakeSourceElementKind.ImplicitTypeRef)
isThis = false
extractArgumentsFrom(classWrapper.superTypeCallEntry, stubMode)
}
val explicitVisibility = if (primaryConstructor != null) modifiers.getVisibility() else null
val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility, Modality.FINAL).apply {
isExpect = modifiers.hasExpect() || classWrapper.hasExpect()
isActual = modifiers.hasActual()
isInner = classWrapper.isInner()
isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.Private
isFromEnumClass = classWrapper.isEnum()
}
return PrimaryConstructor(
buildPrimaryConstructor {
source = primaryConstructor?.toFirSourceElement()
?: selfTypeSource?.fakeElement(FirFakeSourceElementKind.ImplicitConstructor)
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = classWrapper.delegatedSelfTypeRef
this.status = status
symbol = FirConstructorSymbol(callableIdForClassConstructor())
annotations += modifiers.annotations
typeParameters += constructorTypeParametersFromConstructedClass(classWrapper.classBuilder.typeParameters)
this.valueParameters += valueParameters.map { it.firValueParameter }
delegatedConstructor = firDelegatedCall
this.body = body
}, valueParameters
)
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseMemberDeclarationRest
* at INIT keyword
*/
private fun convertAnonymousInitializer(anonymousInitializer: LighterASTNode): FirDeclaration {
var firBlock: FirBlock? = null
anonymousInitializer.forEachChildren {
when (it.tokenType) {
BLOCK -> firBlock = convertBlock(it)
}
}
return buildAnonymousInitializer {
source = anonymousInitializer.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
body = if (stubMode) buildEmptyExpressionBlock() else firBlock ?: buildEmptyExpressionBlock()
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseSecondaryConstructor
*/
private fun convertSecondaryConstructor(secondaryConstructor: LighterASTNode, classWrapper: ClassWrapper): FirConstructor {
var modifiers = Modifier()
val firValueParameters = mutableListOf()
var constructorDelegationCall: FirDelegatedConstructorCall? = null
var block: LighterASTNode? = null
secondaryConstructor.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
VALUE_PARAMETER_LIST -> firValueParameters += convertValueParameters(it)
CONSTRUCTOR_DELEGATION_CALL -> constructorDelegationCall = convertConstructorDelegationCall(it, classWrapper)
BLOCK -> block = it
}
}
val delegatedSelfTypeRef = classWrapper.delegatedSelfTypeRef
val explicitVisibility = modifiers.getVisibility()
val status = FirDeclarationStatusImpl(explicitVisibility, Modality.FINAL).apply {
isExpect = modifiers.hasExpect() || classWrapper.hasExpect()
isActual = modifiers.hasActual()
isInner = classWrapper.isInner()
isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.Private
isFromEnumClass = classWrapper.isEnum()
}
val target = FirFunctionTarget(labelName = null, isLambda = false)
return buildConstructor {
source = secondaryConstructor.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = delegatedSelfTypeRef
this.status = status
symbol = FirConstructorSymbol(callableIdForClassConstructor())
delegatedConstructor = constructorDelegationCall
context.firFunctionTargets += target
annotations += modifiers.annotations
typeParameters += constructorTypeParametersFromConstructedClass(classWrapper.classBuilder.typeParameters)
valueParameters += firValueParameters.map { it.firValueParameter }
val (body, _) = convertFunctionBody(block, null)
this.body = body
context.firFunctionTargets.removeLast()
}.also {
target.bind(it)
}
}
/**
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.convert(
* KtConstructorDelegationCall, FirTypeRef, Boolean)
*/
private fun convertConstructorDelegationCall(
constructorDelegationCall: LighterASTNode,
classWrapper: ClassWrapper
): FirDelegatedConstructorCall {
var thisKeywordPresent = false
val firValueArguments = mutableListOf()
constructorDelegationCall.forEachChildren {
when (it.tokenType) {
CONSTRUCTOR_DELEGATION_REFERENCE -> if (it.asText == "this") thisKeywordPresent = true
VALUE_ARGUMENT_LIST -> firValueArguments += expressionConverter.convertValueArguments(it)
}
}
val isImplicit = constructorDelegationCall.asText.isEmpty()
val isThis = thisKeywordPresent //|| (isImplicit && classWrapper.hasPrimaryConstructor)
val delegatedType =
when {
isThis -> classWrapper.delegatedSelfTypeRef
else -> classWrapper.delegatedSuperTypeRef
}
return buildDelegatedConstructorCall {
source = if (isImplicit) {
constructorDelegationCall.toFirSourceElement().fakeElement(FirFakeSourceElementKind.ImplicitConstructor)
} else {
constructorDelegationCall.toFirSourceElement()
}
constructedTypeRef = delegatedType.copyWithNewSourceKind(FirFakeSourceElementKind.ImplicitTypeRef)
this.isThis = isThis
extractArgumentsFrom(firValueArguments, stubMode)
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeAlias
*/
private fun convertTypeAlias(typeAlias: LighterASTNode): FirDeclaration {
var modifiers = Modifier()
var identifier: String? = null
lateinit var firType: FirTypeRef
val firTypeParameters = mutableListOf()
typeAlias.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> firTypeParameters += convertTypeParameters(it, emptyList())
TYPE_REFERENCE -> firType = convertType(it)
}
}
val typeAliasName = identifier.nameAsSafeName()
return withChildClassName(typeAliasName) {
return@withChildClassName buildTypeAlias {
source = typeAlias.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
name = typeAliasName
status = FirDeclarationStatusImpl(modifiers.getVisibility(), Modality.FINAL).apply {
isExpect = modifiers.hasExpect()
isActual = modifiers.hasActual()
}
symbol = FirTypeAliasSymbol(context.currentClassId)
expandedTypeRef = firType
annotations += modifiers.annotations
typeParameters += firTypeParameters
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseProperty
*/
fun convertPropertyDeclaration(property: LighterASTNode, classWrapper: ClassWrapper? = null): FirDeclaration {
var modifiers = Modifier()
var identifier: String? = null
val firTypeParameters = mutableListOf()
var isReturnType = false
var delegateExpression: LighterASTNode? = null
var isVar = false
var receiverType: FirTypeRef? = null
var returnType: FirTypeRef = implicitType
val typeConstraints = mutableListOf()
val accessors = mutableListOf()
var propertyInitializer: FirExpression? = null
var typeParameterList: LighterASTNode? = null
property.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> typeParameterList = it
COLON -> isReturnType = true
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
PROPERTY_DELEGATE -> delegateExpression = it
VAR_KEYWORD -> isVar = true
PROPERTY_ACCESSOR -> {
accessors += it
}
else -> if (it.isExpression()) propertyInitializer = expressionConverter.getAsFirExpression(it, "Should have initializer")
}
}
typeParameterList?.let { firTypeParameters += convertTypeParameters(it, typeConstraints) }
val propertyName = identifier.nameAsSafeName()
val parentNode = property.getParent()
val isLocal = !(parentNode?.tokenType == KT_FILE || parentNode?.tokenType == CLASS_BODY)
val propertySource = property.toFirSourceElement()
return buildProperty {
source = propertySource
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = returnType
name = propertyName
this.isVar = isVar
initializer = propertyInitializer
if (isLocal) {
this.isLocal = true
symbol = FirPropertySymbol(propertyName)
val delegateBuilder = delegateExpression?.let {
FirWrappedDelegateExpressionBuilder().apply {
source = it.toFirSourceElement()
expression = expressionConverter.getAsFirExpression(it, "Incorrect delegate expression")
}
}
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL).apply {
isLateInit = modifiers.hasLateinit()
}
val receiver = delegateExpression?.let {
expressionConverter.getAsFirExpression(it, "Incorrect delegate expression")
}
generateAccessorsByDelegate(
delegateBuilder,
classWrapper?.classBuilder,
baseSession,
isExtension = false,
stubMode,
receiver
)
} else {
this.isLocal = false
receiverTypeRef = receiverType
symbol = FirPropertySymbol(callableIdForName(propertyName))
withCapturedTypeParameters {
typeParameters += firTypeParameters
addCapturedTypeParameters(firTypeParameters)
val delegateBuilder = delegateExpression?.let {
FirWrappedDelegateExpressionBuilder().apply {
source = it.toFirSourceElement()
expression = expressionConverter.getAsFirExpression(it, "Should have delegate")
}
}
val propertyVisibility = modifiers.getVisibility()
val convertedAccessors = accessors.map { convertGetterOrSetter(it, returnType, propertyVisibility, modifiers) }
this.getter = convertedAccessors.find { it.isGetter }
?: FirDefaultPropertyGetter(null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility)
this.setter =
if (isVar) {
convertedAccessors.find { it.isSetter }
?: FirDefaultPropertySetter(null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility)
} else null
// Upward propagation of `inline` and `external` modifiers (from accessors to property)
// Note that, depending on `var` or `val`, checking setter's modifiers should be careful: for `val`, setter doesn't
// exist (null); for `var`, the retrieval of the specific modifier is supposed to be `true`
status = FirDeclarationStatusImpl(propertyVisibility, modifiers.getModality()).apply {
isExpect = modifiers.hasExpect() || classWrapper?.hasExpect() == true
isActual = modifiers.hasActual()
isOverride = modifiers.hasOverride()
isConst = modifiers.isConst()
isLateInit = modifiers.hasLateinit()
isInline = modifiers.hasInline() || (getter!!.isInline && setter?.isInline != false)
isExternal = modifiers.hasExternal() || (getter!!.isExternal && setter?.isExternal != false)
}
val receiver = delegateExpression?.let {
expressionConverter.getAsFirExpression(it, "Should have delegate")
}
generateAccessorsByDelegate(
delegateBuilder,
classWrapper?.classBuilder,
baseSession,
isExtension = receiverType != null,
stubMode,
receiver
)
}
}
annotations += modifiers.annotations
}
}
/**
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitDestructuringDeclaration
*/
private fun convertDestructingDeclaration(destructingDeclaration: LighterASTNode): DestructuringDeclaration {
var isVar = false
val entries = mutableListOf>()
val source = destructingDeclaration.toFirSourceElement()
var firExpression: FirExpression =
buildErrorExpression(null, ConeSimpleDiagnostic("Destructuring declaration without initializer", DiagnosticKind.Syntax))
destructingDeclaration.forEachChildren {
when (it.tokenType) {
VAR_KEYWORD -> isVar = true
DESTRUCTURING_DECLARATION_ENTRY -> entries += convertDestructingDeclarationEntry(it)
else -> if (it.isExpression()) firExpression =
expressionConverter.getAsFirExpression(it, "Destructuring declaration without initializer")
}
}
return DestructuringDeclaration(isVar, entries, firExpression, source)
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseMultiDeclarationName
*/
private fun convertDestructingDeclarationEntry(entry: LighterASTNode): FirVariable<*> {
var modifiers = Modifier()
var identifier: String? = null
var firType: FirTypeRef? = null
entry.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.asText
TYPE_REFERENCE -> firType = convertType(it)
}
}
val name = identifier.nameAsSafeName()
return buildProperty {
source = entry.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = firType ?: implicitType
this.name = name
isVar = false
symbol = FirPropertySymbol(name)
isLocal = true
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL)
annotations += modifiers.annotations
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePropertyGetterOrSetter
*/
private fun convertGetterOrSetter(
getterOrSetter: LighterASTNode,
propertyTypeRef: FirTypeRef,
propertyVisibility: Visibility,
propertyModifiers: Modifier
): FirPropertyAccessor {
var modifiers = Modifier()
var isGetter = true
var returnType: FirTypeRef? = null
var firValueParameters: FirValueParameter = buildDefaultSetterValueParameter {
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = propertyTypeRef
symbol = FirVariableSymbol(NAME_FOR_DEFAULT_VALUE_PARAMETER)
}
var block: LighterASTNode? = null
var expression: LighterASTNode? = null
var outerContractDescription: FirContractDescription? = null
getterOrSetter.forEachChildren {
if (it.asText == "set") isGetter = false
when (it.tokenType) {
SET_KEYWORD -> isGetter = false
MODIFIER_LIST -> modifiers = convertModifierList(it)
TYPE_REFERENCE -> returnType = convertType(it)
VALUE_PARAMETER_LIST -> firValueParameters = convertSetterParameter(it, propertyTypeRef)
CONTRACT_EFFECT_LIST -> outerContractDescription = obtainContractDescription(it)
BLOCK -> block = it
else -> if (it.isExpression()) expression = it
}
}
var accessorVisibility = modifiers.getVisibility()
if (accessorVisibility == Visibilities.Unknown) {
accessorVisibility = propertyVisibility
}
val status =
// Downward propagation of `inline` and `external` modifiers (from property to its accessors)
FirDeclarationStatusImpl(accessorVisibility, Modality.FINAL).apply {
isInline = propertyModifiers.hasInline() || modifiers.hasInline()
isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal()
}
val sourceElement = getterOrSetter.toFirSourceElement()
if (block == null && expression == null) {
return FirDefaultPropertyAccessor
.createGetterOrSetter(
sourceElement,
baseSession,
FirDeclarationOrigin.Source,
propertyTypeRef,
accessorVisibility,
isGetter
)
.also {
it.annotations += modifiers.annotations
it.status = status
}
}
val target = FirFunctionTarget(labelName = null, isLambda = false)
return buildPropertyAccessor {
source = sourceElement
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = returnType ?: if (isGetter) propertyTypeRef else implicitUnitType
symbol = FirPropertyAccessorSymbol()
this.isGetter = isGetter
this.status = status
context.firFunctionTargets += target
annotations += modifiers.annotations
if (!isGetter) {
valueParameters += firValueParameters
}
val hasContractEffectList = outerContractDescription != null
val bodyWithContractDescription = convertFunctionBody(block, expression, hasContractEffectList)
this.body = bodyWithContractDescription.first
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
contractDescription?.let {
this.contractDescription = it
}
context.firFunctionTargets.removeLast()
}.also {
target.bind(it)
}
}
private fun obtainContractDescription(rawContractDescription: LighterASTNode): FirContractDescription? =
buildRawContractDescription {
source = rawContractDescription.toFirSourceElement()
extractRawEffects(rawContractDescription, rawEffects)
}
private fun extractRawEffects(rawContractDescription: LighterASTNode, destination: MutableList) {
rawContractDescription.forEachChildren {
val errorReason = "The contract effect is not an expression"
when (it.tokenType) {
CONTRACT_EFFECT -> {
val effect = it.getFirstChild()
if (effect == null) {
val errorExpression = buildErrorExpression(null, ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionRequired))
destination.add(errorExpression)
} else {
val expression = expressionConverter.convertExpression(effect, errorReason)
destination.add(expression as FirExpression)
}
}
else -> Unit
}
}
}
/**
* this is just a VALUE_PARAMETER_LIST
*
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePropertyGetterOrSetter
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.toFirValueParameter
*/
private fun convertSetterParameter(setterParameter: LighterASTNode, propertyTypeRef: FirTypeRef): FirValueParameter {
var modifiers = Modifier()
lateinit var firValueParameter: FirValueParameter
setterParameter.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
VALUE_PARAMETER -> firValueParameter = convertValueParameter(it).firValueParameter
}
}
return buildValueParameter {
source = setterParameter.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = if (firValueParameter.returnTypeRef == implicitType) propertyTypeRef else firValueParameter.returnTypeRef
name = firValueParameter.name
symbol = FirVariableSymbol(firValueParameter.name)
defaultValue = firValueParameter.defaultValue
isCrossinline = modifiers.hasCrossinline() || firValueParameter.isCrossinline
isNoinline = modifiers.hasNoinline() || firValueParameter.isNoinline
isVararg = modifiers.hasVararg() || firValueParameter.isVararg
annotations += modifiers.annotations + firValueParameter.annotations
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunction
*/
fun convertFunctionDeclaration(functionDeclaration: LighterASTNode, classWrapper: ClassWrapper? = null): FirDeclaration {
var modifiers = Modifier()
var identifier: String? = null
val firTypeParameters = mutableListOf()
var valueParametersList: LighterASTNode? = null
var isReturnType = false
var receiverType: FirTypeRef? = null
var returnType: FirTypeRef? = null
val typeConstraints = mutableListOf()
var block: LighterASTNode? = null
var expression: LighterASTNode? = null
var hasEqToken = false
var typeParameterList: LighterASTNode? = null
var outerContractDescription: FirContractDescription? = null
functionDeclaration.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> typeParameterList = it
VALUE_PARAMETER_LIST -> valueParametersList = it //must convert later, because it can contains "return"
COLON -> isReturnType = true
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
CONTRACT_EFFECT_LIST -> outerContractDescription = obtainContractDescription(it)
BLOCK -> block = it
EQ -> hasEqToken = true
else -> if (it.isExpression()) expression = it
}
}
typeParameterList?.let { firTypeParameters += convertTypeParameters(it, typeConstraints) }
if (returnType == null) {
returnType =
if (block != null || !hasEqToken) implicitUnitType
else implicitType
}
val parentNode = functionDeclaration.getParent()
val isLocal = !(parentNode?.tokenType == KT_FILE || parentNode?.tokenType == CLASS_BODY)
val target: FirFunctionTarget
val functionBuilder = if (identifier == null && isLocal) {
target = FirFunctionTarget(labelName = functionDeclaration.getLabelName(), isLambda = false)
FirAnonymousFunctionBuilder().apply {
source = functionDeclaration.toFirSourceElement()
receiverTypeRef = receiverType
symbol = FirAnonymousFunctionSymbol()
isLambda = false
}
} else {
val functionName = identifier.nameAsSafeName()
val labelName = runIf(!functionName.isSpecial) { functionName.identifier }
target = FirFunctionTarget(labelName, isLambda = false)
FirSimpleFunctionBuilder().apply {
source = functionDeclaration.toFirSourceElement()
receiverTypeRef = receiverType
name = functionName
status = FirDeclarationStatusImpl(
if (isLocal) Visibilities.Local else modifiers.getVisibility(),
modifiers.getModality()
).apply {
isExpect = modifiers.hasExpect() || classWrapper?.hasExpect() == true
isActual = modifiers.hasActual()
isOverride = modifiers.hasOverride()
isOperator = modifiers.hasOperator()
isInfix = modifiers.hasInfix()
isInline = modifiers.hasInline()
isTailRec = modifiers.hasTailrec()
isExternal = modifiers.hasExternal()
isSuspend = modifiers.hasSuspend()
}
symbol = FirNamedFunctionSymbol(callableIdForName(functionName, isLocal))
}
}
return functionBuilder.apply {
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = returnType!!
context.firFunctionTargets += target
annotations += modifiers.annotations
withCapturedTypeParameters {
if (this is FirSimpleFunctionBuilder) {
typeParameters += firTypeParameters
addCapturedTypeParameters(typeParameters)
}
valueParametersList?.let { list -> valueParameters += convertValueParameters(list).map { it.firValueParameter } }
val hasContractEffectList = outerContractDescription != null
val bodyWithContractDescription = convertFunctionBody(block, expression, hasContractEffectList)
this.body = bodyWithContractDescription.first
val contractDescription = outerContractDescription ?: bodyWithContractDescription.second
contractDescription?.let {
// TODO: add error reporting for contracts on lambdas
if (this is FirSimpleFunctionBuilder) {
this.contractDescription = it
}
}
}
context.firFunctionTargets.removeLast()
}.build().also {
target.bind(it)
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionBody
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.buildFirBody
*/
private fun convertFunctionBody(
blockNode: LighterASTNode?,
expression: LighterASTNode?,
hasContractEffectList: Boolean = false
): Pair {
return when {
blockNode != null -> {
val block = convertBlock(blockNode)
if (hasContractEffectList) {
block to null
} else {
block.extractContractDescriptionIfPossible()
}
}
expression != null -> FirSingleExpressionBlock(
expressionConverter.getAsFirExpression(expression, "Function has no body (but should)").toReturn()
) to null
else -> null to null
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock
*/
fun convertBlock(block: LighterASTNode?): FirBlock {
if (block == null) return buildEmptyExpressionBlock()
if (block.tokenType != BLOCK) {
return FirSingleExpressionBlock(
expressionConverter.getAsFirExpression(block)
)
}
return if (!stubMode) {
val blockTree = LightTree2Fir.buildLightTreeBlockExpression(block.asText)
return DeclarationsConverter(
baseSession, baseScopeProvider, stubMode, blockTree, offset = tree.getStartOffset(block), context
).convertBlockExpression(blockTree.root)
} else {
val firExpression = buildExpressionStub()
FirSingleExpressionBlock(
firExpression.toReturn(baseSource = firExpression.source)
)
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseDelegationSpecifierList
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.extractSuperTypeListEntriesTo
*
* SUPER_TYPE_ENTRY - userType
* SUPER_TYPE_CALL_ENTRY - constructorInvocation
* DELEGATED_SUPER_TYPE_ENTRY - explicitDelegation
*/
//TODO make wrapper for result?
private data class DelegationSpecifiers(
val delegatedSuperTypeRef: FirTypeRef?,
val superTypesRef: List,
val delegatedConstructorArguments: List,
val delegatedConstructorSource: FirLightSourceElement?,
val delegateFields: List,
val primaryConstructorBody: FirBlock?
)
private fun convertDelegationSpecifiers(
delegationSpecifiers: LighterASTNode,
containerSymbol: AbstractFirBasedSymbol<*>,
delegatedTypeRef: FirTypeRef
): DelegationSpecifiers {
val superTypeRefs = mutableListOf()
val superTypeCallEntry = mutableListOf()
var delegatedSuperTypeRef: FirTypeRef? = null
var delegateConstructorSource: FirLightSourceElement? = null
val delegateFields = mutableListOf()
val initializeDelegateStatements = mutableListOf()
var delegateNumber = 0
delegationSpecifiers.forEachChildren {
when (it.tokenType) {
SUPER_TYPE_ENTRY -> {
superTypeRefs += convertType(it)
}
SUPER_TYPE_CALL_ENTRY -> convertConstructorInvocation(it).apply {
delegatedSuperTypeRef = first
superTypeRefs += first
superTypeCallEntry += second
delegateConstructorSource = it.toFirSourceElement(FirFakeSourceElementKind.DelegatingConstructorCall)
}
DELEGATED_SUPER_TYPE_ENTRY -> {
superTypeRefs += convertExplicitDelegation(
it,
delegateNumber,
delegateFields,
initializeDelegateStatements,
containerSymbol,
delegatedTypeRef
)
delegateNumber++
}
}
}
val body = if (initializeDelegateStatements.isNotEmpty()) {
buildBlock {
for (statement in initializeDelegateStatements) {
statements += statement
}
}
} else null
return DelegationSpecifiers(
delegatedSuperTypeRef, superTypeRefs, superTypeCallEntry, delegateConstructorSource,
delegateFields, body
)
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseDelegationSpecifier
*
* constructorInvocation
* : userType valueArguments
* ;
*/
private fun convertConstructorInvocation(constructorInvocation: LighterASTNode): Pair> {
var firTypeRef: FirTypeRef = implicitType
val firValueArguments = mutableListOf()
constructorInvocation.forEachChildren {
when (it.tokenType) {
CONSTRUCTOR_CALLEE -> if (it.asText.isNotEmpty()) firTypeRef = convertType(it) //is empty in enum entry constructor
VALUE_ARGUMENT_LIST -> firValueArguments += expressionConverter.convertValueArguments(it)
}
}
return Pair(firTypeRef, firValueArguments)
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseDelegationSpecifier
*
* explicitDelegation
* : userType "by" element
* ;
*/
private fun convertExplicitDelegation(
explicitDelegation: LighterASTNode,
delegateNumber: Int,
delegateFields: MutableList,
initializeDelegateStatements: MutableList,
containerSymbol: AbstractFirBasedSymbol<*>,
delegatedSelfTypeRef: FirTypeRef
): FirTypeRef {
lateinit var firTypeRef: FirTypeRef
var firExpression: FirExpression? = buildErrorExpression(
explicitDelegation.toFirSourceElement(), ConeSimpleDiagnostic("Should have delegate", DiagnosticKind.Syntax)
)
explicitDelegation.forEachChildren {
when (it.tokenType) {
TYPE_REFERENCE -> firTypeRef = convertType(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have delegate")
}
}
val delegateName = Name.special("<\$\$delegate_$delegateNumber>")
delegateFields.add(
buildField {
source = firExpression!!.source
session = baseSession
origin = FirDeclarationOrigin.Synthetic
name = delegateName
returnTypeRef = firTypeRef
symbol = FirFieldSymbol(CallableId(name))
isVar = false
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL)
}
)
initializeDelegateStatements.add(
buildVariableAssignment {
source = firExpression!!.source
calleeReference =
buildResolvedNamedReference {
name = delegateName
resolvedSymbol = delegateFields[delegateNumber].symbol
}
rValue = firExpression!!
dispatchReceiver = buildThisReceiverExpression {
calleeReference = buildImplicitThisReference {
boundSymbol = containerSymbol
}
typeRef = delegatedSelfTypeRef
}
}
)
return firTypeRef
}
/***** TYPES *****/
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeParameterList
*/
private fun convertTypeParameters(typeParameterList: LighterASTNode, typeConstraints: List): List {
return typeParameterList.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
TYPE_PARAMETER -> container += convertTypeParameter(node, typeConstraints)
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeConstraintList
*/
private fun convertTypeConstraints(typeConstraints: LighterASTNode): List {
return typeConstraints.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
TYPE_CONSTRAINT -> container += convertTypeConstraint(node)
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeConstraint
*/
private fun convertTypeConstraint(typeConstraint: LighterASTNode): TypeConstraint {
lateinit var identifier: String
lateinit var firType: FirTypeRef
val annotations = mutableListOf()
typeConstraint.forEachChildren {
when (it.tokenType) {
//annotations will be saved later, on mapping stage with type parameters
ANNOTATION, ANNOTATION_ENTRY -> annotations += convertAnnotation(it)
REFERENCE_EXPRESSION -> identifier = it.asText
TYPE_REFERENCE -> firType = convertType(it)
}
}
return TypeConstraint(annotations, identifier, firType)
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeParameter
*/
private fun convertTypeParameter(typeParameter: LighterASTNode, typeConstraints: List): FirTypeParameter {
var typeParameterModifiers = TypeParameterModifier()
var identifier: String? = null
var firType: FirTypeRef? = null
typeParameter.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> typeParameterModifiers = convertTypeParameterModifiers(it)
IDENTIFIER -> identifier = it.asText
TYPE_REFERENCE -> firType = convertType(it)
}
}
return buildTypeParameter {
source = typeParameter.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
name = identifier.nameAsSafeName()
symbol = FirTypeParameterSymbol()
variance = typeParameterModifiers.getVariance()
isReified = typeParameterModifiers.hasReified()
annotations += typeParameterModifiers.annotations
firType?.let { bounds += it }
for (typeConstraint in typeConstraints) {
if (typeConstraint.identifier == identifier) {
bounds += typeConstraint.firTypeRef
annotations += typeConstraint.annotations
}
}
addDefaultBoundIfNecessary()
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeRef
*/
fun convertType(type: LighterASTNode): FirTypeRef {
if (type.asText.isEmpty()) {
return buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Unwrapped type is null", DiagnosticKind.Syntax) }
}
var typeModifiers = TypeModifier()
var firType: FirTypeRef = buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Incomplete code", DiagnosticKind.Syntax) }
var afterLPar = false
type.forEachChildren {
when (it.tokenType) {
LPAR -> afterLPar = true
TYPE_REFERENCE -> firType = convertType(it)
MODIFIER_LIST -> if (!afterLPar || typeModifiers.hasNoAnnotations()) typeModifiers = convertTypeModifierList(it)
USER_TYPE -> firType = convertUserType(it)
NULLABLE_TYPE -> firType = convertNullableType(it)
FUNCTION_TYPE -> firType = convertFunctionType(it, isSuspend = typeModifiers.hasSuspend)
DYNAMIC_TYPE -> firType = buildDynamicTypeRef {
source = type.toFirSourceElement()
isMarkedNullable = false
}
TokenType.ERROR_ELEMENT -> firType =
buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Unwrapped type is null", DiagnosticKind.Syntax) }
}
}
return firType.also { (it.annotations as MutableList) += typeModifiers.annotations }
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeRefContents
*/
private fun convertReceiverType(receiverType: LighterASTNode): FirTypeRef {
receiverType.forEachChildren {
when (it.tokenType) {
TYPE_REFERENCE -> return convertType(it)
}
}
//TODO specify error
throw Exception()
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseNullableTypeSuffix
*/
private fun convertNullableType(nullableType: LighterASTNode): FirTypeRef {
lateinit var firType: FirTypeRef
nullableType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> firType =
convertUserType(it, true)
FUNCTION_TYPE -> firType = convertFunctionType(it, true)
NULLABLE_TYPE -> firType = convertNullableType(it)
DYNAMIC_TYPE -> firType = buildDynamicTypeRef {
source = nullableType.toFirSourceElement()
isMarkedNullable = true
}
}
}
return firType
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseUserType
*/
private fun convertUserType(userType: LighterASTNode, isNullable: Boolean = false): FirTypeRef {
var simpleFirUserType: FirUserTypeRef? = null
var identifier: String? = null
val firTypeArguments = mutableListOf()
userType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> simpleFirUserType = convertUserType(it) as? FirUserTypeRef //simple user type
REFERENCE_EXPRESSION -> identifier = it.asText
TYPE_ARGUMENT_LIST -> firTypeArguments += convertTypeArguments(it)
}
}
if (identifier == null)
return buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Incomplete user type", DiagnosticKind.Syntax) }
val theSource = userType.toFirSourceElement()
val qualifierPart = FirQualifierPartImpl(
identifier.nameAsSafeName(),
FirTypeArgumentListImpl(theSource).apply {
typeArguments += firTypeArguments
}
)
return buildUserTypeRef {
source = theSource
isMarkedNullable = isNullable
qualifier.add(qualifierPart)
simpleFirUserType?.qualifier?.let { this.qualifier.addAll(0, it) }
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeArgumentList
*/
fun convertTypeArguments(typeArguments: LighterASTNode): List {
return typeArguments.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
TYPE_PROJECTION -> container += convertTypeProjection(node)
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.tryParseTypeArgumentList
*/
private fun convertTypeProjection(typeProjection: LighterASTNode): FirTypeProjection {
var modifiers = TypeProjectionModifier()
lateinit var firType: FirTypeRef
var isStarProjection = false
typeProjection.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertTypeArgumentModifierList(it)
TYPE_REFERENCE -> firType = convertType(it)
MUL -> isStarProjection = true
}
}
//annotations from modifiers must be ignored
return if (isStarProjection) buildStarProjection { source = typeProjection.toFirSourceElement() }
else buildTypeProjectionWithVariance {
source = typeProjection.toFirSourceElement()
typeRef = firType
variance = modifiers.getVariance()
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionType
*/
private fun convertFunctionType(functionType: LighterASTNode, isNullable: Boolean = false, isSuspend: Boolean = false): FirTypeRef {
var receiverTypeReference: FirTypeRef? = null
lateinit var returnTypeReference: FirTypeRef
val valueParametersList = mutableListOf()
functionType.forEachChildren {
when (it.tokenType) {
FUNCTION_TYPE_RECEIVER -> receiverTypeReference = convertReceiverType(it)
VALUE_PARAMETER_LIST -> valueParametersList += convertValueParameters(it)
TYPE_REFERENCE -> returnTypeReference = convertType(it)
}
}
return buildFunctionTypeRef {
source = functionType.toFirSourceElement()
isMarkedNullable = isNullable
receiverTypeRef = receiverTypeReference
returnTypeRef = returnTypeReference
valueParameters += valueParametersList.map { it.firValueParameter }
if (receiverTypeReference != null) {
annotations += extensionFunctionAnnotation
}
this.isSuspend = isSuspend
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseValueParameterList
*/
fun convertValueParameters(valueParameters: LighterASTNode): List {
return valueParameters.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
VALUE_PARAMETER -> container += convertValueParameter(node)
}
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseValueParameter
*/
fun convertValueParameter(valueParameter: LighterASTNode): ValueParameter {
var modifiers = Modifier()
var isVal = false
var isVar = false
var identifier: String? = null
var firType: FirTypeRef? = null
var firExpression: FirExpression? = null
var destructuringDeclaration: DestructuringDeclaration? = null
valueParameter.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
VAL_KEYWORD -> isVal = true
VAR_KEYWORD -> isVar = true
IDENTIFIER -> identifier = it.asText
TYPE_REFERENCE -> firType = convertType(it)
DESTRUCTURING_DECLARATION -> destructuringDeclaration = convertDestructingDeclaration(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have default value")
}
}
val name = identifier.nameAsSafeName()
val firValueParameter = buildValueParameter {
source = valueParameter.toFirSourceElement()
session = baseSession
origin = FirDeclarationOrigin.Source
returnTypeRef = firType ?: implicitType
this.name = name
symbol = FirVariableSymbol(name)
defaultValue = firExpression
isCrossinline = modifiers.hasCrossinline()
isNoinline = modifiers.hasNoinline()
isVararg = modifiers.hasVararg()
annotations += modifiers.annotations
}
return ValueParameter(isVal, isVar, modifiers, firValueParameter, destructuringDeclaration)
}
private val extensionFunctionAnnotation = buildAnnotationCall {
annotationTypeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(ClassId.fromString(EXTENSION_FUNCTION_ANNOTATION)),
emptyArray(),
false
)
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
}
}