Write syntactically incorrect constructions processing (light tree to FIR)

This commit is contained in:
Ivan Cilcic
2019-07-25 16:28:29 +03:00
committed by Mikhail Glukhikh
parent ef535a2d85
commit c253ff7953
16 changed files with 373 additions and 324 deletions
@@ -46,12 +46,12 @@ open class BaseConverter(
return kidsRef.get()
}
fun LighterASTNode.getExpressionInParentheses(): LighterASTNode {
fun LighterASTNode.getExpressionInParentheses(): LighterASTNode? {
this.forEachChildren {
if (it.isExpression()) return it
}
throw Exception()
return null
}
protected inline fun LighterASTNode.forEachChildren(vararg skipTokens: KtToken, f: (LighterASTNode) -> Unit) {
@@ -9,6 +9,7 @@ import com.intellij.lang.LighterASTNode
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.KtNodeType
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirFunctionTarget
@@ -43,10 +44,10 @@ import org.jetbrains.kotlin.types.Variance
object ConverterUtil {
private val expressionSet = listOf(
KtNodeTypes.REFERENCE_EXPRESSION,
KtNodeTypes.DOT_QUALIFIED_EXPRESSION,
KtNodeTypes.LAMBDA_EXPRESSION,
KtNodeTypes.FUN
REFERENCE_EXPRESSION,
DOT_QUALIFIED_EXPRESSION,
LAMBDA_EXPRESSION,
FUN
)
fun String?.nameAsSafeName(defaultName: String = ""): Name {
@@ -157,10 +158,20 @@ object ConverterUtil {
inline fun isClassLocal(classNode: LighterASTNode, getParent: LighterASTNode.() -> LighterASTNode?): Boolean {
var currentNode: LighterASTNode? = classNode
while (currentNode != null) {
if (currentNode.tokenType == KtNodeTypes.BLOCK) {
val tokenType = currentNode.tokenType
val parent = currentNode.getParent()
if (tokenType == PROPERTY || tokenType == FUN) {
val grandParent = parent?.getParent()
when {
parent?.tokenType == KT_FILE -> return true
parent?.tokenType == CLASS_BODY && !(grandParent?.tokenType == OBJECT_DECLARATION && grandParent?.getParent()?.tokenType == OBJECT_LITERAL) -> return true
parent?.tokenType == BLOCK && grandParent?.tokenType == SCRIPT -> return true
}
}
if (tokenType == BLOCK) {
return true
}
currentNode = currentNode.getParent()
currentNode = parent
}
return false
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.lightTree.converter
import com.intellij.lang.LighterASTNode
import com.intellij.psi.TokenType
import com.intellij.psi.tree.IFileElementType
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes.*
@@ -49,6 +50,7 @@ import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
class DeclarationsConverter(
@@ -141,15 +143,14 @@ class DeclarationsConverter(
return packageName
}
private fun convertImportAlias(importAlias: LighterASTNode): String {
private fun convertImportAlias(importAlias: LighterASTNode): String? {
importAlias.forEachChildren {
when (it.tokenType) {
IDENTIFIER -> return it.getAsString()
}
}
//TODO specify error
throw Exception()
return null
}
/**
@@ -178,7 +179,7 @@ class DeclarationsConverter(
null,
importedFqName,
isAllUnder,
aliasName.nameAsSafeName()
aliasName?.let { Name.identifier(it) }
)
}
@@ -332,7 +333,7 @@ class DeclarationsConverter(
*/
private fun convertClass(classNode: LighterASTNode): FirDeclaration {
var modifiers = Modifier(session)
lateinit var classKind: ClassKind
var classKind: ClassKind = ClassKind.CLASS //TODO
var identifier: String? = null
val firTypeParameters = mutableListOf<FirTypeParameter>()
var primaryConstructor: LighterASTNode? = null
@@ -360,17 +361,20 @@ class DeclarationsConverter(
}
}
classKind = when {
modifiers.isEnum() -> ClassKind.ENUM_CLASS
modifiers.isAnnotation() -> ClassKind.ANNOTATION_CLASS
else -> classKind
}
val defaultDelegatedSuperTypeRef = when {
modifiers.isEnum() -> implicitEnumType
modifiers.isAnnotation() -> implicitAnnotationType
modifiers.isEnum() && (classKind == ClassKind.CLASS || classKind == ClassKind.INTERFACE) -> implicitEnumType
modifiers.isAnnotation() && (classKind == ClassKind.CLASS || classKind == ClassKind.INTERFACE) -> implicitAnnotationType
else -> implicitAnyType
}
if (classKind == ClassKind.CLASS) {
classKind = when {
modifiers.isEnum() -> ClassKind.ENUM_CLASS
modifiers.isAnnotation() -> ClassKind.ANNOTATION_CLASS
else -> classKind
}
}
val className = identifier.nameAsSafeName(if (modifiers.isCompanion()) "Companion" else "")
superTypeRefs.ifEmpty { superTypeRefs += defaultDelegatedSuperTypeRef }
val isLocal = isClassLocal(classNode) { getParent() }
@@ -387,8 +391,8 @@ class DeclarationsConverter(
modifiers.hasActual(),
classKind,
isInner = modifiers.isInner(),
isCompanion = modifiers.isCompanion(),
isData = modifiers.isDataClass(),
isCompanion = modifiers.isCompanion() && classKind == ClassKind.OBJECT,
isData = modifiers.isDataClass() && classKind != ClassKind.OBJECT,
isInline = modifiers.hasInline()
)
firClass.annotations += modifiers.annotations
@@ -406,13 +410,16 @@ class DeclarationsConverter(
val firPrimaryConstructor = convertPrimaryConstructor(primaryConstructor, classWrapper)
firPrimaryConstructor?.let { firClass.declarations += it }
//parse properties
val properties = primaryConstructor
.getChildNodesByType(VALUE_PARAMETER_LIST)
.flatMap { convertValueParameters(it) }
.filter { it.hasValOrVar() }
.map { it.toFirProperty() }
firClass.addDeclarations(properties)
val properties = mutableListOf<FirProperty>()
if (primaryConstructor != null && firPrimaryConstructor != null) {
//parse properties
properties += primaryConstructor
.getChildNodesByType(VALUE_PARAMETER_LIST)
.flatMap { convertValueParameters(it) }
.filter { it.hasValOrVar() }
.map { it.toFirProperty() }
firClass.addDeclarations(properties)
}
//parse declarations
classBody?.let {
@@ -465,7 +472,7 @@ class DeclarationsConverter(
val classWrapper = ClassWrapper(
this@DeclarationsConverter.session, SpecialNames.NO_NAME_PROVIDED, modifiers, ClassKind.OBJECT,
hasPrimaryConstructor = false,
hasSecondaryConstructor = false,
hasSecondaryConstructor = classBody.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(),
delegatedSelfTypeRef = delegatedType,
delegatedSuperTypeRef = delegatedType,
superTypeCallEntry = superTypeCallEntry
@@ -490,6 +497,7 @@ class DeclarationsConverter(
var hasInitializerList = false
val enumSuperTypeCallEntry = mutableListOf<FirExpression>()
val firDeclarations = mutableListOf<FirDeclaration>()
var classBodyNode: LighterASTNode? = null
enumEntry.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
@@ -498,7 +506,7 @@ class DeclarationsConverter(
hasInitializerList = true
enumSuperTypeCallEntry += convertInitializerList(it)
}
CLASS_BODY -> firDeclarations += convertClassBody(it, classWrapper)
CLASS_BODY -> classBodyNode = it
}
}
@@ -512,16 +520,23 @@ class DeclarationsConverter(
)
firEnumEntry.annotations += modifiers.annotations
val defaultDelegatedSuperTypeRef = when {
modifiers.isEnum() -> implicitEnumType
modifiers.isAnnotation() -> implicitAnnotationType
else -> implicitAnyType
}
val enumClassWrapper = ClassWrapper(
session, enumEntryName, modifiers, ClassKind.ENUM_ENTRY,
hasPrimaryConstructor = true, hasSecondaryConstructor = false,
hasPrimaryConstructor = true,
hasSecondaryConstructor = classBodyNode.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(),
delegatedSelfTypeRef = toDelegatedSelfType(firEnumEntry),
delegatedSuperTypeRef = if (hasInitializerList) classWrapper.getFirUserTypeFromClassName() else implicitAnyType,
delegatedSuperTypeRef = if (hasInitializerList) classWrapper.getFirUserTypeFromClassName() else defaultDelegatedSuperTypeRef,
superTypeCallEntry = enumSuperTypeCallEntry
)
firEnumEntry.superTypeRefs += enumClassWrapper.delegatedSuperTypeRef
val firEnumPrimaryConstructor = convertPrimaryConstructor(null, enumClassWrapper)!!
firEnumEntry.addDeclaration(firEnumPrimaryConstructor)
convertPrimaryConstructor(null, enumClassWrapper)?.let { firEnumEntry.addDeclaration(it) }
classBodyNode?.also { firDeclarations += convertClassBody(it, /*classWrapper*/enumClassWrapper) }
firDeclarations.forEach { firEnumEntry.addDeclaration(it) }
return@withChildClassName firEnumEntry
@@ -641,6 +656,10 @@ class DeclarationsConverter(
}
}
val delegatedSelfTypeRef =
if (classWrapper.isObjectLiteral()) FirErrorTypeRefImpl(session, null, "Constructor in object")
else classWrapper.delegatedSelfTypeRef
val firConstructor = FirConstructorImpl(
session,
null,
@@ -648,13 +667,13 @@ class DeclarationsConverter(
modifiers.getVisibility(),
modifiers.hasExpect(),
modifiers.hasActual(),
classWrapper.delegatedSelfTypeRef,
delegatedSelfTypeRef,
constructorDelegationCall
)
FunctionUtil.firFunctions += firConstructor
firConstructor.annotations += modifiers.annotations
firConstructor.typeParameters += ConverterUtil.typeParametersFromSelfType(classWrapper.delegatedSelfTypeRef)
firConstructor.typeParameters += ConverterUtil.typeParametersFromSelfType(delegatedSelfTypeRef)
firConstructor.valueParameters += firValueParameters.map { it.firValueParameter }
firConstructor.body = convertFunctionBody(block, null)
FunctionUtil.firFunctions.removeLast()
@@ -680,10 +699,15 @@ class DeclarationsConverter(
val isImplicit = constructorDelegationCall.getAsString().isEmpty()
val isThis = (isImplicit && classWrapper.hasPrimaryConstructor) || thisKeywordPresent
val delegatedType = when {
isThis -> classWrapper.delegatedSelfTypeRef
else -> classWrapper.delegatedSuperTypeRef
}
val delegatedType =
if (classWrapper.isObjectLiteral() || classWrapper.isInterface()) when {
isThis -> FirErrorTypeRefImpl(session, null, "Constructor in object")
else -> FirErrorTypeRefImpl(session, null, "No super type")
}
else when {
isThis -> classWrapper.delegatedSelfTypeRef
else -> classWrapper.delegatedSuperTypeRef
}
return FirDelegatedConstructorCallImpl(
session,
@@ -698,7 +722,7 @@ class DeclarationsConverter(
*/
private fun convertTypeAlias(typeAlias: LighterASTNode): FirDeclaration {
var modifiers = Modifier(session)
lateinit var identifier: String
var identifier: String? = null
lateinit var firType: FirTypeRef
val firTypeParameters = mutableListOf<FirTypeParameter>()
typeAlias.forEachChildren {
@@ -733,10 +757,10 @@ class DeclarationsConverter(
*/
fun convertPropertyDeclaration(property: LighterASTNode): FirDeclaration {
var modifiers = Modifier(session)
lateinit var identifier: String
var identifier: String? = null
val firTypeParameters = mutableListOf<FirTypeParameter>()
var isReturnType = false
var firDelegateExpression: FirExpression? = null
var delegateExpression: LighterASTNode? = null
var isVar = false
var receiverType: FirTypeRef? = null
var returnType: FirTypeRef = implicitType
@@ -752,13 +776,13 @@ class DeclarationsConverter(
COLON -> isReturnType = true
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
PROPERTY_DELEGATE -> firDelegateExpression = expressionConverter.getAsFirExpression(it)
PROPERTY_DELEGATE -> delegateExpression = it
VAR_KEYWORD -> isVar = true
PROPERTY_ACCESSOR -> {
val propertyAccessor = convertGetterOrSetter(it, returnType)
if (propertyAccessor.isGetter) getter = propertyAccessor else setter = propertyAccessor
}
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have initializer")
}
}
@@ -774,7 +798,7 @@ class DeclarationsConverter(
returnType,
isVar,
firExpression,
delegate = firDelegateExpression
delegate = delegateExpression?.let { expressionConverter.getAsFirExpression(it, "Incorrect delegate expression") }
).apply {
annotations += modifiers.annotations
}
@@ -797,7 +821,7 @@ class DeclarationsConverter(
firExpression,
getter ?: FirDefaultPropertyGetter(session, null, returnType, modifiers.getVisibility()),
if (isVar) setter ?: FirDefaultPropertySetter(session, null, returnType, modifiers.getVisibility()) else null,
firDelegateExpression
delegateExpression?.let { expressionConverter.getAsFirExpression(it, "Should have delegate") }
).apply {
this.typeParameters += firTypeParameters
this.joinTypeParameters(typeConstraints)
@@ -812,12 +836,13 @@ class DeclarationsConverter(
private fun convertDestructingDeclaration(destructingDeclaration: LighterASTNode): DestructuringDeclaration {
var isVar = false
val entries = mutableListOf<FirVariable<*>>()
var firExpression: FirExpression? = null
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Destructuring declaration without initializer")
destructingDeclaration.forEachChildren {
when (it.tokenType) {
VAR_KEYWORD -> isVar = true
DESTRUCTURING_DECLARATION_ENTRY -> entries += convertDestructingDeclarationEntry(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it)
else -> if (it.isExpression()) firExpression =
expressionConverter.getAsFirExpression(it, "Destructuring declaration without initializer")
}
}
@@ -829,7 +854,7 @@ class DeclarationsConverter(
*/
private fun convertDestructingDeclarationEntry(entry: LighterASTNode): FirVariable<*> {
var modifiers = Modifier(session)
lateinit var identifier: String
var identifier: String? = null
var firType: FirTypeRef? = null
entry.forEachChildren {
when (it.tokenType) {
@@ -882,7 +907,7 @@ class DeclarationsConverter(
firAccessor.valueParameters += firValueParameters
}
firAccessor.body = convertFunctionBody(block, expression?.let { expressionConverter.getAsFirExpression(it) })
firAccessor.body = convertFunctionBody(block, expression)
FunctionUtil.firFunctions.removeLast()
return firAccessor
}
@@ -909,11 +934,11 @@ class DeclarationsConverter(
firValueParameter.name,
if (firValueParameter.returnTypeRef == implicitType) propertyTypeRef else firValueParameter.returnTypeRef,
firValueParameter.defaultValue,
isCrossinline = modifiers.hasCrossinline(),
isNoinline = modifiers.hasNoinline(),
isVararg = modifiers.hasVararg()
isCrossinline = modifiers.hasCrossinline() || firValueParameter.isCrossinline,
isNoinline = modifiers.hasNoinline() || firValueParameter.isNoinline,
isVararg = modifiers.hasVararg() || firValueParameter.isVararg
).apply {
annotations += modifiers.annotations
annotations += modifiers.annotations + firValueParameter.annotations
}
}
@@ -924,30 +949,32 @@ class DeclarationsConverter(
var modifiers = Modifier(session)
var identifier: String? = null
val firTypeParameters = mutableListOf<FirTypeParameter>()
val valueParametersList = mutableListOf<ValueParameter>()
var valueParametersList: LighterASTNode? = null
var isReturnType = false
var receiverType: FirTypeRef? = null
var returnType: FirTypeRef? = null
val typeConstraints = mutableListOf<TypeConstraint>()
var block: LighterASTNode? = null
var expression: LighterASTNode? = null
var hasEqToken = false
functionDeclaration.forEachChildren {
when (it.tokenType) {
MODIFIER_LIST -> modifiers = convertModifierList(it)
IDENTIFIER -> identifier = it.getAsString()
TYPE_PARAMETER_LIST -> firTypeParameters += convertTypeParameters(it)
VALUE_PARAMETER_LIST -> valueParametersList += convertValueParameters(it)
VALUE_PARAMETER_LIST -> valueParametersList = it //must convert later, because it can contains "return"
COLON -> isReturnType = true
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
BLOCK -> block = it
EQ -> hasEqToken = true
else -> if (it.isExpression()) expression = it
}
}
if (returnType == null) {
returnType =
if (block != null || (block == null && expression == null)) implicitUnitType
if (block != null || !hasEqToken) implicitUnitType
else implicitType
}
@@ -986,8 +1013,8 @@ class DeclarationsConverter(
firFunction.joinTypeParameters(typeConstraints)
}
firFunction.valueParameters += valueParametersList.map { it.firValueParameter }
firFunction.body = convertFunctionBody(block, expression?.let { expressionConverter.getAsFirExpression(it) })
valueParametersList?.let { firFunction.valueParameters += convertValueParameters(it).map { it.firValueParameter } }
firFunction.body = convertFunctionBody(block, expression)
FunctionUtil.firFunctions.removeLast()
return firFunction
}
@@ -996,10 +1023,13 @@ class DeclarationsConverter(
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionBody
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.buildFirBody
*/
private fun convertFunctionBody(blockNode: LighterASTNode?, firExpression: FirExpression?): FirBlock? {
private fun convertFunctionBody(blockNode: LighterASTNode?, expression: LighterASTNode?): FirBlock? {
return when {
blockNode != null -> return convertBlock(blockNode)
firExpression != null -> FirSingleExpressionBlock(session, firExpression.toReturn())
expression != null -> FirSingleExpressionBlock(
session,
expressionConverter.getAsFirExpression<FirExpression>(expression, "Function has no body (but should)").toReturn()
)
else -> null
}
}
@@ -1081,11 +1111,11 @@ class DeclarationsConverter(
*/
private fun convertExplicitDelegation(explicitDelegation: LighterASTNode): FirDelegatedTypeRef {
lateinit var firTypeRef: FirTypeRef
var firExpression: FirExpression? = null
var firExpression: FirExpression? = FirErrorExpressionImpl(session, null, "Should have delegate")
explicitDelegation.forEachChildren {
when (it.tokenType) {
TYPE_REFERENCE -> firTypeRef = convertType(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have delegate")
}
}
@@ -1143,7 +1173,7 @@ class DeclarationsConverter(
*/
private fun convertTypeParameter(typeParameter: LighterASTNode): FirTypeParameter {
var typeParameterModifiers = TypeParameterModifier(session)
lateinit var identifier: String
var identifier: String? = null
var firType: FirTypeRef? = null
typeParameter.forEachChildren {
when (it.tokenType) {
@@ -1171,16 +1201,22 @@ class DeclarationsConverter(
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeRef
*/
fun convertType(type: LighterASTNode): FirTypeRef {
if (type.getAsString().isEmpty()) {
return FirErrorTypeRefImpl(session, null, "Unwrapped type is null")
}
var typeModifiers = TypeModifier(session) //TODO what with suspend?
lateinit var firType: FirTypeRef
var firType: FirTypeRef = FirErrorTypeRefImpl(session, null, "Incomplete code")
var afterLPar = false
type.forEachChildren {
when (it.tokenType) {
LPAR -> afterLPar = true
TYPE_REFERENCE -> firType = convertType(it)
MODIFIER_LIST -> typeModifiers = convertTypeModifierList(it)
USER_TYPE -> firType = convertUserType(it).also { firUserType -> (firUserType as FirUserTypeRefImpl).qualifier.reverse() }
MODIFIER_LIST -> if (!afterLPar || typeModifiers.hasNoAnnotations()) typeModifiers = convertTypeModifierList(it)
USER_TYPE -> firType = convertUserType(it)
NULLABLE_TYPE -> firType = convertNullableType(it)
FUNCTION_TYPE -> firType = convertFunctionType(it)
DYNAMIC_TYPE -> firType = FirDynamicTypeRefImpl(session, null, false)
TokenType.ERROR_ELEMENT -> firType = FirErrorTypeRefImpl(session, null, "Unwrapped type is null")
}
}
@@ -1209,7 +1245,7 @@ class DeclarationsConverter(
nullableType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> firType =
convertUserType(it, true).also { firUserType -> (firUserType as FirUserTypeRefImpl).qualifier.reverse() }
convertUserType(it, true)
FUNCTION_TYPE -> firType = convertFunctionType(it, true)
NULLABLE_TYPE -> firType = convertNullableType(it)
DYNAMIC_TYPE -> firType = FirDynamicTypeRefImpl(session, null, true)
@@ -1222,18 +1258,21 @@ class DeclarationsConverter(
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseUserType
*/
private fun convertUserType(userType: LighterASTNode, isNullable: Boolean = false): FirUserTypeRef {
private fun convertUserType(userType: LighterASTNode, isNullable: Boolean = false): FirTypeRef {
var simpleFirUserType: FirUserTypeRef? = null
lateinit var identifier: String
var identifier: String? = null
val firTypeArguments = mutableListOf<FirTypeProjection>()
userType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> simpleFirUserType = convertUserType(it) //simple user type
USER_TYPE -> simpleFirUserType = convertUserType(it) as? FirUserTypeRef //simple user type
REFERENCE_EXPRESSION -> identifier = it.getAsString()
TYPE_ARGUMENT_LIST -> firTypeArguments += convertTypeArguments(it)
}
}
if (identifier == null)
return FirErrorTypeRefImpl(session, null, "Incomplete user type")
val qualifier = FirQualifierPartImpl(
identifier.nameAsSafeName()
).apply { typeArguments += firTypeArguments }
@@ -1244,7 +1283,7 @@ class DeclarationsConverter(
isNullable
).apply {
this.qualifier.add(qualifier)
simpleFirUserType?.qualifier?.let { this@apply.qualifier.addAll(it) }
simpleFirUserType?.qualifier?.let { this@apply.qualifier.addAll(0, it) }
}
}
@@ -1338,7 +1377,7 @@ class DeclarationsConverter(
IDENTIFIER -> identifier = it.getAsString()
TYPE_REFERENCE -> firType = convertType(it)
DESTRUCTURING_DECLARATION -> destructuringDeclaration = convertDestructingDeclaration(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it)
else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have default value")
}
}
@@ -6,33 +6,31 @@
package org.jetbrains.kotlin.fir.lightTree.converter
import com.intellij.lang.LighterASTNode
import com.intellij.psi.TokenType
import com.intellij.psi.impl.source.tree.java.PsiForStatementImpl
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.builder.*
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousObjectImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirErrorLoop
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
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.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.fir.ClassWrapper
import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter
import org.jetbrains.kotlin.fir.lightTree.fir.WhenEntry
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirExplicitSuperReference
import org.jetbrains.kotlin.fir.references.FirExplicitThisReference
@@ -57,12 +55,12 @@ class ExpressionsConverter(
private val declarationsConverter: DeclarationsConverter
) : BaseConverter(session, tree) {
inline fun <reified R : FirElement> getAsFirExpression(expression: LighterASTNode): R {
return convertExpression(expression) 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)
}
/***** EXPRESSIONS *****/
fun convertExpression(expression: LighterASTNode): FirElement {
fun convertExpression(expression: LighterASTNode, errorReason: String): FirElement {
if (!stubMode) {
return when (expression.tokenType) {
LAMBDA_EXPRESSION -> {
@@ -93,22 +91,28 @@ class ExpressionsConverter(
BREAK, CONTINUE -> convertLoopJump(expression)
RETURN -> convertReturn(expression)
THROW -> convertThrow(expression)
PARENTHESIZED, PROPERTY_DELEGATE, INDICES -> convertExpression(expression.getExpressionInParentheses())
PARENTHESIZED -> getAsFirExpression(expression.getExpressionInParentheses(), "Empty parentheses")
PROPERTY_DELEGATE, INDICES, CONDITION, LOOP_RANGE ->
getAsFirExpression(expression.getExpressionInParentheses(), errorReason)
THIS_EXPRESSION -> convertThisExpression(expression)
SUPER_EXPRESSION -> convertSuperExpression(expression)
OBJECT_LITERAL -> declarationsConverter.convertObjectLiteral(expression)
FUN -> declarationsConverter.convertFunctionDeclaration(expression)
else -> FirExpressionStub(session, null)
else -> FirErrorExpressionImpl(session, null, errorReason)
}
}
return FirExpressionStub(session, null)
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseFunctionLiteral
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitLambdaExpression
*/
private fun convertLambdaExpression(lambdaExpression: LighterASTNode): FirExpression {
val valueParameterList = mutableListOf<ValueParameter>()
lateinit var block: LighterASTNode
var block: LighterASTNode? = null
lambdaExpression.getChildNodesByType(FUNCTION_LITERAL).first().forEachChildren {
when (it.tokenType) {
VALUE_PARAMETER_LIST -> valueParameterList += declarationsConverter.convertValueParameters(it)
@@ -141,7 +145,8 @@ class ExpressionsConverter(
label = FunctionUtil.firLabels.pop() ?: FunctionUtil.firFunctionCalls.lastOrNull()?.calleeReference?.name?.let {
FirLabelImpl(this@ExpressionsConverter.session, null, it.asString())
}
val bodyExpression = declarationsConverter.convertBlockExpression(block)
val bodyExpression = block?.let { declarationsConverter.convertBlockExpression(it) }
?: FirErrorExpressionImpl(session, null, "Lambda has no body")
body = if (bodyExpression is FirBlockImpl) {
if (bodyExpression.statements.isEmpty()) {
bodyExpression.statements.add(FirUnitExpression(this@ExpressionsConverter.session, null))
@@ -167,8 +172,8 @@ class ExpressionsConverter(
private fun convertBinaryExpression(binaryExpression: LighterASTNode): FirStatement {
var isLeftArgument = true
lateinit var operationTokenName: String
lateinit var leftArgNode: LighterASTNode
lateinit var rightArgAsFir: FirExpression
var leftArgNode: LighterASTNode? = null
var rightArgAsFir: FirExpression = FirErrorExpressionImpl(session, null, "No right operand")
binaryExpression.forEachChildren {
when (it.tokenType) {
OPERATION_REFERENCE -> {
@@ -179,7 +184,7 @@ class ExpressionsConverter(
if (isLeftArgument) {
leftArgNode = it
} else {
rightArgAsFir = getAsFirExpression(it)
rightArgAsFir = getAsFirExpression(it, "No right operand")
}
}
}
@@ -188,16 +193,16 @@ class ExpressionsConverter(
val operationToken = operationTokenName.getOperationSymbol()
when (operationToken) {
ELVIS ->
return getAsFirExpression<FirExpression>(leftArgNode).generateNotNullOrOther(
return getAsFirExpression<FirExpression>(leftArgNode, "No left operand").generateNotNullOrOther(
session, rightArgAsFir, "elvis", null
)
ANDAND, OROR ->
return getAsFirExpression<FirExpression>(leftArgNode).generateLazyLogicalOperation(
return getAsFirExpression<FirExpression>(leftArgNode, "No left operand").generateLazyLogicalOperation(
session, rightArgAsFir, operationToken == ANDAND, null
)
in OperatorConventions.IN_OPERATIONS ->
return rightArgAsFir.generateContainsOperation(
session, getAsFirExpression(leftArgNode), operationToken == NOT_IN, null, null
session, getAsFirExpression(leftArgNode, "No left operand"), operationToken == NOT_IN, null, null
)
}
val conventionCallName = operationToken.toBinaryName()
@@ -207,7 +212,7 @@ class ExpressionsConverter(
this@ExpressionsConverter.session, null,
conventionCallName ?: operationTokenName.nameAsSafeName()
)
explicitReceiver = getAsFirExpression(leftArgNode)
explicitReceiver = getAsFirExpression(leftArgNode, "No left operand")
arguments += rightArgAsFir
}
} else {
@@ -216,7 +221,7 @@ class ExpressionsConverter(
return convertAssignment(leftArgNode, rightArgAsFir, firOperation)
} else {
FirOperatorCallImpl(session, null, firOperation).apply {
arguments += getAsFirExpression<FirExpression>(leftArgNode)
arguments += getAsFirExpression<FirExpression>(leftArgNode, "No left operand")
arguments += rightArgAsFir
}
}
@@ -229,13 +234,13 @@ class ExpressionsConverter(
*/
private fun convertBinaryWithType(binaryExpression: LighterASTNode): FirTypeOperatorCall {
lateinit var operationTokenName: String
lateinit var leftArgAsFir: FirExpression
var leftArgAsFir: FirExpression = FirErrorExpressionImpl(session, null, "No left operand")
lateinit var firType: FirTypeRef
binaryExpression.forEachChildren {
when (it.tokenType) {
OPERATION_REFERENCE -> operationTokenName = it.getAsString()
TYPE_REFERENCE -> firType = declarationsConverter.convertType(it)
else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it)
else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it, "No left operand")
}
}
@@ -250,13 +255,13 @@ class ExpressionsConverter(
*/
private fun convertIsExpression(isExpression: LighterASTNode): FirTypeOperatorCall {
lateinit var operationTokenName: String
lateinit var leftArgAsFir: FirExpression
var leftArgAsFir: FirExpression = FirErrorExpressionImpl(session, null, "No left operand")
lateinit var firType: FirTypeRef
isExpression.forEachChildren {
when (it.tokenType) {
OPERATION_REFERENCE -> operationTokenName = it.getAsString()
TYPE_REFERENCE -> firType = declarationsConverter.convertType(it)
else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it)
else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it, "No left operand")
}
}
@@ -276,6 +281,8 @@ class ExpressionsConverter(
labeledExpression.forEachChildren {
when (it.tokenType) {
LABEL_QUALIFIER -> FunctionUtil.firLabels += FirLabelImpl(session, null, it.toString().replace("@", ""))
BLOCK -> firExpression = declarationsConverter.convertBlock(it)
PROPERTY -> firExpression = declarationsConverter.convertPropertyDeclaration(it)
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
}
}
@@ -294,7 +301,7 @@ class ExpressionsConverter(
*/
private fun convertUnaryExpression(unaryExpression: LighterASTNode): FirExpression {
lateinit var operationTokenName: String
lateinit var argument: LighterASTNode
var argument: LighterASTNode? = null
unaryExpression.forEachChildren {
when (it.tokenType) {
OPERATION_REFERENCE -> operationTokenName = it.getAsString()
@@ -304,7 +311,7 @@ class ExpressionsConverter(
val operationToken = operationTokenName.getOperationSymbol()
if (operationToken == EXCLEXCL) {
return bangBangToWhen(session, getAsFirExpression(argument))
return bangBangToWhen(session, getAsFirExpression(argument, "No operand"))
}
val conventionCallName = operationToken.toUnaryName()
@@ -318,12 +325,12 @@ class ExpressionsConverter(
}
FirFunctionCallImpl(session, null).apply {
calleeReference = FirSimpleNamedReference(this@ExpressionsConverter.session, null, conventionCallName)
explicitReceiver = getAsFirExpression(argument)
explicitReceiver = getAsFirExpression(argument, "No operand")
}
} else {
val firOperation = operationToken.toFirOperation()
FirOperatorCallImpl(session, null, firOperation).apply {
arguments += getAsFirExpression<FirExpression>(argument)
arguments += getAsFirExpression<FirExpression>(argument, "No operand")
}
}
}
@@ -353,9 +360,9 @@ class ExpressionsConverter(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitClassLiteralExpression
*/
private fun convertClassLiteralExpression(classLiteralExpression: LighterASTNode): FirExpression {
lateinit var firReceiverExpression: FirExpression
var firReceiverExpression: FirExpression = FirErrorExpressionImpl(session, null, "No receiver in class literal")
classLiteralExpression.forEachChildren {
if (it.isExpression()) firReceiverExpression = getAsFirExpression(it)
if (it.isExpression()) firReceiverExpression = getAsFirExpression(it, "No receiver in class literal")
}
return FirGetClassCallImpl(session, null).apply {
@@ -376,7 +383,7 @@ class ExpressionsConverter(
COLONCOLON -> isReceiver = false
else -> if (it.isExpression()) {
if (isReceiver) {
firReceiverExpression = getAsFirExpression(it)
firReceiverExpression = getAsFirExpression(it, "Incorrect receiver expression")
} else {
firCallableReference = convertSimpleNameExpression(it)
}
@@ -397,8 +404,8 @@ class ExpressionsConverter(
private fun convertQualifiedExpression(dotQualifiedExpression: LighterASTNode): FirExpression {
var isSelector = false
var isSafe = false
var firSelector: FirExpression? = null //after dot
lateinit var firReceiver: FirExpression //before dot
var firSelector: FirExpression = FirErrorExpressionImpl(session, null, "Qualified expression without selector") //after dot
var firReceiver: FirExpression? = null //before dot
dotQualifiedExpression.forEachChildren {
when (it.tokenType) {
DOT -> isSelector = true
@@ -406,20 +413,21 @@ class ExpressionsConverter(
isSafe = true
isSelector = true
}
else -> if (isSelector) firSelector = getAsFirExpression(it) else firReceiver = getAsFirExpression(it)
else -> {
if (isSelector && it.tokenType != TokenType.ERROR_ELEMENT)
firSelector = getAsFirExpression(it, "Incorrect selector expression")
else
firReceiver = getAsFirExpression(it, "Incorrect receiver expression")
}
}
}
if (firSelector == null) {
return FirErrorExpressionImpl(session, null, "Qualified expression without selector")
}
//TODO use contracts?
if (firSelector is FirModifiableQualifiedAccess<*>) {
(firSelector as FirModifiableQualifiedAccess<*>).safe = isSafe
(firSelector as FirModifiableQualifiedAccess<*>).explicitReceiver = firReceiver
}
return firSelector!!
return firSelector
}
/**
@@ -435,12 +443,13 @@ class ExpressionsConverter(
REFERENCE_EXPRESSION -> name = it.getAsString()
TYPE_ARGUMENT_LIST -> firTypeArguments += declarationsConverter.convertTypeArguments(it)
VALUE_ARGUMENT_LIST, LAMBDA_ARGUMENT -> valueArguments += it
else -> additionalArgument = getAsFirExpression(it)
else -> if (it.tokenType != TokenType.ERROR_ELEMENT) additionalArgument =
getAsFirExpression(it, "Incorrect invoke receiver")
}
}
return FirFunctionCallImpl(session, null).apply {
val calleeReference = when {
this.calleeReference = when {
name != null -> FirSimpleNamedReference(this@ExpressionsConverter.session, null, name.nameAsSafeName())
additionalArgument != null -> {
arguments += additionalArgument!!
@@ -448,7 +457,7 @@ class ExpressionsConverter(
}
else -> FirErrorNamedReference(this@ExpressionsConverter.session, null, "Call has no callee")
}
this.calleeReference = calleeReference
FunctionUtil.firFunctionCalls += this
this.extractArgumentsFrom(valueArguments.flatMap { convertValueArguments(it) }, stubMode)
typeArguments += firTypeArguments
@@ -472,8 +481,11 @@ class ExpressionsConverter(
FirConstExpressionImpl(session, null, IrConstKind.String, it.getAsString())
}
ESCAPE_STRING_TEMPLATE_ENTRY -> {
sb.append(escapedStringToCharacter(it.getAsString()))
FirConstExpressionImpl(session, null, IrConstKind.String, escapedStringToCharacter(it.getAsString())?.toString() ?: "")
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
@@ -503,9 +515,9 @@ class ExpressionsConverter(
}
private fun convertShortOrLongStringTemplate(shortOrLongString: LighterASTNode): FirExpression {
lateinit var firExpression: FirExpression
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Incorrect template argument")
shortOrLongString.forEachChildren(LONG_TEMPLATE_ENTRY_START, LONG_TEMPLATE_ENTRY_END) {
firExpression = getAsFirExpression(it)
firExpression = getAsFirExpression(it, "Incorrect template argument")
}
return firExpression
}
@@ -571,22 +583,24 @@ class ExpressionsConverter(
val whenEntries = mutableListOf<WhenEntry>()
whenExpression.forEachChildren {
when (it.tokenType) {
PROPERTY -> subjectVariable = declarationsConverter.convertPropertyDeclaration(it) as FirVariable<*>
DESTRUCTURING_DECLARATION -> subjectExpression = getAsFirExpression(it)
PROPERTY -> subjectVariable = (declarationsConverter.convertPropertyDeclaration(it) as FirVariable<*>).let { variable ->
FirVariableImpl(
session, null, variable.name, variable.returnTypeRef,
isVar = false, initializer = variable.initializer
)
}
DESTRUCTURING_DECLARATION -> subjectExpression =
getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.getAsString()}")
WHEN_ENTRY -> whenEntries += convertWhenEntry(it)
else -> if (it.isExpression()) subjectExpression = getAsFirExpression(it)
else -> if (it.isExpression()) subjectExpression =
getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.getAsString()}")
}
}
subjectExpression = subjectVariable?.initializer ?: subjectExpression
val hasSubject = subjectExpression != null
val subject = FirWhenSubject()
return FirWhenExpressionImpl(
session,
null,
subjectExpression,
subjectVariable
).apply {
return FirWhenExpressionImpl(session, null, subjectExpression, subjectVariable).apply {
if (hasSubject) {
subject.bind(this)
}
@@ -615,7 +629,7 @@ class ExpressionsConverter(
*/
private fun convertWhenEntry(whenEntry: LighterASTNode): WhenEntry {
var isElse = false
lateinit var firBlock: FirBlock
var firBlock: FirBlock = FirEmptyExpressionBlock(session)
val conditions = mutableListOf<FirExpression>()
whenEntry.forEachChildren {
when (it.tokenType) {
@@ -632,10 +646,10 @@ class ExpressionsConverter(
}
private fun convertWhenConditionExpression(whenCondition: LighterASTNode): FirExpression {
lateinit var firExpression: FirExpression
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "No expression in condition with expression")
whenCondition.forEachChildren {
when (it.tokenType) {
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "No expression in condition with expression")
}
}
@@ -646,7 +660,7 @@ class ExpressionsConverter(
private fun convertWhenConditionInRange(whenCondition: LighterASTNode): FirExpression {
var isNegate = false
lateinit var firExpression: FirExpression
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "No range in condition with range")
whenCondition.forEachChildren {
when (it.tokenType) {
NOT_IN -> isNegate = true
@@ -680,12 +694,12 @@ class ExpressionsConverter(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitArrayAccessExpression
*/
private fun convertArrayAccessExpression(arrayAccess: LighterASTNode): FirFunctionCall {
lateinit var firExpression: FirExpression
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "No array expression")
val indices: MutableList<FirExpression> = mutableListOf()
arrayAccess.forEachChildren {
when (it.tokenType) {
INDICES -> indices += convertIndices(it)
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "No array expression")
}
}
return FirFunctionCallImpl(session, null).apply {
@@ -701,7 +715,7 @@ class ExpressionsConverter(
private fun convertCollectionLiteralExpresion(expression: LighterASTNode): FirExpression {
val firExpressionList = mutableListOf<FirExpression>()
expression.forEachChildren {
if (it.isExpression()) firExpressionList += getAsFirExpression<FirExpression>(it)
if (it.isExpression()) firExpressionList += getAsFirExpression<FirExpression>(it, "Incorrect collection literal argument")
}
return FirArrayOfCallImpl(session, null).apply {
@@ -715,7 +729,7 @@ class ExpressionsConverter(
private fun convertIndices(indices: LighterASTNode): List<FirExpression> {
val firExpressionList: MutableList<FirExpression> = mutableListOf()
indices.forEachChildren {
if (it.isExpression()) firExpressionList += getAsFirExpression<FirExpression>(it)
if (it.isExpression()) firExpressionList += getAsFirExpression<FirExpression>(it, "Incorrect index expression")
}
return firExpressionList
@@ -738,17 +752,15 @@ class ExpressionsConverter(
*/
private fun convertDoWhile(doWhileLoop: LighterASTNode): FirElement {
var block: LighterASTNode? = null
var condition: FirExpression? = null
var firCondition: FirExpression = FirErrorExpressionImpl(session, null, "No condition in do-while loop")
doWhileLoop.forEachChildren {
when (it.tokenType) {
BODY -> block = it
CONDITION -> condition = convertCondition(it)
CONDITION -> firCondition = getAsFirExpression(it, "No condition in do-while loop")
}
}
return FirDoWhileLoopImpl(
session, null, condition ?: FirErrorExpressionImpl(session, null, "No condition in do-while loop")
).configure { convertLoopBody(block) }
return FirDoWhileLoopImpl(session, null, firCondition).configure { convertLoopBody(block) }
}
/**
@@ -757,17 +769,15 @@ class ExpressionsConverter(
*/
private fun convertWhile(whileLoop: LighterASTNode): FirElement {
var block: LighterASTNode? = null
var condition: FirExpression? = null
var firCondition: FirExpression = FirErrorExpressionImpl(session, null, "No condition in while loop")
whileLoop.forEachChildren {
when (it.tokenType) {
BODY -> block = it
CONDITION -> condition = convertCondition(it)
CONDITION -> firCondition = getAsFirExpression(it, "No condition in while loop")
}
}
return FirWhileLoopImpl(
session, null, condition ?: FirErrorExpressionImpl(session, null, "No condition in while loop")
).configure { convertLoopBody(block) }
return FirWhileLoopImpl(session, null, firCondition).configure { convertLoopBody(block) }
}
/**
@@ -781,7 +791,7 @@ class ExpressionsConverter(
forLoop.forEachChildren {
when (it.tokenType) {
VALUE_PARAMETER -> parameter = declarationsConverter.convertValueParameter(it)
LOOP_RANGE -> convertCondition(it)?.apply { rangeExpression = this }
LOOP_RANGE -> rangeExpression = getAsFirExpression(it, "No range in for loop")
BODY -> blockNode = it
}
}
@@ -873,7 +883,7 @@ class ExpressionsConverter(
tryExpression.forEachChildren {
when (it.tokenType) {
BLOCK -> tryBlock = declarationsConverter.convertBlock(it)
CATCH -> catchClauses += convertCatchClause(it)
CATCH -> convertCatchClause(it)?.also { oneClause -> catchClauses += oneClause }
FINALLY -> finallyBlock = convertFinally(it)
}
}
@@ -888,12 +898,12 @@ class ExpressionsConverter(
/**
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseTry
*/
private fun convertCatchClause(catchClause: LighterASTNode): Pair<ValueParameter?, FirBlock> {
private fun convertCatchClause(catchClause: LighterASTNode): Pair<ValueParameter?, FirBlock>? {
var valueParameter: ValueParameter? = null
var blockNode: LighterASTNode? = null
catchClause.forEachChildren {
when (it.tokenType) {
VALUE_PARAMETER_LIST -> valueParameter = declarationsConverter.convertValueParameters(it).first()
VALUE_PARAMETER_LIST -> valueParameter = declarationsConverter.convertValueParameters(it).firstOrNull() ?: return null
BLOCK -> blockNode = it
}
}
@@ -920,20 +930,18 @@ class ExpressionsConverter(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitIfExpression
*/
private fun convertIfExpression(ifExpression: LighterASTNode): FirExpression {
var condition: FirExpression? = null
var firCondition: FirExpression = FirErrorExpressionImpl(session, null, "If statement should have condition")
var thenBlock: LighterASTNode? = null
var elseBlock: LighterASTNode? = null
ifExpression.forEachChildren {
when (it.tokenType) {
CONDITION -> condition = convertCondition(it)
CONDITION -> firCondition = getAsFirExpression(it, "If statement should have condition")
THEN -> thenBlock = it
ELSE -> elseBlock = it
}
}
return FirWhenExpressionImpl(session, null).apply {
val firCondition =
condition ?: FirErrorExpressionImpl(this@ExpressionsConverter.session, null, "If statement should have condition")
val trueBranch = convertLoopBody(thenBlock)
branches += FirWhenBranchImpl(this@ExpressionsConverter.session, null, firCondition, trueBranch)
val elseBranch = convertLoopBody(elseBlock)
@@ -943,17 +951,6 @@ class ExpressionsConverter(
}
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseCondition
*/
private fun convertCondition(condition: LighterASTNode): FirExpression? {
condition.forEachChildren {
if (it.isExpression()) return getAsFirExpression(it)
}
return null
}
/**
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseJump
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitBreakExpression
@@ -997,16 +994,15 @@ class ExpressionsConverter(
*/
private fun convertReturn(returnExpression: LighterASTNode): FirExpression {
var labelName: String? = null
var firExpression: FirExpression? = null
var firExpression: FirExpression = FirUnitExpression(session, null)
returnExpression.forEachChildren {
when (it.tokenType) {
LABEL_QUALIFIER -> labelName = it.getAsString().replace("@", "")
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
LABEL_QUALIFIER -> labelName = it.getAsStringWithoutBacktick().replace("@", "")
else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "Incorrect return expression")
}
}
val result = firExpression ?: FirUnitExpression(session, null)
return result.toReturn(labelName)
return firExpression.toReturn(labelName)
}
/**
@@ -1014,12 +1010,12 @@ class ExpressionsConverter(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitThrowExpression
*/
private fun convertThrow(throwExpression: LighterASTNode): FirExpression {
var firExpression: FirExpression? = null
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Nothing to throw")
throwExpression.forEachChildren {
if (it.isExpression()) firExpression = getAsFirExpression(it)
if (it.isExpression()) firExpression = getAsFirExpression(it, "Nothing to throw")
}
return FirThrowExpressionImpl(session, null, firExpression ?: FirErrorExpressionImpl(session, null, "Nothing to throw"))
return FirThrowExpressionImpl(session, null, firExpression)
}
/**
@@ -1077,14 +1073,14 @@ class ExpressionsConverter(
private fun convertValueArgument(valueArgument: LighterASTNode): FirExpression {
var identifier: String? = null
var isSpread = false
lateinit var firExpression: FirExpression
var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Argument is absent")
valueArgument.forEachChildren {
when (it.tokenType) {
VALUE_ARGUMENT_NAME -> identifier = it.getAsString()
MUL -> isSpread = true
STRING_TEMPLATE -> firExpression = convertStringTemplate(it)
is KtConstantExpressionElementType -> firExpression = convertConstantExpression(it)
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "Argument is absent")
}
}
return when {
@@ -1097,15 +1093,16 @@ class ExpressionsConverter(
/**
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.initializeLValue
*/
fun convertLValue(leftArgNode: LighterASTNode, container: FirModifiableQualifiedAccess<*>): FirReference {
return when (leftArgNode.tokenType) {
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(leftArgNode) as FirQualifiedAccess).let { firQualifiedAccess ->
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}")
}
@@ -16,16 +16,14 @@ 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.FunctionUtil.pop
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast
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.lightTree.fir.DestructuringDeclaration
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parsing.KotlinExpressionParsing
@@ -42,16 +40,17 @@ fun String.getOperationSymbol(): IElementType {
}
fun ExpressionsConverter.convertAssignment(
leftArgNode: LighterASTNode,
leftArgNode: LighterASTNode?,
rightArgAsFir: FirExpression,
operation: FirOperation
): FirStatement {
if (leftArgNode.tokenType == PARENTHESIZED) {
if (leftArgNode != null && leftArgNode.tokenType == PARENTHESIZED) {
return convertAssignment(leftArgNode.getExpressionInParentheses(), rightArgAsFir, operation)
}
if (leftArgNode.tokenType == ARRAY_ACCESS_EXPRESSION) {
if (leftArgNode != null && leftArgNode.tokenType == ARRAY_ACCESS_EXPRESSION) {
val arrayAccessFunctionCall = getAsFirExpression(leftArgNode) as FirFunctionCall
val firArrayExpression = arrayAccessFunctionCall.explicitReceiver!!
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
@@ -76,12 +75,14 @@ fun ExpressionsConverter.convertAssignment(
}
}
if (operation != FirOperation.ASSIGN &&
leftArgNode.tokenType != REFERENCE_EXPRESSION && leftArgNode.tokenType != THIS_EXPRESSION &&
(leftArgNode.tokenType !in qualifiedAccessTokens || getSelectorType(leftArgNode.getChildrenAsArray()) != REFERENCE_EXPRESSION)
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))
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)
}
@@ -104,7 +105,7 @@ fun ExpressionsConverter.generateIncrementOrDecrementBlock(
return FirBlockImpl(session, null).apply {
val tempName = Name.special("<unary>")
val temporaryVariable = generateTemporaryVariable(
this@generateIncrementOrDecrementBlock.session, null, tempName, getAsFirExpression(argument)
this@generateIncrementOrDecrementBlock.session, null, tempName, getAsFirExpression(argument, "Incorrect expression inside inc/dec")
)
statements += temporaryVariable
val resultName = Name.special("<unary-result>")
@@ -30,12 +30,16 @@ class ClassWrapper(
val delegatedSuperTypeRef: FirTypeRef,
val superTypeCallEntry: MutableList<FirExpression>
) {
fun isObjectLiteral(): Boolean {
return className == SpecialNames.NO_NAME_PROVIDED && isObject()
}
private fun isObject(): Boolean {
return classKind == ClassKind.OBJECT
}
private fun isSealed(): Boolean {
return modifiers.getModality() == Modality.SEALED
return modifiers.hasModality(Modality.SEALED)
}
private fun isEnum(): Boolean {
@@ -16,18 +16,10 @@ import org.jetbrains.kotlin.fir.lightTree.converter.utils.generateDestructuringB
data class DestructuringDeclaration(
val isVar: Boolean,
val entries: List<FirVariable<*>>,
val initializer: FirExpression?
val initializer: FirExpression
) {
fun toFirDestructingDeclaration(session: FirSession): FirExpression {
val baseVariable = generateTemporaryVariable(
session, null, "destruct",
initializer ?: FirErrorExpressionImpl(session, null, "Destructuring declaration without initializer")
)
return generateDestructuringBlock(
session,
this,
baseVariable,
tmpVariable = true
)
val baseVariable = generateTemporaryVariable(session, null, "destruct", initializer)
return generateDestructuringBlock(session, this, baseVariable, tmpVariable = true)
}
}
@@ -17,6 +17,9 @@ 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.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
class ValueParameter(
private val isVal: Boolean,
@@ -31,7 +34,10 @@ class ValueParameter(
fun toFirProperty(): FirProperty {
val name = this.firValueParameter.name
val type = this.firValueParameter.returnTypeRef
var type = this.firValueParameter.returnTypeRef
if (type is FirImplicitTypeRef) {
type = FirErrorTypeRefImpl(this.firValueParameter.session, null, "Incomplete code")
}
return FirMemberPropertyImpl(
this.firValueParameter.session,
@@ -64,9 +64,9 @@ data class WhenEntry(
val condition = conditions.first()
return when (condition) {
is FirOperatorCallImpl -> condition.arguments.first()
is FirFunctionCall -> condition.explicitReceiver!!
is FirTypeOperatorCallImpl -> condition
else -> FirErrorExpressionImpl(session, null, "Unsupported when condition: ${condition.javaClass}")
//is FirFunctionCall -> condition.explicitReceiver!!
//is FirTypeOperatorCallImpl -> condition
else -> FirErrorExpressionImpl(session, null, "No expression in condition with expression")
}
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.lightTree.fir.modifier
import com.intellij.lang.LighterASTNode
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.impl.FirAbstractAnnotatedElement
@@ -24,49 +25,49 @@ class Modifier(
session: FirSession,
psi: PsiElement? = null,
private var classModifier: ClassModifier? = null,
private val classModifiers: MutableList<ClassModifier> = mutableListOf(),
private val memberModifiers: MutableList<MemberModifier> = mutableListOf(),
private var visibilityModifier: VisibilityModifier = VisibilityModifier.UNKNOWN,
private val visibilityModifiers: MutableList<VisibilityModifier> = mutableListOf(),
private val functionModifiers: MutableList<FunctionModifier> = mutableListOf(),
private var propertyModifier: PropertyModifier? = null,
private var inheritanceModifier: InheritanceModifier? = null,
private var parameterModifier: ParameterModifier? = null,
private var platformModifier: PlatformModifier? = null
private val inheritanceModifiers: MutableList<InheritanceModifier> = mutableListOf(),
private val parameterModifiers: MutableList<ParameterModifier> = mutableListOf(),
private val platformModifiers: MutableList<PlatformModifier> = mutableListOf()
) : FirAbstractAnnotatedElement(session, psi) {
fun addModifier(modifier: LighterASTNode) {
val tokenType = modifier.tokenType
when {
CLASS_MODIFIER.contains(tokenType) -> this.classModifier = ClassModifier.valueOf(modifier.toString().toUpperCase())
CLASS_MODIFIER.contains(tokenType) -> this.classModifiers += ClassModifier.valueOf(modifier.toString().toUpperCase())
MEMBER_MODIFIER.contains(tokenType) -> this.memberModifiers += MemberModifier.valueOf(modifier.toString().toUpperCase())
VISIBILITY_MODIFIER.contains(tokenType) -> this.visibilityModifier =
VISIBILITY_MODIFIER.contains(tokenType) -> this.visibilityModifiers +=
VisibilityModifier.valueOf(modifier.toString().toUpperCase())
FUNCTION_MODIFIER.contains(tokenType) -> this.functionModifiers += FunctionModifier.valueOf(modifier.toString().toUpperCase())
PROPERTY_MODIFIER.contains(tokenType) -> this.propertyModifier = PropertyModifier.valueOf(modifier.toString().toUpperCase())
INHERITANCE_MODIFIER.contains(tokenType) -> this.inheritanceModifier =
INHERITANCE_MODIFIER.contains(tokenType) -> this.inheritanceModifiers +=
InheritanceModifier.valueOf(modifier.toString().toUpperCase())
PARAMETER_MODIFIER.contains(tokenType) -> this.parameterModifier = ParameterModifier.valueOf(modifier.toString().toUpperCase())
PLATFORM_MODIFIER.contains(tokenType) -> this.platformModifier = PlatformModifier.valueOf(modifier.toString().toUpperCase())
PARAMETER_MODIFIER.contains(tokenType) -> this.parameterModifiers += ParameterModifier.valueOf(modifier.toString().toUpperCase())
PLATFORM_MODIFIER.contains(tokenType) -> this.platformModifiers += PlatformModifier.valueOf(modifier.toString().toUpperCase())
}
}
fun isEnum(): Boolean {
return classModifier == ClassModifier.ENUM
return classModifiers.contains(ClassModifier.ENUM)
}
fun isAnnotation(): Boolean {
return classModifier == ClassModifier.ANNOTATION
return classModifiers.contains(ClassModifier.ANNOTATION)
}
fun isDataClass(): Boolean {
return classModifier == ClassModifier.DATA
return classModifiers.contains(ClassModifier.DATA)
}
fun isInner(): Boolean {
return classModifier == ClassModifier.INNER
return classModifiers.contains(ClassModifier.INNER)
}
fun isCompanion(): Boolean {
return classModifier == ClassModifier.COMPANION
return classModifiers.contains(ClassModifier.COMPANION)
}
fun hasOverride(): Boolean {
@@ -78,7 +79,13 @@ class Modifier(
}
fun getVisibility(): Visibility {
return visibilityModifier.toVisibility()
return when {
visibilityModifiers.contains(VisibilityModifier.PRIVATE) -> Visibilities.PRIVATE
visibilityModifiers.contains(VisibilityModifier.PUBLIC) -> Visibilities.PUBLIC
visibilityModifiers.contains(VisibilityModifier.PROTECTED) -> Visibilities.PROTECTED
visibilityModifiers.contains(VisibilityModifier.INTERNAL) -> Visibilities.INTERNAL
else -> Visibilities.UNKNOWN
}
}
fun hasTailrec(): Boolean {
@@ -109,27 +116,43 @@ class Modifier(
return propertyModifier == PropertyModifier.CONST
}
fun hasModality(modality: Modality): Boolean {
return when {
modality == Modality.FINAL && inheritanceModifiers.contains(InheritanceModifier.FINAL) -> true
modality == Modality.SEALED && inheritanceModifiers.contains(InheritanceModifier.SEALED) -> true
modality == Modality.ABSTRACT && inheritanceModifiers.contains(InheritanceModifier.ABSTRACT) -> true
modality == Modality.OPEN && inheritanceModifiers.contains(InheritanceModifier.OPEN) -> true
else -> false
}
}
fun getModality(): Modality? {
return inheritanceModifier?.toModality()
return when {
inheritanceModifiers.contains(InheritanceModifier.FINAL) -> Modality.FINAL
inheritanceModifiers.contains(InheritanceModifier.SEALED) -> Modality.SEALED
inheritanceModifiers.contains(InheritanceModifier.ABSTRACT) -> Modality.ABSTRACT
inheritanceModifiers.contains(InheritanceModifier.OPEN) -> Modality.OPEN
else -> null
}
}
fun hasVararg(): Boolean {
return parameterModifier == ParameterModifier.VARARG
return parameterModifiers.contains(ParameterModifier.VARARG)
}
fun hasNoinline(): Boolean {
return parameterModifier == ParameterModifier.NOINLINE
return parameterModifiers.contains(ParameterModifier.NOINLINE)
}
fun hasCrossinline(): Boolean {
return parameterModifier == ParameterModifier.CROSSINLINE
return parameterModifiers.contains(ParameterModifier.CROSSINLINE)
}
fun hasExpect(): Boolean {
return platformModifier == PlatformModifier.EXPECT
return platformModifiers.contains(PlatformModifier.EXPECT) || platformModifiers.contains(PlatformModifier.HEADER)
}
fun hasActual(): Boolean {
return platformModifier == PlatformModifier.ACTUAL
return platformModifiers.contains(PlatformModifier.ACTUAL) || platformModifiers.contains(PlatformModifier.IMPL)
}
}
@@ -41,7 +41,7 @@ object ModifierSets {
SEALED_KEYWORD
)
val PARAMETER_MODIFIER = TokenSet.create(VARARG_KEYWORD, NOINLINE_KEYWORD, CROSSINLINE_KEYWORD)
val PLATFORM_MODIFIER = TokenSet.create(EXPECT_KEYWORD, ACTUAL_KEYWORD)
val PLATFORM_MODIFIER = TokenSet.create(EXPECT_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD, IMPL_KEYWORD)
val VARIANCE_MODIFIER = TokenSet.create(IN_KEYWORD, OUT_KEYWORD)
val REIFICATION_MODIFIER = TokenSet.create(REIFIED_KEYWORD)
}
@@ -24,33 +24,11 @@ enum class MemberModifier {
}
enum class VisibilityModifier {
PUBLIC {
override fun toVisibility(): Visibility {
return Visibilities.PUBLIC
}
},
PRIVATE {
override fun toVisibility(): Visibility {
return Visibilities.PRIVATE
}
},
INTERNAL {
override fun toVisibility(): Visibility {
return Visibilities.INTERNAL
}
},
PROTECTED {
override fun toVisibility(): Visibility {
return Visibilities.PROTECTED
}
},
UNKNOWN {
override fun toVisibility(): Visibility {
return Visibilities.UNKNOWN
}
};
abstract fun toVisibility(): Visibility
PUBLIC,
PRIVATE,
INTERNAL,
PROTECTED,
UNKNOWN
}
enum class FunctionModifier {
@@ -67,28 +45,10 @@ enum class PropertyModifier {
}
enum class InheritanceModifier {
ABSTRACT {
override fun toModality(): Modality {
return Modality.ABSTRACT
}
},
FINAL {
override fun toModality(): Modality {
return Modality.FINAL
}
},
OPEN {
override fun toModality(): Modality {
return Modality.OPEN
}
},
SEALED {
override fun toModality(): Modality {
return Modality.SEALED
}
};
abstract fun toModality(): Modality
ABSTRACT,
FINAL,
OPEN,
SEALED
}
enum class ParameterModifier {
@@ -99,27 +59,15 @@ enum class ParameterModifier {
enum class PlatformModifier {
EXPECT,
ACTUAL
ACTUAL,
HEADER,
IMPL
}
enum class VarianceModifier {
IN {
override fun toVariance(): Variance {
return Variance.IN_VARIANCE
}
},
OUT {
override fun toVariance(): Variance {
return Variance.OUT_VARIANCE
}
},
INVARIANT {
override fun toVariance(): Variance {
return Variance.INVARIANT
}
};
abstract fun toVariance(): Variance
IN,
OUT,
INVARIANT
}
enum class ReificationModifier {
@@ -22,4 +22,8 @@ class TypeModifier(
KtTokens.SUSPEND_KEYWORD -> this.hasSuspend = true
}
}
fun hasNoAnnotations(): Boolean {
return annotations.isEmpty()
}
}
@@ -17,19 +17,24 @@ class TypeParameterModifier(
session: FirSession,
psi: PsiElement? = null,
private var varianceModifier: VarianceModifier = VarianceModifier.INVARIANT,
private val varianceModifiers: MutableList<VarianceModifier> = mutableListOf(),
private var reificationModifier: ReificationModifier? = null
) : FirAbstractAnnotatedElement(session, psi) {
fun addModifier(modifier: LighterASTNode) {
val tokenType = modifier.tokenType
when {
VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifier = VarianceModifier.valueOf(modifier.toString().toUpperCase())
REIFICATION_MODIFIER.contains(tokenType) -> this.reificationModifier = ReificationModifier.valueOf(modifier.toString().toUpperCase())
VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifiers += VarianceModifier.valueOf(modifier.toString().toUpperCase())
REIFICATION_MODIFIER.contains(tokenType) -> this.reificationModifier =
ReificationModifier.valueOf(modifier.toString().toUpperCase())
}
}
fun getVariance(): Variance {
return varianceModifier.toVariance()
return when {
varianceModifiers.contains(VarianceModifier.OUT) -> Variance.OUT_VARIANCE
varianceModifiers.contains(VarianceModifier.IN) -> Variance.IN_VARIANCE
else -> Variance.INVARIANT
}
}
fun hasReified(): Boolean {
@@ -16,16 +16,20 @@ class TypeProjectionModifier(
session: FirSession,
psi: PsiElement? = null,
private var varianceModifier: VarianceModifier = VarianceModifier.INVARIANT
private val varianceModifiers: MutableList<VarianceModifier> = mutableListOf()
) : FirAbstractAnnotatedElement(session, psi) {
fun addModifier(modifier: LighterASTNode) {
val tokenType = modifier.tokenType
when {
VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifier = VarianceModifier.valueOf(modifier.toString().toUpperCase())
VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifiers += VarianceModifier.valueOf(modifier.toString().toUpperCase())
}
}
fun getVariance(): Variance {
return varianceModifier.toVariance()
return when {
varianceModifiers.contains(VarianceModifier.IN) -> Variance.IN_VARIANCE
varianceModifiers.contains(VarianceModifier.OUT) -> Variance.OUT_VARIANCE
else -> Variance.INVARIANT
}
}
}
@@ -27,37 +27,56 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() {
var counter = 0
var errorCounter = 0
val onEachFile: (File) -> Unit = { file ->
if (!compareFir(file)) errorCounter++
counter++
}
println("BASE PATH: $path")
if (!withTestData) {
path.walkTopDown { file ->
if (!compareFir(file)) errorCounter++
counter++
}
path.walkTopDown(onEachFile)
} else {
path.walkTopDownWithTestData { file ->
if (!compareFir(file)) errorCounter++
counter++
}
path.walkTopDownWithTestData(onEachFile)
}
println("All scanned files: $counter")
println("Files that aren't equal to FIR: $errorCounter")
TestCase.assertEquals(0, errorCounter)
}
private fun compareAll(stubMode: Boolean, path: String = System.getProperty("user.dir"), withTestData: Boolean = false) {
private fun compareAll(stubMode: Boolean) {
val lightTreeConverter = LightTree2Fir(stubMode, myProject)
compareBase(path, withTestData) { file ->
compareBase(System.getProperty("user.dir"), withTestData = false) { file ->
val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
//light tree
val firFileFromLightTree = lightTreeConverter.buildFirFile(text, file.name)
val treeFromLightTree = StringBuilder().also { FirRenderer(it).visitFile(firFileFromLightTree) }.toString()
//psi
val ktFile = createPsiFile(FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.path)), text) as KtFile
val firFileFromPsi = ktFile.toFirFile(stubMode)
val treeFromPsi = StringBuilder().also { FirRenderer(it).visitFile(firFileFromPsi) }.toString()
//light tree
val firFileFromLightTree = lightTreeConverter.buildFirFile(text, file.name)
val treeFromLightTree = StringBuilder().also { FirRenderer(it).visitFile(firFileFromLightTree) }.toString()
return@compareBase treeFromLightTree == treeFromPsi
}
}
fun testCompareDiagnostics() {
val lightTreeConverter = LightTree2Fir(false, myProject)
compareBase("compiler/testData/diagnostics/tests", withTestData = true) { file ->
val notEditedText = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
val text = notEditedText.replace("(<!>)|(<!.*?!>)".toRegex(), "").replaceAfter(".java", "")
//psi
val ktFile = createPsiFile(FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.path)), text) as KtFile
val firFileFromPsi = ktFile.toFirFile(stubMode = false)
val treeFromPsi = StringBuilder().also { FirRenderer(it).visitFile(firFileFromPsi) }.toString()
.replace("<Unsupported LValue.*?>".toRegex(), "<Unsupported LValue>")
//light tree
val firFileFromLightTree = lightTreeConverter.buildFirFile(text, file.name)
val treeFromLightTree = StringBuilder().also { FirRenderer(it).visitFile(firFileFromLightTree) }.toString()
.replace("<Unsupported LValue.*?>".toRegex(), "<Unsupported LValue>")
return@compareBase treeFromLightTree == treeFromPsi
}
}
@@ -366,8 +385,4 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() {
visitAnonymousObject = true
)
}
fun testDiagnostics() {
compareAll(false, "compiler/testData/diagnostics/tests", withTestData = true)
}
}