From b2e1dfa6db6901ac56357c690577dfa36663f049 Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Tue, 23 Nov 2021 19:46:36 -0800 Subject: [PATCH] FIR checker: set source for assign call for augmented array set call The source is set on the alternative block but not the XXXAssign call. BTW, the real source is incorrect shared among the FirAugmentedArraySetCall, FirBlock, so this change uses a fake source for the FirBlock and the FirFunctionCall. Using fake source does not seem to be necessary for compilable code because in that case FirAugmentedArraySetCall is transformed to either a FirBlock or a FirFunctionCall. But it's needed for ambiguous code where such transformation fails. In this case, all three FirElements are present and they should not share the same real source. In addition, this change also sets a fake source for the `get` call of the array access to the left hand side of the operator. For example, `m[a] += 1` where `m` is some custom map implementation that does not return `null` from `get`. The (fake) source of the synthetic `get` call in FIR is now `m[a]`. This is handy because the analysis API will resolve `m[a]` to the `get` call. --- .../converter/ExpressionsConverter.kt | 1 + .../kotlin/fir/builder/RawFirBuilder.kt | 1 + .../kotlin/fir/builder/BaseFirBuilder.kt | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index d0eff149520..07db4abeaf2 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -291,6 +291,7 @@ class ExpressionsConverter( if (firOperation in FirOperation.ASSIGNMENTS) { return leftArgNode.generateAssignment( binaryExpression.toFirSourceElement(), + leftArgNode?.toFirSourceElement(), rightArg, rightArgAsFir, firOperation, diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 5a6de38b5de..b2b7bb903c5 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -2176,6 +2176,7 @@ open class RawFirBuilder( if (firOperation in FirOperation.ASSIGNMENTS) { return expression.left.generateAssignment( source, + expression.left?.toFirSourceElement(), expression.right, rightArgument, firOperation, diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index 28ec9ddc898..eabe8a7c0f6 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -537,6 +537,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte val assignment = unwrappedArgument.generateAssignment( desugaredSource, null, + null, if (prefix && unwrappedArgument.elementType != REFERENCE_EXPRESSION) generateResolvedAccessExpression(source, resultVar) else @@ -889,6 +890,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte fun T?.generateAssignment( baseSource: KtSourceElement?, + arrayAccessSource: KtSourceElement?, rhs: T?, value: FirExpression, // value is FIR for rhs operation: FirOperation, @@ -909,7 +911,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte (result.annotations as MutableList) += annotations result } else { - generateAugmentedArraySetCall(unwrappedLhs, baseSource, operation, rhs, annotations, convert) + generateAugmentedArraySetCall(unwrappedLhs, baseSource, arrayAccessSource, operation, rhs, annotations, convert) } } @@ -973,6 +975,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte private fun generateAugmentedArraySetCall( unwrappedReceiver: T, baseSource: KtSourceElement?, + arrayAccessSource: KtSourceElement?, operation: FirOperation, rhs: T?, annotations: List, @@ -981,14 +984,16 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte return buildAugmentedArraySetCall { source = baseSource this.operation = operation - assignCall = generateAugmentedCallForAugmentedArraySetCall(unwrappedReceiver, operation, rhs, convert) - setGetBlock = generateSetGetBlockForAugmentedArraySetCall(unwrappedReceiver, baseSource, operation, rhs, convert) + assignCall = generateAugmentedCallForAugmentedArraySetCall(unwrappedReceiver, baseSource, operation, rhs, convert) + setGetBlock = + generateSetGetBlockForAugmentedArraySetCall(unwrappedReceiver, baseSource, arrayAccessSource, operation, rhs, convert) this.annotations += annotations } } private fun generateAugmentedCallForAugmentedArraySetCall( unwrappedReceiver: T, + baseSource: KtSourceElement?, operation: FirOperation, rhs: T?, convert: T.() -> FirExpression @@ -998,6 +1003,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte * a.get(x, y).plusAssign(z) */ return buildFunctionCall { + source = baseSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment) calleeReference = buildSimpleNamedReference { name = FirOperationNameConventions.ASSIGNMENTS.getValue(operation) } @@ -1016,6 +1022,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte private fun generateSetGetBlockForAugmentedArraySetCall( unwrappedReceiver: T, baseSource: KtSourceElement?, + arrayAccessSource: KtSourceElement?, operation: FirOperation, rhs: T?, convert: T.() -> FirExpression @@ -1037,7 +1044,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte source = null, specialName = "", initializer = baseCall.explicitReceiver ?: buildErrorExpression { - source = baseSource + source = baseSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment) diagnostic = ConeSimpleDiagnostic("No receiver for array access", DiagnosticKind.Syntax) } ) @@ -1047,7 +1054,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte } statements += indexVariables statements += buildFunctionCall { - source = baseSource + source = baseSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment) explicitReceiver = arrayVariable.toQualifiedAccess() calleeReference = buildSimpleNamedReference { name = OperatorNameConventions.SET @@ -1059,6 +1066,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte } val getCall = buildFunctionCall { + source = arrayAccessSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment) explicitReceiver = arrayVariable.toQualifiedAccess() calleeReference = buildSimpleNamedReference { name = OperatorNameConventions.GET