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