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 com.intellij.psi.PsiElement;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.psi.*;
024    import org.jetbrains.jet.lang.resolve.BindingContext;
025    import org.jetbrains.jet.lang.resolve.BindingContextUtils;
026    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
027    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
028    import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
029    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
030    import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant;
031    import org.jetbrains.jet.lang.types.JetType;
032    import org.jetbrains.jet.lang.types.TypeUtils;
033    
034    import java.util.List;
035    
036    import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET;
037    import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET;
038    import static org.jetbrains.k2js.translate.utils.ErrorReportingUtils.message;
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        public static JetFunction getFunctionForDescriptor(@NotNull BindingContext context,
080                @NotNull SimpleFunctionDescriptor descriptor) {
081            PsiElement result = BindingContextUtils.callableDescriptorToDeclaration(context, descriptor);
082            assert result instanceof JetFunction
083                    : message(context, descriptor, "SimpleFunctionDescriptor should have declaration of type JetFunction");
084            return (JetFunction) result;
085        }
086    
087        @NotNull
088        private static JetParameter getParameterForDescriptor(@NotNull BindingContext context,
089                @NotNull ValueParameterDescriptor descriptor) {
090            PsiElement result = BindingContextUtils.descriptorToDeclaration(context, descriptor);
091            assert result instanceof JetParameter :
092                    message(context, descriptor, "ValueParameterDescriptor should have corresponding JetParameter");
093            return (JetParameter) result;
094        }
095    
096        public static boolean hasAncestorClass(@NotNull BindingContext context, @NotNull JetClassOrObject classDeclaration) {
097            ClassDescriptor classDescriptor = getClassDescriptor(context, classDeclaration);
098            List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor);
099            return (JsDescriptorUtils.findAncestorClass(superclassDescriptors) != null);
100        }
101    
102        public static boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) {
103            return BindingContextUtils.getNotNull(context, BindingContext.STATEMENT, expression);
104        }
105    
106        @NotNull
107        public static JetType getTypeByReference(@NotNull BindingContext context,
108                @NotNull JetTypeReference typeReference) {
109            return BindingContextUtils.getNotNull(context, BindingContext.TYPE, typeReference);
110        }
111    
112        @NotNull
113        public static ClassDescriptor getClassDescriptorForTypeReference(@NotNull BindingContext context,
114                @NotNull JetTypeReference typeReference) {
115            return DescriptorUtils.getClassDescriptorForType(getTypeByReference(context, typeReference));
116        }
117    
118        @Nullable
119        public static PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
120                @NotNull JetParameter parameter) {
121            return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
122        }
123    
124        @Nullable
125        public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
126                @NotNull JetReferenceExpression reference) {
127            if (BindingContextUtils.isExpressionWithValidReference(reference, context)) {
128                return BindingContextUtils.getNotNull(context, BindingContext.REFERENCE_TARGET, reference);
129            }
130            return null;
131        }
132    
133        @Nullable
134        public static DeclarationDescriptor getNullableDescriptorForReferenceExpression(@NotNull BindingContext context,
135                @NotNull JetReferenceExpression reference) {
136            return context.get(BindingContext.REFERENCE_TARGET, reference);
137        }
138    
139        @NotNull
140        public static ResolvedCall<?> getResolvedCall(@NotNull BindingContext context, @NotNull JetExpression expression) {
141            ResolvedCall<?> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
142            assert resolvedCall != null : message(expression, expression.getText() + " must resolve to a call");
143            return resolvedCall;
144        }
145    
146        @NotNull
147        public static ResolvedCall<?> getResolvedCallForProperty(@NotNull BindingContext context, @NotNull JetExpression expression) {
148            ResolvedCall<?> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
149            assert resolvedCall != null : message(expression, expression.getText() + " must resolve to a call");
150            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
151                return ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall();
152            }
153            return resolvedCall;
154        }
155    
156        @NotNull
157        public static ResolvedCall<? extends FunctionDescriptor> getResolvedCallForCallExpression(@NotNull BindingContext context,
158                @NotNull JetCallExpression expression) {
159            JetExpression calleeExpression = PsiUtils.getCallee(expression);
160            return getFunctionResolvedCall(context, calleeExpression);
161        }
162    
163        @NotNull
164        public static ResolvedCall<? extends FunctionDescriptor> getFunctionResolvedCall(@NotNull BindingContext context,
165                @NotNull JetExpression expression) {
166            ResolvedCall<?> resolvedCall = getResolvedCall(context, expression);
167            assert resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor
168                    : message(expression, "ResolvedCall for this expression must be ResolvedCall<? extends FunctionDescriptor>");
169            return (ResolvedCall<? extends FunctionDescriptor>) resolvedCall;
170        }
171    
172        public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {
173            return BindingContextUtils.getNotNull(context, BindingContext.VARIABLE_REASSIGNMENT, expression);
174        }
175    
176        @Nullable
177        public static FunctionDescriptor getFunctionDescriptorForOperationExpression(@NotNull BindingContext context,
178                @NotNull JetOperationExpression expression) {
179            DeclarationDescriptor descriptorForReferenceExpression = getNullableDescriptorForReferenceExpression
180                    (context, expression.getOperationReference());
181    
182            if (descriptorForReferenceExpression == null) return null;
183    
184            assert descriptorForReferenceExpression instanceof FunctionDescriptor
185                    : message(expression.getOperationReference(), "Operation should resolve to function descriptor");
186            return (FunctionDescriptor) descriptorForReferenceExpression;
187        }
188    
189        @NotNull
190        public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
191                @NotNull PsiElement element) {
192            return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, element);
193        }
194    
195        @Nullable
196        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression) {
197            CompileTimeConstant<?> compileTimeValue = context.get(BindingContext.COMPILE_TIME_VALUE, expression);
198            if (compileTimeValue != null) {
199                return getCompileTimeValue(context, expression, compileTimeValue);
200            }
201            return null;
202        }
203    
204        @Nullable
205        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression, @NotNull CompileTimeConstant<?> constant) {
206            if (constant != null) {
207                if (constant instanceof IntegerValueTypeConstant) {
208                    JetType expectedType = context.get(BindingContext.EXPRESSION_TYPE, expression);
209                    return ((IntegerValueTypeConstant) constant).getValue(expectedType == null ? TypeUtils.NO_EXPECTED_TYPE : expectedType);
210                }
211                return constant.getValue();
212            }
213            return null;
214        }
215    
216        @NotNull
217        public static JetExpression getDefaultArgument(@NotNull BindingContext context,
218                @NotNull ValueParameterDescriptor parameterDescriptor) {
219            ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
220                    getOriginalDescriptorWhichDeclaresDefaultValue(context, parameterDescriptor);
221            JetParameter psiParameter = getParameterForDescriptor(context, descriptorWhichDeclaresDefaultValue);
222            JetExpression defaultValue = psiParameter.getDefaultValue();
223            assert defaultValue != null : message(context, parameterDescriptor, "No default value found in PSI");
224            return defaultValue;
225        }
226    
227        private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
228                BindingContext context, @NotNull ValueParameterDescriptor parameterDescriptor) {
229            ValueParameterDescriptor result = parameterDescriptor;
230            assert result.hasDefaultValue() :
231                    message(context, parameterDescriptor, "Unsupplied parameter must have default value");
232            while (!result.declaresDefaultValue()) {
233                result = result.getOverriddenDescriptors().iterator().next();
234            }
235            return result;
236        }
237    
238        @NotNull
239        public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
240                @NotNull JetExpression rangeExpression) {
241            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
242        }
243    
244        @NotNull
245        public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
246                @NotNull JetExpression rangeExpression) {
247            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
248        }
249    
250        @NotNull
251        public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
252                @NotNull JetExpression rangeExpression) {
253            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
254        }
255    
256        @NotNull
257        public static JetType getTypeForExpression(@NotNull BindingContext context,
258                @NotNull JetExpression expression) {
259            return BindingContextUtils.getNotNull(context, BindingContext.EXPRESSION_TYPE, expression);
260        }
261    
262        @NotNull
263        public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
264                @NotNull JetArrayAccessExpression arrayAccessExpression,
265                boolean isGet) {
266            return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression);
267        }
268    
269        public static ConstructorDescriptor getConstructor(@NotNull BindingContext bindingContext,
270                @NotNull JetClassOrObject declaration) {
271            ConstructorDescriptor primaryConstructor = getClassDescriptor(bindingContext, declaration).getUnsubstitutedPrimaryConstructor();
272            assert primaryConstructor != null : message(declaration, "Traits do not have initialize methods");
273            return primaryConstructor;
274        }
275    
276        @Nullable
277        public static SimpleFunctionDescriptor getNullableDescriptorForFunction(@NotNull BindingContext bindingContext,
278                @NotNull JetNamedFunction function) {
279            return bindingContext.get(BindingContext.FUNCTION, function);
280        }
281    }