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 }