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
017package org.jetbrains.k2js.translate.utils;
018
019import org.jetbrains.annotations.NotNull;
020import org.jetbrains.annotations.Nullable;
021import org.jetbrains.jet.lang.descriptors.*;
022import org.jetbrains.jet.lang.psi.JetExpression;
023import org.jetbrains.jet.lang.resolve.BindingContext;
024import org.jetbrains.jet.lang.resolve.DescriptorUtils;
025import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
026import org.jetbrains.jet.lang.resolve.name.Name;
027import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
028import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
029import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
030import org.jetbrains.jet.lang.types.JetType;
031import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
032import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033import org.jetbrains.k2js.translate.context.TranslationContext;
034
035import java.util.List;
036import java.util.Set;
037
038import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getSuperclassDescriptors;
039import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
040
041public final class JsDescriptorUtils {
042
043    private JsDescriptorUtils() {
044    }
045
046    private static int valueParametersCount(@NotNull FunctionDescriptor functionDescriptor) {
047        return functionDescriptor.getValueParameters().size();
048    }
049
050    public static boolean hasParameters(@NotNull FunctionDescriptor functionDescriptor) {
051        return (valueParametersCount(functionDescriptor) > 0);
052    }
053
054    public static boolean isCompareTo(@NotNull FunctionDescriptor functionDescriptor) {
055        return (functionDescriptor.getName().equals(OperatorConventions.COMPARE_TO));
056    }
057
058    public static boolean isConstructorDescriptor(@NotNull CallableDescriptor descriptor) {
059        return (descriptor instanceof ConstructorDescriptor);
060    }
061
062    @Nullable
063    public static ClassDescriptor findAncestorClass(@NotNull List<ClassDescriptor> superclassDescriptors) {
064        for (ClassDescriptor descriptor : superclassDescriptors) {
065            if (descriptor.getKind() == ClassKind.CLASS) {
066                return descriptor;
067            }
068        }
069        return null;
070    }
071
072    @Nullable
073    public static ClassDescriptor getSuperclass(@NotNull ClassDescriptor classDescriptor) {
074        return findAncestorClass(getSuperclassDescriptors(classDescriptor));
075    }
076
077    @NotNull
078    public static DeclarationDescriptor getContainingDeclaration(@NotNull DeclarationDescriptor descriptor) {
079        DeclarationDescriptor containing = descriptor.getContainingDeclaration();
080        assert containing != null : "Should be called on objects that have containing declaration.";
081        return containing;
082    }
083
084    public static boolean isExtension(@NotNull CallableDescriptor functionDescriptor) {
085        return (functionDescriptor.getReceiverParameter() != null);
086    }
087
088    //TODO: why callable descriptor
089    @Nullable
090    public static DeclarationDescriptor getExpectedThisDescriptor(@NotNull CallableDescriptor callableDescriptor) {
091        ReceiverParameterDescriptor expectedThisObject = callableDescriptor.getExpectedThisObject();
092        if (expectedThisObject == null) {
093            return null;
094        }
095        return getDeclarationDescriptorForReceiver(expectedThisObject.getValue());
096    }
097
098    @NotNull
099    public static DeclarationDescriptor getDeclarationDescriptorForReceiver
100            (@NotNull ReceiverValue receiverParameter) {
101        DeclarationDescriptor declarationDescriptor =
102                receiverParameter.getType().getConstructor().getDeclarationDescriptor();
103        //TODO: WHY assert?
104        assert declarationDescriptor != null;
105        return declarationDescriptor.getOriginal();
106    }
107
108    @Nullable
109    public static DeclarationDescriptor getExpectedReceiverDescriptor(@NotNull CallableDescriptor callableDescriptor) {
110        ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
111        if (receiverParameter == null) {
112            return null;
113        }
114        return getDeclarationDescriptorForReceiver(receiverParameter.getValue());
115    }
116
117    //TODO: maybe we have similar routine
118    @Nullable
119    public static ClassDescriptor getContainingClass(@NotNull DeclarationDescriptor descriptor) {
120        DeclarationDescriptor containing = descriptor.getContainingDeclaration();
121        while (containing != null) {
122            if (containing instanceof ClassDescriptor && !isClassObject(containing)) {
123                return (ClassDescriptor) containing;
124            }
125            containing = containing.getContainingDeclaration();
126        }
127        return null;
128    }
129
130    @Nullable
131    public static FunctionDescriptor getOverriddenDescriptor(@NotNull FunctionDescriptor functionDescriptor) {
132        Set<? extends FunctionDescriptor> overriddenDescriptors = functionDescriptor.getOverriddenDescriptors();
133        if (overriddenDescriptors.isEmpty()) {
134            return null;
135        }
136        else {
137            //TODO: for now translator can't deal with multiple inheritance good enough
138            return overriddenDescriptors.iterator().next();
139        }
140    }
141
142    private static boolean isDefaultAccessor(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
143        return accessorDescriptor == null || accessorDescriptor.isDefault();
144    }
145
146    public static boolean isAsPrivate(@NotNull PropertyDescriptor propertyDescriptor) {
147        return isExtension(propertyDescriptor) ||
148               !isDefaultAccessor(propertyDescriptor.getGetter()) ||
149               !isDefaultAccessor(propertyDescriptor.getSetter());
150    }
151
152    public static boolean isStandardDeclaration(@NotNull DeclarationDescriptor descriptor) {
153        NamespaceDescriptor namespace = getContainingNamespace(descriptor);
154        if (namespace == null) {
155            return false;
156        }
157        return namespace.equals(KotlinBuiltIns.getInstance().getBuiltInsScope().getContainingDeclaration());
158    }
159
160    @Nullable
161    public static NamespaceDescriptor getContainingNamespace(@NotNull DeclarationDescriptor descriptor) {
162        return DescriptorUtils.getParentOfType(descriptor, NamespaceDescriptor.class);
163    }
164
165    @Nullable
166    public static Name getNameIfStandardType(@NotNull JetExpression expression, @NotNull TranslationContext context) {
167        JetType type = context.bindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
168        return type != null ? getNameIfStandardType(type) : null;
169    }
170
171    @Nullable
172    public static Name getNameIfStandardType(@NotNull JetType type) {
173        ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
174        if (descriptor != null && descriptor.getContainingDeclaration() == KotlinBuiltIns.getInstance().getBuiltInsPackage()) {
175            return descriptor.getName();
176        }
177
178        return null;
179    }
180
181    @NotNull
182    public static DeclarationDescriptor getDeclarationDescriptorForExtensionCallReceiver(
183            @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall
184    ) {
185        ReceiverValue receiverArgument = resolvedCall.getReceiverArgument();
186        if (receiverArgument instanceof ExtensionReceiver) {
187            return ((ExtensionReceiver) receiverArgument).getDeclarationDescriptor();
188        }
189        if (receiverArgument instanceof ClassReceiver) {
190            return ((ClassReceiver) receiverArgument).getDeclarationDescriptor();
191        }
192        throw new IllegalStateException("Unexpected receiver of type " + receiverArgument.getClass());
193    }
194}