Make infix & operator checkers implement CallChecker
Instead of SymbolUsageValidator
This commit is contained in:
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeVariableKt;
|
||||
@@ -39,7 +40,6 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.validation.OperatorValidator;
|
||||
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
@@ -263,7 +263,7 @@ public class DelegatedPropertyResolver {
|
||||
PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
|
||||
|
||||
if (!resultingDescriptor.isOperator()) {
|
||||
OperatorValidator.Companion.report(byKeyword, resultingDescriptor, trace);
|
||||
OperatorCallChecker.Companion.report(byKeyword, resultingDescriptor, trace);
|
||||
}
|
||||
|
||||
symbolUsageValidator.validateCall(resultingCall, resultingCall.getResultingDescriptor(), trace, byKeyword);
|
||||
|
||||
@@ -27,8 +27,6 @@ import org.jetbrains.kotlin.resolve.calls.checkers.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
import org.jetbrains.kotlin.resolve.validation.DeprecatedSymbolValidator
|
||||
import org.jetbrains.kotlin.resolve.validation.InfixValidator
|
||||
import org.jetbrains.kotlin.resolve.validation.OperatorValidator
|
||||
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.DynamicTypesSettings
|
||||
@@ -66,12 +64,14 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
SuspendModifierChecker,
|
||||
CoroutineModifierChecker)
|
||||
|
||||
private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(),
|
||||
SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(),
|
||||
ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, CoroutineSuspendCallChecker,
|
||||
BuilderFunctionsCallChecker)
|
||||
private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(), SafeCallChecker(),
|
||||
InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(),
|
||||
ConstructorHeaderCallChecker, ProtectedConstructorCallChecker,
|
||||
CoroutineSuspendCallChecker, BuilderFunctionsCallChecker
|
||||
)
|
||||
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
||||
private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator(), OperatorValidator(), InfixValidator())
|
||||
private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator())
|
||||
|
||||
|
||||
abstract class PlatformConfigurator(
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.InfixCallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.getNestedTypeVariables
|
||||
@@ -41,7 +42,6 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
|
||||
import org.jetbrains.kotlin.resolve.validation.InfixValidator
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
@@ -136,7 +136,7 @@ fun isConventionCall(call: Call): Boolean {
|
||||
return calleeExpression.getNameForConventionalOperation() != null
|
||||
}
|
||||
|
||||
fun isInfixCall(call: Call): Boolean = InfixValidator.isInfixCall(call.calleeExpression)
|
||||
fun isInfixCall(call: Call): Boolean = InfixCallChecker.isInfixCall(call.calleeExpression)
|
||||
|
||||
fun getUnaryPlusOrMinusOperatorFunctionName(call: Call): Name? {
|
||||
if (call.callElement !is KtPrefixExpression) return null
|
||||
|
||||
+11
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,34 +14,30 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.validation
|
||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtOperationReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
|
||||
class InfixValidator : SymbolUsageValidator {
|
||||
|
||||
override fun validateCall(
|
||||
resolvedCall: ResolvedCall<*>?,
|
||||
targetDescriptor: CallableDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement
|
||||
) {
|
||||
val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return
|
||||
class InfixCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext, languageFeatureSettings: LanguageFeatureSettings) {
|
||||
val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return
|
||||
if (functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return
|
||||
val element = ((resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall ?: resolvedCall).call.calleeExpression
|
||||
if (isInfixCall(element) && !functionDescriptor.isInfix) {
|
||||
val operationRefExpression = element as? KtOperationReferenceExpression ?: return
|
||||
val containingDeclarationName = functionDescriptor.containingDeclaration.fqNameUnsafe.asString()
|
||||
trace.report(Errors.INFIX_MODIFIER_REQUIRED.on(operationRefExpression, functionDescriptor, containingDeclarationName))
|
||||
context.trace.report(Errors.INFIX_MODIFIER_REQUIRED.on(operationRefExpression, functionDescriptor, containingDeclarationName))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +48,4 @@ class InfixValidator : SymbolUsageValidator {
|
||||
return binaryExpression.operationReference === operationRefExpression && !operationRefExpression.isPredefinedOperator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-33
@@ -14,18 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.validation
|
||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
@@ -36,51 +35,41 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.PLUS
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_MINUS
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_PLUS
|
||||
|
||||
class OperatorValidator : SymbolUsageValidator {
|
||||
|
||||
override fun validateCall(resolvedCall: ResolvedCall<*>?, targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) {
|
||||
val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return
|
||||
class OperatorCallChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext, languageFeatureSettings: LanguageFeatureSettings) {
|
||||
val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return
|
||||
if (!checkNotErrorOrDynamic(functionDescriptor)) return
|
||||
|
||||
val jetElement = element as? KtElement ?: return
|
||||
val call = resolvedCall?.call ?: trace.bindingContext[BindingContext.CALL, jetElement]
|
||||
val element = resolvedCall.call.calleeExpression ?: resolvedCall.call.callElement
|
||||
val call = resolvedCall.call
|
||||
|
||||
fun isInvokeCall(): Boolean {
|
||||
return call is CallTransformer.CallForImplicitInvoke
|
||||
}
|
||||
fun isInvokeCall(): Boolean = call is CallTransformer.CallForImplicitInvoke
|
||||
|
||||
fun isMultiDeclaration(): Boolean {
|
||||
return (resolvedCall != null) && (call?.callElement is KtDestructuringDeclarationEntry)
|
||||
}
|
||||
fun isMultiDeclaration(): Boolean = call.callElement is KtDestructuringDeclarationEntry
|
||||
|
||||
fun isConventionOperator(): Boolean {
|
||||
if (jetElement !is KtOperationReferenceExpression) return false
|
||||
return jetElement.getNameForConventionalOperation() != null
|
||||
}
|
||||
|
||||
fun isArrayAccessExpression() = jetElement is KtArrayAccessExpression
|
||||
|
||||
if (resolvedCall is VariableAsFunctionResolvedCall && call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
|
||||
if (resolvedCall is VariableAsFunctionResolvedCall &&
|
||||
call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
|
||||
val outerCall = call.outerCall
|
||||
if (isConventionCall(outerCall)) {
|
||||
throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. Variable: ${resolvedCall.variableCall.resultingDescriptor}")
|
||||
throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. " +
|
||||
"Variable: ${resolvedCall.variableCall.resultingDescriptor}")
|
||||
}
|
||||
}
|
||||
|
||||
if (isMultiDeclaration() || isInvokeCall()) {
|
||||
if (!functionDescriptor.isOperator && call != null) {
|
||||
report(call.callElement, functionDescriptor, trace)
|
||||
if (!functionDescriptor.isOperator) {
|
||||
report(call.callElement, functionDescriptor, context.trace)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val isConventionOperator = isConventionOperator()
|
||||
if (isConventionOperator || isArrayAccessExpression()) {
|
||||
val isConventionOperator = element is KtOperationReferenceExpression && element.getNameForConventionalOperation() != null
|
||||
if (isConventionOperator || element is KtArrayAccessExpression) {
|
||||
if (!functionDescriptor.isOperator) {
|
||||
report(jetElement, functionDescriptor, trace)
|
||||
report(element, functionDescriptor, context.trace)
|
||||
}
|
||||
if (isConventionOperator && call != null) {
|
||||
checkDeprecatedUnaryConventions(call, functionDescriptor, trace)
|
||||
if (isConventionOperator) {
|
||||
checkDeprecatedUnaryConventions(call, functionDescriptor, context.trace)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,4 +97,4 @@ class OperatorValidator : SymbolUsageValidator {
|
||||
return (!functionDescriptor.isDynamic() && !ErrorUtils.isError(functionDescriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-15
@@ -869,22 +869,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
* @return {@code true} iff expression can be assigned to
|
||||
*/
|
||||
public boolean checkLValue(
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull ExpressionTypingContext context,
|
||||
@NotNull KtExpression expression,
|
||||
@Nullable KtExpression rightHandSide,
|
||||
@NotNull KtOperationExpression operationExpression
|
||||
) {
|
||||
return checkLValue(trace, context, expression, rightHandSide, operationExpression, false);
|
||||
}
|
||||
|
||||
private boolean checkLValue(
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull ExpressionTypingContext context,
|
||||
@NotNull KtExpression expressionWithParenthesis,
|
||||
@Nullable KtExpression rightHandSide,
|
||||
@NotNull KtOperationExpression operationExpression,
|
||||
boolean canBeThis
|
||||
@NotNull KtOperationExpression operationExpression
|
||||
) {
|
||||
KtExpression expression = KtPsiUtil.deparenthesize(expressionWithParenthesis);
|
||||
if (expression instanceof KtArrayAccessExpression) {
|
||||
@@ -901,17 +890,20 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
|| operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) {
|
||||
ResolvedCall<?> resolvedCall = ignoreReportsTrace.get(INDEXED_LVALUE_SET, expression);
|
||||
if (resolvedCall != null) {
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
// Call must be validated with the actual, not temporary trace in order to report operator diagnostic
|
||||
// Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace
|
||||
components.symbolUsageValidator.validateCall(resolvedCall, descriptor, trace, expression);
|
||||
BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create(
|
||||
context.replaceBindingTrace(trace), resolvedCall.getCall(), CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
||||
);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, callResolutionContext, components.languageFeatureSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info.getType() != null;
|
||||
}
|
||||
|
||||
if (canBeThis && expression instanceof KtThisExpression) return true;
|
||||
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true);
|
||||
|
||||
boolean result = true;
|
||||
|
||||
+2
-2
@@ -27,11 +27,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.Call;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
|
||||
import org.jetbrains.kotlin.resolve.validation.OperatorValidator;
|
||||
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
|
||||
import org.jetbrains.kotlin.types.DynamicTypesKt;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
@@ -99,7 +99,7 @@ public class ForLoopConventionsChecker {
|
||||
if ((extensionReceiverParameter != null) && (DynamicTypesKt.isDynamic(extensionReceiverParameter.getType()))) return;
|
||||
|
||||
if (!descriptor.isOperator()) {
|
||||
OperatorValidator.Companion.report(expression, descriptor, sink);
|
||||
OperatorCallChecker.Companion.report(expression, descriptor, sink);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user