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 resolveObjectViaTypeAlias(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            DeclarationDescriptor descriptor = context.get(BindingContext.REFERENCE_TARGET, reference);
118            return descriptor != null ? resolveObjectViaTypeAlias(descriptor) : null;
119        }
120    
121        @NotNull
122        private static DeclarationDescriptor resolveObjectViaTypeAlias(@NotNull DeclarationDescriptor descriptor) {
123            if (descriptor instanceof TypeAliasDescriptor) {
124                ClassDescriptor classDescriptor = ((TypeAliasDescriptor) descriptor).getClassDescriptor();
125                assert classDescriptor != null : "Class descriptor must be non-null in resolved typealias: " + descriptor;
126                if (classDescriptor.getKind() != ClassKind.OBJECT && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
127                    classDescriptor = classDescriptor.getCompanionObjectDescriptor();
128                    assert classDescriptor != null : "Resolved typealias must have non-null class descriptor: " + descriptor;
129                }
130                return classDescriptor;
131            }
132            else {
133                return descriptor;
134            }
135        }
136    
137        public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull KtExpression expression) {
138            return BindingContextUtils.getNotNull(context, BindingContext.VARIABLE_REASSIGNMENT, expression);
139        }
140    
141        @Nullable
142        public static CallableDescriptor getCallableDescriptorForOperationExpression(
143                @NotNull BindingContext context,
144                @NotNull KtOperationExpression expression
145        ) {
146            KtSimpleNameExpression operationReference = expression.getOperationReference();
147            DeclarationDescriptor descriptorForReferenceExpression =
148                    getNullableDescriptorForReferenceExpression(context, operationReference);
149    
150            if (descriptorForReferenceExpression == null) return null;
151    
152            assert descriptorForReferenceExpression instanceof CallableDescriptor :
153                    message(operationReference, "Operation should resolve to callable descriptor");
154            return (CallableDescriptor) descriptorForReferenceExpression;
155        }
156    
157        @NotNull
158        public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
159                @NotNull PsiElement element) {
160            return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, element);
161        }
162    
163        @Nullable
164        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull KtExpression expression) {
165            CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context);
166            if (compileTimeValue != null) {
167                return getCompileTimeValue(context, expression, compileTimeValue);
168            }
169            return null;
170        }
171    
172        @Nullable
173        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull KtExpression expression, @NotNull CompileTimeConstant<?> constant) {
174            KotlinType expectedType = context.getType(expression);
175            return constant.getValue(expectedType == null ? TypeUtils.NO_EXPECTED_TYPE : expectedType);
176        }
177    
178        @NotNull
179        public static KtExpression getDefaultArgument(@NotNull ValueParameterDescriptor parameterDescriptor) {
180            ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
181                    getOriginalDescriptorWhichDeclaresDefaultValue(parameterDescriptor);
182            KtParameter psiParameter = getParameterForDescriptor(descriptorWhichDeclaresDefaultValue);
183            KtExpression defaultValue = psiParameter.getDefaultValue();
184            assert defaultValue != null : message(parameterDescriptor, "No default value found in PSI");
185            return defaultValue;
186        }
187    
188        private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
189                @NotNull ValueParameterDescriptor parameterDescriptor
190        ) {
191            ValueParameterDescriptor result = parameterDescriptor;
192            assert DescriptorUtilsKt.hasDefaultValue(result) : message(parameterDescriptor, "Unsupplied parameter must have default value");
193            // TODO: this seems incorrect, as the default value may come from _not the first_ overridden parameter
194            while (!result.declaresDefaultValue()) {
195                result = result.getOverriddenDescriptors().iterator().next();
196            }
197            return result;
198        }
199    
200        @NotNull
201        public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
202                @NotNull KtExpression rangeExpression) {
203            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
204        }
205    
206        @NotNull
207        public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
208                @NotNull KtExpression rangeExpression) {
209            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
210        }
211    
212        @NotNull
213        public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
214                @NotNull KtExpression rangeExpression) {
215            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
216        }
217    
218        @NotNull
219        public static KotlinType getTypeForExpression(@NotNull BindingContext context,
220                @NotNull KtExpression expression) {
221            return BindingContextUtils.getTypeNotNull(context, expression);
222        }
223    
224        @NotNull
225        public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
226                @NotNull KtArrayAccessExpression arrayAccessExpression,
227                boolean isGet) {
228            return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression);
229        }
230    
231    
232        @Nullable
233        @SuppressWarnings("unchecked")
234        public static ResolvedCall<FunctionDescriptor> getSuperCall(@NotNull BindingContext context, KtClassOrObject classDeclaration) {
235            for (KtSuperTypeListEntry specifier : classDeclaration.getSuperTypeListEntries()) {
236                if (specifier instanceof KtSuperTypeCallEntry) {
237                    KtSuperTypeCallEntry superCall = (KtSuperTypeCallEntry) specifier;
238                    return (ResolvedCall<FunctionDescriptor>) CallUtilKt.getResolvedCallWithAssert(superCall, context);
239                }
240            }
241            return null;
242        }
243    }