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