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 }