FIR: add receiver expression to UNSAFE_CALL diagnostic and its variances

This commit is contained in:
Tianyu Geng
2021-04-30 11:57:26 -07:00
committed by Ilya Kirillov
parent 9106ae4f5f
commit 00ffa69cb3
7 changed files with 40 additions and 25 deletions
@@ -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) {
@@ -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)
@@ -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")
@@ -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)
} }
} }
@@ -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,
) )
@@ -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>() {
@@ -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> {