001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.resolve.calls;
018
019 import com.google.common.base.Function;
020 import com.google.common.collect.Collections2;
021 import com.google.common.collect.Lists;
022 import com.intellij.lang.ASTNode;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.kotlin.descriptors.CallableDescriptor;
026 import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
027 import org.jetbrains.kotlin.descriptors.VariableDescriptor;
028 import org.jetbrains.kotlin.psi.*;
029 import org.jetbrains.kotlin.resolve.ChainedTemporaryBindingTrace;
030 import org.jetbrains.kotlin.resolve.DelegatingBindingTrace;
031 import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
032 import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
033 import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext;
034 import org.jetbrains.kotlin.resolve.calls.context.CandidateResolveMode;
035 import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
036 import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
037 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
038 import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl;
039 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
040 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
041 import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
042 import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
043 import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionTask;
044 import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyForInvoke;
045 import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall;
046 import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
047 import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver;
048 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
049 import org.jetbrains.kotlin.types.KotlinType;
050 import org.jetbrains.kotlin.util.OperatorNameConventions;
051
052 import java.util.Collection;
053 import java.util.Collections;
054 import java.util.List;
055
056 /**
057 * CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
058 *
059 * For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
060 * CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
061 *
062 * context#1. calls: 'b.foo' 'invoke(1)'
063 * context#2. calls: 'foo' 'b.invoke(1)'
064 *
065 * If success VariableAsFunctionResolvedCall is created.
066 */
067 public class CallTransformer<D extends CallableDescriptor, F extends D> {
068 private CallTransformer() {}
069
070 /**
071 * Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
072 */
073 @NotNull
074 public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
075 @NotNull ResolutionTask<D, F> task,
076 @NotNull TemporaryBindingTrace candidateTrace,
077 @NotNull CandidateResolveMode candidateResolveMode
078 ) {
079 ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
080 return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing, task.call,
081 ReceiverValue.NO_RECEIVER, candidateResolveMode));
082 }
083
084 /**
085 * Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
086 * the resolved call from callCandidateResolutionContext otherwise
087 */
088 @NotNull
089 public Collection<MutableResolvedCall<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
090 @NotNull CallResolver callResolver,
091 @NotNull ResolutionTask<D, F> task
092 ) {
093 return Collections.singleton((MutableResolvedCall<F>) callCandidateResolutionContext.candidateCall);
094 }
095
096
097 public static CallTransformer<CallableDescriptor, CallableDescriptor> MEMBER_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, CallableDescriptor>();
098
099 public static CallTransformer<VariableDescriptor, VariableDescriptor> VARIABLE_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
100
101 public static Call stripCallArguments(@NotNull Call call) {
102 return new DelegatingCall(call) {
103 @Override
104 public KtValueArgumentList getValueArgumentList() {
105 return null;
106 }
107
108 @NotNull
109 @Override
110 public List<? extends ValueArgument> getValueArguments() {
111 return Collections.emptyList();
112 }
113
114 @NotNull
115 @Override
116 public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
117 return Collections.emptyList();
118 }
119
120 @NotNull
121 @Override
122 public List<KtTypeProjection> getTypeArguments() {
123 return Collections.emptyList();
124 }
125
126 @Override
127 public KtTypeArgumentList getTypeArgumentList() {
128 return null;
129 }
130
131 @NotNull
132 @Override
133 public KtElement getCallElement() {
134 KtExpression calleeExpression = getCalleeExpression();
135 assert calleeExpression != null : "No callee expression: " + getCallElement().getText();
136
137 return calleeExpression;
138 }
139 };
140 }
141
142 public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
143 @NotNull
144 @Override
145 public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
146 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace,
147 @NotNull CandidateResolveMode candidateResolveMode
148 ) {
149
150 if (candidate.getDescriptor() instanceof FunctionDescriptor) {
151 return super.createCallContexts(candidate, task, candidateTrace, candidateResolveMode);
152 }
153
154 assert candidate.getDescriptor() instanceof VariableDescriptor;
155
156 boolean hasReceiver = candidate.getReceiverArgument().exists();
157 Call variableCall = stripCallArguments(task.call);
158 ResolutionCandidate<CallableDescriptor> variableCandidate = ResolutionCandidate.create(
159 variableCall,
160 candidate.getDescriptor(),
161 candidate.getDispatchReceiver(),
162 candidate.getReceiverArgument(),
163 candidate.getExplicitReceiverKind(),
164 null);
165 if (!hasReceiver) {
166 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
167 ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
168 task, candidateTrace, task.tracing, variableCall, ReceiverValue.NO_RECEIVER, candidateResolveMode);
169 return Collections.singleton(context);
170 }
171 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
172 variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER, candidateResolveMode);
173
174 Call variableCallWithoutReceiver = stripReceiver(variableCall);
175 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
176 variableCallWithoutReceiver,
177 candidate.getDescriptor(),
178 candidate.getDispatchReceiver(),
179 ReceiverValue.NO_RECEIVER,
180 ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
181
182 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
183 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver(),
184 candidateResolveMode);
185
186 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
187 }
188
189 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
190 @NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
191 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull Receiver receiverValue,
192 @NotNull CandidateResolveMode candidateResolveMode
193 ) {
194 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
195 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
196 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue,
197 candidateResolveMode);
198 }
199
200 private Call stripReceiver(@NotNull Call variableCall) {
201 return new DelegatingCall(variableCall) {
202 @Nullable
203 @Override
204 public ASTNode getCallOperationNode() {
205 return null;
206 }
207
208 @NotNull
209 @Override
210 public ReceiverValue getExplicitReceiver() {
211 return ReceiverValue.NO_RECEIVER;
212 }
213 };
214 }
215
216 @NotNull
217 @Override
218 public Collection<MutableResolvedCall<FunctionDescriptor>> transformCall(
219 @NotNull CallCandidateResolutionContext<CallableDescriptor> context,
220 @NotNull CallResolver callResolver,
221 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task
222 ) {
223 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
224 if (descriptor instanceof FunctionDescriptor) {
225 return super.transformCall(context, callResolver, task);
226 }
227
228 assert descriptor instanceof VariableDescriptor;
229 KotlinType returnType = descriptor.getReturnType();
230 if (returnType == null) {
231 return Collections.emptyList();
232 }
233
234 final MutableResolvedCall<VariableDescriptor> variableResolvedCall = (MutableResolvedCall)context.candidateCall;
235
236 KtExpression calleeExpression = task.call.getCalleeExpression();
237 if (calleeExpression == null) return Collections.emptyList();
238
239 ExpressionReceiver variableReceiver = ExpressionReceiver.Companion.create(
240 calleeExpression, variableResolvedCall.getResultingDescriptor().getType(), context.trace.getBindingContext());
241 Call functionCall = new CallForImplicitInvoke(context.explicitExtensionReceiverForInvoke, variableReceiver, task.call);
242
243 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
244 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
245 context.replaceBindingTrace(variableCallTrace).replaceContextDependency(ContextDependency.DEPENDENT),
246 functionCall, context.checkArguments, context.dataFlowInfoForArguments);
247
248 // 'invoke' call resolve
249 TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(
250 calleeExpression, functionCall, variableReceiver.getType());
251 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallForInvoke(
252 basicCallResolutionContext, tracingForInvoke);
253 Collection<MutableResolvedCall<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
254
255 return Collections2.transform(calls, new Function<MutableResolvedCall<FunctionDescriptor>, MutableResolvedCall<FunctionDescriptor>>() {
256 @Override
257 public MutableResolvedCall<FunctionDescriptor> apply(MutableResolvedCall<FunctionDescriptor> functionResolvedCall) {
258 return new VariableAsFunctionResolvedCallImpl(functionResolvedCall, variableResolvedCall);
259 }
260 });
261 }
262 };
263
264 public static class CallForImplicitInvoke extends DelegatingCall {
265 private final Call outerCall;
266 private final Receiver explicitExtensionReceiver;
267 private final ExpressionReceiver calleeExpressionAsDispatchReceiver;
268 private final KtSimpleNameExpression fakeInvokeExpression;
269
270 public CallForImplicitInvoke(
271 @NotNull Receiver explicitExtensionReceiver,
272 @NotNull ExpressionReceiver calleeExpressionAsDispatchReceiver,
273 @NotNull Call call
274 ) {
275 super(call);
276 this.outerCall = call;
277 this.explicitExtensionReceiver = explicitExtensionReceiver;
278 this.calleeExpressionAsDispatchReceiver = calleeExpressionAsDispatchReceiver;
279 this.fakeInvokeExpression =
280 (KtSimpleNameExpression) KtPsiFactoryKt.KtPsiFactory(call.getCallElement())
281 .createExpression(OperatorNameConventions.INVOKE.asString());
282 }
283
284 @Nullable
285 @Override
286 public ASTNode getCallOperationNode() {
287 // if an explicit receiver corresponds to the implicit invoke, there is a corresponding call operation node:
288 // a.b() or a?.b() (where b has an extension function type);
289 // otherwise it's implicit
290 return explicitExtensionReceiver.exists() ? super.getCallOperationNode() : null;
291 }
292
293 @NotNull
294 @Override
295 public Receiver getExplicitReceiver() {
296 return explicitExtensionReceiver;
297 }
298
299 @NotNull
300 @Override
301 public ExpressionReceiver getDispatchReceiver() {
302 return calleeExpressionAsDispatchReceiver;
303 }
304
305 @Override
306 public KtExpression getCalleeExpression() {
307 return fakeInvokeExpression;
308 }
309
310 @NotNull
311 @Override
312 public CallType getCallType() {
313 return CallType.INVOKE;
314 }
315
316 @NotNull
317 public Call getOuterCall() {
318 return outerCall;
319 }
320 }
321 }