Introduce warning for the changing arguments execution order for named varargs (KT-17691)
This commit is contained in:
@@ -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);
|
||||
|
||||
+3
@@ -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(
|
||||
|
||||
+41
@@ -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))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user