Rewrite RawFirBuilder and its utils to be able to reuse it in LightTree converter

This commit is contained in:
Ivan Cilcic
2019-07-30 21:35:19 +03:00
committed by Mikhail Glukhikh
parent 084bad4c25
commit cad0dbf087
10 changed files with 661 additions and 1059 deletions
@@ -9,23 +9,75 @@ import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.psi.tree.IElementType
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.BaseFirBuilder
import org.jetbrains.kotlin.fir.builder.escapedStringToCharacter
import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.isExpression
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName
import org.jetbrains.kotlin.name.Name
open class BaseConverter(
session: FirSession,
private val tree: FlyweightCapableTreeStructure<LighterASTNode>
) {
protected val implicitUnitType = FirImplicitUnitTypeRef(session, null)
protected val implicitAnyType = FirImplicitAnyTypeRef(session, null)
protected val implicitEnumType = FirImplicitEnumTypeRef(session, null)
protected val implicitAnnotationType = FirImplicitAnnotationTypeRef(session, null)
) : BaseFirBuilder<LighterASTNode>(session) {
protected val implicitType = FirImplicitTypeRefImpl(session, null)
override val LighterASTNode.elementType: IElementType
get() = this.tokenType
override val LighterASTNode.asText: String
get() = this.toString()
override val LighterASTNode.unescapedValue: String
get() {
val escape = this.asText
return escapedStringToCharacter(escape)?.toString()
?: escape.replace("\\", "").replace("u", "\\u")
}
override fun LighterASTNode.getReferencedNameAsName(): Name {
return this.asText.nameAsSafeName()
}
override fun LighterASTNode.getLabelName(): String? {
this.forEachChildren {
when (it.tokenType) {
KtNodeTypes.LABEL_QUALIFIER -> return it.asText.replaceFirst("@", "")
}
}
return null
}
override fun LighterASTNode.getExpressionInParentheses(): LighterASTNode? {
this.forEachChildren {
if (it.isExpression()) return it
}
return null
}
override fun LighterASTNode.getChildNodeByType(type: IElementType): LighterASTNode? {
return this.getChildNodesByType(type).firstOrNull()
}
override val LighterASTNode?.selectorExpression: LighterASTNode?
get() {
var isSelector = false
this?.forEachChildren {
when (it.tokenType) {
DOT, SAFE_ACCESS -> isSelector = true
else -> if (isSelector) return it
}
}
return null
}
fun LighterASTNode.getParent(): LighterASTNode? {
return tree.getParent(this)
}
@@ -38,7 +90,7 @@ open class BaseConverter(
} ?: listOf()
}
fun LighterASTNode?.getChildrenAsArray(): Array<LighterASTNode?> {
fun LighterASTNode?.getChildrenAsArray(): Array<out LighterASTNode?> {
if (this == null) return arrayOf()
val kidsRef = Ref<Array<LighterASTNode?>>()
@@ -46,14 +98,6 @@ open class BaseConverter(
return kidsRef.get()
}
fun LighterASTNode.getExpressionInParentheses(): LighterASTNode? {
this.forEachChildren {
if (it.isExpression()) return it
}
return null
}
protected inline fun LighterASTNode.forEachChildren(vararg skipTokens: KtToken, f: (LighterASTNode) -> Unit) {
val kidsArray = this.getChildrenAsArray()
for (kid in kidsArray) {
@@ -62,10 +62,6 @@ object ConverterUtil {
return this.toString().replace("`", "")
}
fun LighterASTNode.getAsString(): String {
return this.toString()
}
fun LighterASTNode.isExpression(): Boolean {
return when (this.tokenType) {
is KtNodeType,
@@ -76,59 +72,6 @@ object ConverterUtil {
}
}
fun toDelegatedSelfType(firClass: FirRegularClass): FirTypeRef {
val typeParameters = firClass.typeParameters.map {
FirTypeParameterImpl(firClass.session, it.psi, FirTypeParameterSymbol(), it.name, Variance.INVARIANT, false).apply {
this.bounds += it.bounds
}
}
return FirResolvedTypeRefImpl(
firClass.session,
null,
ConeClassTypeImpl(
firClass.symbol.toLookupTag(),
typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
false
)
)
}
fun FirExpression.toReturn(labelName: String? = null): FirReturnExpression {
return FirReturnExpressionImpl(
session,
null,
this
).apply {
target = FirFunctionTarget(labelName)
val lastFunction = FunctionUtil.firFunctions.lastOrNull()
if (labelName == null) {
if (lastFunction != null) {
target.bind(lastFunction)
} else {
target.bind(FirErrorFunction(session, psi, "Cannot bind unlabeled return to a function"))
}
} else {
for (firFunction in FunctionUtil.firFunctions.asReversed()) {
when (firFunction) {
is FirAnonymousFunction -> {
if (firFunction.label?.name == labelName) {
target.bind(firFunction)
return@apply
}
}
is FirNamedFunction -> {
if (firFunction.name.asString() == labelName) {
target.bind(firFunction)
return@apply
}
}
}
}
target.bind(FirErrorFunction(session, psi, "Cannot bind label $labelName to a function"))
}
}
}
fun FirTypeParameterContainer.joinTypeParameters(typeConstraints: List<TypeConstraint>) {
typeConstraints.forEach { typeConstraint ->
this.typeParameters.forEach { typeParameter ->
@@ -141,13 +84,6 @@ object ConverterUtil {
}
}
fun typeParametersFromSelfType(delegatedSelfTypeRef: FirTypeRef): List<FirTypeParameter> {
return delegatedSelfTypeRef.coneTypeSafe<ConeKotlinType>()
?.typeArguments
?.map { ((it as ConeTypeParameterType).lookupTag.symbol as FirTypeParameterSymbol).fir }
?: emptyList()
}
fun <T : FirCallWithArgumentList> T.extractArgumentsFrom(container: List<FirExpression>, stubMode: Boolean): T {
if (!stubMode || this is FirAnnotationCall) {
this.arguments += container
@@ -176,152 +112,3 @@ object ConverterUtil {
return false
}
}
object ClassNameUtil {
lateinit var packageFqName: FqName
inline fun <T> withChildClassName(name: Name, l: () -> T): T {
className = className.child(name)
val t = l()
className = className.parent()
return t
}
val currentClassId
get() = ClassId(
packageFqName,
className, false
)
fun callableIdForName(name: Name, local: Boolean = false) =
when {
local -> CallableId(name)
className == FqName.ROOT -> CallableId(packageFqName, name)
else -> CallableId(
packageFqName,
className, name
)
}
fun callableIdForClassConstructor() =
if (className == FqName.ROOT) CallableId(packageFqName, Name.special("<anonymous-init>"))
else CallableId(
packageFqName,
className, className.shortName()
)
var className: FqName = FqName.ROOT
}
object FunctionUtil {
val firFunctions = mutableListOf<FirFunction>()
val firFunctionCalls = mutableListOf<FirFunctionCall>()
val firLabels = mutableListOf<FirLabel>()
val firLoops = mutableListOf<FirLoop>()
fun <T> MutableList<T>.removeLast() {
removeAt(size - 1)
}
fun <T> MutableList<T>.pop(): T? {
val result = lastOrNull()
if (result != null) {
removeAt(size - 1)
}
return result
}
}
object DataClassUtil {
fun generateComponentFunctions(
session: FirSession, firClass: FirClassImpl, properties: List<FirProperty>
) {
var componentIndex = 1
for (property in properties) {
if (!property.isVal && !property.isVar) continue
val name = Name.identifier("component$componentIndex")
componentIndex++
val symbol = FirNamedFunctionSymbol(
CallableId(
ClassNameUtil.packageFqName,
ClassNameUtil.className,
name
)
)
firClass.addDeclaration(
FirMemberFunctionImpl(
session, null, symbol, name,
Visibilities.PUBLIC, Modality.FINAL,
isExpect = false, isActual = false,
isOverride = false, isOperator = false,
isInfix = false, isInline = false,
isTailRec = false, isExternal = false,
isSuspend = false, receiverTypeRef = null,
returnTypeRef = FirImplicitTypeRefImpl(session, null)
).apply {
val componentFunction = this
body = FirSingleExpressionBlock(
session,
FirReturnExpressionImpl(
session, null,
FirQualifiedAccessExpressionImpl(session, null).apply {
val parameterName = property.name
calleeReference = FirResolvedCallableReferenceImpl(
session, null,
parameterName, property.symbol
)
}
).apply {
target = FirFunctionTarget(null)
target.bind(componentFunction)
}
)
}
)
}
}
private val copyName = Name.identifier("copy")
fun generateCopyFunction(
session: FirSession, firClass: FirClassImpl,
firPrimaryConstructor: FirConstructor,
properties: List<FirProperty>
) {
val symbol = FirNamedFunctionSymbol(
CallableId(
ClassNameUtil.packageFqName,
ClassNameUtil.className,
copyName
)
)
firClass.addDeclaration(
FirMemberFunctionImpl(
session, null, symbol, copyName,
Visibilities.PUBLIC, Modality.FINAL,
isExpect = false, isActual = false,
isOverride = false, isOperator = false,
isInfix = false, isInline = false,
isTailRec = false, isExternal = false,
isSuspend = false, receiverTypeRef = null,
returnTypeRef = firPrimaryConstructor.returnTypeRef//FirImplicitTypeRefImpl(session, this)
).apply {
val copyFunction = this
for (property in properties) {
val name = property.name
valueParameters += FirValueParameterImpl(
session, null, name,
property.returnTypeRef,
FirQualifiedAccessExpressionImpl(session, null).apply {
calleeReference = FirResolvedCallableReferenceImpl(session, null, name, property.symbol)
},
isCrossinline = false, isNoinline = false, isVararg = false
)
}
body = FirEmptyExpressionBlock(session)
}
)
}
}
@@ -22,17 +22,11 @@ import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.extractArgumentsFrom
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsStringWithoutBacktick
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.isExpression
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.joinTypeParameters
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.toDelegatedSelfType
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.toReturn
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.isClassLocal
import org.jetbrains.kotlin.fir.lightTree.converter.DataClassUtil.generateComponentFunctions
import org.jetbrains.kotlin.fir.lightTree.converter.DataClassUtil.generateCopyFunction
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast
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
@@ -49,9 +43,11 @@ import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.fir.builder.generateCopyFunction
import org.jetbrains.kotlin.fir.builder.generateComponentFunctions
class DeclarationsConverter(
private val session: FirSession,
session: FirSession,
private val stubMode: Boolean,
tree: FlyweightCapableTreeStructure<LighterASTNode>
) : BaseConverter(session, tree) {
@@ -70,11 +66,11 @@ class DeclarationsConverter(
val fileAnnotationList = mutableListOf<FirAnnotationCall>()
val importList = mutableListOf<FirImport>()
val firDeclarationList = mutableListOf<FirDeclaration>()
ClassNameUtil.packageFqName = FqName.ROOT
packageFqName = FqName.ROOT
file.forEachChildren {
when (it.tokenType) {
FILE_ANNOTATION_LIST -> fileAnnotationList += convertFileAnnotationList(it)
PACKAGE_DIRECTIVE -> ClassNameUtil.packageFqName = convertPackageName(it)
PACKAGE_DIRECTIVE -> packageFqName = convertPackageName(it)
IMPORT_LIST -> importList += convertImportDirectives(it)
CLASS -> firDeclarationList += convertClass(it)
FUN -> firDeclarationList += convertFunctionDeclaration(it)
@@ -88,7 +84,7 @@ class DeclarationsConverter(
session,
null,
fileName,
ClassNameUtil.packageFqName
packageFqName
)
firFile.annotations += fileAnnotationList
firFile.imports += importList
@@ -141,7 +137,7 @@ class DeclarationsConverter(
private fun convertImportAlias(importAlias: LighterASTNode): String? {
importAlias.forEachChildren {
when (it.tokenType) {
IDENTIFIER -> return it.getAsString()
IDENTIFIER -> return it.asText
}
}
@@ -157,7 +153,7 @@ class DeclarationsConverter(
var aliasName: String? = null
importDirective.forEachChildren {
when (it.tokenType) {
DOT_QUALIFIED_EXPRESSION, REFERENCE_EXPRESSION -> importedFqName = FqName(it.getAsString())
DOT_QUALIFIED_EXPRESSION, REFERENCE_EXPRESSION -> importedFqName = FqName(it.asText)
MUL -> isAllUnder = true
IMPORT_ALIAS -> aliasName = convertImportAlias(it)
}
@@ -337,7 +333,7 @@ class DeclarationsConverter(
CLASS_KEYWORD -> classKind = ClassKind.CLASS
INTERFACE_KEYWORD -> classKind = ClassKind.INTERFACE
OBJECT_KEYWORD -> classKind = ClassKind.OBJECT
IDENTIFIER -> identifier = it.getAsString()
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> firTypeParameters += convertTypeParameters(it)
PRIMARY_CONSTRUCTOR -> primaryConstructor = it
SUPER_TYPE_LIST -> convertDelegationSpecifiers(it).apply {
@@ -368,11 +364,11 @@ class DeclarationsConverter(
superTypeRefs.ifEmpty { superTypeRefs += defaultDelegatedSuperTypeRef }
val isLocal = isClassLocal(classNode) { getParent() }
return ClassNameUtil.withChildClassName(className) {
return withChildClassName(className) {
val firClass = FirClassImpl(
session,
null,
FirClassSymbol(ClassNameUtil.currentClassId),
FirClassSymbol(currentClassId),
className,
if (isLocal) Visibilities.LOCAL else modifiers.getVisibility(),
modifiers.getModality(),
@@ -393,7 +389,7 @@ class DeclarationsConverter(
session, className, modifiers, classKind,
primaryConstructor != null,
classBody.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(),
toDelegatedSelfType(firClass), delegatedSuperTypeRef ?: defaultDelegatedSuperTypeRef, superTypeCallEntry
null.toDelegatedSelfType(firClass), delegatedSuperTypeRef ?: defaultDelegatedSuperTypeRef, superTypeCallEntry
)
//parse primary constructor
val primaryConstructorWrapper = convertPrimaryConstructor(primaryConstructor, classWrapper)
@@ -405,7 +401,7 @@ class DeclarationsConverter(
//parse properties
properties += primaryConstructorWrapper.valueParameters
.filter { it.hasValOrVar() }
.map { it.toFirProperty() }
.map { it.toFirProperty(callableIdForName(it.firValueParameter.name)) }
firClass.addDeclarations(properties)
}
@@ -416,8 +412,9 @@ class DeclarationsConverter(
//parse data class
if (modifiers.isDataClass() && firPrimaryConstructor != null) {
generateComponentFunctions(session, firClass, properties)
generateCopyFunction(session, firClass, firPrimaryConstructor, properties)
val zippedParameters = MutableList(properties.size) { null }.zip(properties)
zippedParameters.generateComponentFunctions(session, firClass, packageFqName, Companion.className)
zippedParameters.generateCopyFunction(session, null, firClass, packageFqName, Companion.className, firPrimaryConstructor)
// TODO: equals, hashCode, toString
}
@@ -488,7 +485,7 @@ class DeclarationsConverter(
enumEntry.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.getAsString()
IDENTIFIER -> identifier = it.asText
INITIALIZER_LIST -> {
hasInitializerList = true
enumSuperTypeCallEntry += convertInitializerList(it)
@@ -498,11 +495,11 @@ class DeclarationsConverter(
}
val enumEntryName = identifier.nameAsSafeName()
return ClassNameUtil.withChildClassName(enumEntryName) {
return withChildClassName(enumEntryName) {
val firEnumEntry = FirEnumEntryImpl(
session,
null,
FirClassSymbol(ClassNameUtil.currentClassId),
FirClassSymbol(currentClassId),
enumEntryName
)
firEnumEntry.annotations += modifiers.annotations
@@ -517,7 +514,7 @@ class DeclarationsConverter(
session, enumEntryName, modifiers, ClassKind.ENUM_ENTRY,
hasPrimaryConstructor = true,
hasSecondaryConstructor = classBodyNode.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(),
delegatedSelfTypeRef = toDelegatedSelfType(firEnumEntry),
delegatedSelfTypeRef = null.toDelegatedSelfType(firEnumEntry),
delegatedSuperTypeRef = if (hasInitializerList) classWrapper.getFirUserTypeFromClassName() else defaultDelegatedSuperTypeRef,
superTypeCallEntry = enumSuperTypeCallEntry
)
@@ -594,7 +591,7 @@ class DeclarationsConverter(
FirPrimaryConstructorImpl(
session,
null,
FirConstructorSymbol(ClassNameUtil.callableIdForClassConstructor()),
FirConstructorSymbol(callableIdForClassConstructor()),
if (primaryConstructor != null) modifiers.getVisibility() else defaultVisibility,
modifiers.hasExpect(),
modifiers.hasActual(),
@@ -602,7 +599,7 @@ class DeclarationsConverter(
firDelegatedCall
).apply {
annotations += modifiers.annotations
this.typeParameters += ConverterUtil.typeParametersFromSelfType(classWrapper.delegatedSelfTypeRef)
this.typeParameters += typeParametersFromSelfType(classWrapper.delegatedSelfTypeRef)
this.valueParameters += valueParameters.map { it.firValueParameter }
}, valueParameters
)
@@ -652,7 +649,7 @@ class DeclarationsConverter(
val firConstructor = FirConstructorImpl(
session,
null,
FirConstructorSymbol(ClassNameUtil.callableIdForClassConstructor()),
FirConstructorSymbol(callableIdForClassConstructor()),
modifiers.getVisibility(),
modifiers.hasExpect(),
modifiers.hasActual(),
@@ -660,12 +657,12 @@ class DeclarationsConverter(
constructorDelegationCall
)
FunctionUtil.firFunctions += firConstructor
firFunctions += firConstructor
firConstructor.annotations += modifiers.annotations
firConstructor.typeParameters += ConverterUtil.typeParametersFromSelfType(delegatedSelfTypeRef)
firConstructor.typeParameters += typeParametersFromSelfType(delegatedSelfTypeRef)
firConstructor.valueParameters += firValueParameters.map { it.firValueParameter }
firConstructor.body = convertFunctionBody(block, null)
FunctionUtil.firFunctions.removeLast()
firFunctions.removeLast()
return firConstructor
}
@@ -681,12 +678,12 @@ class DeclarationsConverter(
val firValueArguments = mutableListOf<FirExpression>()
constructorDelegationCall.forEachChildren {
when (it.tokenType) {
CONSTRUCTOR_DELEGATION_REFERENCE -> if (it.getAsString() == "this") thisKeywordPresent = true
CONSTRUCTOR_DELEGATION_REFERENCE -> if (it.asText == "this") thisKeywordPresent = true
VALUE_ARGUMENT_LIST -> firValueArguments += expressionConverter.convertValueArguments(it)
}
}
val isImplicit = constructorDelegationCall.getAsString().isEmpty()
val isImplicit = constructorDelegationCall.asText.isEmpty()
val isThis = (isImplicit && classWrapper.hasPrimaryConstructor) || thisKeywordPresent
val delegatedType =
if (classWrapper.isObjectLiteral() || classWrapper.isInterface()) when {
@@ -717,18 +714,18 @@ class DeclarationsConverter(
typeAlias.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.getAsString()
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> firTypeParameters += convertTypeParameters(it)
TYPE_REFERENCE -> firType = convertType(it)
}
}
val typeAliasName = identifier.nameAsSafeName()
return ClassNameUtil.withChildClassName(typeAliasName) {
return withChildClassName(typeAliasName) {
return@withChildClassName FirTypeAliasImpl(
session,
null,
FirTypeAliasSymbol(ClassNameUtil.currentClassId),
FirTypeAliasSymbol(currentClassId),
typeAliasName,
modifiers.getVisibility(),
modifiers.hasExpect(),
@@ -760,7 +757,7 @@ class DeclarationsConverter(
property.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.getAsString()
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> firTypeParameters += convertTypeParameters(it)
COLON -> isReturnType = true
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
@@ -795,7 +792,7 @@ class DeclarationsConverter(
FirMemberPropertyImpl(
session,
null,
FirPropertySymbol(ClassNameUtil.callableIdForName(propertyName)),
FirPropertySymbol(callableIdForName(propertyName)),
propertyName,
modifiers.getVisibility(),
modifiers.getModality(),
@@ -848,7 +845,7 @@ class DeclarationsConverter(
entry.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.getAsString()
IDENTIFIER -> identifier = it.asText
TYPE_REFERENCE -> firType = convertType(it)
}
}
@@ -871,7 +868,7 @@ class DeclarationsConverter(
var block: LighterASTNode? = null
var expression: LighterASTNode? = null
getterOrSetter.forEachChildren {
if (it.getAsString() == "set") isGetter = false
if (it.asText == "set") isGetter = false
when (it.tokenType) {
SET_KEYWORD -> isGetter = false
MODIFIER_LIST -> modifiers = convertModifierList(it)
@@ -889,7 +886,7 @@ class DeclarationsConverter(
modifiers.getVisibility(),
returnType ?: if (isGetter) propertyTypeRef else implicitUnitType
)
FunctionUtil.firFunctions += firAccessor
firFunctions += firAccessor
firAccessor.annotations += modifiers.annotations
if (!isGetter) {
@@ -897,7 +894,7 @@ class DeclarationsConverter(
}
firAccessor.body = convertFunctionBody(block, expression)
FunctionUtil.firFunctions.removeLast()
firFunctions.removeLast()
return firAccessor
}
@@ -949,7 +946,7 @@ class DeclarationsConverter(
functionDeclaration.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.getAsString()
IDENTIFIER -> identifier = it.asText
TYPE_PARAMETER_LIST -> firTypeParameters += convertTypeParameters(it)
VALUE_PARAMETER_LIST -> valueParametersList = it //must convert later, because it can contains "return"
COLON -> isReturnType = true
@@ -976,7 +973,7 @@ class DeclarationsConverter(
FirMemberFunctionImpl(
session,
null,
FirNamedFunctionSymbol(ClassNameUtil.callableIdForName(functionName, isLocal)),
FirNamedFunctionSymbol(callableIdForName(functionName, isLocal)),
functionName,
if (isLocal) Visibilities.LOCAL else modifiers.getVisibility(),
modifiers.getModality(),
@@ -994,7 +991,7 @@ class DeclarationsConverter(
)
}
FunctionUtil.firFunctions += firFunction
firFunctions += firFunction
firFunction.annotations += modifiers.annotations
if (firFunction is FirMemberFunctionImpl) {
@@ -1004,7 +1001,7 @@ class DeclarationsConverter(
valueParametersList?.let { firFunction.valueParameters += convertValueParameters(it).map { it.firValueParameter } }
firFunction.body = convertFunctionBody(block, expression)
FunctionUtil.firFunctions.removeLast()
firFunctions.removeLast()
return firFunction
}
@@ -1035,7 +1032,7 @@ class DeclarationsConverter(
)
}
return if (!stubMode) {
val blockTree = LightTree2Fir.buildLightTreeBlockExpression(block.getAsString())
val blockTree = LightTree2Fir.buildLightTreeBlockExpression(block.asText)
return DeclarationsConverter(session, stubMode, blockTree).convertBlockExpression(blockTree.root)
} else {
FirSingleExpressionBlock(
@@ -1084,7 +1081,7 @@ class DeclarationsConverter(
val firValueArguments = mutableListOf<FirExpression>()
constructorInvocation.forEachChildren {
when (it.tokenType) {
CONSTRUCTOR_CALLEE -> if (it.getAsString().isNotEmpty()) firTypeRef = convertType(it) //is empty in enum entry constructor
CONSTRUCTOR_CALLEE -> if (it.asText.isNotEmpty()) firTypeRef = convertType(it) //is empty in enum entry constructor
VALUE_ARGUMENT_LIST -> firValueArguments += expressionConverter.convertValueArguments(it)
}
}
@@ -1149,7 +1146,7 @@ class DeclarationsConverter(
when (it.tokenType) {
//annotations will be saved later, on mapping stage with type parameters
ANNOTATION, ANNOTATION_ENTRY -> annotations += convertAnnotation(it)
REFERENCE_EXPRESSION -> identifier = it.getAsString()
REFERENCE_EXPRESSION -> identifier = it.asText
TYPE_REFERENCE -> firType = convertType(it)
}
}
@@ -1167,7 +1164,7 @@ class DeclarationsConverter(
typeParameter.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> typeParameterModifiers = convertTypeParameterModifiers(it)
IDENTIFIER -> identifier = it.getAsString()
IDENTIFIER -> identifier = it.asText
TYPE_REFERENCE -> firType = convertType(it)
}
}
@@ -1190,7 +1187,7 @@ class DeclarationsConverter(
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeRef
*/
fun convertType(type: LighterASTNode): FirTypeRef {
if (type.getAsString().isEmpty()) {
if (type.asText.isEmpty()) {
return FirErrorTypeRefImpl(session, null, "Unwrapped type is null")
}
var typeModifiers = TypeModifier(session) //TODO what with suspend?
@@ -1254,7 +1251,7 @@ class DeclarationsConverter(
userType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> simpleFirUserType = convertUserType(it) as? FirUserTypeRef //simple user type
REFERENCE_EXPRESSION -> identifier = it.getAsString()
REFERENCE_EXPRESSION -> identifier = it.asText
TYPE_ARGUMENT_LIST -> firTypeArguments += convertTypeArguments(it)
}
}
@@ -1363,7 +1360,7 @@ class DeclarationsConverter(
MODIFIER_LIST -> modifiers = convertModifierList(it)
VAL_KEYWORD -> isVal = true
VAR_KEYWORD -> isVar = true
IDENTIFIER -> identifier = it.getAsString()
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")
@@ -21,14 +21,13 @@ import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.labels.FirLabelImpl
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.extractArgumentsFrom
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsStringWithoutBacktick
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.isExpression
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.toReturn
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.pop
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast
import org.jetbrains.kotlin.fir.lightTree.converter.utils.*
import org.jetbrains.kotlin.fir.lightTree.converter.utils.bangBangToWhen
import org.jetbrains.kotlin.fir.lightTree.converter.utils.generateDestructuringBlock
import org.jetbrains.kotlin.fir.lightTree.converter.utils.getOperationSymbol
import org.jetbrains.kotlin.fir.lightTree.converter.utils.qualifiedAccessTokens
import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter
import org.jetbrains.kotlin.fir.lightTree.fir.WhenEntry
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
@@ -38,23 +37,25 @@ import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
import org.jetbrains.kotlin.resolve.constants.evaluate.*
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
class ExpressionsConverter(
val session: FirSession,
session: FirSession,
private val stubMode: Boolean,
tree: FlyweightCapableTreeStructure<LighterASTNode>,
private val declarationsConverter: DeclarationsConverter
) : BaseConverter(session, tree) {
inline fun <reified R : FirElement> LighterASTNode?.toFirExpression(errorReason: String = ""): R {
return this?.let { convertExpression(it, errorReason) } as? R ?: (FirErrorExpressionImpl(session, null, errorReason) as R)
}
inline fun <reified R : FirElement> getAsFirExpression(expression: LighterASTNode?, errorReason: String = ""): R {
return expression?.let { convertExpression(it, errorReason) } as? R ?: (FirErrorExpressionImpl(session, null, errorReason) as R)
}
@@ -64,7 +65,7 @@ class ExpressionsConverter(
if (!stubMode) {
return when (expression.tokenType) {
LAMBDA_EXPRESSION -> {
val lambdaTree = LightTree2Fir.buildLightTreeLambdaExpression(expression.getAsString())
val lambdaTree = LightTree2Fir.buildLightTreeLambdaExpression(expression.asText)
ExpressionsConverter(session, stubMode, lambdaTree, declarationsConverter).convertLambdaExpression(lambdaTree.root)
}
BINARY_EXPRESSION -> convertBinaryExpression(expression)
@@ -121,7 +122,7 @@ class ExpressionsConverter(
}
return FirAnonymousFunctionImpl(session, null, implicitType, implicitType).apply {
FunctionUtil.firFunctions += this
firFunctions += this
var destructuringBlock: FirExpression? = null
for (valueParameter in valueParameterList) {
val multiDeclaration = valueParameter.destructuringDeclaration
@@ -142,11 +143,11 @@ class ExpressionsConverter(
valueParameter.firValueParameter
}
}
label = FunctionUtil.firLabels.pop() ?: FunctionUtil.firFunctionCalls.lastOrNull()?.calleeReference?.name?.let {
label = firLabels.pop() ?: firFunctionCalls.lastOrNull()?.calleeReference?.name?.let {
FirLabelImpl(this@ExpressionsConverter.session, null, it.asString())
}
val bodyExpression = block?.let { declarationsConverter.convertBlockExpression(it) }
?: FirErrorExpressionImpl(session, null, "Lambda has no body")
?: FirErrorExpressionImpl(this@ExpressionsConverter.session, null, "Lambda has no body")
body = if (bodyExpression is FirBlockImpl) {
if (bodyExpression.statements.isEmpty()) {
bodyExpression.statements.add(FirUnitExpression(this@ExpressionsConverter.session, null))
@@ -161,7 +162,7 @@ class ExpressionsConverter(
FirSingleExpressionBlock(this@ExpressionsConverter.session, bodyExpression.toReturn())
}
FunctionUtil.firFunctions.removeLast()
firFunctions.removeLast()
}
}
@@ -178,7 +179,7 @@ class ExpressionsConverter(
when (it.tokenType) {
OPERATION_REFERENCE -> {
isLeftArgument = false
operationTokenName = it.getAsString()
operationTokenName = it.asText
}
else -> if (it.isExpression()) {
if (isLeftArgument) {
@@ -218,7 +219,7 @@ class ExpressionsConverter(
} else {
val firOperation = operationToken.toFirOperation()
if (firOperation in FirOperation.ASSIGNMENTS) {
return convertAssignment(leftArgNode, rightArgAsFir, firOperation)
return leftArgNode.generateAssignment(null, rightArgAsFir, firOperation) { toFirExpression() }
} else {
FirOperatorCallImpl(session, null, firOperation).apply {
arguments += getAsFirExpression<FirExpression>(leftArgNode, "No left operand")
@@ -238,7 +239,7 @@ class ExpressionsConverter(
lateinit var firType: FirTypeRef
binaryExpression.forEachChildren {
when (it.tokenType) {
OPERATION_REFERENCE -> operationTokenName = it.getAsString()
OPERATION_REFERENCE -> operationTokenName = it.asText
TYPE_REFERENCE -> firType = declarationsConverter.convertType(it)
else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it, "No left operand")
}
@@ -259,7 +260,7 @@ class ExpressionsConverter(
lateinit var firType: FirTypeRef
isExpression.forEachChildren {
when (it.tokenType) {
OPERATION_REFERENCE -> operationTokenName = it.getAsString()
OPERATION_REFERENCE -> operationTokenName = it.asText
TYPE_REFERENCE -> firType = declarationsConverter.convertType(it)
else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it, "No left operand")
}
@@ -276,19 +277,19 @@ class ExpressionsConverter(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitLabeledExpression
*/
private fun convertLabeledExpression(labeledExpression: LighterASTNode): FirElement {
val size = FunctionUtil.firLabels.size
val size = firLabels.size
var firExpression: FirElement? = null
labeledExpression.forEachChildren {
when (it.tokenType) {
LABEL_QUALIFIER -> FunctionUtil.firLabels += FirLabelImpl(session, null, it.toString().replace("@", ""))
LABEL_QUALIFIER -> firLabels += FirLabelImpl(session, null, it.toString().replace("@", ""))
BLOCK -> firExpression = declarationsConverter.convertBlock(it)
PROPERTY -> firExpression = declarationsConverter.convertPropertyDeclaration(it)
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
}
}
if (size != FunctionUtil.firLabels.size) {
FunctionUtil.firLabels.removeLast()
if (size != firLabels.size) {
firLabels.removeLast()
//println("Unused label: ${labeledExpression.getAsString()}")
}
return firExpression ?: FirErrorExpressionImpl(session, null, "Empty label")
@@ -304,7 +305,7 @@ class ExpressionsConverter(
var argument: LighterASTNode? = null
unaryExpression.forEachChildren {
when (it.tokenType) {
OPERATION_REFERENCE -> operationTokenName = it.getAsString()
OPERATION_REFERENCE -> operationTokenName = it.asText
else -> if (it.isExpression()) argument = it
}
}
@@ -318,10 +319,11 @@ class ExpressionsConverter(
return if (conventionCallName != null) {
if (operationToken in OperatorConventions.INCREMENT_OPERATIONS) {
return generateIncrementOrDecrementBlock(
null,
argument,
callName = conventionCallName,
prefix = unaryExpression.tokenType == PREFIX_EXPRESSION
)
) { toFirExpression() }
}
FirFunctionCallImpl(session, null).apply {
calleeReference = FirSimpleNamedReference(this@ExpressionsConverter.session, null, conventionCallName)
@@ -440,7 +442,7 @@ class ExpressionsConverter(
var additionalArgument: FirExpression? = null
callSuffix.forEachChildren {
when (it.tokenType) {
REFERENCE_EXPRESSION -> name = it.getAsString()
REFERENCE_EXPRESSION -> name = it.asText
TYPE_ARGUMENT_LIST -> firTypeArguments += declarationsConverter.convertTypeArguments(it)
VALUE_ARGUMENT_LIST, LAMBDA_ARGUMENT -> valueArguments += it
else -> if (it.tokenType != TokenType.ERROR_ELEMENT) additionalArgument =
@@ -458,119 +460,33 @@ class ExpressionsConverter(
else -> FirErrorNamedReference(this@ExpressionsConverter.session, null, "Call has no callee")
}
FunctionUtil.firFunctionCalls += this
firFunctionCalls += this
this.extractArgumentsFrom(valueArguments.flatMap { convertValueArguments(it) }, stubMode)
typeArguments += firTypeArguments
FunctionUtil.firFunctionCalls.removeLast()
firFunctionCalls.removeLast()
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseStringTemplate
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.toInterpolatingCall
*/
private fun convertStringTemplate(stringTemplate: LighterASTNode): FirExpression {
val sb = StringBuilder()
var hasExpressions = false
var result: FirExpression? = null
var callCreated = false
stringTemplate.forEachChildren(OPEN_QUOTE, CLOSING_QUOTE) {
val nextArgument = when (it.tokenType) {
LITERAL_STRING_TEMPLATE_ENTRY -> {
sb.append(it.getAsString())
FirConstExpressionImpl(session, null, IrConstKind.String, it.getAsString())
}
ESCAPE_STRING_TEMPLATE_ENTRY -> {
val escape = it.getAsString()
val unescaped = escapedStringToCharacter(escape)?.toString()
?: escape.replace("\\", "").replace("u", "\\u")
sb.append(unescaped)
FirConstExpressionImpl(session, null, IrConstKind.String, unescaped)
}
SHORT_STRING_TEMPLATE_ENTRY, LONG_STRING_TEMPLATE_ENTRY -> {
hasExpressions = true
convertShortOrLongStringTemplate(it)
}
else -> {
hasExpressions = true
FirErrorExpressionImpl(session, null, "Incorrect template entry: ${it.getAsString()}")
}
}
result = when {
result == null -> nextArgument
callCreated && result is FirStringConcatenationCallImpl -> (result as FirStringConcatenationCallImpl).apply {
//TODO smart cast to FirStringConcatenationCallImpl isn't working
arguments += nextArgument
}
else -> {
callCreated = true
FirStringConcatenationCallImpl(session, null).apply {
arguments += result!!
arguments += nextArgument
}
}
}
}
return if (hasExpressions) result!! else FirConstExpressionImpl(session, null, IrConstKind.String, sb.toString())
return stringTemplate.getChildrenAsArray().toInterpolatingCall(null) { convertShortOrLongStringTemplate(it) }
}
private fun convertShortOrLongStringTemplate(shortOrLongString: LighterASTNode): FirExpression {
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Incorrect template argument")
shortOrLongString.forEachChildren(LONG_TEMPLATE_ENTRY_START, LONG_TEMPLATE_ENTRY_END) {
firExpression = getAsFirExpression(it, "Incorrect template argument")
private fun LighterASTNode?.convertShortOrLongStringTemplate(errorReason: String): FirExpression {
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, errorReason)
this?.forEachChildren(LONG_TEMPLATE_ENTRY_START, LONG_TEMPLATE_ENTRY_END) {
firExpression = getAsFirExpression(it, errorReason)
}
return firExpression
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseLiteralConstant
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.generateConstantExpressionByLiteral
*/
private fun convertConstantExpression(constantExpression: LighterASTNode): FirExpression {
val type = constantExpression.tokenType
val text: String = constantExpression.getAsString()
val convertedText: Any? = when (type) {
INTEGER_CONSTANT, FLOAT_CONSTANT -> parseNumericLiteral(text, type)
BOOLEAN_CONSTANT -> parseBoolean(text)
else -> null
}
return when (type) {
INTEGER_CONSTANT ->
if (convertedText is Long &&
(hasLongSuffix(text) || hasUnsignedLongSuffix(text) || hasUnsignedSuffix(text) ||
convertedText > Int.MAX_VALUE || convertedText < Int.MIN_VALUE)
) {
FirConstExpressionImpl(
session, null, IrConstKind.Long, convertedText, "Incorrect long: $text"
)
} else if (convertedText is Number) {
// TODO: support byte / short
FirConstExpressionImpl(session, null, IrConstKind.Int, convertedText.toInt(), "Incorrect int: $text")
} else {
FirErrorExpressionImpl(session, null, reason = "Incorrect constant expression: $text")
}
FLOAT_CONSTANT ->
if (convertedText is Float) {
FirConstExpressionImpl(
session, null, IrConstKind.Float, convertedText, "Incorrect float: $text"
)
} else {
FirConstExpressionImpl(
session, null, IrConstKind.Double, convertedText as Double, "Incorrect double: $text"
)
}
CHARACTER_CONSTANT ->
FirConstExpressionImpl(
session, null, IrConstKind.Char, text.parseCharacter(), "Incorrect character: $text"
)
BOOLEAN_CONSTANT ->
FirConstExpressionImpl(session, null, IrConstKind.Boolean, convertedText as Boolean)
NULL ->
FirConstExpressionImpl(session, null, IrConstKind.Null, null)
else ->
throw AssertionError("Unknown literal type: $type, $text")
}
return generateConstantExpressionByLiteral(constantExpression)
}
/**
@@ -590,10 +506,10 @@ class ExpressionsConverter(
)
}
DESTRUCTURING_DECLARATION -> subjectExpression =
getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.getAsString()}")
getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.asText}")
WHEN_ENTRY -> whenEntries += convertWhenEntry(it)
else -> if (it.isExpression()) subjectExpression =
getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.getAsString()}")
getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.asText}")
}
}
@@ -742,7 +658,7 @@ class ExpressionsConverter(
private fun convertSimpleNameExpression(referenceExpression: LighterASTNode): FirQualifiedAccessExpression {
return FirQualifiedAccessExpressionImpl(session, null).apply {
calleeReference =
FirSimpleNamedReference(this@ExpressionsConverter.session, null, referenceExpression.getAsString().nameAsSafeName())
FirSimpleNamedReference(this@ExpressionsConverter.session, null, referenceExpression.asText.nameAsSafeName())
}
}
@@ -963,13 +879,13 @@ class ExpressionsConverter(
when (it.tokenType) {
CONTINUE_KEYWORD -> isBreak = false
//BREAK -> isBreak = true
LABEL_QUALIFIER -> labelName = it.getAsString().replace("@", "")
LABEL_QUALIFIER -> labelName = it.asText.replace("@", "")
}
}
return (if (isBreak) FirBreakExpressionImpl(session, null) else FirContinueExpressionImpl(session, null)).apply {
target = FirLoopTarget(labelName)
val lastLoop = FunctionUtil.firLoops.lastOrNull()
val lastLoop = firLoops.lastOrNull()
if (labelName == null) {
if (lastLoop != null) {
target.bind(lastLoop)
@@ -977,7 +893,7 @@ class ExpressionsConverter(
target.bind(FirErrorLoop(this@ExpressionsConverter.session, null, "Cannot bind unlabeled jump to a loop"))
}
} else {
for (firLoop in FunctionUtil.firLoops.asReversed()) {
for (firLoop in firLoops.asReversed()) {
if (firLoop.label?.name == labelName) {
target.bind(firLoop)
return this
@@ -1002,7 +918,7 @@ class ExpressionsConverter(
}
}
return firExpression.toReturn(labelName)
return firExpression.toReturn(labelName = labelName)
}
/**
@@ -1023,12 +939,7 @@ class ExpressionsConverter(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitThisExpression
*/
private fun convertThisExpression(thisExpression: LighterASTNode): FirQualifiedAccessExpression {
var label: String? = null
thisExpression.forEachChildren {
when (it.tokenType) {
LABEL_QUALIFIER -> label = it.getAsString().replaceFirst("@", "")
}
}
val label: String? = thisExpression.getLabelName()
return FirQualifiedAccessExpressionImpl(session, null).apply {
calleeReference = FirExplicitThisReference(this@ExpressionsConverter.session, null, label)
@@ -1076,7 +987,7 @@ class ExpressionsConverter(
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Argument is absent")
valueArgument.forEachChildren {
when (it.tokenType) {
VALUE_ARGUMENT_NAME -> identifier = it.getAsString()
VALUE_ARGUMENT_NAME -> identifier = it.asText
MUL -> isSpread = true
STRING_TEMPLATE -> firExpression = convertStringTemplate(it)
is KtConstantExpressionElementType -> firExpression = convertConstantExpression(it)
@@ -1089,22 +1000,4 @@ class ExpressionsConverter(
else -> firExpression
}
}
/**
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.initializeLValue
*/
fun convertLValue(leftArgNode: LighterASTNode?, container: FirModifiableQualifiedAccess<*>): FirReference {
return when (leftArgNode?.tokenType) {
null -> FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode?.tokenType}")
THIS_EXPRESSION -> convertThisExpression(leftArgNode).calleeReference
REFERENCE_EXPRESSION -> FirSimpleNamedReference(session, null, leftArgNode.getAsString().nameAsSafeName())
in qualifiedAccessTokens -> (getAsFirExpression<FirExpression>(leftArgNode) as? FirQualifiedAccess)?.let { firQualifiedAccess ->
container.explicitReceiver = firQualifiedAccess.explicitReceiver
container.safe = firQualifiedAccess.safe
return@let firQualifiedAccess.calleeReference
} ?: FirErrorNamedReference(session, null, "Unsupported qualified LValue: ${leftArgNode.getAsString()}")
PARENTHESIZED -> convertLValue(leftArgNode.getExpressionInParentheses(), container)
else -> FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode.tokenType}")
}
}
}
@@ -5,29 +5,29 @@
package org.jetbrains.kotlin.fir.lightTree.converter.utils
import com.intellij.lang.LighterASTNode
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION
import org.jetbrains.kotlin.KtNodeTypes.SAFE_ACCESS_EXPRESSION
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.*
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.builder.generateNotNullOrOther
import org.jetbrains.kotlin.fir.builder.generateResolvedAccessExpression
import org.jetbrains.kotlin.fir.declarations.impl.FirVariableImpl
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName
import org.jetbrains.kotlin.fir.lightTree.converter.ExpressionsConverter
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.pop
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirVariable
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirComponentCallImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirThrowExpressionImpl
import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.lexer.KtTokens.AS_SAFE
import org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER
import org.jetbrains.kotlin.parsing.KotlinExpressionParsing
import org.jetbrains.kotlin.util.OperatorNameConventions
val qualifiedAccessTokens = TokenSet.create(DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION)
@@ -39,118 +39,6 @@ fun String.getOperationSymbol(): IElementType {
return IDENTIFIER
}
fun ExpressionsConverter.convertAssignment(
leftArgNode: LighterASTNode?,
rightArgAsFir: FirExpression,
operation: FirOperation
): FirStatement {
if (leftArgNode != null && leftArgNode.tokenType == PARENTHESIZED) {
return convertAssignment(leftArgNode.getExpressionInParentheses(), rightArgAsFir, operation)
}
if (leftArgNode != null && leftArgNode.tokenType == ARRAY_ACCESS_EXPRESSION) {
val arrayAccessFunctionCall = getAsFirExpression(leftArgNode) as FirFunctionCall
val firArrayExpression = arrayAccessFunctionCall.explicitReceiver
?: FirErrorExpressionImpl(session, null, "No array expression")
val arraySet = if (operation != FirOperation.ASSIGN) {
FirArraySetCallImpl(session, null, rightArgAsFir, operation).apply {
indexes += arrayAccessFunctionCall.arguments
}
} else {
return FirFunctionCallImpl(session, null).apply {
calleeReference = FirSimpleNamedReference(this@convertAssignment.session, null, OperatorNameConventions.SET)
explicitReceiver = firArrayExpression
arguments += arrayAccessFunctionCall.arguments
arguments += rightArgAsFir
}
}
if (leftArgNode.getChildNodesByType(REFERENCE_EXPRESSION).isNotEmpty()) {
return arraySet.apply {
lValue = (firArrayExpression as FirQualifiedAccess).calleeReference
}
}
return FirBlockImpl(this@convertAssignment.session, null).apply {
val name = Name.special("<array-set>")
statements += generateTemporaryVariable(this@convertAssignment.session, null, name, firArrayExpression)
statements += arraySet.apply { lValue = FirSimpleNamedReference(this@convertAssignment.session, null, name) }
}
}
if (operation != FirOperation.ASSIGN &&
leftArgNode?.tokenType != REFERENCE_EXPRESSION && leftArgNode?.tokenType != THIS_EXPRESSION &&
(leftArgNode?.tokenType !in qualifiedAccessTokens || getSelectorType(leftArgNode.getChildrenAsArray()) != REFERENCE_EXPRESSION)
) {
return FirBlockImpl(session, null).apply {
val name = Name.special("<complex-set>")
statements += generateTemporaryVariable(
this@convertAssignment.session, null, name, getAsFirExpression(leftArgNode, "No LValue in assignment")
)
statements += FirVariableAssignmentImpl(this@convertAssignment.session, null, rightArgAsFir, operation).apply {
lValue = FirSimpleNamedReference(this@convertAssignment.session, null, name)
}
}
}
return FirVariableAssignmentImpl(session, null, rightArgAsFir, operation).apply {
lValue = convertLValue(leftArgNode, this)
}
}
fun ExpressionsConverter.generateIncrementOrDecrementBlock(
argument: LighterASTNode?,
callName: Name,
prefix: Boolean
): FirExpression {
if (argument == null) {
return FirErrorExpressionImpl(session, null, "Inc/dec without operand")
}
return FirBlockImpl(session, null).apply {
val tempName = Name.special("<unary>")
val temporaryVariable = generateTemporaryVariable(
this@generateIncrementOrDecrementBlock.session, null, tempName, getAsFirExpression(argument, "Incorrect expression inside inc/dec")
)
statements += temporaryVariable
val resultName = Name.special("<unary-result>")
val resultInitializer = FirFunctionCallImpl(this@generateIncrementOrDecrementBlock.session, null).apply {
this.calleeReference = FirSimpleNamedReference(this@generateIncrementOrDecrementBlock.session, null, callName)
this.explicitReceiver = generateResolvedAccessExpression(
this@generateIncrementOrDecrementBlock.session, null, temporaryVariable
)
}
val resultVar = generateTemporaryVariable(this@generateIncrementOrDecrementBlock.session, null, resultName, resultInitializer)
val assignment = convertAssignment(
argument,
if (prefix && argument.tokenType != REFERENCE_EXPRESSION)
generateResolvedAccessExpression(this@generateIncrementOrDecrementBlock.session, null, resultVar)
else
resultInitializer,
FirOperation.ASSIGN
)
fun appendAssignment() {
if (assignment is FirBlock) {
statements += assignment.statements
} else {
statements += assignment
}
}
if (prefix) {
if (argument.tokenType != REFERENCE_EXPRESSION) {
statements += resultVar
appendAssignment()
statements += generateResolvedAccessExpression(this@generateIncrementOrDecrementBlock.session, null, resultVar)
} else {
appendAssignment()
statements += generateAccessExpression(
this@generateIncrementOrDecrementBlock.session, null, argument.getAsString().nameAsSafeName()
)
}
} else {
appendAssignment()
statements += generateResolvedAccessExpression(this@generateIncrementOrDecrementBlock.session, null, temporaryVariable)
}
}
}
fun generateDestructuringBlock(
session: FirSession,
multiDeclaration: DestructuringDeclaration,
@@ -186,23 +74,3 @@ fun bangBangToWhen(session: FirSession, baseExpression: FirExpression): FirWhenE
), "bangbang", null
)
}
private fun getSelectorType(qualifiedAccessChildren: Array<LighterASTNode?>): IElementType? {
var isSelector = false
qualifiedAccessChildren.forEach {
if (it == null) return null
when (it.tokenType) {
DOT, SAFE_ACCESS -> isSelector = true
else -> if (isSelector) return it.tokenType
}
}
return null
}
fun FirAbstractLoop.configure(generateBlock: () -> FirBlock): FirAbstractLoop {
label = FunctionUtil.firLabels.pop()
FunctionUtil.firLoops += this
block = generateBlock()
FunctionUtil.firLoops.removeLast()
return this
}
@@ -13,9 +13,9 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirMemberPropertyImpl
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImpl
import org.jetbrains.kotlin.fir.lightTree.converter.ClassNameUtil
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier
import org.jetbrains.kotlin.fir.references.FirPropertyFromParameterCallableReference
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
@@ -32,7 +32,7 @@ class ValueParameter(
return isVal || isVar
}
fun toFirProperty(): FirProperty {
fun toFirProperty(callableId: CallableId): FirProperty {
val name = this.firValueParameter.name
var type = this.firValueParameter.returnTypeRef
if (type is FirImplicitTypeRef) {
@@ -42,7 +42,7 @@ class ValueParameter(
return FirMemberPropertyImpl(
this.firValueParameter.session,
null,
FirPropertySymbol(ClassNameUtil.callableIdForName(name)),
FirPropertySymbol(callableId),
name,
modifiers.getVisibility(),
modifiers.getModality(),
@@ -0,0 +1,441 @@
/*
* Copyright 2010-2019 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.builder
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.fir.FirFunctionTarget
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirReference
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirExplicitThisReference
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.lexer.KtTokens.CLOSING_QUOTE
import org.jetbrains.kotlin.lexer.KtTokens.OPEN_QUOTE
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.constants.evaluate.*
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
//T can be either PsiElement, or LighterASTNode
abstract class BaseFirBuilder<T>(val session: FirSession) {
protected val implicitUnitType = FirImplicitUnitTypeRef(session, null)
protected val implicitAnyType = FirImplicitAnyTypeRef(session, null)
protected val implicitEnumType = FirImplicitEnumTypeRef(session, null)
protected val implicitAnnotationType = FirImplicitAnnotationTypeRef(session, null)
abstract val T.elementType: IElementType
abstract val T.asText: String
abstract val T.unescapedValue: String
abstract fun T.getReferencedNameAsName(): Name
abstract fun T.getLabelName(): String?
abstract fun T.getExpressionInParentheses(): T?
abstract fun T.getChildNodeByType(type: IElementType): T?
abstract val T?.selectorExpression: T?
/**** Class name utils ****/
// var packageFqName: FqName = FqName.ROOT
// var className: FqName = FqName.ROOT
// val currentClassId get() = ClassId(packageFqName, className, false)
inline fun <T> withChildClassName(name: Name, l: () -> T): T {
className = className.child(name)
val t = l()
className = className.parent()
return t
}
fun callableIdForName(name: Name, local: Boolean = false) =
when {
local -> CallableId(name)
className == FqName.ROOT -> CallableId(packageFqName, name)
else -> CallableId(packageFqName, className, name)
}
fun callableIdForClassConstructor() =
if (className == FqName.ROOT) CallableId(packageFqName, Name.special("<anonymous-init>"))
else CallableId(packageFqName, className, className.shortName())
/**** Function utils ****/
companion object {
val firFunctions = mutableListOf<FirFunction>()
val firFunctionCalls = mutableListOf<FirFunctionCall>()
val firLabels = mutableListOf<FirLabel>()
val firLoops = mutableListOf<FirLoop>()
lateinit var packageFqName: FqName
var className: FqName = FqName.ROOT
val currentClassId get() = ClassId(packageFqName, className, false)
}
fun <T> MutableList<T>.removeLast() {
removeAt(size - 1)
}
fun <T> MutableList<T>.pop(): T? {
val result = lastOrNull()
if (result != null) {
removeAt(size - 1)
}
return result
}
/**** Common utils ****/
fun FirExpression.toReturn(basePsi: PsiElement? = psi, labelName: String? = null): FirReturnExpression {
return FirReturnExpressionImpl(
this@BaseFirBuilder.session,
basePsi,
this
).apply {
target = FirFunctionTarget(labelName)
val lastFunction = firFunctions.lastOrNull()
if (labelName == null) {
if (lastFunction != null) {
target.bind(lastFunction)
} else {
target.bind(FirErrorFunction(this@BaseFirBuilder.session, psi, "Cannot bind unlabeled return to a function"))
}
} else {
for (firFunction in firFunctions.asReversed()) {
when (firFunction) {
is FirAnonymousFunction -> {
if (firFunction.label?.name == labelName) {
target.bind(firFunction)
return@apply
}
}
is FirNamedFunction -> {
if (firFunction.name.asString() == labelName) {
target.bind(firFunction)
return@apply
}
}
}
}
target.bind(FirErrorFunction(this@BaseFirBuilder.session, psi, "Cannot bind label $labelName to a function"))
}
}
}
fun KtClassOrObject?.toDelegatedSelfType(firClass: FirRegularClass): FirTypeRef {
val typeParameters = firClass.typeParameters.map {
FirTypeParameterImpl(session, it.psi, FirTypeParameterSymbol(), it.name, Variance.INVARIANT, false).apply {
this.bounds += it.bounds
}
}
return FirResolvedTypeRefImpl(
session,
this,
ConeClassTypeImpl(
firClass.symbol.toLookupTag(),
typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
false
)
)
}
fun typeParametersFromSelfType(delegatedSelfTypeRef: FirTypeRef): List<FirTypeParameter> {
return delegatedSelfTypeRef.coneTypeSafe<ConeKotlinType>()
?.typeArguments
?.map { ((it as ConeTypeParameterType).lookupTag.symbol as FirTypeParameterSymbol).fir }
?: emptyList()
}
fun FirAbstractLoop.configure(generateBlock: () -> FirBlock): FirAbstractLoop {
label = firLabels.pop()
firLoops += this
block = generateBlock()
firLoops.removeLast()
return this
}
/**** Conversion utils ****/
private fun <T> T.getPsiOrNull(): PsiElement? {
return if (this is PsiElement) this else null
}
fun generateConstantExpressionByLiteral(expression: T): FirExpression {
val type = expression.elementType
val text: String = expression.asText
val convertedText: Any? = when (type) {
INTEGER_CONSTANT, FLOAT_CONSTANT -> parseNumericLiteral(text, type)
BOOLEAN_CONSTANT -> parseBoolean(text)
else -> null
}
return when (type) {
INTEGER_CONSTANT ->
if (convertedText is Long &&
(hasLongSuffix(text) || hasUnsignedLongSuffix(text) || hasUnsignedSuffix(text) ||
convertedText > Int.MAX_VALUE || convertedText < Int.MIN_VALUE)
) {
FirConstExpressionImpl(
session, expression.getPsiOrNull(), IrConstKind.Long, convertedText, "Incorrect long: $text"
)
} else if (convertedText is Number) {
// TODO: support byte / short
FirConstExpressionImpl(session, expression.getPsiOrNull(), IrConstKind.Int, convertedText.toInt(), "Incorrect int: $text")
} else {
FirErrorExpressionImpl(session, expression.getPsiOrNull(), reason = "Incorrect constant expression: $text")
}
FLOAT_CONSTANT ->
if (convertedText is Float) {
FirConstExpressionImpl(
session, expression.getPsiOrNull(), IrConstKind.Float, convertedText, "Incorrect float: $text"
)
} else {
FirConstExpressionImpl(
session, expression.getPsiOrNull(), IrConstKind.Double, convertedText as Double, "Incorrect double: $text"
)
}
CHARACTER_CONSTANT ->
FirConstExpressionImpl(
session, expression.getPsiOrNull(), IrConstKind.Char, text.parseCharacter(), "Incorrect character: $text"
)
BOOLEAN_CONSTANT ->
FirConstExpressionImpl(session, expression.getPsiOrNull(), IrConstKind.Boolean, convertedText as Boolean)
NULL ->
FirConstExpressionImpl(session, expression.getPsiOrNull(), IrConstKind.Null, null)
else ->
throw AssertionError("Unknown literal type: $type, $text")
}
}
fun Array<out T?>.toInterpolatingCall(
base: KtStringTemplateExpression?,
convertTemplateEntry: T?.(String) -> FirExpression
): FirExpression {
val sb = StringBuilder()
var hasExpressions = false
var result: FirExpression? = null
var callCreated = false
L@ for (entry in this) {
if (entry == null) continue
val nextArgument = when (entry.elementType) {
OPEN_QUOTE, CLOSING_QUOTE -> continue@L
LITERAL_STRING_TEMPLATE_ENTRY -> {
sb.append(entry.asText)
FirConstExpressionImpl(session, entry.getPsiOrNull(), IrConstKind.String, entry.asText)
}
ESCAPE_STRING_TEMPLATE_ENTRY -> {
sb.append(entry.unescapedValue)
FirConstExpressionImpl(session, entry.getPsiOrNull(), IrConstKind.String, entry.unescapedValue)
}
SHORT_STRING_TEMPLATE_ENTRY, LONG_STRING_TEMPLATE_ENTRY -> {
hasExpressions = true
entry.convertTemplateEntry("Incorrect template argument")
}
else -> {
hasExpressions = true
FirErrorExpressionImpl(
session, entry.getPsiOrNull(), "Incorrect template entry: ${entry.asText}"
)
}
}
result = when {
result == null -> nextArgument
callCreated && result is FirStringConcatenationCallImpl -> result.apply {
arguments += nextArgument
}
else -> {
callCreated = true
FirStringConcatenationCallImpl(session, base).apply {
arguments += result!!
arguments += nextArgument
}
}
}
}
return if (hasExpressions) result!! else FirConstExpressionImpl(session, base, IrConstKind.String, sb.toString())
}
/**
* given:
* argument++
*
* result:
* {
* val <unary> = argument
* argument = <unary>.inc()
* ^<unary>
* }
*
* given:
* ++argument
*
* result:
* {
* val <unary> = argument
* argument = <unary>.inc()
* ^argument
* }
*
*/
// TODO: Refactor, support receiver capturing in case of a.b
fun generateIncrementOrDecrementBlock(
baseExpression: KtUnaryExpression?,
argument: T?,
callName: Name,
prefix: Boolean,
convert: T.() -> FirExpression
): FirExpression {
if (argument == null) {
return FirErrorExpressionImpl(session, argument, "Inc/dec without operand")
}
return FirBlockImpl(session, baseExpression).apply {
val tempName = Name.special("<unary>")
val temporaryVariable = generateTemporaryVariable(this@BaseFirBuilder.session, baseExpression, tempName, argument.convert())
statements += temporaryVariable
val resultName = Name.special("<unary-result>")
val resultInitializer = FirFunctionCallImpl(this@BaseFirBuilder.session, baseExpression).apply {
this.calleeReference = FirSimpleNamedReference(this@BaseFirBuilder.session, baseExpression?.operationReference, callName)
this.explicitReceiver = generateResolvedAccessExpression(this@BaseFirBuilder.session, baseExpression, temporaryVariable)
}
val resultVar = generateTemporaryVariable(this@BaseFirBuilder.session, baseExpression, resultName, resultInitializer)
val assignment = argument.generateAssignment(
baseExpression,
if (prefix && argument.elementType != REFERENCE_EXPRESSION)
generateResolvedAccessExpression(this@BaseFirBuilder.session, baseExpression, resultVar)
else
resultInitializer,
FirOperation.ASSIGN, convert
)
fun appendAssignment() {
if (assignment is FirBlock) {
statements += assignment.statements
} else {
statements += assignment
}
}
if (prefix) {
if (argument.elementType != REFERENCE_EXPRESSION) {
statements += resultVar
appendAssignment()
statements += generateResolvedAccessExpression(this@BaseFirBuilder.session, baseExpression, resultVar)
} else {
appendAssignment()
statements += generateAccessExpression(this@BaseFirBuilder.session, baseExpression, argument.getReferencedNameAsName())
}
} else {
appendAssignment()
statements += generateResolvedAccessExpression(this@BaseFirBuilder.session, baseExpression, temporaryVariable)
}
}
}
fun FirModifiableQualifiedAccess<*>.initializeLValue(
left: T?,
convertQualified: T.() -> FirQualifiedAccess?
): FirReference {
val tokenType = left?.elementType
if (left != null) {
when (tokenType) {
REFERENCE_EXPRESSION -> {
return FirSimpleNamedReference(this@BaseFirBuilder.session, left.getPsiOrNull(), left.getReferencedNameAsName())
}
THIS_EXPRESSION -> {
return FirExplicitThisReference(this@BaseFirBuilder.session, left.getPsiOrNull(), left.getLabelName())
}
DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION -> {
val firMemberAccess = left.convertQualified()
return if (firMemberAccess != null) {
explicitReceiver = firMemberAccess.explicitReceiver
safe = firMemberAccess.safe
firMemberAccess.calleeReference
} else {
FirErrorNamedReference(
this@BaseFirBuilder.session, left.getPsiOrNull(), "Unsupported qualified LValue: ${left.asText}"
)
}
}
PARENTHESIZED -> {
return initializeLValue(left.getExpressionInParentheses(), convertQualified)
}
}
}
return FirErrorNamedReference(this@BaseFirBuilder.session, left.getPsiOrNull(), "Unsupported LValue: $tokenType")
}
fun T?.generateAssignment(
psi: PsiElement?,
value: FirExpression,
operation: FirOperation,
convert: T.() -> FirExpression
): FirStatement {
val tokenType = this?.elementType
if (tokenType == PARENTHESIZED) {
return this!!.getExpressionInParentheses().generateAssignment(psi, value, operation, convert)
}
if (tokenType == ARRAY_ACCESS_EXPRESSION) {
val firArrayAccess = this!!.convert() as FirFunctionCallImpl
val arraySet = if (operation != FirOperation.ASSIGN) {
FirArraySetCallImpl(session, psi, value, operation).apply {
indexes += firArrayAccess.arguments
}
} else {
return firArrayAccess.apply {
calleeReference = FirSimpleNamedReference(this@BaseFirBuilder.session, psi, OperatorNameConventions.SET)
arguments += value
}
}
val arrayExpression = this.getChildNodeByType(REFERENCE_EXPRESSION)
if (arrayExpression != null) {
return arraySet.apply {
lValue = initializeLValue(arrayExpression) { convert() as? FirQualifiedAccess }
}
}
return FirBlockImpl(session, arrayExpression).apply {
val name = Name.special("<array-set>")
statements += generateTemporaryVariable(
this@BaseFirBuilder.session, this@generateAssignment.getPsiOrNull(), name, firArrayAccess.explicitReceiver!!
)
statements += arraySet.apply { lValue = FirSimpleNamedReference(this@BaseFirBuilder.session, arrayExpression, name) }
}
}
if (operation != FirOperation.ASSIGN &&
tokenType != REFERENCE_EXPRESSION && tokenType != THIS_EXPRESSION &&
((tokenType != DOT_QUALIFIED_EXPRESSION && tokenType != SAFE_ACCESS_EXPRESSION) || this.selectorExpression?.elementType != REFERENCE_EXPRESSION)
) {
return FirBlockImpl(session, this.getPsiOrNull()).apply {
val name = Name.special("<complex-set>")
statements += generateTemporaryVariable(
this@BaseFirBuilder.session, this@generateAssignment.getPsiOrNull(), name,
this@generateAssignment?.convert()
?: FirErrorExpressionImpl(this@BaseFirBuilder.session, this.getPsiOrNull(), "No LValue in assignment")
)
statements += FirVariableAssignmentImpl(this@BaseFirBuilder.session, psi, value, operation).apply {
lValue = FirSimpleNamedReference(this@BaseFirBuilder.session, this.getPsiOrNull(), name)
}
}
}
return FirVariableAssignmentImpl(session, psi, value, operation).apply {
lValue = initializeLValue(this@generateAssignment) { convert() as? FirQualifiedAccess }
}
}
}
@@ -102,53 +102,6 @@ internal fun translateEscape(c: Char): Char? =
else -> null
}
internal fun generateConstantExpressionByLiteral(expression: KtConstantExpression): FirExpression {
val type = expression.node.elementType
val text: String = expression.text
val convertedText: Any? = when (type) {
KtNodeTypes.INTEGER_CONSTANT, KtNodeTypes.FLOAT_CONSTANT -> parseNumericLiteral(text, type)
KtNodeTypes.BOOLEAN_CONSTANT -> parseBoolean(text)
else -> null
}
return when (type) {
KtNodeTypes.INTEGER_CONSTANT ->
if (convertedText is Long &&
(hasLongSuffix(text) || hasUnsignedLongSuffix(text) || hasUnsignedSuffix(text) ||
convertedText > Int.MAX_VALUE || convertedText < Int.MIN_VALUE)
) {
FirConstExpressionImpl(
expression, IrConstKind.Long, convertedText, "Incorrect long: $text"
)
} else if (convertedText is Number) {
// TODO: support byte / short
FirConstExpressionImpl(expression, IrConstKind.Int, convertedText.toInt(), "Incorrect int: $text")
} else {
FirErrorExpressionImpl(expression, reason = "Incorrect constant expression: $text")
}
KtNodeTypes.FLOAT_CONSTANT ->
if (convertedText is Float) {
FirConstExpressionImpl(
expression, IrConstKind.Float, convertedText, "Incorrect float: $text"
)
} else {
FirConstExpressionImpl(
expression, IrConstKind.Double, convertedText as Double, "Incorrect double: $text"
)
}
KtNodeTypes.CHARACTER_CONSTANT ->
FirConstExpressionImpl(
expression, IrConstKind.Char, text.parseCharacter(), "Incorrect character: $text"
)
KtNodeTypes.BOOLEAN_CONSTANT ->
FirConstExpressionImpl(expression, IrConstKind.Boolean, convertedText as Boolean)
KtNodeTypes.NULL ->
FirConstExpressionImpl(expression, IrConstKind.Null, null)
else ->
throw AssertionError("Unknown literal type: $type, $text")
}
}
fun IElementType.toBinaryName(): Name? {
return OperatorConventions.BINARY_OPERATION_NAMES[this]
}
@@ -281,53 +234,6 @@ internal fun Array<KtWhenCondition>.toFirWhenCondition(
return firCondition!!
}
internal fun Array<KtStringTemplateEntry>.toInterpolatingCall(
base: KtStringTemplateExpression,
convert: KtExpression?.(String) -> FirExpression
): FirExpression {
val sb = StringBuilder()
var hasExpressions = false
var result: FirExpression? = null
var callCreated = false
for (entry in this) {
val nextArgument = when (entry) {
is KtLiteralStringTemplateEntry -> {
sb.append(entry.text)
FirConstExpressionImpl(entry, IrConstKind.String, entry.text)
}
is KtEscapeStringTemplateEntry -> {
sb.append(entry.unescapedValue)
FirConstExpressionImpl(entry, IrConstKind.String, entry.unescapedValue)
}
is KtStringTemplateEntryWithExpression -> {
val innerExpression = entry.expression
hasExpressions = true
innerExpression.convert("Incorrect template argument")
}
else -> {
hasExpressions = true
FirErrorExpressionImpl(
entry, "Incorrect template entry: ${entry.text}"
)
}
}
result = when {
result == null -> nextArgument
callCreated && result is FirStringConcatenationCallImpl -> result.apply {
arguments += nextArgument
}
else -> {
callCreated = true
FirStringConcatenationCallImpl(base).apply {
arguments += result!!
arguments += nextArgument
}
}
}
}
return if (hasExpressions) result!! else FirConstExpressionImpl(base, IrConstKind.String, sb.toString())
}
fun FirExpression.generateContainsOperation(
argument: FirExpression,
inverted: Boolean,
@@ -346,85 +252,6 @@ fun FirExpression.generateContainsOperation(
}
}
/**
* given:
* argument++
*
* result:
* {
* val <unary> = argument
* argument = <unary>.inc()
* ^<unary>
* }
*
* given:
* ++argument
*
* result:
* {
* val <unary> = argument
* argument = <unary>.inc()
* ^argument
* }
*
*/
// TODO: Refactor, support receiver capturing in case of a.b
internal fun generateIncrementOrDecrementBlock(
session: FirSession,
baseExpression: KtUnaryExpression,
argument: KtExpression?,
callName: Name,
prefix: Boolean,
convert: KtExpression.() -> FirExpression
): FirExpression {
if (argument == null) {
return FirErrorExpressionImpl(argument, "Inc/dec without operand")
}
return FirBlockImpl(baseExpression).apply {
val tempName = Name.special("<unary>")
val temporaryVariable = generateTemporaryVariable(session, baseExpression, tempName, argument.convert())
statements += temporaryVariable
val resultName = Name.special("<unary-result>")
val resultInitializer = FirFunctionCallImpl(baseExpression).apply {
this.calleeReference = FirSimpleNamedReference(baseExpression.operationReference, callName)
this.explicitReceiver = generateResolvedAccessExpression(baseExpression, temporaryVariable)
}
val resultVar = generateTemporaryVariable(session, baseExpression, resultName, resultInitializer)
val assignment = argument.generateAssignment(
session, baseExpression,
if (prefix && argument !is KtSimpleNameExpression)
generateResolvedAccessExpression(baseExpression, resultVar)
else
resultInitializer,
FirOperation.ASSIGN, convert
)
fun appendAssignment() {
if (assignment is FirBlock) {
statements += assignment.statements
} else {
statements += assignment
}
}
if (prefix) {
if (argument !is KtSimpleNameExpression) {
statements += resultVar
appendAssignment()
statements += generateResolvedAccessExpression(baseExpression, resultVar)
} else {
appendAssignment()
statements += generateAccessExpression(baseExpression, argument.getReferencedNameAsName())
}
} else {
appendAssignment()
statements += generateResolvedAccessExpression(baseExpression, temporaryVariable)
}
}
}
fun generateAccessExpression(psi: PsiElement?, name: Name): FirQualifiedAccessExpression =
FirQualifiedAccessExpressionImpl(psi).apply {
calleeReference = FirSimpleNamedReference(psi, name)
@@ -472,164 +299,3 @@ fun generateTemporaryVariable(
fun generateTemporaryVariable(
session: FirSession, psi: PsiElement?, specialName: String, initializer: FirExpression
): FirVariable<*> = generateTemporaryVariable(session, psi, Name.special("<$specialName>"), initializer)
private fun FirModifiableQualifiedAccess<*>.initializeLValue(
left: KtExpression?,
convertQualified: KtQualifiedExpression.() -> FirQualifiedAccess?
): FirReference {
return when (left) {
is KtSimpleNameExpression -> {
FirSimpleNamedReference(left, left.getReferencedNameAsName())
}
is KtThisExpression -> {
FirExplicitThisReference(left, left.getLabelName())
}
is KtQualifiedExpression -> {
val firMemberAccess = left.convertQualified()
if (firMemberAccess != null) {
explicitReceiver = firMemberAccess.explicitReceiver
safe = firMemberAccess.safe
firMemberAccess.calleeReference
} else {
FirErrorNamedReference(left, "Unsupported qualified LValue: ${left.text}")
}
}
is KtParenthesizedExpression -> {
initializeLValue(left.expression, convertQualified)
}
else -> {
FirErrorNamedReference(left, "Unsupported LValue: ${left?.javaClass}")
}
}
}
internal fun KtExpression?.generateAssignment(
session: FirSession,
psi: PsiElement?,
value: FirExpression,
operation: FirOperation,
convert: KtExpression.() -> FirExpression
): FirStatement {
if (this is KtParenthesizedExpression) {
return expression.generateAssignment(session, psi, value, operation, convert)
}
if (this is KtArrayAccessExpression) {
val arrayExpression = this.arrayExpression
val firArrayExpression = arrayExpression?.convert() ?: FirErrorExpressionImpl(arrayExpression, "No array expression")
val arraySet = if (operation != FirOperation.ASSIGN) {
FirArraySetCallImpl(psi, value, operation).apply {
for (indexExpression in indexExpressions) {
indexes += indexExpression.convert()
}
}
} else {
return FirFunctionCallImpl(psi).apply {
calleeReference = FirSimpleNamedReference(psi, OperatorNameConventions.SET)
explicitReceiver = firArrayExpression
for (indexExpression in indexExpressions) {
arguments += indexExpression.convert()
}
arguments += value
}
}
if (arrayExpression is KtSimpleNameExpression) {
return arraySet.apply {
lValue = initializeLValue(arrayExpression) { convert() as? FirQualifiedAccess }
}
}
return FirBlockImpl(arrayExpression).apply {
val name = Name.special("<array-set>")
statements += generateTemporaryVariable(session, this@generateAssignment, name, firArrayExpression)
statements += arraySet.apply { lValue = FirSimpleNamedReference(arrayExpression, name) }
}
}
if (operation != FirOperation.ASSIGN &&
this !is KtSimpleNameExpression && this !is KtThisExpression &&
(this !is KtQualifiedExpression || selectorExpression !is KtSimpleNameExpression)
) {
return FirBlockImpl(this).apply {
val name = Name.special("<complex-set>")
statements += generateTemporaryVariable(
session, this@generateAssignment, name,
this@generateAssignment?.convert() ?: FirErrorExpressionImpl(this@generateAssignment, "No LValue in assignment")
)
statements += FirVariableAssignmentImpl(psi, value, operation).apply {
lValue = FirSimpleNamedReference(this@generateAssignment, name)
}
}
}
return FirVariableAssignmentImpl(psi, value, operation).apply {
lValue = initializeLValue(this@generateAssignment) { convert() as? FirQualifiedAccess }
}
}
internal fun FirModifiableAccessorsOwner.generateAccessorsByDelegate(session: FirSession, member: Boolean, stubMode: Boolean) {
val variable = this as FirVariable<*>
val delegateFieldSymbol = delegateFieldSymbol ?: return
val delegate = delegate as? FirWrappedDelegateExpressionImpl ?: return
fun delegateAccess() = FirQualifiedAccessExpressionImpl(null).apply {
calleeReference = FirDelegateFieldReferenceImpl(null, delegateFieldSymbol)
}
fun thisRef() =
if (member) FirQualifiedAccessExpressionImpl(null).apply {
calleeReference = FirExplicitThisReference(null, null)
}
else FirConstExpressionImpl(null, IrConstKind.Null, null)
fun propertyRef() = FirCallableReferenceAccessImpl(null).apply {
calleeReference = FirResolvedCallableReferenceImpl(null, variable.name, variable.symbol)
typeRef = FirImplicitKPropertyTypeRef(null, ConeStarProjection)
}
delegate.delegateProvider = if (stubMode) FirExpressionStub(null) else FirFunctionCallImpl(null).apply {
explicitReceiver = delegate.expression
calleeReference = FirSimpleNamedReference(null, PROVIDE_DELEGATE)
arguments += thisRef()
arguments += propertyRef()
}
if (stubMode) return
getter = (getter as? FirPropertyAccessorImpl)
?: FirPropertyAccessorImpl(session, null, true, Visibilities.UNKNOWN, FirImplicitTypeRefImpl(null)).apply Accessor@{
body = FirSingleExpressionBlock(
FirReturnExpressionImpl(
null,
FirFunctionCallImpl(null).apply {
explicitReceiver = delegateAccess()
calleeReference = FirSimpleNamedReference(null, GET_VALUE)
arguments += thisRef()
arguments += propertyRef()
}
).apply {
target = FirFunctionTarget(null)
target.bind(this@Accessor)
}
)
}
setter = (setter as? FirPropertyAccessorImpl)
?: FirPropertyAccessorImpl(session, null, false, Visibilities.UNKNOWN, FirImplicitUnitTypeRef(null)).apply {
val parameter = FirValueParameterImpl(
session, null, DELEGATED_SETTER_PARAM,
FirImplicitTypeRefImpl(null),
defaultValue = null, isCrossinline = false,
isNoinline = false, isVararg = false
)
valueParameters += parameter
body = FirSingleExpressionBlock(
FirFunctionCallImpl(null).apply {
explicitReceiver = delegateAccess()
calleeReference = FirSimpleNamedReference(null, SET_VALUE)
arguments += thisRef()
arguments += propertyRef()
arguments += FirQualifiedAccessExpressionImpl(null).apply {
calleeReference = FirResolvedCallableReferenceImpl(psi, DELEGATED_SETTER_PARAM, parameter.symbol)
}
}
)
}
}
private val GET_VALUE = Name.identifier("getValue")
private val SET_VALUE = Name.identifier("setValue")
private val PROVIDE_DELEGATE = Name.identifier("provideDelegate")
private val DELEGATED_SETTER_PARAM = Name.special("<set-?>")
@@ -23,16 +23,15 @@ import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtTypeReference
internal fun KtClassOrObject.generateComponentFunctions(
fun List<Pair<KtParameter?, FirProperty>>.generateComponentFunctions(
session: FirSession, firClass: FirClassImpl, packageFqName: FqName, classFqName: FqName
) {
var componentIndex = 1
val zippedParameters =
primaryConstructorParameters.zip(firClass.declarations.filterIsInstance<FirProperty>())
for ((ktParameter, firProperty) in zippedParameters) {
if (!ktParameter.hasValOrVar()) continue
for ((ktParameter, firProperty) in this) {
if (!firProperty.isVal && !firProperty.isVar) continue
val name = Name.identifier("component$componentIndex")
componentIndex++
val symbol = FirNamedFunctionSymbol(CallableId(packageFqName, classFqName, name))
@@ -52,7 +51,7 @@ internal fun KtClassOrObject.generateComponentFunctions(
FirReturnExpressionImpl(
ktParameter,
FirQualifiedAccessExpressionImpl(ktParameter).apply {
val parameterName = ktParameter.nameAsSafeName
val parameterName = firProperty.name
calleeReference = FirResolvedCallableReferenceImpl(
ktParameter,
parameterName, firProperty.symbol
@@ -70,15 +69,14 @@ internal fun KtClassOrObject.generateComponentFunctions(
private val copyName = Name.identifier("copy")
internal fun KtClassOrObject.generateCopyFunction(
session: FirSession, firClass: FirClassImpl, packageFqName: FqName, classFqName: FqName,
firPrimaryConstructor: FirConstructor,
toFirOrErrorTypeRef: KtTypeReference?.() -> FirTypeRef
fun List<Pair<KtParameter?, FirProperty>>.generateCopyFunction(
session: FirSession, classOrObject: KtClassOrObject?, firClass: FirClassImpl, packageFqName: FqName, classFqName: FqName,
firPrimaryConstructor: FirConstructor
) {
val symbol = FirNamedFunctionSymbol(CallableId(packageFqName, classFqName, copyName))
firClass.addDeclaration(
FirMemberFunctionImpl(
session, this, symbol, copyName,
session, classOrObject, symbol, copyName,
Visibilities.PUBLIC, Modality.FINAL,
isExpect = false, isActual = false,
isOverride = false, isOperator = false,
@@ -88,13 +86,11 @@ internal fun KtClassOrObject.generateCopyFunction(
returnTypeRef = firPrimaryConstructor.returnTypeRef//FirImplicitTypeRefImpl(session, this)
).apply {
val copyFunction = this
val zippedParameters =
primaryConstructorParameters.zip(firClass.declarations.filterIsInstance<FirProperty>())
for ((ktParameter, firProperty) in zippedParameters) {
val name = ktParameter.nameAsSafeName
for ((ktParameter, firProperty) in this@generateCopyFunction) {
val name = firProperty.name
valueParameters += FirValueParameterImpl(
session, ktParameter, name,
ktParameter.typeReference.toFirOrErrorTypeRef(),
firProperty.returnTypeRef,
FirQualifiedAccessExpressionImpl(ktParameter).apply {
calleeReference = FirResolvedCallableReferenceImpl(ktParameter, name, firProperty.symbol)
},
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.builder
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
@@ -33,20 +34,40 @@ import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
private val implicitUnitType = FirImplicitUnitTypeRef(null)
private val implicitAnyType = FirImplicitAnyTypeRef(null)
private val implicitEnumType = FirImplicitEnumTypeRef(null)
private val implicitAnnotationType = FirImplicitAnnotationTypeRef(null)
class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder<PsiElement>(session) {
fun buildFirFile(file: KtFile): FirFile {
return file.accept(Visitor(), Unit) as FirFile
}
override val PsiElement.elementType: IElementType
get() = node.elementType
override val PsiElement.asText: String
get() = text
override val PsiElement.unescapedValue: String
get() = (this as KtEscapeStringTemplateEntry).unescapedValue
override fun PsiElement.getChildNodeByType(type: IElementType): PsiElement? {
return children.firstOrNull { it.node.elementType == type }
}
override fun PsiElement.getReferencedNameAsName(): Name {
return (this as KtSimpleNameExpression).getReferencedNameAsName()
}
override fun PsiElement.getLabelName(): String? {
return (this as KtExpressionWithLabel).getLabelName()
}
override fun PsiElement.getExpressionInParentheses(): PsiElement? {
return (this as KtParenthesizedExpression).expression
}
override val PsiElement?.selectorExpression: PsiElement?
get() = (this as? KtQualifiedExpression)?.selectorExpression
private val KtModifierListOwner.visibility: Visibility
get() = with(modifierList) {
when {
@@ -126,38 +147,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
FirSingleExpressionBlock(convert())
}
private fun FirExpression.toReturn(basePsi: PsiElement? = psi, labelName: String? = null): FirReturnExpression {
return FirReturnExpressionImpl(basePsi, this).apply {
target = FirFunctionTarget(labelName)
val lastFunction = firFunctions.lastOrNull()
if (labelName == null) {
if (lastFunction != null) {
target.bind(lastFunction)
} else {
target.bind(FirErrorFunction(this@RawFirBuilder.session, psi, "Cannot bind unlabeled return to a function"))
}
} else {
for (firFunction in firFunctions.asReversed()) {
when (firFunction) {
is FirAnonymousFunction -> {
if (firFunction.label?.name == labelName) {
target.bind(firFunction)
return@apply
}
}
is FirNamedFunction -> {
if (firFunction.name.asString() == labelName) {
target.bind(firFunction)
return@apply
}
}
}
}
target.bind(FirErrorFunction(this@RawFirBuilder.session, psi, "Cannot bind label $labelName to a function"))
}
}
}
private fun KtDeclarationWithBody.buildFirBody(): FirBlock? =
when {
!hasBody() ->
@@ -404,8 +393,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
return firConstructor
}
lateinit var packageFqName: FqName
override fun visitKtFile(file: KtFile, data: Unit): FirElement {
packageFqName = file.packageFqName
val firFile = FirFileImpl(session, file, file.name, packageFqName)
@@ -426,29 +413,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
return firFile
}
private fun KtClassOrObject.toDelegatedSelfType(firClass: FirRegularClass): FirTypeRef {
val typeParameters = firClass.typeParameters.map {
FirTypeParameterImpl(session, it.psi, FirTypeParameterSymbol(), it.name, Variance.INVARIANT, false).apply {
this.bounds += it.bounds
addDefaultBoundIfNecessary()
}
}
return FirResolvedTypeRefImpl(
this,
ConeClassTypeImpl(
firClass.symbol.toLookupTag(),
typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
false
)
)
}
private fun FirTypeParameterImpl.addDefaultBoundIfNecessary() {
if (bounds.isEmpty()) {
bounds += FirImplicitNullableAnyTypeRef(null)
}
}
override fun visitEnumEntry(enumEntry: KtEnumEntry, data: Unit): FirElement {
return withChildClassName(enumEntry.nameAsSafeName) {
val firEnumEntry = FirEnumEntryImpl(
@@ -471,28 +435,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
}
}
inline fun <T> withChildClassName(name: Name, l: () -> T): T {
className = className.child(name)
val t = l()
className = className.parent()
return t
}
val currentClassId get() = ClassId(packageFqName, className, false)
fun callableIdForName(name: Name, local: Boolean = false) =
when {
local -> CallableId(name)
className == FqName.ROOT -> CallableId(packageFqName, name)
else -> CallableId(packageFqName, className, name)
}
fun callableIdForClassConstructor() =
if (className == FqName.ROOT) CallableId(packageFqName, Name.special("<anonymous-init>"))
else CallableId(packageFqName, className, className.shortName())
var className: FqName = FqName.ROOT
override fun visitClassOrObject(classOrObject: KtClassOrObject, data: Unit): FirElement {
return withChildClassName(classOrObject.nameAsSafeName) {
@@ -544,10 +486,11 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
}
if (classOrObject.hasModifier(DATA_KEYWORD) && firPrimaryConstructor != null) {
classOrObject.generateComponentFunctions(session, firClass, packageFqName, className)
classOrObject.generateCopyFunction(session, firClass, packageFqName, className, firPrimaryConstructor) {
toFirOrErrorType()
}
val zippedParameters = classOrObject.primaryConstructorParameters.zip(
firClass.declarations.filterIsInstance<FirProperty>()
)
zippedParameters.generateComponentFunctions(session, firClass, packageFqName, className)
zippedParameters.generateCopyFunction(session, classOrObject, firClass, packageFqName, className, firPrimaryConstructor)
// TODO: equals, hashCode, toString
}
@@ -589,20 +532,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
}
}
private val firFunctions = mutableListOf<FirFunction>()
private fun <T> MutableList<T>.removeLast() {
removeAt(size - 1)
}
private fun <T> MutableList<T>.pop(): T? {
val result = lastOrNull()
if (result != null) {
removeAt(size - 1)
}
return result
}
override fun visitNamedFunction(function: KtNamedFunction, data: Unit): FirElement {
val typeReference = function.typeReference
val returnType = if (function.hasBlockBody()) {
@@ -722,13 +651,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
return firConstructor
}
private fun typeParametersFromSelfType(delegatedSelfTypeRef: FirTypeRef): List<FirTypeParameter> {
return delegatedSelfTypeRef.coneTypeSafe<ConeKotlinType>()
?.typeArguments
?.map { ((it as ConeTypeParameterType).lookupTag.symbol as FirTypeParameterSymbol).fir }
?: emptyList()
}
private fun KtConstructorDelegationCall.convert(
delegatedSuperTypeRef: FirTypeRef?,
delegatedSelfTypeRef: FirTypeRef,
@@ -956,7 +878,9 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
generateConstantExpressionByLiteral(expression)
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Unit): FirElement {
return expression.entries.toInterpolatingCall(expression) { toFirExpression(it) }
return expression.entries.toInterpolatingCall(expression) {
(this as KtStringTemplateEntryWithExpression).expression.toFirExpression(it)
}
}
override fun visitReturnExpression(expression: KtReturnExpression, data: Unit): FirElement {
@@ -1037,16 +961,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
}
}
private val firLoops = mutableListOf<FirLoop>()
private fun FirAbstractLoop.configure(generateBlock: () -> FirBlock): FirAbstractLoop {
label = firLabels.pop()
firLoops += this
block = generateBlock()
firLoops.removeLast()
return this
}
override fun visitDoWhileExpression(expression: KtDoWhileExpression, data: Unit): FirElement {
return FirDoWhileLoopImpl(
expression, expression.condition.toFirExpression("No condition in do-while loop")
@@ -1187,8 +1101,8 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
} else {
val firOperation = operationToken.toFirOperation()
if (firOperation in FirOperation.ASSIGNMENTS) {
return expression.left.generateAssignment(session, expression, rightArgument, firOperation) {
toFirExpression("Incorrect expression in assignment: ${expression.text}")
return expression.left.generateAssignment(expression, rightArgument, firOperation) {
(this as KtExpression).toFirExpression("Incorrect expression in assignment: ${expression.text}")
}
} else {
FirOperatorCallImpl(expression, firOperation).apply {
@@ -1227,10 +1141,10 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
return if (conventionCallName != null) {
if (operationToken in OperatorConventions.INCREMENT_OPERATIONS) {
return generateIncrementOrDecrementBlock(
session, expression, argument,
expression, argument,
callName = conventionCallName,
prefix = expression is KtPrefixExpression
) { toFirExpression("Incorrect expression inside inc/dec") }
) { (this as KtExpression).toFirExpression("Incorrect expression inside inc/dec") }
}
FirFunctionCallImpl(expression).apply {
calleeReference = FirSimpleNamedReference(
@@ -1246,8 +1160,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
}
}
private val firFunctionCalls = mutableListOf<FirFunctionCall>()
override fun visitCallExpression(expression: KtCallExpression, data: Unit): FirElement {
val calleeExpression = expression.calleeExpression
return FirFunctionCallImpl(expression).apply {
@@ -1315,8 +1227,6 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
return expression.expression?.accept(this, data) ?: FirErrorExpressionImpl(expression, "Empty parentheses")
}
private val firLabels = mutableListOf<FirLabel>()
override fun visitLabeledExpression(expression: KtLabeledExpression, data: Unit): FirElement {
val labelName = expression.getLabelName()
val size = firLabels.size