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.calls.tasks.DynamicCallsKt;
034 import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
035 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
036 import org.jetbrains.kotlin.types.KotlinType;
037 import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
038 import org.jetbrains.kotlin.util.OperatorNameConventions;
039
040 import java.util.Collection;
041 import java.util.List;
042 import java.util.Set;
043
044 import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject;
045 import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
046 import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
047
048 public final class JsDescriptorUtils {
049 // TODO: maybe we should use external annotations or something else.
050 private static final Set<String> FAKE_CLASSES = ContainerUtil.immutableSet(
051 KotlinBuiltIns.FQ_NAMES.any.asString()
052 );
053
054 private JsDescriptorUtils() {
055 }
056
057 private static int valueParametersCount(@NotNull FunctionDescriptor functionDescriptor) {
058 return functionDescriptor.getValueParameters().size();
059 }
060
061 public static boolean hasParameters(@NotNull FunctionDescriptor functionDescriptor) {
062 return (valueParametersCount(functionDescriptor) > 0);
063 }
064
065 public static boolean isCompareTo(@NotNull CallableDescriptor descriptor) {
066 return descriptor.getName().equals(OperatorNameConventions.COMPARE_TO);
067 }
068
069 @Nullable
070 public static ClassDescriptor findAncestorClass(@NotNull List<ClassDescriptor> superclassDescriptors) {
071 for (ClassDescriptor descriptor : superclassDescriptors) {
072 if (descriptor.getKind() == ClassKind.CLASS || descriptor.getKind() == ClassKind.ENUM_CLASS) {
073 return descriptor;
074 }
075 }
076 return null;
077 }
078
079 @Nullable
080 public static ClassDescriptor getSuperclass(@NotNull ClassDescriptor classDescriptor) {
081 return findAncestorClass(getSuperclassDescriptors(classDescriptor));
082 }
083
084 @NotNull
085 public static List<KotlinType> getSupertypesWithoutFakes(ClassDescriptor descriptor) {
086 Collection<KotlinType> supertypes = descriptor.getTypeConstructor().getSupertypes();
087 return ContainerUtil.filter(supertypes, new Condition<KotlinType>() {
088 @Override
089 public boolean value(KotlinType type) {
090 ClassDescriptor classDescriptor = getClassDescriptorForType(type);
091
092 return !FAKE_CLASSES.contains(getFqNameSafe(classDescriptor).asString()) &&
093 !(classDescriptor.getKind() == ClassKind.INTERFACE && isNativeObject(classDescriptor));
094 }
095 });
096 }
097
098 @NotNull
099 public static DeclarationDescriptor getContainingDeclaration(@NotNull DeclarationDescriptor descriptor) {
100 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
101 assert containing != null : "Should be called on objects that have containing declaration.";
102 return containing;
103 }
104
105 @NotNull
106 public static ReceiverParameterDescriptor getReceiverParameterForReceiver(@NotNull ReceiverValue receiverParameter) {
107 DeclarationDescriptor declarationDescriptor = getDeclarationDescriptorForReceiver(receiverParameter);
108 return getReceiverParameterForDeclaration(declarationDescriptor);
109 }
110
111 @NotNull
112 private static DeclarationDescriptor getDeclarationDescriptorForReceiver(@NotNull ReceiverValue receiverParameter) {
113 if (receiverParameter instanceof ImplicitReceiver) {
114 DeclarationDescriptor declarationDescriptor = ((ImplicitReceiver) receiverParameter).getDeclarationDescriptor();
115 return declarationDescriptor.getOriginal();
116 }
117
118 throw new UnsupportedOperationException("Unsupported receiver type: " + receiverParameter.getClass() +
119 ", receiverParameter = " + receiverParameter);
120 }
121
122 @NotNull
123 public static ReceiverParameterDescriptor getReceiverParameterForDeclaration(DeclarationDescriptor declarationDescriptor) {
124 if (declarationDescriptor instanceof ClassDescriptor) {
125 return ((ClassDescriptor) declarationDescriptor).getThisAsReceiverParameter();
126 }
127 else if (declarationDescriptor instanceof CallableMemberDescriptor) {
128 ReceiverParameterDescriptor receiverDescriptor = ((CallableMemberDescriptor) declarationDescriptor).getExtensionReceiverParameter();
129 assert receiverDescriptor != null;
130 return receiverDescriptor;
131 }
132
133 throw new UnsupportedOperationException("Unsupported declaration type: " + declarationDescriptor.getClass() +
134 ", declarationDescriptor = " + declarationDescriptor);
135 }
136
137 private static boolean isDefaultAccessor(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
138 return accessorDescriptor == null || accessorDescriptor.isDefault();
139 }
140
141 public static boolean sideEffectsPossibleOnRead(@NotNull PropertyDescriptor property) {
142 return DynamicCallsKt.isDynamic(property) || !isDefaultAccessor(property.getGetter()) ||
143 ModalityKt.isOverridableOrOverrides(property) || isStaticInitializationPossible(property);
144 }
145
146 private static boolean isStaticInitializationPossible(PropertyDescriptor property) {
147 DeclarationDescriptor container = property.getContainingDeclaration();
148 return container instanceof PackageFragmentDescriptor || DescriptorUtils.isObject(container);
149 }
150
151 public static boolean isSimpleFinalProperty(@NotNull PropertyDescriptor propertyDescriptor) {
152 return !isExtension(propertyDescriptor) &&
153 isDefaultAccessor(propertyDescriptor.getGetter()) &&
154 isDefaultAccessor(propertyDescriptor.getSetter()) &&
155 !TranslationUtils.shouldAccessViaFunctions(propertyDescriptor) &&
156 !ModalityKt.isOverridableOrOverrides(propertyDescriptor);
157 }
158
159 @Nullable
160 public static Name getNameIfStandardType(@NotNull KtExpression expression, @NotNull TranslationContext context) {
161 KotlinType type = context.bindingContext().getType(expression);
162 return type != null ? DescriptorUtilsKt.getNameIfStandardType(type) : null;
163 }
164
165 @NotNull
166 public static String getModuleName(@NotNull DeclarationDescriptor descriptor) {
167 String externalModuleName = getExternalModuleName(descriptor);
168 if (externalModuleName != null) return externalModuleName;
169
170 return getModuleNameFromDescriptorName(descriptor);
171 }
172
173 @Nullable
174 public static String getExternalModuleName(@NotNull DeclarationDescriptor descriptor) {
175 if (KotlinBuiltIns.isBuiltIn(descriptor)) return Namer.KOTLIN_LOWER_NAME;
176
177 PsiElement element = descriptorToDeclaration(descriptor);
178 if (element == null && descriptor instanceof PropertyAccessorDescriptor) {
179 element = descriptorToDeclaration(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
180 }
181
182 if (element == null) return getModuleNameFromDescriptorName(descriptor);
183
184 return element.getContainingFile().getUserData(LibrarySourcesConfig.EXTERNAL_MODULE_NAME);
185 }
186
187 @NotNull
188 public static DeclarationDescriptor findRealInlineDeclaration(@NotNull DeclarationDescriptor descriptor) {
189 if (descriptor instanceof FunctionDescriptor) {
190 FunctionDescriptor d = (FunctionDescriptor) descriptor;
191 if (d.getKind().isReal() || !d.isInline()) return descriptor;
192 CallableMemberDescriptor real = findRealDeclaration(d);
193 assert real != null : "Couldn't find definition of a fake inline descriptor " + descriptor;
194 return real;
195 }
196 return descriptor;
197 }
198
199 @Nullable
200 private static FunctionDescriptor findRealDeclaration(FunctionDescriptor descriptor) {
201 if (descriptor.getModality() == Modality.ABSTRACT) return null;
202 if (descriptor.getKind().isReal()) return descriptor;
203
204 for (FunctionDescriptor o : descriptor.getOverriddenDescriptors()) {
205 FunctionDescriptor child = findRealDeclaration(o);
206 if (child != null) {
207 return child;
208 }
209 }
210 return null;
211 }
212
213 private static String getModuleNameFromDescriptorName(@NotNull DeclarationDescriptor descriptor) {
214 ModuleDescriptor moduleDescriptor = DescriptorUtils.getContainingModule(findRealInlineDeclaration(descriptor));
215 String moduleName = moduleDescriptor.getName().asString();
216 return moduleName.substring(1, moduleName.length() - 1);
217 }
218
219
220 public static boolean isImmediateSubtypeOfError(@NotNull ClassDescriptor descriptor) {
221 if (!isExceptionClass(descriptor)) return false;
222 ClassDescriptor superClass = org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getSuperClassOrAny(descriptor);
223 return TypeUtilsKt.isThrowable(superClass.getDefaultType()) || AnnotationsUtils.isNativeObject(superClass);
224 }
225
226 public static boolean isExceptionClass(@NotNull ClassDescriptor descriptor) {
227 ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
228 return TypeUtilsKt.isSubtypeOf(descriptor.getDefaultType(), module.getBuiltIns().getThrowable().getDefaultType());
229 }
230 }