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 }