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