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 CallableDescriptor getCallableDescriptorForOperationExpression(
178 @NotNull BindingContext context,
179 @NotNull JetOperationExpression expression
180 ) {
181 JetSimpleNameExpression operationReference = expression.getOperationReference();
182 DeclarationDescriptor descriptorForReferenceExpression =
183 getNullableDescriptorForReferenceExpression(context, operationReference);
184
185 if (descriptorForReferenceExpression == null) return null;
186
187 assert descriptorForReferenceExpression instanceof CallableDescriptor :
188 message(operationReference, "Operation should resolve to callable descriptor");
189 return (CallableDescriptor) descriptorForReferenceExpression;
190 }
191
192 @NotNull
193 public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
194 @NotNull PsiElement element) {
195 return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, element);
196 }
197
198 @Nullable
199 public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression) {
200 CompileTimeConstant<?> compileTimeValue = context.get(BindingContext.COMPILE_TIME_VALUE, expression);
201 if (compileTimeValue != null) {
202 return getCompileTimeValue(context, expression, compileTimeValue);
203 }
204 return null;
205 }
206
207 @Nullable
208 public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression, @NotNull CompileTimeConstant<?> constant) {
209 if (constant != null) {
210 if (constant instanceof IntegerValueTypeConstant) {
211 JetType expectedType = context.get(BindingContext.EXPRESSION_TYPE, expression);
212 return ((IntegerValueTypeConstant) constant).getValue(expectedType == null ? TypeUtils.NO_EXPECTED_TYPE : expectedType);
213 }
214 return constant.getValue();
215 }
216 return null;
217 }
218
219 @NotNull
220 public static JetExpression getDefaultArgument(@NotNull BindingContext context,
221 @NotNull ValueParameterDescriptor parameterDescriptor) {
222 ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
223 getOriginalDescriptorWhichDeclaresDefaultValue(context, parameterDescriptor);
224 JetParameter psiParameter = getParameterForDescriptor(context, descriptorWhichDeclaresDefaultValue);
225 JetExpression defaultValue = psiParameter.getDefaultValue();
226 assert defaultValue != null : message(context, parameterDescriptor, "No default value found in PSI");
227 return defaultValue;
228 }
229
230 private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
231 BindingContext context, @NotNull ValueParameterDescriptor parameterDescriptor) {
232 ValueParameterDescriptor result = parameterDescriptor;
233 assert result.hasDefaultValue() :
234 message(context, parameterDescriptor, "Unsupplied parameter must have default value");
235 while (!result.declaresDefaultValue()) {
236 result = result.getOverriddenDescriptors().iterator().next();
237 }
238 return result;
239 }
240
241 @NotNull
242 public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
243 @NotNull JetExpression rangeExpression) {
244 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
245 }
246
247 @NotNull
248 public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
249 @NotNull JetExpression rangeExpression) {
250 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
251 }
252
253 @NotNull
254 public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
255 @NotNull JetExpression rangeExpression) {
256 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
257 }
258
259 @NotNull
260 public static JetType getTypeForExpression(@NotNull BindingContext context,
261 @NotNull JetExpression expression) {
262 return BindingContextUtils.getNotNull(context, BindingContext.EXPRESSION_TYPE, expression);
263 }
264
265 @NotNull
266 public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
267 @NotNull JetArrayAccessExpression arrayAccessExpression,
268 boolean isGet) {
269 return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression);
270 }
271
272 public static ConstructorDescriptor getConstructor(@NotNull BindingContext bindingContext,
273 @NotNull JetClassOrObject declaration) {
274 ConstructorDescriptor primaryConstructor = getClassDescriptor(bindingContext, declaration).getUnsubstitutedPrimaryConstructor();
275 assert primaryConstructor != null : message(declaration, "Traits do not have initialize methods");
276 return primaryConstructor;
277 }
278
279 @Nullable
280 public static SimpleFunctionDescriptor getNullableDescriptorForFunction(@NotNull BindingContext bindingContext,
281 @NotNull JetNamedFunction function) {
282 return bindingContext.get(BindingContext.FUNCTION, function);
283 }
284 }