From 00ffa69cb3cb06e94248488b7b4e6fa646a32033 Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Fri, 30 Apr 2021 11:57:26 -0700 Subject: [PATCH] FIR: add receiver expression to UNSAFE_CALL diagnostic and its variances --- .../diagnostics/FirDiagnosticsList.kt | 9 +++---- .../fir/analysis/diagnostics/FirErrors.kt | 2 +- .../diagnostics/FirDefaultErrorMessages.kt | 11 +++++---- .../coneDiagnosticToFirDiagnostic.kt | 24 +++++++++++++------ .../diagnostics/KtFirDataClassConverters.kt | 1 + .../api/fir/diagnostics/KtFirDiagnostics.kt | 9 +++---- .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 9 +++---- 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index db29c68814e..1ebde0cc98a 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -715,19 +715,20 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val NULLABILITY by object : DiagnosticGroup("Nullability") { val UNSAFE_CALL by error(PositioningStrategy.DOT_BY_QUALIFIED) { parameter("receiverType") + parameter("receiverExpression") } val UNSAFE_IMPLICIT_INVOKE_CALL by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter("receiverType") } val UNSAFE_INFIX_CALL by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { - parameter("lhs") + parameter("receiverExpression") parameter("operator") - parameter("rhs") + parameter("argumentExpression") } val UNSAFE_OPERATOR_CALL by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { - parameter("lhs") + parameter("receiverExpression") parameter("operator") - parameter("rhs") + parameter("argumentExpression") } val ITERATOR_ON_NULLABLE by error() val UNNECESSARY_SAFE_CALL by warning(PositioningStrategy.SAFE_ACCESS) { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 0ff05736234..b1896ed864d 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -419,7 +419,7 @@ object FirErrors { val WRONG_IMPLIES_CONDITION by warning0() // Nullability - val UNSAFE_CALL by error1(SourceElementPositioningStrategies.DOT_BY_QUALIFIED) + val UNSAFE_CALL by error2(SourceElementPositioningStrategies.DOT_BY_QUALIFIED) val UNSAFE_IMPLICIT_INVOKE_CALL by error1(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val UNSAFE_INFIX_CALL by error3(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val UNSAFE_OPERATOR_CALL by error3(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 069f340d88c..1ec08513503 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -130,13 +130,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_UPPER_BOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_PARAMETER_TYPE -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WITH_SUSPEND_FUNCTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE_SUBCLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY @@ -968,7 +968,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put( UNSAFE_CALL, "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}", - RENDER_TYPE + RENDER_TYPE, + NOT_RENDERED, ) map.put( UNSAFE_IMPLICIT_INVOKE_CALL, @@ -981,14 +982,14 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { "Use ''?.''-qualified call instead", FIR, TO_STRING, - FIR + FIR, ) map.put( UNSAFE_OPERATOR_CALL, "Operator call corresponds to a dot-qualified call ''{0}.{1}({2})'' which is not allowed on a nullable receiver ''{0}''. ", FIR, TO_STRING, - FIR + FIR, ) map.put(UNNECESSARY_NOT_NULL_ASSERTION, "Unnecessary non-null assertion (!!) on a non-null receiver of type {0}", RENDER_TYPE) map.put(NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION, "Non-null assertion (!!) is called on a lambda expression") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index f38a3fb4e20..fea281218e9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -97,24 +97,34 @@ private fun mapUnsafeCallError( val candidateFunction = candidate.symbol.fir as? FirSimpleFunction val candidateFunctionName = candidateFunction?.name - val left = candidate.callInfo.explicitReceiver - val right = candidate.callInfo.argumentList.arguments.singleOrNull() - if (left != null && right != null && + val receiverExpression = candidate.callInfo.explicitReceiver + val singleArgument = candidate.callInfo.argumentList.arguments.singleOrNull() + if (receiverExpression != null && singleArgument != null && source.elementType == KtNodeTypes.OPERATION_REFERENCE && (candidateFunction?.isOperator == true || candidateFunction?.isInfix == true) ) { val operationToken = source.getChild(KtTokens.IDENTIFIER) if (candidateFunction.isInfix && operationToken?.elementType == KtTokens.IDENTIFIER) { - return FirErrors.UNSAFE_INFIX_CALL.on(source, left, candidateFunctionName!!.asString(), right) + return FirErrors.UNSAFE_INFIX_CALL.on( + source, + receiverExpression, + candidateFunctionName!!.asString(), + singleArgument, + ) } if (candidateFunction.isOperator && operationToken == null) { - return FirErrors.UNSAFE_OPERATOR_CALL.on(source, left, candidateFunctionName!!.asString(), right) + return FirErrors.UNSAFE_OPERATOR_CALL.on( + source, + receiverExpression, + candidateFunctionName!!.asString(), + singleArgument, + ) } } return if (source.kind == FirFakeSourceElementKind.ArrayAccessNameReference) { - FirErrors.UNSAFE_CALL.on(source, rootCause.actualType) + FirErrors.UNSAFE_CALL.on(source, rootCause.actualType, receiverExpression) } else { - FirErrors.UNSAFE_CALL.on(qualifiedAccessSource ?: source, rootCause.actualType) + FirErrors.UNSAFE_CALL.on(qualifiedAccessSource ?: source, rootCause.actualType, receiverExpression) } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 852c75e7e60..a48313ef676 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -2035,6 +2035,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert add(FirErrors.UNSAFE_CALL) { firDiagnostic -> UnsafeCallImpl( firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), + firDiagnostic.b?.source?.psi as? KtExpression, firDiagnostic as FirPsiDiagnostic<*>, token, ) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 0a2f2ff65b2..790bec74624 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1430,6 +1430,7 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract class UnsafeCall : KtFirDiagnostic() { override val diagnosticClass get() = UnsafeCall::class abstract val receiverType: KtType + abstract val receiverExpression: KtExpression? } abstract class UnsafeImplicitInvokeCall : KtFirDiagnostic() { @@ -1439,16 +1440,16 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract class UnsafeInfixCall : KtFirDiagnostic() { override val diagnosticClass get() = UnsafeInfixCall::class - abstract val lhs: KtExpression + abstract val receiverExpression: KtExpression abstract val operator: String - abstract val rhs: KtExpression + abstract val argumentExpression: KtExpression } abstract class UnsafeOperatorCall : KtFirDiagnostic() { override val diagnosticClass get() = UnsafeOperatorCall::class - abstract val lhs: KtExpression + abstract val receiverExpression: KtExpression abstract val operator: String - abstract val rhs: KtExpression + abstract val argumentExpression: KtExpression } abstract class IteratorOnNullable : KtFirDiagnostic() { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index a0e9dcdd4e9..998d4d239c0 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2321,6 +2321,7 @@ internal class WrongImpliesConditionImpl( internal class UnsafeCallImpl( override val receiverType: KtType, + override val receiverExpression: KtExpression?, firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, ) : KtFirDiagnostic.UnsafeCall(), KtAbstractFirDiagnostic { @@ -2336,9 +2337,9 @@ internal class UnsafeImplicitInvokeCallImpl( } internal class UnsafeInfixCallImpl( - override val lhs: KtExpression, + override val receiverExpression: KtExpression, override val operator: String, - override val rhs: KtExpression, + override val argumentExpression: KtExpression, firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, ) : KtFirDiagnostic.UnsafeInfixCall(), KtAbstractFirDiagnostic { @@ -2346,9 +2347,9 @@ internal class UnsafeInfixCallImpl( } internal class UnsafeOperatorCallImpl( - override val lhs: KtExpression, + override val receiverExpression: KtExpression, override val operator: String, - override val rhs: KtExpression, + override val argumentExpression: KtExpression, firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, ) : KtFirDiagnostic.UnsafeOperatorCall(), KtAbstractFirDiagnostic {