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 CallableDescriptor descriptor) { 060 return descriptor.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 @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 ThisReceiver) { 114 DeclarationDescriptor declarationDescriptor = ((ThisReceiver) receiverParameter).getDeclarationDescriptor(); 115 return declarationDescriptor.getOriginal(); 116 } 117 118 throw new UnsupportedOperationException("Unsupported receiver type: " + receiverParameter.getClass() + 119 ", receiverParameter = " + receiverParameter); 120 } 121 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).getReceiverParameter(); 128 assert receiverDescriptor != null; 129 return receiverDescriptor; 130 } 131 132 throw new UnsupportedOperationException("Unsupported declaration type: " + declarationDescriptor.getClass() + 133 ", declarationDescriptor = " + declarationDescriptor); 134 } 135 136 //TODO: maybe we have similar routine 137 @Nullable 138 public static ClassDescriptor getContainingClass(@NotNull DeclarationDescriptor descriptor) { 139 DeclarationDescriptor containing = descriptor.getContainingDeclaration(); 140 while (containing != null) { 141 if (containing instanceof ClassDescriptor && !isClassObject(containing)) { 142 return (ClassDescriptor) containing; 143 } 144 containing = containing.getContainingDeclaration(); 145 } 146 return null; 147 } 148 149 @Nullable 150 public static FunctionDescriptor getOverriddenDescriptor(@NotNull FunctionDescriptor functionDescriptor) { 151 Set<? extends FunctionDescriptor> overriddenDescriptors = functionDescriptor.getOverriddenDescriptors(); 152 if (overriddenDescriptors.isEmpty()) { 153 return null; 154 } 155 else { 156 //TODO: for now translator can't deal with multiple inheritance good enough 157 return overriddenDescriptors.iterator().next(); 158 } 159 } 160 161 private static boolean isDefaultAccessor(@Nullable PropertyAccessorDescriptor accessorDescriptor) { 162 return accessorDescriptor == null || accessorDescriptor.isDefault(); 163 } 164 165 public static boolean isSimpleFinalProperty(@NotNull PropertyDescriptor propertyDescriptor) { 166 return !isExtension(propertyDescriptor) && 167 isDefaultAccessor(propertyDescriptor.getGetter()) && 168 isDefaultAccessor(propertyDescriptor.getSetter()) && 169 !propertyDescriptor.getModality().isOverridable(); 170 } 171 172 public static boolean isBuiltin(@NotNull DeclarationDescriptor descriptor) { 173 PackageFragmentDescriptor containingPackageFragment = DescriptorUtils.getParentOfType(descriptor, PackageFragmentDescriptor.class); 174 return containingPackageFragment == KotlinBuiltIns.getInstance().getBuiltInsPackageFragment(); 175 } 176 177 @Nullable 178 public static Name getNameIfStandardType(@NotNull JetExpression expression, @NotNull TranslationContext context) { 179 JetType type = context.bindingContext().get(BindingContext.EXPRESSION_TYPE, expression); 180 return type != null ? getNameIfStandardType(type) : null; 181 } 182 183 @Nullable 184 public static Name getNameIfStandardType(@NotNull JetType type) { 185 ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); 186 if (descriptor != null && descriptor.getContainingDeclaration() == KotlinBuiltIns.getInstance().getBuiltInsPackageFragment()) { 187 return descriptor.getName(); 188 } 189 190 return null; 191 } 192 }