Introduce warning for the changing arguments execution order for named varargs (KT-17691)

This commit is contained in:
Victor Petukhov
2020-09-29 15:34:49 +03:00
parent d62c665e99
commit d02432cf93
43 changed files with 1187 additions and 75 deletions
@@ -628,6 +628,8 @@ public interface Errors {
DiagnosticFactory1<KtParameter, KotlinType> FORBIDDEN_VARARG_PARAMETER_TYPE = DiagnosticFactory1.create(ERROR, PARAMETER_VARARG_MODIFIER);
DiagnosticFactory0<PsiElement> CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS = DiagnosticFactory0.create(WARNING);
// Named parameters
DiagnosticFactory0<KtParameter> DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE = DiagnosticFactory0.create(ERROR, PARAMETER_DEFAULT_VALUE);
@@ -269,6 +269,9 @@ public class DefaultErrorMessages {
MAP.put(USELESS_VARARG_ON_PARAMETER, "Vararg on this parameter is useless");
MAP.put(MULTIPLE_VARARG_PARAMETERS, "Multiple vararg-parameters are prohibited");
MAP.put(FORBIDDEN_VARARG_PARAMETER_TYPE, "Forbidden vararg parameter type: {0}", RENDER_TYPE);
MAP.put(CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS, "Arguments execution order is going to be changed in a future release." +
"The expression for named vararg argument will be executed in the order in which it was listed, not at the end." +
"See KT-17691 for more details.");
MAP.put(EXPECTED_DECLARATION_WITH_BODY, "Expected declaration must not have a body");
MAP.put(EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL, "Explicit delegation call for constructor of an expected class is not allowed");
@@ -54,7 +54,7 @@ private val DEFAULT_CALL_CHECKERS = listOf(
NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker(),
MissingDependencySupertypeChecker.ForCalls, AbstractClassInstantiationChecker, SuspendConversionCallChecker,
UnitConversionCallChecker, FunInterfaceConstructorReferenceChecker, NullableExtensionOperatorWithSafeCallChecker,
ReferencingToUnderscoreNamedParameterOfCatchBlockChecker
ReferencingToUnderscoreNamedParameterOfCatchBlockChecker, VarargWrongExecutionOrderChecker
)
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.calls.model.*
object VarargWrongExecutionOrderChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val isCorrectExecutionOrderForVarargArgumentsAlreadyUsed =
context.languageVersionSettings.getFeatureSupport(LanguageFeature.UseCorrectExecutionOrderForVarargArguments) == LanguageFeature.State.ENABLED
if (isCorrectExecutionOrderForVarargArgumentsAlreadyUsed) return
val valueArguments = resolvedCall.call.valueArguments
val varargIndex = valueArguments.indexOfFirst {
resolvedCall.getParameterForArgument(it)?.isVararg == true
}.takeIf { it != -1 } ?: return
val nonVarargIndex = valueArguments.indexOfLast {
resolvedCall.getParameterForArgument(it)?.isVararg != true
}.takeIf { it != -1 } ?: return
if (varargIndex > nonVarargIndex) return
val varargValueArgument = valueArguments[varargIndex]
if (!varargValueArgument.isNamed() || varargValueArgument !is PsiElement) return
// If named form for vararg is used then we can have only one real value argument on a call site
context.trace.report(Errors.CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS.on(varargValueArgument))
}
}
@@ -630,7 +630,7 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>() : ResolvedCall<D>
private fun createValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> =
LinkedHashMap<ValueParameterDescriptor, ResolvedValueArgument>().also { result ->
val needToUseCorrectExecutionOrderForVarargArguments =
languageVersionSettings.getFeatureSupport(LanguageFeature.UseCorrectExecutionOrderForVarargArguments) == LanguageFeature.State.ENABLED
languageVersionSettings.supportsFeature(LanguageFeature.UseCorrectExecutionOrderForVarargArguments)
var varargMappings: MutableList<Pair<ValueParameterDescriptor, VarargValueArgument>>? = null
for ((originalParameter, resolvedCallArgument) in argumentMappingByOriginal) {
val resultingParameter = resultingDescriptor.valueParameters[originalParameter.index]