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