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