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(),