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