FIR: set missed source in various FirElements
This could be caught by debuggability tests, such as stepping tests, which are not enabled for FIR yet. Instead, for now, full pipeline tests will raise index out-of-bound errors due to the undefined offsets, which stem from null source.
This commit is contained in:
committed by
Mikhail Glukhikh
parent
46cc01602e
commit
f4531b0f34
@@ -30,8 +30,8 @@ import org.jetbrains.kotlin.fir.symbols.AccessorSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
|
||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedReceiverParameterDescriptor
|
import org.jetbrains.kotlin.ir.descriptors.WrappedReceiverParameterDescriptor
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
@@ -46,17 +46,15 @@ import org.jetbrains.kotlin.ir.util.functions
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
internal fun <T : IrElement> FirElement.convertWithOffsets(
|
internal fun <T : IrElement> FirElement.convertWithOffsets(
|
||||||
f: (startOffset: Int, endOffset: Int) -> T
|
f: (startOffset: Int, endOffset: Int) -> T
|
||||||
): T {
|
): T {
|
||||||
if (psi is PsiCompiledElement) return f(-1, -1)
|
if (psi is PsiCompiledElement) return f(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||||
val startOffset = psi?.startOffsetSkippingComments ?: -1
|
val startOffset = psi?.startOffsetSkippingComments ?: UNDEFINED_OFFSET
|
||||||
val endOffset = psi?.endOffset ?: -1
|
val endOffset = psi?.endOffset ?: UNDEFINED_OFFSET
|
||||||
return f(startOffset, endOffset)
|
return f(startOffset, endOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -550,7 +550,11 @@ class Fir2IrVisitor(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
// TODO: Other conditions to check?
|
// TODO: Other conditions to check?
|
||||||
if (expression.typeRef.coneTypeSafe<ConeKotlinType>()?.hasEnhancedNullability != true) {
|
// [TypeOperatorLowering] will retrieve the source (from start offset to end offset) as an assertion message.
|
||||||
|
// Avoid type casting if we can't determine the source for some reasons, e.g., implicit `this` receiver.
|
||||||
|
if (expression.source == null ||
|
||||||
|
expression.typeRef.coneTypeSafe<ConeKotlinType>()?.hasEnhancedNullability != true
|
||||||
|
) {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
return IrTypeOperatorCallImpl(
|
return IrTypeOperatorCallImpl(
|
||||||
|
|||||||
+1
@@ -1510,6 +1510,7 @@ class DeclarationsConverter(
|
|||||||
}
|
}
|
||||||
rValue = firExpression!!
|
rValue = firExpression!!
|
||||||
dispatchReceiver = buildThisReceiverExpression {
|
dispatchReceiver = buildThisReceiverExpression {
|
||||||
|
source = firExpression!!.source
|
||||||
calleeReference = buildImplicitThisReference {
|
calleeReference = buildImplicitThisReference {
|
||||||
boundSymbol = containerSymbol
|
boundSymbol = containerSymbol
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -665,18 +665,21 @@ class ExpressionsConverter(
|
|||||||
if (hasSubject) {
|
if (hasSubject) {
|
||||||
val firCondition = entry.toFirWhenCondition()
|
val firCondition = entry.toFirWhenCondition()
|
||||||
buildWhenBranch {
|
buildWhenBranch {
|
||||||
|
source = branch.source
|
||||||
condition = firCondition
|
condition = firCondition
|
||||||
result = branch
|
result = branch
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val firCondition = entry.toFirWhenConditionWithoutSubject()
|
val firCondition = entry.toFirWhenConditionWithoutSubject()
|
||||||
buildWhenBranch {
|
buildWhenBranch {
|
||||||
|
source = branch.source
|
||||||
condition = firCondition
|
condition = firCondition
|
||||||
result = branch
|
result = branch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buildWhenBranch {
|
buildWhenBranch {
|
||||||
|
source = branch.source
|
||||||
condition = buildElseIfTrueCondition()
|
condition = buildElseIfTrueCondition()
|
||||||
result = branch
|
result = branch
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -51,8 +51,9 @@ class ValueParameter(
|
|||||||
returnTypeRef = type.copyWithNewSourceKind(FirFakeSourceElementKind.PropertyFromParameter)
|
returnTypeRef = type.copyWithNewSourceKind(FirFakeSourceElementKind.PropertyFromParameter)
|
||||||
this.name = name
|
this.name = name
|
||||||
initializer = buildQualifiedAccessExpression {
|
initializer = buildQualifiedAccessExpression {
|
||||||
|
source = firValueParameter.source
|
||||||
calleeReference = buildPropertyFromParameterResolvedNamedReference {
|
calleeReference = buildPropertyFromParameterResolvedNamedReference {
|
||||||
this.name = name
|
this.name = name
|
||||||
resolvedSymbol = this@ValueParameter.firValueParameter.symbol
|
resolvedSymbol = this@ValueParameter.firValueParameter.symbol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -561,11 +561,13 @@ class RawFirBuilder(
|
|||||||
source = delegateSource
|
source = delegateSource
|
||||||
calleeReference =
|
calleeReference =
|
||||||
buildResolvedNamedReference {
|
buildResolvedNamedReference {
|
||||||
|
source = delegateSource
|
||||||
name = delegateName
|
name = delegateName
|
||||||
resolvedSymbol = delegateField.symbol
|
resolvedSymbol = delegateField.symbol
|
||||||
}
|
}
|
||||||
rValue = delegateExpression
|
rValue = delegateExpression
|
||||||
dispatchReceiver = buildThisReceiverExpression {
|
dispatchReceiver = buildThisReceiverExpression {
|
||||||
|
source = delegateSource
|
||||||
calleeReference = buildImplicitThisReference {
|
calleeReference = buildImplicitThisReference {
|
||||||
boundSymbol = containerSymbol
|
boundSymbol = containerSymbol
|
||||||
}
|
}
|
||||||
@@ -1533,6 +1535,7 @@ class RawFirBuilder(
|
|||||||
}
|
}
|
||||||
if (expression.elseKeyword != null) {
|
if (expression.elseKeyword != null) {
|
||||||
branches += buildWhenBranch {
|
branches += buildWhenBranch {
|
||||||
|
source = expression.elseKeyword?.toFirPsiSourceElement()
|
||||||
condition = buildElseIfTrueCondition()
|
condition = buildElseIfTrueCondition()
|
||||||
result = expression.`else`.toFirBlock()
|
result = expression.`else`.toFirBlock()
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -1038,6 +1038,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
|||||||
source = parameterSource
|
source = parameterSource
|
||||||
typeRef = firPropertyReturnTypeRefWithCorrectSourceKind
|
typeRef = firPropertyReturnTypeRefWithCorrectSourceKind
|
||||||
dispatchReceiver = buildThisReceiverExpression {
|
dispatchReceiver = buildThisReceiverExpression {
|
||||||
|
source = parameterSource
|
||||||
calleeReference = buildImplicitThisReference {
|
calleeReference = buildImplicitThisReference {
|
||||||
boundSymbol = classBuilder.symbol
|
boundSymbol = classBuilder.symbol
|
||||||
}
|
}
|
||||||
@@ -1112,6 +1113,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
|||||||
|
|
||||||
private fun FirVariable<*>.toQualifiedAccess(): FirQualifiedAccessExpression = buildQualifiedAccessExpression {
|
private fun FirVariable<*>.toQualifiedAccess(): FirQualifiedAccessExpression = buildQualifiedAccessExpression {
|
||||||
calleeReference = buildResolvedNamedReference {
|
calleeReference = buildResolvedNamedReference {
|
||||||
|
source = this@toQualifiedAccess.source
|
||||||
name = this@toQualifiedAccess.name
|
name = this@toQualifiedAccess.name
|
||||||
resolvedSymbol = this@toQualifiedAccess.symbol
|
resolvedSymbol = this@toQualifiedAccess.symbol
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -190,7 +190,7 @@ fun FirExpression.generateComparisonExpression(
|
|||||||
|
|
||||||
val compareToCall = createConventionCall(
|
val compareToCall = createConventionCall(
|
||||||
operationReferenceSource,
|
operationReferenceSource,
|
||||||
baseSource?.fakeElement(FirFakeSourceElementKind.GeneratedCompararisonExpression),
|
baseSource?.fakeElement(FirFakeSourceElementKind.GeneratedComparisonExpression),
|
||||||
argument,
|
argument,
|
||||||
OperatorNameConventions.COMPARE_TO
|
OperatorNameConventions.COMPARE_TO
|
||||||
)
|
)
|
||||||
@@ -229,13 +229,13 @@ private fun FirExpression.createConventionCall(
|
|||||||
|
|
||||||
fun generateAccessExpression(
|
fun generateAccessExpression(
|
||||||
qualifiedSource: FirSourceElement?,
|
qualifiedSource: FirSourceElement?,
|
||||||
calleReferenceSource: FirSourceElement?,
|
calleeReferenceSource: FirSourceElement?,
|
||||||
name: Name
|
name: Name
|
||||||
): FirQualifiedAccessExpression =
|
): FirQualifiedAccessExpression =
|
||||||
buildQualifiedAccessExpression {
|
buildQualifiedAccessExpression {
|
||||||
this.source = qualifiedSource
|
this.source = qualifiedSource
|
||||||
calleeReference = buildSimpleNamedReference {
|
calleeReference = buildSimpleNamedReference {
|
||||||
this.source = calleReferenceSource
|
this.source = calleeReferenceSource
|
||||||
this.name = name
|
this.name = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,6 +379,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
|
|||||||
val annotations = getter?.annotations
|
val annotations = getter?.annotations
|
||||||
val returnTarget = FirFunctionTarget(null, isLambda = false)
|
val returnTarget = FirFunctionTarget(null, isLambda = false)
|
||||||
getter = buildPropertyAccessor {
|
getter = buildPropertyAccessor {
|
||||||
|
this.source = delegateBuilder.source
|
||||||
this.session = session
|
this.session = session
|
||||||
origin = FirDeclarationOrigin.Source
|
origin = FirDeclarationOrigin.Source
|
||||||
returnTypeRef = buildImplicitTypeRef()
|
returnTypeRef = buildImplicitTypeRef()
|
||||||
@@ -410,12 +411,14 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
|
|||||||
if (isVar && (setter == null || setter is FirDefaultPropertyAccessor)) {
|
if (isVar && (setter == null || setter is FirDefaultPropertyAccessor)) {
|
||||||
val annotations = setter?.annotations
|
val annotations = setter?.annotations
|
||||||
setter = buildPropertyAccessor {
|
setter = buildPropertyAccessor {
|
||||||
|
this.source = delegateBuilder.source
|
||||||
this.session = session
|
this.session = session
|
||||||
origin = FirDeclarationOrigin.Source
|
origin = FirDeclarationOrigin.Source
|
||||||
returnTypeRef = session.builtinTypes.unitType
|
returnTypeRef = session.builtinTypes.unitType
|
||||||
isGetter = false
|
isGetter = false
|
||||||
status = FirDeclarationStatusImpl(Visibilities.Unknown, Modality.FINAL)
|
status = FirDeclarationStatusImpl(Visibilities.Unknown, Modality.FINAL)
|
||||||
val parameter = buildValueParameter {
|
val parameter = buildValueParameter {
|
||||||
|
source = delegateBuilder.source
|
||||||
this.session = session
|
this.session = session
|
||||||
origin = FirDeclarationOrigin.Source
|
origin = FirDeclarationOrigin.Source
|
||||||
returnTypeRef = buildImplicitTypeRef()
|
returnTypeRef = buildImplicitTypeRef()
|
||||||
@@ -429,6 +432,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
|
|||||||
symbol = FirPropertyAccessorSymbol()
|
symbol = FirPropertyAccessorSymbol()
|
||||||
body = FirSingleExpressionBlock(
|
body = FirSingleExpressionBlock(
|
||||||
buildFunctionCall {
|
buildFunctionCall {
|
||||||
|
source = delegateBuilder.source
|
||||||
explicitReceiver = delegateAccess()
|
explicitReceiver = delegateAccess()
|
||||||
calleeReference = buildSimpleNamedReference {
|
calleeReference = buildSimpleNamedReference {
|
||||||
name = SET_VALUE
|
name = SET_VALUE
|
||||||
@@ -438,6 +442,7 @@ fun FirPropertyBuilder.generateAccessorsByDelegate(
|
|||||||
arguments += propertyRef()
|
arguments += propertyRef()
|
||||||
arguments += buildQualifiedAccessExpression {
|
arguments += buildQualifiedAccessExpression {
|
||||||
calleeReference = buildResolvedNamedReference {
|
calleeReference = buildResolvedNamedReference {
|
||||||
|
source = delegateBuilder.source
|
||||||
name = DELEGATED_SETTER_PARAM
|
name = DELEGATED_SETTER_PARAM
|
||||||
resolvedSymbol = parameter.symbol
|
resolvedSymbol = parameter.symbol
|
||||||
}
|
}
|
||||||
@@ -493,6 +498,7 @@ fun FirQualifiedAccess.wrapWithSafeCall(receiver: FirExpression): FirSafeCallExp
|
|||||||
this.originalReceiverRef = FirExpressionRef<FirExpression>().apply {
|
this.originalReceiverRef = FirExpressionRef<FirExpression>().apply {
|
||||||
bind(receiver)
|
bind(receiver)
|
||||||
}
|
}
|
||||||
|
this.source = receiver.source
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceExplicitReceiver(checkedSafeCallSubject)
|
replaceExplicitReceiver(checkedSafeCallSubject)
|
||||||
|
|||||||
@@ -94,6 +94,9 @@ sealed class ImplicitReceiverValue<S : AbstractFirBasedSymbol<*>>(
|
|||||||
|
|
||||||
private fun receiverExpression(symbol: AbstractFirBasedSymbol<*>, type: ConeKotlinType): FirThisReceiverExpression =
|
private fun receiverExpression(symbol: AbstractFirBasedSymbol<*>, type: ConeKotlinType): FirThisReceiverExpression =
|
||||||
buildThisReceiverExpression {
|
buildThisReceiverExpression {
|
||||||
|
// NB: we can't use `symbol.fir.source` as the source of `this` receiver. For instance, if this is an implicit receiver for a class,
|
||||||
|
// the entire class itself will be set as a source. If combined with an implicit type operation, a certain assertion, like null
|
||||||
|
// check assertion, will retrieve source as an assertion message, which is literally the entire class (!).
|
||||||
calleeReference = buildImplicitThisReference {
|
calleeReference = buildImplicitThisReference {
|
||||||
boundSymbol = symbol
|
boundSymbol = symbol
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -57,6 +57,9 @@ internal fun remapArgumentsWithVararg(
|
|||||||
(valueParameter.isVararg && arg !is FirNamedArgumentExpression)
|
(valueParameter.isVararg && arg !is FirNamedArgumentExpression)
|
||||||
) {
|
) {
|
||||||
arguments += arg
|
arguments += arg
|
||||||
|
if (this.source == null) {
|
||||||
|
this.source = arg.source
|
||||||
|
}
|
||||||
} else if (arguments.isEmpty()) {
|
} else if (arguments.isEmpty()) {
|
||||||
// `arg` is BEFORE the vararg arguments.
|
// `arg` is BEFORE the vararg arguments.
|
||||||
newArgumentMapping[arg] = valueParameter
|
newArgumentMapping[arg] = valueParameter
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ sealed class FirFakeSourceElementKind : FirSourceElementKind() {
|
|||||||
// `a > b` will be wrapped in FirComparisonExpression
|
// `a > b` will be wrapped in FirComparisonExpression
|
||||||
// with real source which points to initial `a > b` expression
|
// with real source which points to initial `a > b` expression
|
||||||
// and inner FirFunctionCall will refer to a fake source
|
// and inner FirFunctionCall will refer to a fake source
|
||||||
object GeneratedCompararisonExpression : FirFakeSourceElementKind()
|
object GeneratedComparisonExpression : FirFakeSourceElementKind()
|
||||||
|
|
||||||
// a ?: b --> when(val $subj = a) { .... }
|
// a ?: b --> when(val $subj = a) { .... }
|
||||||
// where `val $subj = a` has a fake source
|
// where `val $subj = a` has a fake source
|
||||||
|
|||||||
Reference in New Issue
Block a user