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