Refactor FakeCallResolver and usages

Remove useless overload, inline another to the single usage in tests, make some
parameters non-null
This commit is contained in:
Alexander Udalov
2016-06-30 15:11:40 +03:00
parent 95ed3ed78b
commit 1690dcd8df
3 changed files with 65 additions and 85 deletions
@@ -32,8 +32,6 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
enum class FakeCallKind {
ITERATOR,
@@ -45,47 +43,15 @@ class FakeCallResolver(
private val project: Project,
private val callResolver: CallResolver
) {
fun resolveFakeCall(
context: ExpressionTypingContext,
receiver: ReceiverValue?,
name: Name,
callElement: KtExpression?,
reportErrorsOn: KtExpression? = callElement,
callKind: FakeCallKind = FakeCallKind.OTHER,
vararg argumentTypes: KotlinType
): OverloadResolutionResults<FunctionDescriptor> {
val traceWithFakeArgumentInfo = TemporaryBindingTrace.create(context.trace, "trace to store fake argument for", name)
val fakeArguments = ArrayList<KtExpression>()
for (type in argumentTypes) {
fakeArguments.add(ExpressionTypingUtils.createFakeExpressionOfType(project, traceWithFakeArgumentInfo,
"fakeArgument" + fakeArguments.size, type))
}
return makeAndResolveFakeCall(receiver, context.replaceBindingTrace(traceWithFakeArgumentInfo),
fakeArguments, name, callElement, callKind, reportErrorsOn).second
}
@JvmOverloads
fun resolveFakeCall(
context: ResolutionContext<*>,
receiver: ReceiverValue,
receiver: ReceiverValue?,
name: Name,
callElement: KtExpression,
reportErrorsOn: KtExpression = callElement,
callKind: FakeCallKind = FakeCallKind.OTHER,
valueArguments: List<KtExpression> = emptyList()
reportErrorsOn: KtExpression,
callKind: FakeCallKind,
valueArguments: List<KtExpression>
): OverloadResolutionResults<FunctionDescriptor> {
return makeAndResolveFakeCall(receiver, context, valueArguments, name, callElement, callKind, reportErrorsOn).second
}
fun makeAndResolveFakeCall(
receiver: ReceiverValue?,
context: ResolutionContext<*>,
valueArguments: List<KtExpression>,
name: Name,
callElement: KtExpression?,
callKind: FakeCallKind = FakeCallKind.OTHER,
reportErrorsOn: KtExpression? = callElement
): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> {
val fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name)
val fakeBindingTrace = context.replaceBindingTrace(fakeTrace)
@@ -93,17 +59,19 @@ class FakeCallResolver(
val result = makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake, isSuccess ->
unreportedDiagnostic = fakeTrace.bindingContext.diagnostics.noSuppression().forElement(fake).firstOrNull { it.severity == Severity.ERROR }
if (!isSuccess) return@makeAndResolveFakeCallInContext
fakeTrace.commit({ slice, key ->
// excluding all entries related to fake expression
// convert all errors on this expression to ITERATOR_MISSING on callElement
key != fake
}, true)
if (isSuccess) {
fakeTrace.commit(
{ slice, key ->
// excluding all entries related to fake expression
// convert all errors on this expression to ITERATOR_MISSING on callElement
key != fake
}, true
)
}
}
val resolutionResults = result.second
if ((!resolutionResults.isSuccess || unreportedDiagnostic != null) && reportErrorsOn != null) {
if (!resolutionResults.isSuccess || unreportedDiagnostic != null) {
val isUnsafeCall = unreportedDiagnostic?.factory == Errors.UNSAFE_CALL
val diagnostic = when (callKind) {
FakeCallKind.ITERATOR ->
@@ -127,22 +95,26 @@ class FakeCallResolver(
context.trace.report(diagnostic)
}
}
return result
return resolutionResults
}
@JvmOverloads fun makeAndResolveFakeCallInContext(
@JvmOverloads
fun makeAndResolveFakeCallInContext(
receiver: ReceiverValue?,
context: ResolutionContext<*>,
valueArguments: List<KtExpression>,
name: Name,
callElement: KtExpression?,
callElement: KtExpression,
onComplete: (KtSimpleNameExpression, Boolean) -> Unit = { x, y -> }
): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> {
val fake = KtPsiFactory(project).createSimpleName(name.asString())
val call = CallMaker.makeCallWithExpressions(callElement ?: fake, receiver, null, fake, valueArguments)
val results = callResolver.resolveCallWithGivenName(context, call, fake, name)
val fakeCalleeExpression = KtPsiFactory(project).createSimpleName(name.asString())
val call = CallMaker.makeCallWithExpressions(
callElement, receiver, /* callOperationNode = */ null, fakeCalleeExpression, valueArguments
)
val results = callResolver.resolveCallWithGivenName(context, call, fakeCalleeExpression, name)
onComplete(fake, results.isSuccess)
onComplete(fakeCalleeExpression, results.isSuccess)
return Pair(call, results)
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.types.expressions;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -25,7 +24,6 @@ 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.KtExpression;
import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
@@ -56,38 +54,35 @@ public class ForLoopConventionsChecker {
}
@Nullable
public KotlinType checkIterableConvention(@NotNull ExpressionReceiver loopRange, ExpressionTypingContext context) {
public KotlinType checkIterableConvention(@NotNull ExpressionReceiver loopRange, @NotNull ExpressionTypingContext context) {
KtExpression loopRangeExpression = loopRange.getExpression();
// Make a fake call loopRange.iterator(), and try to resolve it
Pair<Call, OverloadResolutionResults<FunctionDescriptor>> calls = fakeCallResolver.makeAndResolveFakeCall(
loopRange, context, Collections.<KtExpression>emptyList(), OperatorNameConventions.ITERATOR, loopRangeExpression,
FakeCallKind.ITERATOR, loopRangeExpression
OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = fakeCallResolver.resolveFakeCall(
context, loopRange, OperatorNameConventions.ITERATOR, loopRangeExpression,
loopRangeExpression, FakeCallKind.ITERATOR, Collections.<KtExpression>emptyList()
);
OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = calls.getSecond();
if (!iteratorResolutionResults.isSuccess()) return null;
if (iteratorResolutionResults.isSuccess()) {
ResolvedCall<FunctionDescriptor> iteratorResolvedCall = iteratorResolutionResults.getResultingCall();
context.trace.record(LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall);
FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor();
ResolvedCall<FunctionDescriptor> iteratorResolvedCall = iteratorResolutionResults.getResultingCall();
context.trace.record(LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall);
FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor();
checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace);
checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace);
KotlinType iteratorType = iteratorFunction.getReturnType();
//noinspection ConstantConditions
KotlinType hasNextType = checkConventionForIterator(
context, loopRangeExpression, iteratorType, OperatorNameConventions.HAS_NEXT,
HAS_NEXT_FUNCTION_AMBIGUITY, HAS_NEXT_MISSING, HAS_NEXT_FUNCTION_NONE_APPLICABLE, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL
);
if (hasNextType != null && !builtIns.isBooleanOrSubtype(hasNextType)) {
context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRangeExpression, hasNextType));
}
return checkConventionForIterator(
context, loopRangeExpression, iteratorType, OperatorNameConventions.NEXT,
NEXT_AMBIGUITY, NEXT_MISSING, NEXT_NONE_APPLICABLE, LOOP_RANGE_NEXT_RESOLVED_CALL
);
KotlinType iteratorType = iteratorFunction.getReturnType();
//noinspection ConstantConditions
KotlinType hasNextType = checkConventionForIterator(
context, loopRangeExpression, iteratorType, OperatorNameConventions.HAS_NEXT,
HAS_NEXT_FUNCTION_AMBIGUITY, HAS_NEXT_MISSING, HAS_NEXT_FUNCTION_NONE_APPLICABLE, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL
);
if (hasNextType != null && !builtIns.isBooleanOrSubtype(hasNextType)) {
context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRangeExpression, hasNextType));
}
return null;
return checkConventionForIterator(
context, loopRangeExpression, iteratorType, OperatorNameConventions.NEXT,
NEXT_AMBIGUITY, NEXT_MISSING, NEXT_NONE_APPLICABLE, LOOP_RANGE_NEXT_RESOLVED_CALL
);
}
private static void checkIfOperatorModifierPresent(KtExpression expression, FunctionDescriptor descriptor, DiagnosticSink sink) {
@@ -112,7 +107,8 @@ public class ForLoopConventionsChecker {
@NotNull WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> resolvedCallKey
) {
OverloadResolutionResults<FunctionDescriptor> nextResolutionResults = fakeCallResolver.resolveFakeCall(
context, new TransientReceiver(iteratorType), name, loopRangeExpression
context, new TransientReceiver(iteratorType), name, loopRangeExpression, loopRangeExpression, FakeCallKind.OTHER,
Collections.<KtExpression>emptyList()
);
if (nextResolutionResults.isAmbiguity()) {
context.trace.report(ambiguity.on(loopRangeExpression, iteratorType));
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
@@ -41,13 +42,12 @@ import org.jetbrains.kotlin.tests.di.InjectionKt;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
import org.jetbrains.kotlin.types.expressions.FakeCallKind;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static org.jetbrains.kotlin.psi.KtPsiFactoryKt.KtPsiFactory;
import static org.junit.Assert.assertNotNull;
public class ExpectedResolveDataUtil {
@@ -150,8 +150,20 @@ public class ExpectedResolveDataUtil {
new BindingTraceContext(), lexicalScope,
DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE);
KtExpression callElement = KtPsiFactory(project).createExpression(name);
TemporaryBindingTrace traceWithFakeArgumentInfo =
TemporaryBindingTrace.create(context.trace, "trace to store fake argument for", name);
List<KtExpression> fakeArguments = new ArrayList<KtExpression>(parameterTypes.length);
for (KotlinType type : parameterTypes) {
fakeArguments.add(ExpressionTypingUtils.createFakeExpressionOfType(
project, traceWithFakeArgumentInfo, "fakeArgument" + fakeArguments.size(), type
));
}
OverloadResolutionResults<FunctionDescriptor> functions = container.getFakeCallResolver().resolveFakeCall(
context, null, Name.identifier(name), null, null, FakeCallKind.OTHER, parameterTypes);
context, null, Name.identifier(name), callElement, callElement, FakeCallKind.OTHER, fakeArguments
);
for (ResolvedCall<? extends FunctionDescriptor> resolvedCall : functions.getResultingCalls()) {
List<ValueParameterDescriptor> unsubstitutedValueParameters = resolvedCall.getResultingDescriptor().getValueParameters();