001    /*
002     * Copyright 2010-2013 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.k2js.translate.reference;
018    
019    import com.google.dart.compiler.backend.js.ast.JsExpression;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
023    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
024    import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
025    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
026    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
027    import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
028    import org.jetbrains.k2js.translate.context.TranslationContext;
029    
030    import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getDeclarationDescriptorForExtensionCallReceiver;
031    
032    public final class CallParametersResolver {
033        public static CallParameters resolveCallParameters(@Nullable JsExpression qualifier,
034                @Nullable JsExpression callee,
035                @NotNull CallableDescriptor descriptor,
036                @NotNull ResolvedCall<? extends CallableDescriptor> call,
037                @NotNull TranslationContext context) {
038            return (new CallParametersResolver(qualifier, callee, descriptor, call, context)).resolve();
039        }
040    
041        // the actual qualifier for the call at the call site
042        @Nullable
043        private final JsExpression qualifier;
044        @Nullable
045        private final JsExpression callee;
046        @NotNull
047        private final CallableDescriptor descriptor;
048        @NotNull
049        private final TranslationContext context;
050        @NotNull
051        private final ResolvedCall<? extends CallableDescriptor> resolvedCall;
052        private final boolean isExtensionCall;
053    
054        private CallParametersResolver(@Nullable JsExpression qualifier,
055                @Nullable JsExpression callee,
056                @NotNull CallableDescriptor descriptor,
057                @NotNull ResolvedCall<? extends CallableDescriptor> call,
058                @NotNull TranslationContext context) {
059            this.qualifier = qualifier;
060            this.callee = callee;
061            this.descriptor = descriptor;
062            this.context = context;
063            this.resolvedCall = call;
064            this.isExtensionCall = resolvedCall.getReceiverArgument().exists();
065        }
066    
067        @NotNull
068        private CallParameters resolve() {
069            JsExpression receiver = isExtensionCall ? getExtensionFunctionCallReceiver() : null;
070            JsExpression functionReference = getFunctionReference();
071            JsExpression thisObject = getThisObject();
072            return new CallParameters(receiver, functionReference, thisObject);
073        }
074    
075        @NotNull
076        private JsExpression getFunctionReference() {
077            if (callee != null) {
078                return callee;
079            }
080            if (!(resolvedCall instanceof VariableAsFunctionResolvedCall)) {
081                return ReferenceTranslator.translateAsLocalNameReference(descriptor, context);
082            }
083            ResolvedCallWithTrace<FunctionDescriptor> call = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
084            return CallBuilder.build(context).resolvedCall(call).translate();
085        }
086    
087        @Nullable
088        private JsExpression getThisObject() {
089            if (qualifier != null && !isExtensionCall) {
090                return qualifier;
091            }
092            return context.thisAliasProvider().get(resolvedCall);
093        }
094    
095        @NotNull
096        private JsExpression getExtensionFunctionCallReceiver() {
097            if (qualifier != null) {
098                return qualifier;
099            }
100            DeclarationDescriptor receiverDescriptor = getDeclarationDescriptorForExtensionCallReceiver(resolvedCall);
101            return context.getThisObject(receiverDescriptor);
102        }
103    }