FIR: add receiver expression to UNSAFE_CALL diagnostic and its variances
This commit is contained in:
committed by
Ilya Kirillov
parent
9106ae4f5f
commit
00ffa69cb3
+5
-4
@@ -715,19 +715,20 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
|||||||
val NULLABILITY by object : DiagnosticGroup("Nullability") {
|
val NULLABILITY by object : DiagnosticGroup("Nullability") {
|
||||||
val UNSAFE_CALL by error<PsiElement>(PositioningStrategy.DOT_BY_QUALIFIED) {
|
val UNSAFE_CALL by error<PsiElement>(PositioningStrategy.DOT_BY_QUALIFIED) {
|
||||||
parameter<ConeKotlinType>("receiverType")
|
parameter<ConeKotlinType>("receiverType")
|
||||||
|
parameter<FirExpression?>("receiverExpression")
|
||||||
}
|
}
|
||||||
val UNSAFE_IMPLICIT_INVOKE_CALL by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
val UNSAFE_IMPLICIT_INVOKE_CALL by error<PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||||
parameter<ConeKotlinType>("receiverType")
|
parameter<ConeKotlinType>("receiverType")
|
||||||
}
|
}
|
||||||
val UNSAFE_INFIX_CALL by error<KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
val UNSAFE_INFIX_CALL by error<KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||||
parameter<FirExpression>("lhs")
|
parameter<FirExpression>("receiverExpression")
|
||||||
parameter<String>("operator")
|
parameter<String>("operator")
|
||||||
parameter<FirExpression>("rhs")
|
parameter<FirExpression>("argumentExpression")
|
||||||
}
|
}
|
||||||
val UNSAFE_OPERATOR_CALL by error<KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
val UNSAFE_OPERATOR_CALL by error<KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||||
parameter<FirExpression>("lhs")
|
parameter<FirExpression>("receiverExpression")
|
||||||
parameter<String>("operator")
|
parameter<String>("operator")
|
||||||
parameter<FirExpression>("rhs")
|
parameter<FirExpression>("argumentExpression")
|
||||||
}
|
}
|
||||||
val ITERATOR_ON_NULLABLE by error<KtExpression>()
|
val ITERATOR_ON_NULLABLE by error<KtExpression>()
|
||||||
val UNNECESSARY_SAFE_CALL by warning<PsiElement>(PositioningStrategy.SAFE_ACCESS) {
|
val UNNECESSARY_SAFE_CALL by warning<PsiElement>(PositioningStrategy.SAFE_ACCESS) {
|
||||||
|
|||||||
+1
-1
@@ -419,7 +419,7 @@ object FirErrors {
|
|||||||
val WRONG_IMPLIES_CONDITION by warning0<PsiElement>()
|
val WRONG_IMPLIES_CONDITION by warning0<PsiElement>()
|
||||||
|
|
||||||
// Nullability
|
// Nullability
|
||||||
val UNSAFE_CALL by error1<PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.DOT_BY_QUALIFIED)
|
val UNSAFE_CALL by error2<PsiElement, ConeKotlinType, FirExpression?>(SourceElementPositioningStrategies.DOT_BY_QUALIFIED)
|
||||||
val UNSAFE_IMPLICIT_INVOKE_CALL by error1<PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val UNSAFE_IMPLICIT_INVOKE_CALL by error1<PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
val UNSAFE_INFIX_CALL by error3<KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val UNSAFE_INFIX_CALL by error3<KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
val UNSAFE_OPERATOR_CALL by error3<KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val UNSAFE_OPERATOR_CALL by error3<KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
|
|||||||
+6
-5
@@ -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_SUPERTYPE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_UPPER_BOUND
|
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.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_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_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_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_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.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.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.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY
|
||||||
@@ -968,7 +968,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
map.put(
|
map.put(
|
||||||
UNSAFE_CALL,
|
UNSAFE_CALL,
|
||||||
"Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}",
|
"Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}",
|
||||||
RENDER_TYPE
|
RENDER_TYPE,
|
||||||
|
NOT_RENDERED,
|
||||||
)
|
)
|
||||||
map.put(
|
map.put(
|
||||||
UNSAFE_IMPLICIT_INVOKE_CALL,
|
UNSAFE_IMPLICIT_INVOKE_CALL,
|
||||||
@@ -981,14 +982,14 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
"Use ''?.''-qualified call instead",
|
"Use ''?.''-qualified call instead",
|
||||||
FIR,
|
FIR,
|
||||||
TO_STRING,
|
TO_STRING,
|
||||||
FIR
|
FIR,
|
||||||
)
|
)
|
||||||
map.put(
|
map.put(
|
||||||
UNSAFE_OPERATOR_CALL,
|
UNSAFE_OPERATOR_CALL,
|
||||||
"Operator call corresponds to a dot-qualified call ''{0}.{1}({2})'' which is not allowed on a nullable receiver ''{0}''. ",
|
"Operator call corresponds to a dot-qualified call ''{0}.{1}({2})'' which is not allowed on a nullable receiver ''{0}''. ",
|
||||||
FIR,
|
FIR,
|
||||||
TO_STRING,
|
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(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")
|
map.put(NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION, "Non-null assertion (!!) is called on a lambda expression")
|
||||||
|
|||||||
+17
-7
@@ -97,24 +97,34 @@ private fun mapUnsafeCallError(
|
|||||||
|
|
||||||
val candidateFunction = candidate.symbol.fir as? FirSimpleFunction
|
val candidateFunction = candidate.symbol.fir as? FirSimpleFunction
|
||||||
val candidateFunctionName = candidateFunction?.name
|
val candidateFunctionName = candidateFunction?.name
|
||||||
val left = candidate.callInfo.explicitReceiver
|
val receiverExpression = candidate.callInfo.explicitReceiver
|
||||||
val right = candidate.callInfo.argumentList.arguments.singleOrNull()
|
val singleArgument = candidate.callInfo.argumentList.arguments.singleOrNull()
|
||||||
if (left != null && right != null &&
|
if (receiverExpression != null && singleArgument != null &&
|
||||||
source.elementType == KtNodeTypes.OPERATION_REFERENCE &&
|
source.elementType == KtNodeTypes.OPERATION_REFERENCE &&
|
||||||
(candidateFunction?.isOperator == true || candidateFunction?.isInfix == true)
|
(candidateFunction?.isOperator == true || candidateFunction?.isInfix == true)
|
||||||
) {
|
) {
|
||||||
val operationToken = source.getChild(KtTokens.IDENTIFIER)
|
val operationToken = source.getChild(KtTokens.IDENTIFIER)
|
||||||
if (candidateFunction.isInfix && operationToken?.elementType == 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) {
|
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) {
|
return if (source.kind == FirFakeSourceElementKind.ArrayAccessNameReference) {
|
||||||
FirErrors.UNSAFE_CALL.on(source, rootCause.actualType)
|
FirErrors.UNSAFE_CALL.on(source, rootCause.actualType, receiverExpression)
|
||||||
} else {
|
} else {
|
||||||
FirErrors.UNSAFE_CALL.on(qualifiedAccessSource ?: source, rootCause.actualType)
|
FirErrors.UNSAFE_CALL.on(qualifiedAccessSource ?: source, rootCause.actualType, receiverExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -2035,6 +2035,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
add(FirErrors.UNSAFE_CALL) { firDiagnostic ->
|
add(FirErrors.UNSAFE_CALL) { firDiagnostic ->
|
||||||
UnsafeCallImpl(
|
UnsafeCallImpl(
|
||||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||||
|
firDiagnostic.b?.source?.psi as? KtExpression,
|
||||||
firDiagnostic as FirPsiDiagnostic<*>,
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
|
|||||||
+5
-4
@@ -1430,6 +1430,7 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract class UnsafeCall : KtFirDiagnostic<PsiElement>() {
|
abstract class UnsafeCall : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = UnsafeCall::class
|
override val diagnosticClass get() = UnsafeCall::class
|
||||||
abstract val receiverType: KtType
|
abstract val receiverType: KtType
|
||||||
|
abstract val receiverExpression: KtExpression?
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class UnsafeImplicitInvokeCall : KtFirDiagnostic<PsiElement>() {
|
abstract class UnsafeImplicitInvokeCall : KtFirDiagnostic<PsiElement>() {
|
||||||
@@ -1439,16 +1440,16 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
|
|
||||||
abstract class UnsafeInfixCall : KtFirDiagnostic<KtExpression>() {
|
abstract class UnsafeInfixCall : KtFirDiagnostic<KtExpression>() {
|
||||||
override val diagnosticClass get() = UnsafeInfixCall::class
|
override val diagnosticClass get() = UnsafeInfixCall::class
|
||||||
abstract val lhs: KtExpression
|
abstract val receiverExpression: KtExpression
|
||||||
abstract val operator: String
|
abstract val operator: String
|
||||||
abstract val rhs: KtExpression
|
abstract val argumentExpression: KtExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class UnsafeOperatorCall : KtFirDiagnostic<KtExpression>() {
|
abstract class UnsafeOperatorCall : KtFirDiagnostic<KtExpression>() {
|
||||||
override val diagnosticClass get() = UnsafeOperatorCall::class
|
override val diagnosticClass get() = UnsafeOperatorCall::class
|
||||||
abstract val lhs: KtExpression
|
abstract val receiverExpression: KtExpression
|
||||||
abstract val operator: String
|
abstract val operator: String
|
||||||
abstract val rhs: KtExpression
|
abstract val argumentExpression: KtExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class IteratorOnNullable : KtFirDiagnostic<KtExpression>() {
|
abstract class IteratorOnNullable : KtFirDiagnostic<KtExpression>() {
|
||||||
|
|||||||
+5
-4
@@ -2321,6 +2321,7 @@ internal class WrongImpliesConditionImpl(
|
|||||||
|
|
||||||
internal class UnsafeCallImpl(
|
internal class UnsafeCallImpl(
|
||||||
override val receiverType: KtType,
|
override val receiverType: KtType,
|
||||||
|
override val receiverExpression: KtExpression?,
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.UnsafeCall(), KtAbstractFirDiagnostic<PsiElement> {
|
) : KtFirDiagnostic.UnsafeCall(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
@@ -2336,9 +2337,9 @@ internal class UnsafeImplicitInvokeCallImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class UnsafeInfixCallImpl(
|
internal class UnsafeInfixCallImpl(
|
||||||
override val lhs: KtExpression,
|
override val receiverExpression: KtExpression,
|
||||||
override val operator: String,
|
override val operator: String,
|
||||||
override val rhs: KtExpression,
|
override val argumentExpression: KtExpression,
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.UnsafeInfixCall(), KtAbstractFirDiagnostic<KtExpression> {
|
) : KtFirDiagnostic.UnsafeInfixCall(), KtAbstractFirDiagnostic<KtExpression> {
|
||||||
@@ -2346,9 +2347,9 @@ internal class UnsafeInfixCallImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class UnsafeOperatorCallImpl(
|
internal class UnsafeOperatorCallImpl(
|
||||||
override val lhs: KtExpression,
|
override val receiverExpression: KtExpression,
|
||||||
override val operator: String,
|
override val operator: String,
|
||||||
override val rhs: KtExpression,
|
override val argumentExpression: KtExpression,
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.UnsafeOperatorCall(), KtAbstractFirDiagnostic<KtExpression> {
|
) : KtFirDiagnostic.UnsafeOperatorCall(), KtAbstractFirDiagnostic<KtExpression> {
|
||||||
|
|||||||
Reference in New Issue
Block a user