Check 'operator' on next() and hasNext()

This commit is contained in:
Yan Zhulanow
2015-09-24 21:51:40 +03:00
parent 2c7f68ff71
commit 35362a0f3b
3 changed files with 26 additions and 0 deletions
@@ -68,6 +68,8 @@ public class OperatorModifierChecker : DeclarationChecker {
INVOKE == name -> {}
CONTAINS == name -> {}
ITERATOR == name -> {}
NEXT == name -> {}
HAS_NEXT == name -> {}
EQUALS == name -> {}
COMPARE_TO == name -> {}
UNARY_OPERATION_NAMES.any { it.value == name } && functionDescriptor.valueParameters.isEmpty() -> {}
@@ -21,15 +21,22 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
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;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
@@ -70,6 +77,8 @@ public class ForLoopConventionsChecker {
context.trace.record(LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall);
FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor();
checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace);
symbolUsageValidator.validateCall(iteratorFunction, context.trace, loopRangeExpression);
JetType iteratorType = iteratorFunction.getReturnType();
@@ -94,6 +103,16 @@ public class ForLoopConventionsChecker {
return null;
}
private static void checkIfOperatorModifierPresent(JetExpression expression, FunctionDescriptor descriptor, DiagnosticSink sink) {
if (ErrorUtils.isError(descriptor)) return;
ReceiverParameterDescriptor extensionReceiverParameter = descriptor.getExtensionReceiverParameter();
if ((extensionReceiverParameter != null) && (DynamicTypesKt.isDynamic(extensionReceiverParameter.getType()))) return;
if (!descriptor.isOperator()) {
OperatorValidator.Companion.report(expression, descriptor, sink);
}
}
@Nullable
private JetType checkConventionForIterator(
@NotNull ExpressionTypingContext context,
@@ -122,6 +141,9 @@ public class ForLoopConventionsChecker {
context.trace.record(resolvedCallKey, loopRangeExpression, resolvedCall);
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
symbolUsageValidator.validateCall(functionDescriptor, context.trace, loopRangeExpression);
checkIfOperatorModifierPresent(loopRangeExpression, functionDescriptor, context.trace);
return functionDescriptor.getReturnType();
}
return null;
@@ -33,6 +33,8 @@ public class OperatorConventions {
public static final Name CONTAINS = Name.identifier("contains");
public static final Name INVOKE = Name.identifier("invoke");
public static final Name ITERATOR = Name.identifier("iterator");
public static final Name NEXT = Name.identifier("next");
public static final Name HAS_NEXT = Name.identifier("hasNext");
private OperatorConventions() {}