org.jetbrains.kotlin.fir.expressions.FirExpressionUtil.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.expressions
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorLoop
import org.jetbrains.kotlin.fir.expressions.impl.FirBlockImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.TransformData
import org.jetbrains.kotlin.fir.visitors.transformInplace
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.utils.addIfNotNull
inline val FirAnnotation.unexpandedConeClassLikeType: ConeClassLikeType?
get() = ((annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)
inline val FirAnnotation.unexpandedClassId: ClassId?
get() = unexpandedConeClassLikeType?.lookupTag?.classId
fun buildConstOrErrorExpression(source: KtSourceElement?, kind: ConstantValueKind, value: T?, diagnostic: ConeDiagnostic): FirExpression =
value?.let {
buildConstExpression(source, kind, it, setType = false)
} ?: buildErrorExpression {
this.source = source
this.diagnostic = diagnostic
}
inline val FirCall.arguments: List get() = argumentList.arguments
inline val FirCall.argument: FirExpression get() = argumentList.arguments.first()
inline val FirCall.dynamicVararg: FirVarargArgumentsExpression?
get() = arguments.firstOrNull() as? FirVarargArgumentsExpression
inline val FirCall.dynamicVarargArguments: List?
get() = dynamicVararg?.arguments
inline val FirFunctionCall.isCalleeDynamic: Boolean
get() = calleeReference.toResolvedNamedFunctionSymbol()?.origin == FirDeclarationOrigin.DynamicScope
inline val FirCall.resolvedArgumentMapping: LinkedHashMap?
get() = when (val argumentList = argumentList) {
is FirResolvedArgumentList -> argumentList.mapping
else -> null
}
fun FirExpression.toResolvedCallableReference(): FirResolvedNamedReference? {
return toReference()?.resolved
}
fun FirExpression.toReference(): FirReference? {
return when (this) {
is FirWrappedArgumentExpression -> expression.toResolvedCallableReference()
is FirSmartCastExpression -> originalExpression.toReference()
is FirDesugaredAssignmentValueReferenceExpression -> expressionRef.value.toReference()
is FirResolvable -> calleeReference
else -> null
}
}
fun FirExpression.toResolvedCallableSymbol(): FirCallableSymbol<*>? {
return toResolvedCallableReference()?.resolvedSymbol as? FirCallableSymbol<*>?
}
fun buildErrorLoop(source: KtSourceElement?, diagnostic: ConeDiagnostic): FirErrorLoop {
return buildErrorLoop {
this.source = source
this.diagnostic = diagnostic
}.also {
it.block.replaceTypeRef(buildErrorTypeRef {
this.diagnostic = diagnostic
})
}
}
fun buildErrorExpression(
source: KtSourceElement?,
diagnostic: ConeDiagnostic,
element: FirElement? = null
): FirErrorExpression {
return buildErrorExpression {
this.source = source
this.diagnostic = diagnostic
this.expression = element as? FirExpression
this.nonExpressionElement = element.takeUnless { it is FirExpression }
}
}
fun FirBlock.transformStatementsIndexed(transformer: FirTransformer, dataProducer: (Int) -> TransformData): FirBlock {
when (this) {
is FirBlockImpl -> statements.transformInplace(transformer, dataProducer)
is FirSingleExpressionBlock -> {
(dataProducer(0) as? TransformData.Data)?.value?.let { transformStatements(transformer, it) }
}
}
return this
}
fun FirBlock.replaceFirstStatement(factory: (T) -> FirStatement): T {
require(this is FirBlockImpl) {
"replaceFirstStatement should not be called for ${this::class.simpleName}"
}
@Suppress("UNCHECKED_CAST")
val existing = statements[0] as T
statements[0] = factory(existing)
return existing
}
fun FirExpression.unwrapArgument(): FirExpression = (this as? FirWrappedArgumentExpression)?.expression ?: this
fun FirExpression.unwrapAndFlattenArgument(): List = buildList { unwrapAndFlattenArgumentTo(this) }
private fun FirExpression.unwrapAndFlattenArgumentTo(list: MutableList) {
when (val unwrapped = unwrapArgument()) {
is FirArrayLiteral, is FirFunctionCall -> (unwrapped as FirCall).arguments.forEach { it.unwrapAndFlattenArgumentTo(list) }
is FirVarargArgumentsExpression -> unwrapped.arguments.forEach { it.unwrapAndFlattenArgumentTo(list) }
else -> list.add(unwrapped)
}
}
val FirVariableAssignment.explicitReceiver: FirExpression? get() = unwrapLValue()?.explicitReceiver
val FirVariableAssignment.dispatchReceiver: FirExpression get() = unwrapLValue()?.dispatchReceiver ?: FirNoReceiverExpression
val FirVariableAssignment.extensionReceiver: FirExpression get() = unwrapLValue()?.extensionReceiver ?: FirNoReceiverExpression
val FirVariableAssignment.calleeReference: FirReference? get() = lValue.toReference()
val FirVariableAssignment.contextReceiverArguments: List get() = unwrapLValue()?.contextReceiverArguments ?: emptyList()
fun FirVariableAssignment.unwrapLValue(): FirQualifiedAccessExpression? {
val lValue = lValue
return lValue as? FirQualifiedAccessExpression
?: (lValue as? FirDesugaredAssignmentValueReferenceExpression)?.expressionRef?.value as? FirQualifiedAccessExpression
}
val FirElement.calleeReference: FirReference?
get() = (this as? FirResolvable)?.calleeReference ?: (this as? FirVariableAssignment)?.calleeReference
fun FirExpression.unwrapSmartcastExpression(): FirExpression =
when (this) {
is FirSmartCastExpression -> originalExpression
else -> this
}
/**
* A callable reference is bound iff
* - one of [dispatchReceiver] or [extensionReceiver] is **not** [FirNoReceiverExpression] and
* - it's not referring to a static member.
*/
val FirCallableReferenceAccess.isBound: Boolean
get() = (dispatchReceiver != FirNoReceiverExpression || extensionReceiver != FirNoReceiverExpression) &&
calleeReference.toResolvedCallableSymbol()?.isStatic != true
val FirQualifiedAccessExpression.allReceiverExpressions: List
get() = buildList {
addIfNotNull(dispatchReceiver)
addIfNotNull(extensionReceiver)
addAll(contextReceiverArguments)
}
inline fun FirFunctionCall.forAllReifiedTypeParameters(block: (ConeKotlinType, FirTypeProjectionWithVariance) -> Unit) {
val functionSymbol = calleeReference.toResolvedNamedFunctionSymbol() ?: return
for ((typeParameterSymbol, typeArgument) in functionSymbol.typeParameterSymbols.zip(typeArguments)) {
if (typeParameterSymbol.isReified && typeArgument is FirTypeProjectionWithVariance) {
val type = typeArgument.typeRef.coneTypeOrNull ?: continue
block(type, typeArgument)
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy