FIR checker: pass expected array type in ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION

This is needed by the IDE quickfix to generate the correct `arrayOf` (or
`intArrayOf`, etc`) wrapper call.
This commit is contained in:
Tianyu Geng
2021-10-20 03:39:18 +03:00
committed by teamcity
parent 9f062df258
commit b48870c11f
7 changed files with 33 additions and 11 deletions
@@ -1475,12 +1475,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
} }
add(FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.errorFactory) { firDiagnostic -> add(FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.errorFactory) { firDiagnostic ->
AssigningSingleElementToVarargInNamedFormFunctionErrorImpl( AssigningSingleElementToVarargInNamedFormFunctionErrorImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as KtPsiDiagnostic, firDiagnostic as KtPsiDiagnostic,
token, token,
) )
} }
add(FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.warningFactory) { firDiagnostic -> add(FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION.warningFactory) { firDiagnostic ->
AssigningSingleElementToVarargInNamedFormFunctionWarningImpl( AssigningSingleElementToVarargInNamedFormFunctionWarningImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as KtPsiDiagnostic, firDiagnostic as KtPsiDiagnostic,
token, token,
) )
@@ -1062,10 +1062,12 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract class AssigningSingleElementToVarargInNamedFormFunctionError : KtFirDiagnostic<KtExpression>() { abstract class AssigningSingleElementToVarargInNamedFormFunctionError : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = AssigningSingleElementToVarargInNamedFormFunctionError::class override val diagnosticClass get() = AssigningSingleElementToVarargInNamedFormFunctionError::class
abstract val expectedArrayType: KtType
} }
abstract class AssigningSingleElementToVarargInNamedFormFunctionWarning : KtFirDiagnostic<KtExpression>() { abstract class AssigningSingleElementToVarargInNamedFormFunctionWarning : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = AssigningSingleElementToVarargInNamedFormFunctionWarning::class override val diagnosticClass get() = AssigningSingleElementToVarargInNamedFormFunctionWarning::class
abstract val expectedArrayType: KtType
} }
abstract class AssigningSingleElementToVarargInNamedFormAnnotationError : KtFirDiagnostic<KtExpression>() { abstract class AssigningSingleElementToVarargInNamedFormAnnotationError : KtFirDiagnostic<KtExpression>() {
@@ -1270,11 +1270,13 @@ internal class SpreadOfNullableImpl(
) : KtFirDiagnostic.SpreadOfNullable(), KtAbstractFirDiagnostic<PsiElement> ) : KtFirDiagnostic.SpreadOfNullable(), KtAbstractFirDiagnostic<PsiElement>
internal class AssigningSingleElementToVarargInNamedFormFunctionErrorImpl( internal class AssigningSingleElementToVarargInNamedFormFunctionErrorImpl(
override val expectedArrayType: KtType,
override val firDiagnostic: KtPsiDiagnostic, override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.AssigningSingleElementToVarargInNamedFormFunctionError(), KtAbstractFirDiagnostic<KtExpression> ) : KtFirDiagnostic.AssigningSingleElementToVarargInNamedFormFunctionError(), KtAbstractFirDiagnostic<KtExpression>
internal class AssigningSingleElementToVarargInNamedFormFunctionWarningImpl( internal class AssigningSingleElementToVarargInNamedFormFunctionWarningImpl(
override val expectedArrayType: KtType,
override val firDiagnostic: KtPsiDiagnostic, override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.AssigningSingleElementToVarargInNamedFormFunctionWarning(), KtAbstractFirDiagnostic<KtExpression> ) : KtFirDiagnostic.AssigningSingleElementToVarargInNamedFormFunctionWarning(), KtAbstractFirDiagnostic<KtExpression>
@@ -493,7 +493,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val SPREAD_OF_NULLABLE by error<PsiElement>(PositioningStrategy.SPREAD_OPERATOR) val SPREAD_OF_NULLABLE by error<PsiElement>(PositioningStrategy.SPREAD_OPERATOR)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm) val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm) {
parameter<ConeKotlinType>("expectedArrayType")
}
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm) val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_ANNOTATION by warning<KtExpression>() val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_ANNOTATION by warning<KtExpression>()
val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_FUNCTION by warning<KtExpression>() val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_FUNCTION by warning<KtExpression>()
@@ -334,7 +334,7 @@ object FirErrors {
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>() val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>() val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>()
val SPREAD_OF_NULLABLE by error0<PsiElement>(SourceElementPositioningStrategies.SPREAD_OPERATOR) val SPREAD_OF_NULLABLE by error0<PsiElement>(SourceElementPositioningStrategies.SPREAD_OPERATOR)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm) val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError1<KtExpression, ConeKotlinType>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm) val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_ANNOTATION by warning0<KtExpression>() val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_ANNOTATION by warning0<KtExpression>()
val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_FUNCTION by warning0<KtExpression>() val REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_FUNCTION by warning0<KtExpression>()
@@ -18,7 +18,9 @@ import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isArrayType import org.jetbrains.kotlin.fir.types.isArrayType
object FirNamedVarargChecker : FirCallChecker() { object FirNamedVarargChecker : FirCallChecker() {
@@ -28,9 +30,6 @@ object FirNamedVarargChecker : FirCallChecker() {
expression !is FirDelegatedConstructorCall && expression !is FirDelegatedConstructorCall &&
expression !is FirArrayOfCall) return expression !is FirArrayOfCall) return
val isAnnotation = expression is FirAnnotation val isAnnotation = expression is FirAnnotation
val singleElementToVarargErrorFactory =
if (isAnnotation) FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION
else FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION
val redundantSpreadWarningFactory = val redundantSpreadWarningFactory =
if (isAnnotation) FirErrors.REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_ANNOTATION if (isAnnotation) FirErrors.REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_ANNOTATION
else FirErrors.REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_FUNCTION else FirErrors.REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_FUNCTION
@@ -40,7 +39,7 @@ object FirNamedVarargChecker : FirCallChecker() {
else LanguageFeature.AllowAssigningArrayElementsToVarargsInNamedFormForFunctions else LanguageFeature.AllowAssigningArrayElementsToVarargsInNamedFormForFunctions
) )
fun checkArgument(argument: FirExpression, isVararg: Boolean) { fun checkArgument(argument: FirExpression, isVararg: Boolean, expectedArrayType: ConeKotlinType?) {
if (argument !is FirNamedArgumentExpression) return if (argument !is FirNamedArgumentExpression) return
if (argument.isSpread) { if (argument.isSpread) {
if (isVararg && (expression as? FirResolvable)?.calleeReference !is FirErrorNamedReference) { if (isVararg && (expression as? FirResolvable)?.calleeReference !is FirErrorNamedReference) {
@@ -53,20 +52,34 @@ object FirNamedVarargChecker : FirCallChecker() {
if (argument.expression is FirArrayOfCall) return if (argument.expression is FirArrayOfCall) return
if (allowAssignArray && typeRef.isArrayType) return if (allowAssignArray && typeRef.isArrayType) return
reporter.reportOn(argument.expression.source, singleElementToVarargErrorFactory, context) if (isAnnotation) {
reporter.reportOn(
argument.expression.source,
FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION,
context
)
} else {
require(expectedArrayType != null) { "expectedArrayType must be passed for function call" }
reporter.reportOn(
argument.expression.source,
FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION,
expectedArrayType,
context,
)
}
} }
if (expression is FirArrayOfCall) { if (expression is FirArrayOfCall) {
// FirArrayOfCall has the `vararg` argument expression pre-flattened and doesn't have an argument mapping. // FirArrayOfCall has the `vararg` argument expression pre-flattened and doesn't have an argument mapping.
expression.arguments.forEach { checkArgument(it, it is FirNamedArgumentExpression) } expression.arguments.forEach { checkArgument(it, it is FirNamedArgumentExpression, null /* not used for annotation call */) }
} else { } else {
val argumentMap = expression.argumentMapping ?: return val argumentMap = expression.argumentMapping ?: return
for ((argument, parameter) in argumentMap) { for ((argument, parameter) in argumentMap) {
if (!parameter.isVararg) continue if (!parameter.isVararg) continue
if (argument is FirVarargArgumentsExpression) { if (argument is FirVarargArgumentsExpression) {
argument.arguments.forEach { checkArgument(it, true) } argument.arguments.forEach { checkArgument(it, true, parameter.returnTypeRef.coneType) }
} else { } else {
checkArgument(argument, false) checkArgument(argument, false, parameter.returnTypeRef.coneType)
} }
} }
} }
@@ -839,7 +839,8 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(SPREAD_OF_NULLABLE, "The spread operator (*foo) may not be applied to an argument of nullable type") map.put(SPREAD_OF_NULLABLE, "The spread operator (*foo) may not be applied to an argument of nullable type")
map.put( map.put(
ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION, ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION,
"Assigning single elements to varargs in named form is forbidden" "Assigning single elements to varargs in named form is forbidden",
NOT_RENDERED
) )
map.put( map.put(
ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION, ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION,