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