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