FIR: Allow selector of safe calls to be a FirStatement
It's necessary to allow a?.b += v be interpreted as a?.(b += v) But currently FirAssignmentOperatorStatement is not FirQualifiedAccess ^KT-41034 In Progress
This commit is contained in:
+1
-1
@@ -155,7 +155,7 @@ internal class KtFirCallResolver(
|
|||||||
)
|
)
|
||||||
// FIR does not resolve to a symbol for equality calls.
|
// FIR does not resolve to a symbol for equality calls.
|
||||||
is FirEqualityOperatorCall -> toKtCallInfo(psi)
|
is FirEqualityOperatorCall -> toKtCallInfo(psi)
|
||||||
is FirSafeCallExpression -> regularQualifiedAccess.toKtCallInfo(
|
is FirSafeCallExpression -> selector.toKtCallInfo(
|
||||||
psi,
|
psi,
|
||||||
resolveCalleeExpressionOfFunctionCall,
|
resolveCalleeExpressionOfFunctionCall,
|
||||||
resolveFragmentOfCall
|
resolveFragmentOfCall
|
||||||
|
|||||||
@@ -1595,21 +1595,21 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
|
|||||||
|
|
||||||
+"?."
|
+"?."
|
||||||
|
|
||||||
val nestedQualifier = safeCallExpression.regularQualifiedAccess
|
val selector = safeCallExpression.selector
|
||||||
if (nestedQualifier.explicitReceiver == safeCallExpression.checkedSubjectRef.value) {
|
if (selector is FirQualifiedAccess && selector.explicitReceiver == safeCallExpression.checkedSubjectRef.value) {
|
||||||
when (nestedQualifier) {
|
when (selector) {
|
||||||
is FirFunctionCall -> {
|
is FirFunctionCall -> {
|
||||||
return generate(nestedQualifier, skipReceiver = true)
|
return generate(selector, skipReceiver = true)
|
||||||
}
|
}
|
||||||
is FirQualifiedAccessExpression -> {
|
is FirQualifiedAccessExpression -> {
|
||||||
return generate(nestedQualifier, skipReceiver = true)
|
return generate(selector, skipReceiver = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+"{ "
|
+"{ "
|
||||||
|
|
||||||
generate(nestedQualifier)
|
generate(selector)
|
||||||
|
|
||||||
+" }"
|
+" }"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ class Fir2IrVisitor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return conversionScope.withSafeCallSubject(receiverVariable) {
|
return conversionScope.withSafeCallSubject(receiverVariable) {
|
||||||
val afterNotNullCheck = safeCallExpression.regularQualifiedAccess.accept(this, data) as IrExpression
|
val afterNotNullCheck = safeCallExpression.selector.accept(this, data) as IrExpression
|
||||||
components.createSafeCallConstruction(receiverVariable, variableSymbol, afterNotNullCheck)
|
components.createSafeCallConstruction(receiverVariable, variableSymbol, afterNotNullCheck)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -966,7 +966,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
|||||||
value: FirExpression,
|
value: FirExpression,
|
||||||
annotations: List<FirAnnotation>
|
annotations: List<FirAnnotation>
|
||||||
): FirSafeCallExpression {
|
): FirSafeCallExpression {
|
||||||
val nestedAccess = safeCallNonAssignment.regularQualifiedAccess
|
val nestedAccess = safeCallNonAssignment.selector as FirQualifiedAccess
|
||||||
|
|
||||||
val assignment = buildVariableAssignment {
|
val assignment = buildVariableAssignment {
|
||||||
source = baseSource
|
source = baseSource
|
||||||
@@ -976,7 +976,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
|||||||
this.annotations += annotations
|
this.annotations += annotations
|
||||||
}
|
}
|
||||||
|
|
||||||
safeCallNonAssignment.replaceRegularQualifiedAccess(
|
safeCallNonAssignment.replaceSelector(
|
||||||
assignment
|
assignment
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.fir.types.impl.*
|
|||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotated
|
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -583,7 +582,7 @@ fun FirQualifiedAccess.wrapWithSafeCall(receiver: FirExpression, source: KtSourc
|
|||||||
this.checkedSubjectRef = FirExpressionRef<FirCheckedSafeCallSubject>().apply {
|
this.checkedSubjectRef = FirExpressionRef<FirCheckedSafeCallSubject>().apply {
|
||||||
bind(checkedSafeCallSubject)
|
bind(checkedSafeCallSubject)
|
||||||
}
|
}
|
||||||
this.regularQualifiedAccess = this@wrapWithSafeCall
|
this.selector = this@wrapWithSafeCall
|
||||||
this.source = source
|
this.source = source
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,9 @@ import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
|||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirPropertyWithExplicitBackingFieldResolvedNamedReference
|
import org.jetbrains.kotlin.fir.resolve.calls.FirPropertyWithExplicitBackingFieldResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
|
||||||
import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
|
import org.jetbrains.kotlin.fir.resolve.dfa.PropertyStability
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
|
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData
|
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData
|
||||||
@@ -50,7 +48,6 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||||
import org.jetbrains.kotlin.types.SmartcastStability
|
import org.jetbrains.kotlin.types.SmartcastStability
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
fun List<FirQualifierPart>.toTypeProjections(): Array<ConeTypeProjection> =
|
fun List<FirQualifierPart>.toTypeProjections(): Array<ConeTypeProjection> =
|
||||||
@@ -395,7 +392,7 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
|||||||
session: FirSession,
|
session: FirSession,
|
||||||
) {
|
) {
|
||||||
val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>()
|
val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>()
|
||||||
val typeAfterNullCheck = regularQualifiedAccess.expressionTypeOrUnitForAssignment() ?: return
|
val typeAfterNullCheck = (selector as? FirQualifiedAccess)?.expressionTypeOrUnitForAssignment() ?: return
|
||||||
val isReceiverActuallyNullable = if (session.languageVersionSettings.supportsFeature(LanguageFeature.SafeCallsAreAlwaysNullable)) {
|
val isReceiverActuallyNullable = if (session.languageVersionSettings.supportsFeature(LanguageFeature.SafeCallsAreAlwaysNullable)) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
|||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.*
|
import org.jetbrains.kotlin.fir.resolve.inference.preprocessCallableReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.preprocessLambdaArgument
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
||||||
import org.jetbrains.kotlin.fir.returnExpressions
|
import org.jetbrains.kotlin.fir.returnExpressions
|
||||||
@@ -63,8 +64,8 @@ fun Candidate.resolveArgumentExpression(
|
|||||||
// and then add constraint: typeOf(`$not-null-receiver$.bar()`).makeNullable() <: EXPECTED_TYPE
|
// and then add constraint: typeOf(`$not-null-receiver$.bar()`).makeNullable() <: EXPECTED_TYPE
|
||||||
// NB: argument.regularQualifiedAccess is either a call or a qualified access
|
// NB: argument.regularQualifiedAccess is either a call or a qualified access
|
||||||
is FirSafeCallExpression -> {
|
is FirSafeCallExpression -> {
|
||||||
val nestedQualifier = argument.regularQualifiedAccess
|
val nestedQualifier = argument.selector
|
||||||
if (nestedQualifier is FirExpression) {
|
if (nestedQualifier is FirQualifiedAccessExpression) {
|
||||||
resolveSubCallArgument(
|
resolveSubCallArgument(
|
||||||
csBuilder,
|
csBuilder,
|
||||||
nestedQualifier,
|
nestedQualifier,
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ fun PostponedArgumentsAnalyzerContext.addSubsystemFromExpression(statement: FirS
|
|||||||
is FirElvisExpression
|
is FirElvisExpression
|
||||||
-> (statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
-> (statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
||||||
|
|
||||||
is FirSafeCallExpression -> addSubsystemFromExpression(statement.regularQualifiedAccess)
|
is FirSafeCallExpression -> addSubsystemFromExpression(statement.selector)
|
||||||
is FirWrappedArgumentExpression -> addSubsystemFromExpression(statement.expression)
|
is FirWrappedArgumentExpression -> addSubsystemFromExpression(statement.expression)
|
||||||
is FirBlock -> statement.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
is FirBlock -> statement.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -464,7 +464,7 @@ fun FirStatement.processAllContainingCallCandidates(processBlocks: Boolean, proc
|
|||||||
}
|
}
|
||||||
|
|
||||||
is FirSafeCallExpression -> {
|
is FirSafeCallExpression -> {
|
||||||
this.regularQualifiedAccess.processAllContainingCallCandidates(processBlocks, processor)
|
this.selector.processAllContainingCallCandidates(processBlocks, processor)
|
||||||
}
|
}
|
||||||
|
|
||||||
is FirWhenExpression -> {
|
is FirWhenExpression -> {
|
||||||
|
|||||||
+1
-1
@@ -354,7 +354,7 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
safeCallExpression: FirSafeCallExpression,
|
safeCallExpression: FirSafeCallExpression,
|
||||||
data: ExpectedArgumentType?
|
data: ExpectedArgumentType?
|
||||||
): FirStatement {
|
): FirStatement {
|
||||||
safeCallExpression.transformRegularQualifiedAccess(
|
safeCallExpression.transformSelector(
|
||||||
this,
|
this,
|
||||||
data?.getExpectedType(
|
data?.getExpectedType(
|
||||||
safeCallExpression
|
safeCallExpression
|
||||||
|
|||||||
+3
-3
@@ -119,7 +119,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
transformSuperReceiver(
|
transformSuperReceiver(
|
||||||
callee,
|
callee,
|
||||||
qualifiedAccessExpression,
|
qualifiedAccessExpression,
|
||||||
containingSafeCallExpression?.takeIf { qualifiedAccessExpression == it.receiver }?.regularQualifiedAccess
|
containingSafeCallExpression?.takeIf { qualifiedAccessExpression == it.receiver }?.selector as? FirQualifiedAccess
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is FirDelegateFieldReference -> {
|
is FirDelegateFieldReference -> {
|
||||||
@@ -312,7 +312,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
|
|
||||||
safeCallExpression.apply {
|
safeCallExpression.apply {
|
||||||
checkedSubjectRef.value.propagateTypeFromOriginalReceiver(receiver, components.session)
|
checkedSubjectRef.value.propagateTypeFromOriginalReceiver(receiver, components.session)
|
||||||
transformRegularQualifiedAccess(this@FirExpressionsResolveTransformer, data)
|
transformSelector(this@FirExpressionsResolveTransformer, data)
|
||||||
propagateTypeFromQualifiedAccessAfterNullCheck(receiver, session)
|
propagateTypeFromQualifiedAccessAfterNullCheck(receiver, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,7 +685,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
// AS operator doesn't add expected type to any other expressions
|
// AS operator doesn't add expected type to any other expressions
|
||||||
// See https://kotlinlang.org/docs/whatsnew12.html#support-for-foo-as-a-shorthand-for-this-foo
|
// See https://kotlinlang.org/docs/whatsnew12.html#support-for-foo-as-a-shorthand-for-this-foo
|
||||||
// And limitations at org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleterKt.isFunctionForExpectTypeFromCastFeature(org.jetbrains.kotlin.fir.declarations.FirFunction<?>)
|
// And limitations at org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleterKt.isFunctionForExpectTypeFromCastFeature(org.jetbrains.kotlin.fir.declarations.FirFunction<?>)
|
||||||
if (argument is FirFunctionCall || (argument is FirSafeCallExpression && argument.regularQualifiedAccess is FirFunctionCall)) {
|
if (argument is FirFunctionCall || (argument is FirSafeCallExpression && argument.selector is FirFunctionCall)) {
|
||||||
val expectedType = conversionTypeRef.coneTypeSafe<ConeKotlinType>()?.takeIf {
|
val expectedType = conversionTypeRef.coneTypeSafe<ConeKotlinType>()?.takeIf {
|
||||||
// is not bare type
|
// is not bare type
|
||||||
it !is ConeClassLikeType ||
|
it !is ConeClassLikeType ||
|
||||||
|
|||||||
+1
-1
@@ -62,7 +62,7 @@ class VariableStorageImpl(private val session: FirSession) : VariableStorage() {
|
|||||||
private fun FirElement.unwrapElement(): FirElement = when (this) {
|
private fun FirElement.unwrapElement(): FirElement = when (this) {
|
||||||
is FirWhenSubjectExpression -> whenRef.value.let { it.subjectVariable ?: it.subject }?.unwrapElement() ?: this
|
is FirWhenSubjectExpression -> whenRef.value.let { it.subjectVariable ?: it.subject }?.unwrapElement() ?: this
|
||||||
is FirExpressionWithSmartcast -> originalExpression.unwrapElement()
|
is FirExpressionWithSmartcast -> originalExpression.unwrapElement()
|
||||||
is FirSafeCallExpression -> regularQualifiedAccess.unwrapElement()
|
is FirSafeCallExpression -> selector.unwrapElement()
|
||||||
is FirCheckedSafeCallSubject -> originalReceiverRef.value.unwrapElement()
|
is FirCheckedSafeCallSubject -> originalReceiverRef.value.unwrapElement()
|
||||||
is FirCheckNotNullCall -> argument.unwrapElement()
|
is FirCheckNotNullCall -> argument.unwrapElement()
|
||||||
else -> this
|
else -> this
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ val FirElement.symbol: FirBasedSymbol<*>?
|
|||||||
is FirResolvable -> symbol
|
is FirResolvable -> symbol
|
||||||
is FirDeclaration -> symbol
|
is FirDeclaration -> symbol
|
||||||
is FirWhenSubjectExpression -> whenRef.value.subject?.symbol
|
is FirWhenSubjectExpression -> whenRef.value.subject?.symbol
|
||||||
is FirSafeCallExpression -> regularQualifiedAccess.symbol
|
is FirSafeCallExpression -> selector.symbol
|
||||||
else -> null
|
else -> null
|
||||||
}?.takeIf {
|
}?.takeIf {
|
||||||
(this as? FirExpression)?.unwrapSmartcastExpression() is FirThisReceiverExpression ||
|
(this as? FirExpression)?.unwrapSmartcastExpression() is FirThisReceiverExpression ||
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ abstract class FirSafeCallExpression : FirExpression() {
|
|||||||
abstract override val annotations: List<FirAnnotation>
|
abstract override val annotations: List<FirAnnotation>
|
||||||
abstract val receiver: FirExpression
|
abstract val receiver: FirExpression
|
||||||
abstract val checkedSubjectRef: FirExpressionRef<FirCheckedSafeCallSubject>
|
abstract val checkedSubjectRef: FirExpressionRef<FirCheckedSafeCallSubject>
|
||||||
abstract val regularQualifiedAccess: FirQualifiedAccess
|
abstract val selector: FirStatement
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitSafeCallExpression(this, data)
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitSafeCallExpression(this, data)
|
||||||
|
|
||||||
@@ -32,11 +32,11 @@ abstract class FirSafeCallExpression : FirExpression() {
|
|||||||
|
|
||||||
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
|
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
|
||||||
|
|
||||||
abstract fun replaceRegularQualifiedAccess(newRegularQualifiedAccess: FirQualifiedAccess)
|
abstract fun replaceSelector(newSelector: FirStatement)
|
||||||
|
|
||||||
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirSafeCallExpression
|
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirSafeCallExpression
|
||||||
|
|
||||||
abstract fun <D> transformReceiver(transformer: FirTransformer<D>, data: D): FirSafeCallExpression
|
abstract fun <D> transformReceiver(transformer: FirTransformer<D>, data: D): FirSafeCallExpression
|
||||||
|
|
||||||
abstract fun <D> transformRegularQualifiedAccess(transformer: FirTransformer<D>, data: D): FirSafeCallExpression
|
abstract fun <D> transformSelector(transformer: FirTransformer<D>, data: D): FirSafeCallExpression
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -13,8 +13,8 @@ import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
|
|||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject
|
import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.FirExpressionBuilder
|
import org.jetbrains.kotlin.fir.expressions.builder.FirExpressionBuilder
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirSafeCallExpressionImpl
|
import org.jetbrains.kotlin.fir.expressions.impl.FirSafeCallExpressionImpl
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
@@ -33,7 +33,7 @@ class FirSafeCallExpressionBuilder : FirAnnotationContainerBuilder, FirExpressio
|
|||||||
override val annotations: MutableList<FirAnnotation> = mutableListOf()
|
override val annotations: MutableList<FirAnnotation> = mutableListOf()
|
||||||
lateinit var receiver: FirExpression
|
lateinit var receiver: FirExpression
|
||||||
lateinit var checkedSubjectRef: FirExpressionRef<FirCheckedSafeCallSubject>
|
lateinit var checkedSubjectRef: FirExpressionRef<FirCheckedSafeCallSubject>
|
||||||
lateinit var regularQualifiedAccess: FirQualifiedAccess
|
lateinit var selector: FirStatement
|
||||||
|
|
||||||
override fun build(): FirSafeCallExpression {
|
override fun build(): FirSafeCallExpression {
|
||||||
return FirSafeCallExpressionImpl(
|
return FirSafeCallExpressionImpl(
|
||||||
@@ -42,7 +42,7 @@ class FirSafeCallExpressionBuilder : FirAnnotationContainerBuilder, FirExpressio
|
|||||||
annotations,
|
annotations,
|
||||||
receiver,
|
receiver,
|
||||||
checkedSubjectRef,
|
checkedSubjectRef,
|
||||||
regularQualifiedAccess,
|
selector,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -10,8 +10,8 @@ import org.jetbrains.kotlin.fir.FirExpressionRef
|
|||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject
|
import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.fir.visitors.*
|
import org.jetbrains.kotlin.fir.visitors.*
|
||||||
|
|
||||||
@@ -26,20 +26,20 @@ internal class FirSafeCallExpressionImpl(
|
|||||||
override val annotations: MutableList<FirAnnotation>,
|
override val annotations: MutableList<FirAnnotation>,
|
||||||
override var receiver: FirExpression,
|
override var receiver: FirExpression,
|
||||||
override val checkedSubjectRef: FirExpressionRef<FirCheckedSafeCallSubject>,
|
override val checkedSubjectRef: FirExpressionRef<FirCheckedSafeCallSubject>,
|
||||||
override var regularQualifiedAccess: FirQualifiedAccess,
|
override var selector: FirStatement,
|
||||||
) : FirSafeCallExpression() {
|
) : FirSafeCallExpression() {
|
||||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||||
typeRef.accept(visitor, data)
|
typeRef.accept(visitor, data)
|
||||||
annotations.forEach { it.accept(visitor, data) }
|
annotations.forEach { it.accept(visitor, data) }
|
||||||
receiver.accept(visitor, data)
|
receiver.accept(visitor, data)
|
||||||
regularQualifiedAccess.accept(visitor, data)
|
selector.accept(visitor, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirSafeCallExpressionImpl {
|
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirSafeCallExpressionImpl {
|
||||||
typeRef = typeRef.transform(transformer, data)
|
typeRef = typeRef.transform(transformer, data)
|
||||||
transformAnnotations(transformer, data)
|
transformAnnotations(transformer, data)
|
||||||
transformReceiver(transformer, data)
|
transformReceiver(transformer, data)
|
||||||
transformRegularQualifiedAccess(transformer, data)
|
transformSelector(transformer, data)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,8 +53,8 @@ internal class FirSafeCallExpressionImpl(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <D> transformRegularQualifiedAccess(transformer: FirTransformer<D>, data: D): FirSafeCallExpressionImpl {
|
override fun <D> transformSelector(transformer: FirTransformer<D>, data: D): FirSafeCallExpressionImpl {
|
||||||
regularQualifiedAccess = regularQualifiedAccess.transform(transformer, data)
|
selector = selector.transform(transformer, data)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ internal class FirSafeCallExpressionImpl(
|
|||||||
typeRef = newTypeRef
|
typeRef = newTypeRef
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun replaceRegularQualifiedAccess(newRegularQualifiedAccess: FirQualifiedAccess) {
|
override fun replaceSelector(newSelector: FirStatement) {
|
||||||
regularQualifiedAccess = newRegularQualifiedAccess
|
selector = newSelector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -707,7 +707,7 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
|
|||||||
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression) {
|
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression) {
|
||||||
safeCallExpression.receiver.accept(this)
|
safeCallExpression.receiver.accept(this)
|
||||||
print("?.{ ")
|
print("?.{ ")
|
||||||
safeCallExpression.regularQualifiedAccess.accept(this)
|
safeCallExpression.selector.accept(this)
|
||||||
print(" }")
|
print(" }")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -506,7 +506,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
|||||||
// Special node that might be used as a reference to receiver of a safe call after null check
|
// Special node that might be used as a reference to receiver of a safe call after null check
|
||||||
+field("checkedSubjectRef", safeCallCheckedSubjectReferenceType)
|
+field("checkedSubjectRef", safeCallCheckedSubjectReferenceType)
|
||||||
// One that uses checkedReceiver as a receiver
|
// One that uses checkedReceiver as a receiver
|
||||||
+field("regularQualifiedAccess", qualifiedAccess, withReplace = true).withTransform()
|
+field("selector", statement, withReplace = true).withTransform()
|
||||||
}
|
}
|
||||||
|
|
||||||
checkedSafeCallSubject.configure {
|
checkedSafeCallSubject.configure {
|
||||||
|
|||||||
+11
-11
@@ -12,14 +12,11 @@ import org.jetbrains.kotlin.checkers.utils.TypeOfCall
|
|||||||
import org.jetbrains.kotlin.diagnostics.*
|
import org.jetbrains.kotlin.diagnostics.*
|
||||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
|
||||||
import org.jetbrains.kotlin.fir.psi
|
import org.jetbrains.kotlin.fir.psi
|
||||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
@@ -176,13 +173,16 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression) {
|
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression) {
|
||||||
result.addIfNotNull(
|
val selector = safeCallExpression.selector
|
||||||
createCallDiagnosticIfExpected(
|
if (selector is FirQualifiedAccess) {
|
||||||
safeCallExpression,
|
result.addIfNotNull(
|
||||||
safeCallExpression.regularQualifiedAccess.calleeReference as FirNamedReference,
|
createCallDiagnosticIfExpected(
|
||||||
diagnosedRangesToDiagnosticNames
|
safeCallExpression,
|
||||||
|
selector.calleeReference as FirNamedReference,
|
||||||
|
diagnosedRangesToDiagnosticNames
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
super.visitSafeCallExpression(safeCallExpression)
|
super.visitSafeCallExpression(safeCallExpression)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -742,7 +742,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
|||||||
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: StringBuilder) {
|
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: StringBuilder) {
|
||||||
safeCallExpression.receiver.accept(this, data)
|
safeCallExpression.receiver.accept(this, data)
|
||||||
data.append("?.{ ")
|
data.append("?.{ ")
|
||||||
safeCallExpression.regularQualifiedAccess.accept(this, data)
|
safeCallExpression.selector.accept(this, data)
|
||||||
data.append(" }")
|
data.append(" }")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user