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 org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.lang.descriptors.*;
022    import org.jetbrains.jet.lang.psi.JetExpression;
023    import org.jetbrains.jet.lang.resolve.BindingContext;
024    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
025    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
026    import org.jetbrains.jet.lang.resolve.name.Name;
027    import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
028    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
029    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
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.List;
036    import java.util.Set;
037    
038    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getSuperclassDescriptors;
039    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
040    
041    public final class JsDescriptorUtils {
042    
043        private JsDescriptorUtils() {
044        }
045    
046        private static int valueParametersCount(@NotNull FunctionDescriptor functionDescriptor) {
047            return functionDescriptor.getValueParameters().size();
048        }
049    
050        public static boolean hasParameters(@NotNull FunctionDescriptor functionDescriptor) {
051            return (valueParametersCount(functionDescriptor) > 0);
052        }
053    
054        public static boolean isCompareTo(@NotNull FunctionDescriptor functionDescriptor) {
055            return (functionDescriptor.getName().equals(OperatorConventions.COMPARE_TO));
056        }
057    
058        public static boolean isConstructorDescriptor(@NotNull CallableDescriptor descriptor) {
059            return (descriptor instanceof ConstructorDescriptor);
060        }
061    
062        @Nullable
063        public static ClassDescriptor findAncestorClass(@NotNull List<ClassDescriptor> superclassDescriptors) {
064            for (ClassDescriptor descriptor : superclassDescriptors) {
065                if (descriptor.getKind() == ClassKind.CLASS) {
066                    return descriptor;
067                }
068            }
069            return null;
070        }
071    
072        @Nullable
073        public static ClassDescriptor getSuperclass(@NotNull ClassDescriptor classDescriptor) {
074            return findAncestorClass(getSuperclassDescriptors(classDescriptor));
075        }
076    
077        @NotNull
078        public static DeclarationDescriptor getContainingDeclaration(@NotNull DeclarationDescriptor descriptor) {
079            DeclarationDescriptor containing = descriptor.getContainingDeclaration();
080            assert containing != null : "Should be called on objects that have containing declaration.";
081            return containing;
082        }
083    
084        public static boolean isExtension(@NotNull CallableDescriptor functionDescriptor) {
085            return (functionDescriptor.getReceiverParameter() != null);
086        }
087    
088        //TODO: why callable descriptor
089        @Nullable
090        public static DeclarationDescriptor getExpectedThisDescriptor(@NotNull CallableDescriptor callableDescriptor) {
091            ReceiverParameterDescriptor expectedThisObject = callableDescriptor.getExpectedThisObject();
092            if (expectedThisObject == null) {
093                return null;
094            }
095            return getDeclarationDescriptorForReceiver(expectedThisObject.getValue());
096        }
097    
098        @NotNull
099        public static DeclarationDescriptor getDeclarationDescriptorForReceiver
100                (@NotNull ReceiverValue receiverParameter) {
101            DeclarationDescriptor declarationDescriptor =
102                    receiverParameter.getType().getConstructor().getDeclarationDescriptor();
103            //TODO: WHY assert?
104            assert declarationDescriptor != null;
105            return declarationDescriptor.getOriginal();
106        }
107    
108        @Nullable
109        public static DeclarationDescriptor getExpectedReceiverDescriptor(@NotNull CallableDescriptor callableDescriptor) {
110            ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
111            if (receiverParameter == null) {
112                return null;
113            }
114            return getDeclarationDescriptorForReceiver(receiverParameter.getValue());
115        }
116    
117        //TODO: maybe we have similar routine
118        @Nullable
119        public static ClassDescriptor getContainingClass(@NotNull DeclarationDescriptor descriptor) {
120            DeclarationDescriptor containing = descriptor.getContainingDeclaration();
121            while (containing != null) {
122                if (containing instanceof ClassDescriptor && !isClassObject(containing)) {
123                    return (ClassDescriptor) containing;
124                }
125                containing = containing.getContainingDeclaration();
126            }
127            return null;
128        }
129    
130        @Nullable
131        public static FunctionDescriptor getOverriddenDescriptor(@NotNull FunctionDescriptor functionDescriptor) {
132            Set<? extends FunctionDescriptor> overriddenDescriptors = functionDescriptor.getOverriddenDescriptors();
133            if (overriddenDescriptors.isEmpty()) {
134                return null;
135            }
136            else {
137                //TODO: for now translator can't deal with multiple inheritance good enough
138                return overriddenDescriptors.iterator().next();
139            }
140        }
141    
142        private static boolean isDefaultAccessor(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
143            return accessorDescriptor == null || accessorDescriptor.isDefault();
144        }
145    
146        public static boolean isAsPrivate(@NotNull PropertyDescriptor propertyDescriptor) {
147            return isExtension(propertyDescriptor) ||
148                   !isDefaultAccessor(propertyDescriptor.getGetter()) ||
149                   !isDefaultAccessor(propertyDescriptor.getSetter());
150        }
151    
152        public static boolean isStandardDeclaration(@NotNull DeclarationDescriptor descriptor) {
153            NamespaceDescriptor namespace = getContainingNamespace(descriptor);
154            if (namespace == null) {
155                return false;
156            }
157            return namespace.equals(KotlinBuiltIns.getInstance().getBuiltInsScope().getContainingDeclaration());
158        }
159    
160        @Nullable
161        public static NamespaceDescriptor getContainingNamespace(@NotNull DeclarationDescriptor descriptor) {
162            return DescriptorUtils.getParentOfType(descriptor, NamespaceDescriptor.class);
163        }
164    
165        @Nullable
166        public static Name getNameIfStandardType(@NotNull JetExpression expression, @NotNull TranslationContext context) {
167            JetType type = context.bindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
168            return type != null ? getNameIfStandardType(type) : null;
169        }
170    
171        @Nullable
172        public static Name getNameIfStandardType(@NotNull JetType type) {
173            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
174            if (descriptor != null && descriptor.getContainingDeclaration() == KotlinBuiltIns.getInstance().getBuiltInsPackage()) {
175                return descriptor.getName();
176            }
177    
178            return null;
179        }
180    
181        @NotNull
182        public static DeclarationDescriptor getDeclarationDescriptorForExtensionCallReceiver(
183                @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall
184        ) {
185            ReceiverValue receiverArgument = resolvedCall.getReceiverArgument();
186            if (receiverArgument instanceof ExtensionReceiver) {
187                return ((ExtensionReceiver) receiverArgument).getDeclarationDescriptor();
188            }
189            if (receiverArgument instanceof ClassReceiver) {
190                return ((ClassReceiver) receiverArgument).getDeclarationDescriptor();
191            }
192            throw new IllegalStateException("Unexpected receiver of type " + receiverArgument.getClass());
193        }
194    }