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,
141                @NotNull JetExpression expression) {
142            ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
143            assert resolvedCall != null : message(expression, expression.getText() + " must resolve to a call");
144            return resolvedCall;
145        }
146    
147        @NotNull
148        public static ResolvedCall<?> getResolvedCallForProperty(@NotNull BindingContext context,
149                @NotNull JetExpression expression) {
150            ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
151            assert resolvedCall != null : message(expression, expression.getText() + "must resolve to a call");
152            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
153                return ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall();
154            }
155            return resolvedCall;
156        }
157    
158        @NotNull
159        public static ResolvedCall<? extends FunctionDescriptor> getResolvedCallForCallExpression(@NotNull BindingContext context,
160                @NotNull JetCallExpression expression) {
161            JetExpression calleeExpression = PsiUtils.getCallee(expression);
162            return getFunctionResolvedCall(context, calleeExpression);
163        }
164    
165        @NotNull
166        public static ResolvedCall<? extends FunctionDescriptor> getFunctionResolvedCall(@NotNull BindingContext context,
167                @NotNull JetExpression expression) {
168            ResolvedCall<?> resolvedCall = getResolvedCall(context, expression);
169            assert resolvedCall.getResultingDescriptor() instanceof FunctionDescriptor
170                    : message(expression, "ResolvedCall for this expression must be ResolvedCall<? extends FunctionDescriptor>");
171            return (ResolvedCall<? extends FunctionDescriptor>) resolvedCall;
172        }
173    
174        public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {
175            return BindingContextUtils.getNotNull(context, BindingContext.VARIABLE_REASSIGNMENT, expression);
176        }
177    
178        @Nullable
179        public static FunctionDescriptor getFunctionDescriptorForOperationExpression(@NotNull BindingContext context,
180                @NotNull JetOperationExpression expression) {
181            DeclarationDescriptor descriptorForReferenceExpression = getNullableDescriptorForReferenceExpression
182                    (context, expression.getOperationReference());
183    
184            if (descriptorForReferenceExpression == null) return null;
185    
186            assert descriptorForReferenceExpression instanceof FunctionDescriptor
187                    : message(expression.getOperationReference(), "Operation should resolve to function descriptor");
188            return (FunctionDescriptor) descriptorForReferenceExpression;
189        }
190    
191        @NotNull
192        public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
193                @NotNull PsiElement element) {
194            return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, element);
195        }
196    
197        @Nullable
198        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression) {
199            CompileTimeConstant<?> compileTimeValue = context.get(BindingContext.COMPILE_TIME_VALUE, expression);
200            if (compileTimeValue != null) {
201                return getCompileTimeValue(context, expression, compileTimeValue);
202            }
203            return null;
204        }
205    
206        @Nullable
207        public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression, @NotNull CompileTimeConstant<?> constant) {
208            if (constant != null) {
209                if (constant instanceof IntegerValueTypeConstant) {
210                    JetType expectedType = context.get(BindingContext.EXPRESSION_TYPE, expression);
211                    return ((IntegerValueTypeConstant) constant).getValue(expectedType == null ? TypeUtils.NO_EXPECTED_TYPE : expectedType);
212                }
213                return constant.getValue();
214            }
215            return null;
216        }
217    
218        @NotNull
219        public static JetExpression getDefaultArgument(@NotNull BindingContext context,
220                @NotNull ValueParameterDescriptor parameterDescriptor) {
221            ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
222                    getOriginalDescriptorWhichDeclaresDefaultValue(context, parameterDescriptor);
223            JetParameter psiParameter = getParameterForDescriptor(context, descriptorWhichDeclaresDefaultValue);
224            JetExpression defaultValue = psiParameter.getDefaultValue();
225            assert defaultValue != null : message(context, parameterDescriptor, "No default value found in PSI");
226            return defaultValue;
227        }
228    
229        private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
230                BindingContext context, @NotNull ValueParameterDescriptor parameterDescriptor) {
231            ValueParameterDescriptor result = parameterDescriptor;
232            assert result.hasDefaultValue() :
233                    message(context, parameterDescriptor, "Unsupplied parameter must have default value");
234            while (!result.declaresDefaultValue()) {
235                result = result.getOverriddenDescriptors().iterator().next();
236            }
237            return result;
238        }
239    
240        @NotNull
241        public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
242                @NotNull JetExpression rangeExpression) {
243            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
244        }
245    
246        @NotNull
247        public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
248                @NotNull JetExpression rangeExpression) {
249            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
250        }
251    
252        @NotNull
253        public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
254                @NotNull JetExpression rangeExpression) {
255            return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
256        }
257    
258        @NotNull
259        public static JetType getTypeForExpression(@NotNull BindingContext context,
260                @NotNull JetExpression expression) {
261            return BindingContextUtils.getNotNull(context, BindingContext.EXPRESSION_TYPE, expression);
262        }
263    
264        @NotNull
265        public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
266                @NotNull JetArrayAccessExpression arrayAccessExpression,
267                boolean isGet) {
268            return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression);
269        }
270    
271        public static ConstructorDescriptor getConstructor(@NotNull BindingContext bindingContext,
272                @NotNull JetClassOrObject declaration) {
273            ConstructorDescriptor primaryConstructor = getClassDescriptor(bindingContext, declaration).getUnsubstitutedPrimaryConstructor();
274            assert primaryConstructor != null : message(declaration, "Traits do not have initialize methods");
275            return primaryConstructor;
276        }
277    
278        @Nullable
279        public static SimpleFunctionDescriptor getNullableDescriptorForFunction(@NotNull BindingContext bindingContext,
280                @NotNull JetNamedFunction function) {
281            return bindingContext.get(BindingContext.FUNCTION, function);
282        }
283    }