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:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-27
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user