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.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
enum class FakeCallKind { enum class FakeCallKind {
ITERATOR, ITERATOR,
@@ -45,47 +43,15 @@ class FakeCallResolver(
private val project: Project, private val project: Project,
private val callResolver: CallResolver 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( fun resolveFakeCall(
context: ResolutionContext<*>, context: ResolutionContext<*>,
receiver: ReceiverValue, receiver: ReceiverValue?,
name: Name, name: Name,
callElement: KtExpression, callElement: KtExpression,
reportErrorsOn: KtExpression = callElement, reportErrorsOn: KtExpression,
callKind: FakeCallKind = FakeCallKind.OTHER, callKind: FakeCallKind,
valueArguments: List<KtExpression> = emptyList() valueArguments: List<KtExpression>
): OverloadResolutionResults<FunctionDescriptor> { ): 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 fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name)
val fakeBindingTrace = context.replaceBindingTrace(fakeTrace) val fakeBindingTrace = context.replaceBindingTrace(fakeTrace)
@@ -93,17 +59,19 @@ class FakeCallResolver(
val result = makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake, isSuccess -> val result = makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake, isSuccess ->
unreportedDiagnostic = fakeTrace.bindingContext.diagnostics.noSuppression().forElement(fake).firstOrNull { it.severity == Severity.ERROR } unreportedDiagnostic = fakeTrace.bindingContext.diagnostics.noSuppression().forElement(fake).firstOrNull { it.severity == Severity.ERROR }
if (!isSuccess) return@makeAndResolveFakeCallInContext if (isSuccess) {
fakeTrace.commit(
fakeTrace.commit({ slice, key -> { slice, key ->
// excluding all entries related to fake expression // excluding all entries related to fake expression
// convert all errors on this expression to ITERATOR_MISSING on callElement // convert all errors on this expression to ITERATOR_MISSING on callElement
key != fake key != fake
}, true) }, true
)
}
} }
val resolutionResults = result.second val resolutionResults = result.second
if ((!resolutionResults.isSuccess || unreportedDiagnostic != null) && reportErrorsOn != null) { if (!resolutionResults.isSuccess || unreportedDiagnostic != null) {
val isUnsafeCall = unreportedDiagnostic?.factory == Errors.UNSAFE_CALL val isUnsafeCall = unreportedDiagnostic?.factory == Errors.UNSAFE_CALL
val diagnostic = when (callKind) { val diagnostic = when (callKind) {
FakeCallKind.ITERATOR -> FakeCallKind.ITERATOR ->
@@ -127,22 +95,26 @@ class FakeCallResolver(
context.trace.report(diagnostic) context.trace.report(diagnostic)
} }
} }
return result
return resolutionResults
} }
@JvmOverloads fun makeAndResolveFakeCallInContext( @JvmOverloads
fun makeAndResolveFakeCallInContext(
receiver: ReceiverValue?, receiver: ReceiverValue?,
context: ResolutionContext<*>, context: ResolutionContext<*>,
valueArguments: List<KtExpression>, valueArguments: List<KtExpression>,
name: Name, name: Name,
callElement: KtExpression?, callElement: KtExpression,
onComplete: (KtSimpleNameExpression, Boolean) -> Unit = { x, y -> } onComplete: (KtSimpleNameExpression, Boolean) -> Unit = { x, y -> }
): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> { ): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> {
val fake = KtPsiFactory(project).createSimpleName(name.asString()) val fakeCalleeExpression = KtPsiFactory(project).createSimpleName(name.asString())
val call = CallMaker.makeCallWithExpressions(callElement ?: fake, receiver, null, fake, valueArguments) val call = CallMaker.makeCallWithExpressions(
val results = callResolver.resolveCallWithGivenName(context, call, fake, name) 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) return Pair(call, results)
} }
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.types.expressions; package org.jetbrains.kotlin.types.expressions;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 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.DiagnosticFactory1;
import org.jetbrains.kotlin.diagnostics.DiagnosticSink; import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker; import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
@@ -56,38 +54,35 @@ public class ForLoopConventionsChecker {
} }
@Nullable @Nullable
public KotlinType checkIterableConvention(@NotNull ExpressionReceiver loopRange, ExpressionTypingContext context) { public KotlinType checkIterableConvention(@NotNull ExpressionReceiver loopRange, @NotNull ExpressionTypingContext context) {
KtExpression loopRangeExpression = loopRange.getExpression(); KtExpression loopRangeExpression = loopRange.getExpression();
// Make a fake call loopRange.iterator(), and try to resolve it // Make a fake call loopRange.iterator(), and try to resolve it
Pair<Call, OverloadResolutionResults<FunctionDescriptor>> calls = fakeCallResolver.makeAndResolveFakeCall( OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = fakeCallResolver.resolveFakeCall(
loopRange, context, Collections.<KtExpression>emptyList(), OperatorNameConventions.ITERATOR, loopRangeExpression, context, loopRange, OperatorNameConventions.ITERATOR, loopRangeExpression,
FakeCallKind.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();
ResolvedCall<FunctionDescriptor> iteratorResolvedCall = iteratorResolutionResults.getResultingCall(); context.trace.record(LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall);
context.trace.record(LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall); FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor();
FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor();
checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace); checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace);
KotlinType iteratorType = iteratorFunction.getReturnType(); KotlinType iteratorType = iteratorFunction.getReturnType();
//noinspection ConstantConditions //noinspection ConstantConditions
KotlinType hasNextType = checkConventionForIterator( KotlinType hasNextType = checkConventionForIterator(
context, loopRangeExpression, iteratorType, OperatorNameConventions.HAS_NEXT, context, loopRangeExpression, iteratorType, OperatorNameConventions.HAS_NEXT,
HAS_NEXT_FUNCTION_AMBIGUITY, HAS_NEXT_MISSING, HAS_NEXT_FUNCTION_NONE_APPLICABLE, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL HAS_NEXT_FUNCTION_AMBIGUITY, HAS_NEXT_MISSING, HAS_NEXT_FUNCTION_NONE_APPLICABLE, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL
); );
if (hasNextType != null && !builtIns.isBooleanOrSubtype(hasNextType)) { if (hasNextType != null && !builtIns.isBooleanOrSubtype(hasNextType)) {
context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRangeExpression, 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
);
} }
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) { private static void checkIfOperatorModifierPresent(KtExpression expression, FunctionDescriptor descriptor, DiagnosticSink sink) {
@@ -112,7 +107,8 @@ public class ForLoopConventionsChecker {
@NotNull WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> resolvedCallKey @NotNull WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> resolvedCallKey
) { ) {
OverloadResolutionResults<FunctionDescriptor> nextResolutionResults = fakeCallResolver.resolveFakeCall( 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()) { if (nextResolutionResults.isAmbiguity()) {
context.trace.report(ambiguity.on(loopRangeExpression, iteratorType)); 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.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name; 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.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory; 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.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext; import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
import org.jetbrains.kotlin.types.expressions.FakeCallKind; import org.jetbrains.kotlin.types.expressions.FakeCallKind;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.jetbrains.kotlin.psi.KtPsiFactoryKt.KtPsiFactory;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
public class ExpectedResolveDataUtil { public class ExpectedResolveDataUtil {
@@ -150,8 +150,20 @@ public class ExpectedResolveDataUtil {
new BindingTraceContext(), lexicalScope, new BindingTraceContext(), lexicalScope,
DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE); 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( 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()) { for (ResolvedCall<? extends FunctionDescriptor> resolvedCall : functions.getResultingCalls()) {
List<ValueParameterDescriptor> unsubstitutedValueParameters = resolvedCall.getResultingDescriptor().getValueParameters(); List<ValueParameterDescriptor> unsubstitutedValueParameters = resolvedCall.getResultingDescriptor().getValueParameters();