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