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.ReceiverValue;
048 import org.jetbrains.kotlin.types.KotlinType;
049 import org.jetbrains.kotlin.util.OperatorNameConventions;
050
051 import java.util.Collection;
052 import java.util.Collections;
053 import java.util.List;
054
055 /**
056 * CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
057 *
058 * For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
059 * CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
060 *
061 * context#1. calls: 'b.foo' 'invoke(1)'
062 * context#2. calls: 'foo' 'b.invoke(1)'
063 *
064 * If success VariableAsFunctionResolvedCall is created.
065 */
066 public class CallTransformer<D extends CallableDescriptor, F extends D> {
067 private CallTransformer() {}
068
069 /**
070 * Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
071 */
072 @NotNull
073 public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
074 @NotNull ResolutionTask<D, F> task,
075 @NotNull TemporaryBindingTrace candidateTrace,
076 @NotNull CandidateResolveMode candidateResolveMode
077 ) {
078 ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
079 return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing, task.call,
080 ReceiverValue.NO_RECEIVER, candidateResolveMode));
081 }
082
083 /**
084 * Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
085 * the resolved call from callCandidateResolutionContext otherwise
086 */
087 @NotNull
088 public Collection<MutableResolvedCall<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
089 @NotNull CallResolver callResolver,
090 @NotNull ResolutionTask<D, F> task
091 ) {
092 return Collections.singleton((MutableResolvedCall<F>) callCandidateResolutionContext.candidateCall);
093 }
094
095
096 public static CallTransformer<CallableDescriptor, CallableDescriptor> MEMBER_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, CallableDescriptor>();
097
098 public static CallTransformer<VariableDescriptor, VariableDescriptor> VARIABLE_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
099
100 public static Call stripCallArguments(@NotNull Call call) {
101 return new DelegatingCall(call) {
102 @Override
103 public KtValueArgumentList getValueArgumentList() {
104 return null;
105 }
106
107 @NotNull
108 @Override
109 public List<? extends ValueArgument> getValueArguments() {
110 return Collections.emptyList();
111 }
112
113 @NotNull
114 @Override
115 public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
116 return Collections.emptyList();
117 }
118
119 @NotNull
120 @Override
121 public List<KtTypeProjection> getTypeArguments() {
122 return Collections.emptyList();
123 }
124
125 @Override
126 public KtTypeArgumentList getTypeArgumentList() {
127 return null;
128 }
129
130 @NotNull
131 @Override
132 public KtElement getCallElement() {
133 KtExpression calleeExpression = getCalleeExpression();
134 assert calleeExpression != null : "No callee expression: " + getCallElement().getText();
135
136 return calleeExpression;
137 }
138 };
139 }
140
141 public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
142 @NotNull
143 @Override
144 public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
145 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace,
146 @NotNull CandidateResolveMode candidateResolveMode
147 ) {
148
149 if (candidate.getDescriptor() instanceof FunctionDescriptor) {
150 return super.createCallContexts(candidate, task, candidateTrace, candidateResolveMode);
151 }
152
153 assert candidate.getDescriptor() instanceof VariableDescriptor;
154
155 boolean hasReceiver = candidate.getExtensionReceiver().exists();
156 Call variableCall = stripCallArguments(task.call);
157 ResolutionCandidate<CallableDescriptor> variableCandidate = ResolutionCandidate.create(
158 variableCall,
159 candidate.getDescriptor(),
160 candidate.getDispatchReceiver(),
161 candidate.getExtensionReceiver(),
162 candidate.getExplicitReceiverKind(),
163 null);
164 if (!hasReceiver) {
165 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
166 ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
167 task, candidateTrace, task.tracing, variableCall, ReceiverValue.NO_RECEIVER, candidateResolveMode);
168 return Collections.singleton(context);
169 }
170 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
171 variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER, candidateResolveMode);
172
173 Call variableCallWithoutReceiver = stripReceiver(variableCall);
174 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
175 variableCallWithoutReceiver,
176 candidate.getDescriptor(),
177 candidate.getDispatchReceiver(),
178 ReceiverValue.NO_RECEIVER,
179 ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
180
181 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
182 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver(),
183 candidateResolveMode);
184
185 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
186 }
187
188 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
189 @NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
190 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull ReceiverValue receiverValue,
191 @NotNull CandidateResolveMode candidateResolveMode
192 ) {
193 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
194 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
195 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue,
196 candidateResolveMode);
197 }
198
199 private Call stripReceiver(@NotNull Call variableCall) {
200 return new DelegatingCall(variableCall) {
201 @Nullable
202 @Override
203 public ASTNode getCallOperationNode() {
204 return null;
205 }
206
207 @NotNull
208 @Override
209 public ReceiverValue getExplicitReceiver() {
210 return ReceiverValue.NO_RECEIVER;
211 }
212 };
213 }
214
215 @NotNull
216 @Override
217 public Collection<MutableResolvedCall<FunctionDescriptor>> transformCall(
218 @NotNull CallCandidateResolutionContext<CallableDescriptor> context,
219 @NotNull CallResolver callResolver,
220 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task
221 ) {
222 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
223 if (descriptor instanceof FunctionDescriptor) {
224 return super.transformCall(context, callResolver, task);
225 }
226
227 assert descriptor instanceof VariableDescriptor;
228 KotlinType returnType = descriptor.getReturnType();
229 if (returnType == null) {
230 return Collections.emptyList();
231 }
232
233 final MutableResolvedCall<VariableDescriptor> variableResolvedCall = (MutableResolvedCall)context.candidateCall;
234
235 KtExpression calleeExpression = task.call.getCalleeExpression();
236 if (calleeExpression == null) return Collections.emptyList();
237
238 ExpressionReceiver variableReceiver = new ExpressionReceiver(calleeExpression, variableResolvedCall.getResultingDescriptor().getType());
239 Call functionCall = new CallForImplicitInvoke(context.explicitExtensionReceiverForInvoke, variableReceiver, task.call);
240
241 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
242 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
243 context.replaceBindingTrace(variableCallTrace).replaceContextDependency(ContextDependency.DEPENDENT),
244 functionCall, context.checkArguments, context.dataFlowInfoForArguments);
245
246 // 'invoke' call resolve
247 TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(
248 calleeExpression, functionCall, variableReceiver.getType());
249 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallForInvoke(
250 basicCallResolutionContext, tracingForInvoke);
251 Collection<MutableResolvedCall<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
252
253 return Collections2.transform(calls, new Function<MutableResolvedCall<FunctionDescriptor>, MutableResolvedCall<FunctionDescriptor>>() {
254 @Override
255 public MutableResolvedCall<FunctionDescriptor> apply(MutableResolvedCall<FunctionDescriptor> functionResolvedCall) {
256 return new VariableAsFunctionResolvedCallImpl(functionResolvedCall, variableResolvedCall);
257 }
258 });
259 }
260 };
261
262 public static class CallForImplicitInvoke extends DelegatingCall {
263 private final Call outerCall;
264 private final ReceiverValue explicitExtensionReceiver;
265 private final ExpressionReceiver calleeExpressionAsDispatchReceiver;
266 private final KtSimpleNameExpression fakeInvokeExpression;
267
268 public CallForImplicitInvoke(
269 @NotNull ReceiverValue explicitExtensionReceiver,
270 @NotNull ExpressionReceiver calleeExpressionAsDispatchReceiver,
271 @NotNull Call call
272 ) {
273 super(call);
274 this.outerCall = call;
275 this.explicitExtensionReceiver = explicitExtensionReceiver;
276 this.calleeExpressionAsDispatchReceiver = calleeExpressionAsDispatchReceiver;
277 this.fakeInvokeExpression =
278 (KtSimpleNameExpression) KtPsiFactoryKt.KtPsiFactory(call.getCallElement())
279 .createExpression(OperatorNameConventions.INVOKE.asString());
280 }
281
282 @Nullable
283 @Override
284 public ASTNode getCallOperationNode() {
285 // if an explicit receiver corresponds to the implicit invoke, there is a corresponding call operation node:
286 // a.b() or a?.b() (where b has an extension function type);
287 // otherwise it's implicit
288 return explicitExtensionReceiver.exists() ? super.getCallOperationNode() : null;
289 }
290
291 @NotNull
292 @Override
293 public ReceiverValue getExplicitReceiver() {
294 return explicitExtensionReceiver;
295 }
296
297 @NotNull
298 @Override
299 public ExpressionReceiver getDispatchReceiver() {
300 return calleeExpressionAsDispatchReceiver;
301 }
302
303 @Override
304 public KtExpression getCalleeExpression() {
305 return fakeInvokeExpression;
306 }
307
308 @NotNull
309 @Override
310 public CallType getCallType() {
311 return CallType.INVOKE;
312 }
313
314 @NotNull
315 public Call getOuterCall() {
316 return outerCall;
317 }
318 }
319 }