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 CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
101            @NotNull
102            @Override
103            public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
104                    @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace,
105                    @NotNull CandidateResolveMode candidateResolveMode
106            ) {
107    
108                if (candidate.getDescriptor() instanceof FunctionDescriptor) {
109                    return super.createCallContexts(candidate, task, candidateTrace, candidateResolveMode);
110                }
111    
112                assert candidate.getDescriptor() instanceof VariableDescriptor;
113    
114                boolean hasReceiver = candidate.getExtensionReceiver().exists();
115                Call variableCall = stripCallArguments(task.call);
116                ResolutionCandidate<CallableDescriptor> variableCandidate = ResolutionCandidate.create(
117                        variableCall,
118                        candidate.getDescriptor(),
119                        candidate.getDispatchReceiver(),
120                        candidate.getExtensionReceiver(),
121                        candidate.getExplicitReceiverKind(),
122                        null);
123                if (!hasReceiver) {
124                    CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
125                            ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
126                            task, candidateTrace, task.tracing, variableCall, ReceiverValue.NO_RECEIVER, candidateResolveMode);
127                    return Collections.singleton(context);
128                }
129                CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
130                        variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER, candidateResolveMode);
131    
132                Call variableCallWithoutReceiver = stripReceiver(variableCall);
133                ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
134                        variableCallWithoutReceiver,
135                        candidate.getDescriptor(),
136                        candidate.getDispatchReceiver(),
137                        ReceiverValue.NO_RECEIVER,
138                        ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
139    
140                CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
141                        candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver(),
142                        candidateResolveMode);
143    
144                return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
145            }
146    
147            private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
148                    @NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
149                    @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull ReceiverValue receiverValue,
150                    @NotNull CandidateResolveMode candidateResolveMode
151            ) {
152                ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
153                ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
154                return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue,
155                                                             candidateResolveMode);
156            }
157    
158            private Call stripCallArguments(@NotNull Call call) {
159                return new DelegatingCall(call) {
160                    @Override
161                    public KtValueArgumentList getValueArgumentList() {
162                        return null;
163                    }
164    
165                    @NotNull
166                    @Override
167                    public List<? extends ValueArgument> getValueArguments() {
168                        return Collections.emptyList();
169                    }
170    
171                    @NotNull
172                    @Override
173                    public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
174                        return Collections.emptyList();
175                    }
176    
177                    @NotNull
178                    @Override
179                    public List<KtTypeProjection> getTypeArguments() {
180                        return Collections.emptyList();
181                    }
182    
183                    @Override
184                    public KtTypeArgumentList getTypeArgumentList() {
185                        return null;
186                    }
187    
188                    @NotNull
189                    @Override
190                    public KtElement getCallElement() {
191                        KtExpression calleeExpression = getCalleeExpression();
192                        assert calleeExpression != null : "No callee expression: " + getCallElement().getText();
193    
194                        return calleeExpression;
195                    }
196                };
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    }