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                                                                               null, 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<LambdaArgument> 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 Call stripReceiver(@NotNull Call variableCall) {
143            return new DelegatingCall(variableCall) {
144                @Nullable
145                @Override
146                public ASTNode getCallOperationNode() {
147                    return null;
148                }
149    
150                @Nullable
151                @Override
152                public ReceiverValue getExplicitReceiver() {
153                    return null;
154                }
155            };
156        }
157    
158        public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
159            @NotNull
160            @Override
161            public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
162                    @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace,
163                    @NotNull CandidateResolveMode candidateResolveMode
164            ) {
165    
166                if (candidate.getDescriptor() instanceof FunctionDescriptor) {
167                    return super.createCallContexts(candidate, task, candidateTrace, candidateResolveMode);
168                }
169    
170                assert candidate.getDescriptor() instanceof VariableDescriptor;
171    
172                boolean hasReceiver = candidate.getReceiverArgument() != null;
173                Call variableCall = stripCallArguments(task.call);
174                ResolutionCandidate<CallableDescriptor> variableCandidate = ResolutionCandidate.create(
175                        variableCall,
176                        candidate.getDescriptor(),
177                        candidate.getDispatchReceiver(),
178                        candidate.getReceiverArgument(),
179                        candidate.getExplicitReceiverKind(),
180                        null);
181                if (!hasReceiver) {
182                    CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
183                            ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
184                            task, candidateTrace, task.tracing, variableCall, null, candidateResolveMode);
185                    return Collections.singleton(context);
186                }
187                CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
188                        variableCandidate, variableCall, candidateTrace, task, null, candidateResolveMode);
189    
190                Call variableCallWithoutReceiver = stripReceiver(variableCall);
191                ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
192                        variableCallWithoutReceiver,
193                        candidate.getDescriptor(),
194                        candidate.getDispatchReceiver(),
195                        null,
196                        ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
197    
198                CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
199                        candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver(),
200                        candidateResolveMode);
201    
202                return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
203            }
204    
205            private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
206                    @NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
207                    @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @Nullable Receiver receiverValue,
208                    @NotNull CandidateResolveMode candidateResolveMode
209            ) {
210                ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
211                ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
212                return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue,
213                                                             candidateResolveMode);
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                    @Nullable 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 != null ? super.getCallOperationNode() : null;
291            }
292    
293            @Nullable
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    }