From 67dc9ba6e3f6f04d1d8e1e068bc9841b9b3180eb Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 28 Feb 2012 20:36:39 +0400 Subject: [PATCH] KT-1151 Code completion for not imported extension functions - ignore parameters --- .../jetbrains/jet/compiler/TipsManager.java | 94 +++++++-------- .../jet/lang/resolve/calls/CallMaker.java | 4 +- .../jet/lang/resolve/calls/CallResolver.java | 111 ++++++++++++++++-- .../lang/resolve/calls/DelegatingCall.java | 2 +- .../ValueArgumentsToParametersMapper.java | 2 +- .../calls/inference/ConstraintType.java | 4 +- .../ControlStructureTypingVisitor.java | 11 +- .../lang/types/expressions/DataFlowUtils.java | 3 + .../expressions/ExpressionTypingContext.java | 6 + .../expressions/ExpressionTypingUtils.java | 45 +++---- .../completion/JetCompletionContributor.java | 2 +- .../NotImportedExtensionFunction-1.kt | 3 +- .../NotImportedExtensionFunction-2.kt | 4 + 13 files changed, 201 insertions(+), 90 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java b/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java index 64ff3cd9c77..9a00911b087 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java @@ -25,29 +25,21 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetImportDirective; import org.jetbrains.jet.lang.psi.JetNamespaceHeader; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintResolutionListener; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution; +import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.NamespaceType; -import org.jetbrains.jet.lang.types.TypeUtils; -import org.jetbrains.jet.lang.types.Variance; import java.util.*; -import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.RECEIVER; - /** * @author Nikolay Krasko, Alefas */ @@ -146,7 +138,9 @@ public final class TipsManager { return false; } for (ReceiverDescriptor receiverDescriptor : result) { - if (checkReceiverResolution(receiverDescriptor, callableDescriptor)) return false; + if (CallResolver.checkIsExtensionCallable(receiverDescriptor, callableDescriptor)) { + return false; + } } return true; } @@ -183,51 +177,51 @@ public final class TipsManager { new Predicate() { @Override public boolean apply(CallableDescriptor callableDescriptor) { - return checkReceiverResolution(receiverDescriptor, callableDescriptor); + return CallResolver.checkIsExtensionCallable(receiverDescriptor, callableDescriptor); } })); return descriptorsSet; } - /* - * Checks if receiver declaration could be resolved to call expected receiver. - */ - private static boolean checkReceiverResolution ( - @NotNull ReceiverDescriptor expectedReceiver, - @NotNull CallableDescriptor receiverArgument - ) { - JetType type = expectedReceiver.getType(); - if (checkReceiverResolution(expectedReceiver, type, receiverArgument)) return true; - if (type.isNullable()) { - JetType notNullableType = TypeUtils.makeNotNullable(type); - if (checkReceiverResolution(expectedReceiver, notNullableType, receiverArgument)) return true; - } - return false; - } - - private static boolean checkReceiverResolution ( - @NotNull ReceiverDescriptor expectedReceiver, - @NotNull JetType receiverType, - @NotNull CallableDescriptor receiverArgument - ) { - ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING); - for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) { - constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); - } - - ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter(); - if (expectedReceiver.exists() && receiverParameter.exists()) { - constraintSystem.addSubtypingConstraint( - RECEIVER.assertSubtyping(receiverType, receiverParameter.getType())); - } - else if (expectedReceiver.exists() || receiverParameter.exists()) { - // Only one of receivers exist - return false; - } - - ConstraintSystemSolution solution = constraintSystem.solve(); - return solution.getStatus().isSuccessful(); - } +// /* +// * Checks if receiver declaration could be resolved to call expected receiver. +// */ +// private static boolean checkReceiverResolution ( +// @NotNull ReceiverDescriptor expectedReceiver, +// @NotNull CallableDescriptor receiverArgument +// ) { +// JetType type = expectedReceiver.getType(); +// if (checkReceiverResolution(expectedReceiver, type, receiverArgument)) return true; +// if (type.isNullable()) { +// JetType notNullableType = TypeUtils.makeNotNullable(type); +// if (checkReceiverResolution(expectedReceiver, notNullableType, receiverArgument)) return true; +// } +// return false; +// } +// +// private static boolean checkReceiverResolution ( +// @NotNull ReceiverDescriptor expectedReceiver, +// @NotNull JetType receiverType, +// @NotNull CallableDescriptor receiverArgument +// ) { +// ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING); +// for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) { +// constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); +// } +// +// ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter(); +// if (expectedReceiver.exists() && receiverParameter.exists()) { +// constraintSystem.addSubtypingConstraint( +// RECEIVER.assertSubtyping(receiverType, receiverParameter.getType())); +// } +// else if (expectedReceiver.exists() || receiverParameter.exists()) { +// // Only one of receivers exist +// return false; +// } +// +// ConstraintSystemSolution solution = constraintSystem.solve(); +// return solution.getStatus().isSuccessful(); +// } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java index d1d2ec9d373..83fe600bc22 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallMaker.java @@ -140,7 +140,9 @@ public class CallMaker { } } - public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List argumentExpressions) { + public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver, + @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, + @NotNull List argumentExpressions) { List arguments = Lists.newArrayList(); for (JetExpression argumentExpression : argumentExpressions) { arguments.add(makeValueArgument(argumentExpression, calleeExpression)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index aace789cd3f..a2ccc1b7e10 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -113,6 +113,39 @@ public class CallResolver { return doResolveCall(trace, scope, call, expectedType, tasks, functionReference); } + /** + * Get all function from the given scope with the given name and check is they could be satisfied for call on given + * receiver. + * + * @param trace + * @param scope + * @param call + * @param name + * @return + */ + public List resolveCallsByReceiver( + @NotNull BindingTrace trace, + @NotNull JetScope scope, + @NotNull final Call call, + @NotNull String name) { + + List> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks( + scope, call, name, trace.getBindingContext(), dataFlowInfo); + + ArrayList functionDescriptors = new ArrayList(); + + for (ResolutionTask task : tasks) { + Collection> candidates = task.getCandidates(); + for (ResolvedCallImpl candidate : candidates) { + if (checkIsExtensionCallable(call.getExplicitReceiver(), candidate.getCandidateDescriptor())) { + functionDescriptors.add(candidate.getCandidateDescriptor()); + } + } + } + + return functionDescriptors; + } + @NotNull private OverloadResolutionResults resolveSimpleCallToFunctionDescriptor( @NotNull BindingTrace trace, @@ -366,7 +399,11 @@ public class CallResolver { if (callElement instanceof JetBinaryExpression) { JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement; JetSimpleNameExpression operationReference = binaryExpression.getOperationReference(); - String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType()); + + String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? + operationReference.getText() : + OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType()); + JetExpression right = binaryExpression.getRight(); if (right != null) { trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, right.getText())); @@ -433,6 +470,7 @@ public class CallResolver { @NotNull ResolutionTask task, @NotNull TracingStrategy tracing ) { OverloadResolutionResultsImpl results = performResolution(trace, scope, expectedType, task, tracing); + // If resolution fails, we should check for some of the following situations: // class A { // val foo = Bar() // The following is intended to be an anonymous initializer, @@ -448,7 +486,8 @@ public class CallResolver { // {...} // intended to be a returned from the outer literal // } // } - EnumSet someFailed = EnumSet.of(OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES, OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); + EnumSet someFailed = EnumSet.of(OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES, + OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); if (someFailed.contains(results.getResultCode()) && !task.getCall().getFunctionLiteralArguments().isEmpty()) { // We have some candidates that failed for some reason // And we have a suspect: the function literal argument @@ -658,7 +697,7 @@ public class CallResolver { return results; } - private JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) { + private static JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) { JetType effectiveExpectedType = valueParameterDescriptor.getVarargElementType(); if (effectiveExpectedType == null) { effectiveExpectedType = valueParameterDescriptor.getType(); @@ -666,7 +705,7 @@ public class CallResolver { return effectiveExpectedType; } - private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { + private static void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { if (receiver instanceof AutoCastReceiver) { AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; ReceiverDescriptor original = autoCastReceiver.getOriginal(); @@ -703,7 +742,9 @@ public class CallResolver { } } - private void replaceValueParametersWithSubstitutedOnes(ResolvedCallImpl candidateCall, @NotNull D substitutedDescriptor) { + private static void replaceValueParametersWithSubstitutedOnes( + ResolvedCallImpl candidateCall, @NotNull D substitutedDescriptor) { + Map parameterMap = Maps.newHashMap(); for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) { parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); @@ -726,7 +767,9 @@ public class CallResolver { return result; } - private ResolutionStatus checkReceiver(TracingStrategy tracing, ResolvedCallImpl candidateCall, ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument, ResolutionTask task) { + private ResolutionStatus checkReceiver(TracingStrategy tracing, ResolvedCallImpl candidateCall, + ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument, + ResolutionTask task) { ResolutionStatus result = SUCCESS; if (receiverParameter.exists() && receiverArgument.exists()) { ASTNode callOperationNode = task.getCall().getCallOperationNode(); @@ -841,6 +884,7 @@ public class CallResolver { return OverloadResolutionResultsImpl.manyFailedCandidates(results.getResultingCalls()); } } + assert false : "Should not be reachable, cause every status must belong to some level"; Set> noOverrides = OverridingUtil.filterOverrides(failedCandidates, MAP_TO_CANDIDATE); @@ -849,8 +893,10 @@ public class CallResolver { tracing.recordAmbiguity(trace, noOverrides); return OverloadResolutionResultsImpl.manyFailedCandidates(noOverrides); } + failedCandidates = noOverrides; } + ResolvedCallImpl failed = failedCandidates.iterator().next(); failed.getTrace().commit(); return OverloadResolutionResultsImpl.singleFailedCandidate(failed); @@ -861,7 +907,7 @@ public class CallResolver { } } - private boolean allClean(Collection> results) { + private static boolean allClean(Collection> results) { for (ResolvedCallImpl result : results) { if (result.isDirty()) return false; } @@ -939,7 +985,8 @@ public class CallResolver { return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.>emptySet()); } - private List> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List parameterTypes) { + private List> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, + String name, List parameterTypes) { List> result = Lists.newArrayList(); if (receiver.exists()) { Collection> extensionFunctionDescriptors = ResolvedCallImpl.convertCollection(scope.getFunctions(name)); @@ -966,7 +1013,8 @@ public class CallResolver { } } - private boolean lookupExactSignature(Collection> candidates, List parameterTypes, List> result) { + private static boolean lookupExactSignature(Collection> candidates, List parameterTypes, + List> result) { boolean found = false; for (ResolvedCallImpl resolvedCall : candidates) { FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); @@ -979,7 +1027,8 @@ public class CallResolver { return found; } - private boolean findExtensionFunctions(Collection> candidates, ReceiverDescriptor receiver, List parameterTypes, List> result) { + private boolean findExtensionFunctions(Collection> candidates, ReceiverDescriptor receiver, + List parameterTypes, List> result) { boolean found = false; for (ResolvedCallImpl resolvedCall : candidates) { FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); @@ -994,7 +1043,7 @@ public class CallResolver { return found; } - private boolean checkValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull List parameterTypes) { + private static boolean checkValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull List parameterTypes) { List valueParameters = functionDescriptor.getValueParameters(); if (valueParameters.size() != parameterTypes.size()) return false; for (int i = 0; i < valueParameters.size(); i++) { @@ -1004,4 +1053,44 @@ public class CallResolver { } return true; } + + /* + * Checks if receiver declaration could be resolved to call expected receiver. + */ + public static boolean checkIsExtensionCallable ( + @NotNull ReceiverDescriptor expectedReceiver, + @NotNull CallableDescriptor receiverArgument + ) { + JetType type = expectedReceiver.getType(); + if (checkReceiverResolution(expectedReceiver, type, receiverArgument)) return true; + if (type.isNullable()) { + JetType notNullableType = TypeUtils.makeNotNullable(type); + if (checkReceiverResolution(expectedReceiver, notNullableType, receiverArgument)) return true; + } + return false; + } + + private static boolean checkReceiverResolution ( + @NotNull ReceiverDescriptor expectedReceiver, + @NotNull JetType receiverType, + @NotNull CallableDescriptor receiverArgument + ) { + ConstraintSystem constraintSystem = new ConstraintSystemImpl(ConstraintResolutionListener.DO_NOTHING); + for (TypeParameterDescriptor typeParameterDescriptor : receiverArgument.getTypeParameters()) { + constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); + } + + ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter(); + if (expectedReceiver.exists() && receiverParameter.exists()) { + constraintSystem.addSubtypingConstraint( + RECEIVER.assertSubtyping(receiverType, receiverParameter.getType())); + } + else if (expectedReceiver.exists() || receiverParameter.exists()) { + // Only one of receivers exist + return false; + } + + ConstraintSystemSolution solution = constraintSystem.solve(); + return solution.getStatus().isSuccessful(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DelegatingCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DelegatingCall.java index 6112c8e274a..17b50671f80 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DelegatingCall.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DelegatingCall.java @@ -84,8 +84,8 @@ public class DelegatingCall implements Call { return delegate.getTypeArgumentList(); } + @NotNull @Override - @Nullable public PsiElement getCallElement() { return delegate.getCallElement(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java index 595c11f8a22..f16bacc72fa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java @@ -168,7 +168,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; candidateCall.recordValueArgument(valueParameter, new VarargValueArgument()); } else { - // tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); + // tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); tracing.noValueForParameter(temporaryTrace, valueParameter); error = true; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintType.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintType.java index cccbe65b914..333e6c40a2a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintType.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintType.java @@ -22,6 +22,8 @@ import org.jetbrains.jet.lang.types.JetType; import java.text.MessageFormat; /** + * A specific type for subtype constraint of types. + * * @author abreslav */ public enum ConstraintType implements Comparable { @@ -33,7 +35,7 @@ public enum ConstraintType implements Comparable { EXPECTED_TYPE("Resulting type is {0} but {1} was expected"), PARAMETER_BOUND("Type parameter bound is not satisfied: {0} is not a subtype of {1}"); - private final String errorMessageTemplate; // {0} is subtype, {1} is supertye + private final String errorMessageTemplate; // {0} is subtype, {1} is supertype private ConstraintType(@NotNull String errorMessageTemplate) { this.errorMessageTemplate = errorMessageTemplate; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index 0d51a11f4d0..4ceeec0995a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -347,13 +347,22 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { return null; } - public static OverloadResolutionResults resolveFakeCall(ExpressionReceiver receiver, ExpressionTypingContext context, String name) { + public static OverloadResolutionResults resolveFakeCall(ExpressionReceiver receiver, + ExpressionTypingContext context, String name) { JetReferenceExpression fake = JetPsiFactory.createSimpleName(context.getProject(), "fake"); BindingTrace fakeTrace = new BindingTraceContext(); Call call = CallMaker.makeCall(fake, receiver, null, fake, Collections.emptyList()); return context.replaceBindingTrace(fakeTrace).resolveCallWithGivenName(call, fake, name); } + public static List resolveFakeCallWithReceiverOnly(ExpressionReceiver receiver, + ExpressionTypingContext context, String name) { + JetReferenceExpression fake = JetPsiFactory.createSimpleName(context.getProject(), "fake"); + BindingTrace fakeTrace = new BindingTraceContext(); + Call call = CallMaker.makeCall(fake, receiver, null, fake, Collections.emptyList()); + return context.replaceBindingTrace(fakeTrace).resolveForReceiverOnly(call, fake, name); + } + @Nullable private static FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, ExpressionTypingContext context) { OverloadResolutionResults hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.emptyList()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java index 8f80cc88cc2..1576399b249 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java @@ -42,6 +42,9 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST; * @author abreslav */ public class DataFlowUtils { + private DataFlowUtils() { + } + @NotNull public static DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @Nullable final WritableScope scopeToExtend, final ExpressionTypingContext context) { if (condition == null) return context.dataFlowInfo; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java index fffff07eea3..f6931c4ff38 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java @@ -204,6 +204,12 @@ import java.util.Map; // return results == null ? null : results.getResultingDescriptor(); } + @NotNull + public List resolveForReceiverOnly(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name) { + return getCallResolver().resolveCallsByReceiver(trace, scope, call, name); + } + + @Nullable public FunctionDescriptor resolveCall(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetCallExpression callExpression) { OverloadResolutionResults results = getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, callOperationNode, callExpression), expectedType); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 6e2bb13efe6..90fa9e854d8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -29,8 +29,6 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.*; -import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; -import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.scopes.*; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; @@ -39,7 +37,6 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.util.QualifiedNamesUtil; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -167,15 +164,15 @@ public class ExpressionTypingUtils { } /** - * Check that function with the given qualified name can be resolved in given scope for given receiver + * Check that function or property with the given qualified name can be resolved in given scope for given receiver * - * @param functionFQN + * @param callableFQN * @param project * @param scope * @return */ - public static ArrayList canCallBeResolved( - @NotNull String functionFQN, + public static List canFindSuitableCall( + @NotNull String callableFQN, @NotNull Project project, @NotNull JetExpression receiverExpression, @NotNull JetType receiverType, @@ -184,7 +181,7 @@ public class ExpressionTypingUtils { WritableScopeWithImports writableScopeWithImports = new WritableScopeImpl( scope, scope.getContainingDeclaration(), RedeclarationHandler.DO_NOTHING); - JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, functionFQN); + JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, callableFQN); ExpressionReceiver expressionReceiver = new ExpressionReceiver(receiverExpression, receiverType); @@ -209,19 +206,23 @@ public class ExpressionTypingUtils { writableScopeWithImports.changeLockLevel(WritableScope.LockLevel.READING); - OverloadResolutionResults resolutionResult = - ControlStructureTypingVisitor.resolveFakeCall(expressionReceiver, context, QualifiedNamesUtil.fqnToShortName(functionFQN)); - - if (!resolutionResult.isSuccess()) { - return new ArrayList(); - } - - ArrayList resolvedDescriptors = new ArrayList(); - - for (ResolvedCall resolvedCall : resolutionResult.getResultingCalls()) { - resolvedDescriptors.add(resolvedCall.getCandidateDescriptor()); - } - - return resolvedDescriptors; + return ControlStructureTypingVisitor.resolveFakeCallWithReceiverOnly(expressionReceiver, context, QualifiedNamesUtil.fqnToShortName(callableFQN)); + + +// OverloadResolutionResults.Code resultCode = resolutionResult.getResultCode(); +// if (resultCode == OverloadResolutionResults.Code.SUCCESS || +// resultCode == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH || +// resultCode == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) { +// +// ArrayList resolvedDescriptors = new ArrayList(); +// +// for (ResolvedCall resolvedCall : resolutionResult.getResultingCalls()) { +// resolvedDescriptors.add(resolvedCall.getCandidateDescriptor()); +// } +// +// return resolvedDescriptors; +// } +// +// return new ArrayList(); } } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java index 9cdd956b85e..5e3826fd504 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java @@ -135,7 +135,7 @@ public class JetCompletionContributor extends CompletionContributor { for (String functionFQN : functionFQNs) { // System.out.println(functionFQN); - List functionDescriptors = ExpressionTypingUtils.canCallBeResolved( + List functionDescriptors = ExpressionTypingUtils.canFindSuitableCall( functionFQN, position.getProject(), receiverExpression, expressionType, scope); // System.out.println(!functionDescriptors.isEmpty()); diff --git a/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-1.kt b/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-1.kt index 9e3677e446a..4e1c556cdcf 100644 --- a/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-1.kt +++ b/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-1.kt @@ -7,4 +7,5 @@ fun firstFun() { // EXIST: helloFun // EXIST: helloFunPreventAutoInsert -// NUMBER: 2 \ No newline at end of file +// EXIST: helloWithParams +// NUMBER: 3 \ No newline at end of file diff --git a/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-2.kt b/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-2.kt index 7807436bb20..26ba80640b4 100644 --- a/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-2.kt +++ b/idea/testData/completion/basic/multifile/NotImportedExtensionFunction-2.kt @@ -3,5 +3,9 @@ package second fun String.helloFun() { } +fun String.helloWithParams(i : Int) : String { + return "" +} + fun String.helloFunPreventAutoInsert() { } \ No newline at end of file -- GitLab