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.psi.PsiElement;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.descriptors.*;
023    import org.jetbrains.kotlin.psi.*;
024    import org.jetbrains.kotlin.resolve.BindingContext;
025    import org.jetbrains.kotlin.resolve.BindingContextUtils;
026    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
027    import org.jetbrains.kotlin.resolve.DescriptorUtils;
028    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
029    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
030    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
031    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
032    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
033    import org.jetbrains.kotlin.types.KotlinType;
034    import org.jetbrains.kotlin.types.TypeUtils;
035    
036    import java.util.List;
037    
038    import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
039    import static org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_GET;
040    import static org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_SET;
041    
042    /**
043     * This class contains some code related to BindingContext use. Intention is not to pollute other classes.
044     * Every call to BindingContext.get() is supposed to be wrapped by this utility class.
045     */
046    public final class BindingUtils {
047    
048        private BindingUtils() {
049        }
050    
051        @NotNull
052        static private <E extends PsiElement, D extends DeclarationDescriptor>
053        D getDescriptorForExpression(@NotNull BindingContext context, @NotNull E expression, Class<D> descriptorClass) {
054            DeclarationDescriptor descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression);
055            assert descriptor != null;
056            assert descriptorClass.isInstance(descriptor)
057                    : message(expression, expression.toString() + " expected to have of type" + descriptorClass.toString());
058            //noinspection unchecked
059            return (D) descriptor;
060        }
061    
062        @NotNull
063        public static ClassDescriptor getClassDescriptor(@NotNull BindingContext context,
064                @NotNull KtClassOrObject declaration) {
065            return BindingContextUtils.getNotNull(context, BindingContext.CLASS, declaration);
066        }
067    
068        @NotNull
069        public static FunctionDescriptor getFunctionDescriptor(@NotNull BindingContext context,
070                @NotNull KtDeclarationWithBody declaration) {
071            return getDescriptorForExpression(context, declaration, FunctionDescriptor.class);
072        }
073    
074        @NotNull
075        public static PropertyDescriptor getPropertyDescriptor(@NotNull BindingContext context,
076                @NotNull KtProperty declaration) {
077            return getDescriptorForExpression(context, declaration, PropertyDescriptor.class);
078        }
079    
080        @NotNull
081        private static KtParameter getParameterForDescriptor(@NotNull ValueParameterDescriptor descriptor) {
082            PsiElement result = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
083            assert result instanceof KtParameter : message(descriptor, "ValueParameterDescriptor should have corresponding JetParameter");
084            return (KtParameter) result;
085        }
086    
087        public static boolean hasAncestorClass(@NotNull BindingContext context, @NotNull KtClassOrObject classDeclaration) {
088            ClassDescriptor classDescriptor = getClassDescriptor(context, classDeclaration);
089            List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor);
090            return (JsDescriptorUtils.findAncestorClass(superclassDescriptors) != null);
091        }
092    
093        @NotNull
094        public static KotlinType getTypeByReference(@NotNull BindingContext context,
095                @NotNull KtTypeReference typeReference) {
096            return BindingContextUtils.getNotNull(context, BindingContext.TYPE, typeReference);
097        }
098    
099        @Nullable
100        public static PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
101                @NotNull KtParameter parameter) {
102            return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
103        }
104    
105        @Nullable
106        public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
107                @NotNull KtReferenceExpression reference) {
108            if (BindingContextUtils.isExpressionWithValidReference(reference, context)) {
109                return BindingContextUtils.getNotNull(context, BindingContext.REFERENCE_TARGET, reference);
110            }
111            return null;
112        }
113    
114        @Nullable
115        private static DeclarationDescriptor getNullableDescriptorForReferenceExpression(@NotNull BindingContext context,
116                @NotNull KtReferenceExpression reference) {
117            return context.get(BindingContext.REFERENCE_TARGET, reference);
118        }
119    
120        public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull KtExpression expression) {
121            return BindingContextUtils.getNotNull(context, BindingContext.VARIABLE_REASSIGNMENT, expression);
122        }
123    
124        @Nullable
125        public static CallableDescriptor getCallableDescriptorForOperationExpression(
126                @NotNull BindingContext context,
127                @NotNull KtOperationExpression expression
128        ) {
129            KtSimpleNameExpression operationReference = expression.getOperationReference();
130            DeclarationDescriptor descriptorForReferenceExpression =
131                    getNullableDescriptorForReferenceExpression(context, operationReference);
132    
133            if (descriptorForReferenceExpression == null) return null;
134    
135            assert descriptorForReferenceExpression instanceof CallableDescriptor :
136                    message(operationReference, "Operation should resolve to callable descriptor");
137            return (CallableDescriptor) descriptorForReferenceExpression;
138        }
139    
140        @NotNull
141        public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
142                @NotNull PsiElement element) {
143            return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, element);
144        }
145    
146        @Nullable
147        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull KtExpression expression) {
148            CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context);
149            if (compileTimeValue != null) {
150                return getCompileTimeValue(context, expression, compileTimeValue);
151            }
152            return null;
153        }
154    
155        @Nullable
156        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull KtExpression expression, @NotNull CompileTimeConstant<?> constant) {
157            KotlinType expectedType = context.getType(expression);
158            return constant.getValue(expectedType == null ? TypeUtils.NO_EXPECTED_TYPE : expectedType);
159        }
160    
161        @NotNull
162        public static KtExpression getDefaultArgument(@NotNull ValueParameterDescriptor parameterDescriptor) {
163            ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
164                    getOriginalDescriptorWhichDeclaresDefaultValue(parameterDescriptor);
165            KtParameter psiParameter = getParameterForDescriptor(descriptorWhichDeclaresDefaultValue);
166            KtExpression defaultValue = psiParameter.getDefaultValue();
167            assert defaultValue != null : message(parameterDescriptor, "No default value found in PSI");
168            return defaultValue;
169        }
170    
171        private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
172                @NotNull ValueParameterDescriptor parameterDescriptor
173        ) {
174            ValueParameterDescriptor result = parameterDescriptor;
175            assert DescriptorUtilsKt.hasDefaultValue(result) : message(parameterDescriptor, "Unsupplied parameter must have default value");
176            // TODO: this seems incorrect, as the default value may come from _not the first_ overridden parameter
177            while (!result.declaresDefaultValue()) {
178                result = result.getOverriddenDescriptors().iterator().next();
179            }
180            return result;
181        }
182    
183        @NotNull
184        public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
185                @NotNull KtExpression rangeExpression) {
186            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
187        }
188    
189        @NotNull
190        public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
191                @NotNull KtExpression rangeExpression) {
192            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
193        }
194    
195        @NotNull
196        public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
197                @NotNull KtExpression rangeExpression) {
198            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
199        }
200    
201        @NotNull
202        public static KotlinType getTypeForExpression(@NotNull BindingContext context,
203                @NotNull KtExpression expression) {
204            return BindingContextUtils.getTypeNotNull(context, expression);
205        }
206    
207        @NotNull
208        public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
209                @NotNull KtArrayAccessExpression arrayAccessExpression,
210                boolean isGet) {
211            return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression);
212        }
213    
214    
215        @Nullable
216        @SuppressWarnings("unchecked")
217        public static ResolvedCall<FunctionDescriptor> getSuperCall(@NotNull BindingContext context, KtClassOrObject classDeclaration) {
218            for (KtSuperTypeListEntry specifier : classDeclaration.getSuperTypeListEntries()) {
219                if (specifier instanceof KtSuperTypeCallEntry) {
220                    KtSuperTypeCallEntry superCall = (KtSuperTypeCallEntry) specifier;
221                    return (ResolvedCall<FunctionDescriptor>) CallUtilKt.getResolvedCallWithAssert(superCall, context);
222                }
223            }
224            return null;
225        }
226    }