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.types.JetType;
031
032 import java.util.List;
033
034 import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET;
035 import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET;
036 import static org.jetbrains.k2js.translate.utils.ErrorReportingUtils.message;
037
038 /**
039 * This class contains some code related to BindingContext use. Intention is not to pollute other classes.
040 * Every call to BindingContext.get() is supposed to be wrapped by this utility class.
041 */
042 public final class BindingUtils {
043
044 private BindingUtils() {
045 }
046
047 @NotNull
048 static private <E extends PsiElement, D extends DeclarationDescriptor>
049 D getDescriptorForExpression(@NotNull BindingContext context, @NotNull E expression, Class<D> descriptorClass) {
050 DeclarationDescriptor descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression);
051 assert descriptor != null;
052 assert descriptorClass.isInstance(descriptor)
053 : message(expression, expression.toString() + " expected to have of type" + descriptorClass.toString());
054 //noinspection unchecked
055 return (D) descriptor;
056 }
057
058 @NotNull
059 public static ClassDescriptor getClassDescriptor(@NotNull BindingContext context,
060 @NotNull JetClassOrObject declaration) {
061 return getDescriptorForExpression(context, declaration, ClassDescriptor.class);
062 }
063
064 @NotNull
065 public static FunctionDescriptor getFunctionDescriptor(@NotNull BindingContext context,
066 @NotNull JetDeclarationWithBody declaration) {
067 return getDescriptorForExpression(context, declaration, FunctionDescriptor.class);
068 }
069
070 @NotNull
071 public static PropertyDescriptor getPropertyDescriptor(@NotNull BindingContext context,
072 @NotNull JetProperty declaration) {
073 return getDescriptorForExpression(context, declaration, PropertyDescriptor.class);
074 }
075
076 @NotNull
077 public static JetFunction getFunctionForDescriptor(@NotNull BindingContext context,
078 @NotNull SimpleFunctionDescriptor descriptor) {
079 PsiElement result = BindingContextUtils.callableDescriptorToDeclaration(context, descriptor);
080 assert result instanceof JetFunction
081 : message(context, descriptor, "SimpleFunctionDescriptor should have declaration of type JetFunction");
082 return (JetFunction) result;
083 }
084
085 @NotNull
086 private static JetParameter getParameterForDescriptor(@NotNull BindingContext context,
087 @NotNull ValueParameterDescriptor descriptor) {
088 PsiElement result = BindingContextUtils.descriptorToDeclaration(context, descriptor);
089 assert result instanceof JetParameter :
090 message(context, descriptor, "ValueParameterDescriptor should have corresponding JetParameter");
091 return (JetParameter) result;
092 }
093
094 public static boolean hasAncestorClass(@NotNull BindingContext context, @NotNull JetClassOrObject classDeclaration) {
095 ClassDescriptor classDescriptor = getClassDescriptor(context, classDeclaration);
096 List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor);
097 return (JsDescriptorUtils.findAncestorClass(superclassDescriptors) != null);
098 }
099
100 public static boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) {
101 Boolean isStatement = context.get(BindingContext.STATEMENT, expression);
102 assert isStatement != null : message(expression, "Invalid behaviour of get(BindingContext.STATEMENT) at");
103 return isStatement;
104 }
105
106 @NotNull
107 public static JetType getTypeByReference(@NotNull BindingContext context,
108 @NotNull JetTypeReference typeReference) {
109 JetType result = context.get(BindingContext.TYPE, typeReference);
110 assert result != null : message(typeReference, "TypeReference should reference a type");
111 return result;
112 }
113
114 @NotNull
115 public static ClassDescriptor getClassDescriptorForTypeReference(@NotNull BindingContext context,
116 @NotNull JetTypeReference typeReference) {
117 return DescriptorUtils.getClassDescriptorForType(getTypeByReference(context, typeReference));
118 }
119
120 @Nullable
121 public static PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
122 @NotNull JetParameter parameter) {
123 return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
124 }
125
126 @Nullable
127 public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
128 @NotNull JetReferenceExpression reference) {
129 DeclarationDescriptor referencedDescriptor = getNullableDescriptorForReferenceExpression(context, reference);
130 if (BindingContextUtils.isExpressionWithValidReference(reference, context)) {
131 assert referencedDescriptor != null
132 : message(reference, "Reference expression must reference a descriptor for reference " + reference.getText());
133 return referencedDescriptor;
134 }
135 return null;
136 }
137
138 @Nullable
139 public static DeclarationDescriptor getNullableDescriptorForReferenceExpression(@NotNull BindingContext context,
140 @NotNull JetReferenceExpression reference) {
141 return context.get(BindingContext.REFERENCE_TARGET, reference);
142 }
143
144 @NotNull
145 public static ResolvedCall<?> getResolvedCall(@NotNull BindingContext context,
146 @NotNull JetExpression expression) {
147 ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
148 assert resolvedCall != null : message(expression, expression.getText() + " must resolve to a call");
149 return resolvedCall;
150 }
151
152 @NotNull
153 public static ResolvedCall<?> getResolvedCallForProperty(@NotNull BindingContext context,
154 @NotNull JetExpression expression) {
155 ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
156 assert resolvedCall != null : message(expression, expression.getText() + "must resolve to a call");
157 if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
158 return ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall();
159 }
160 return resolvedCall;
161 }
162
163 @NotNull
164 public static ResolvedCall<?> getResolvedCallForCallExpression(@NotNull BindingContext context,
165 @NotNull JetCallExpression expression) {
166 JetExpression calleeExpression = PsiUtils.getCallee(expression);
167 return getResolvedCall(context, calleeExpression);
168 }
169
170 public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {
171 Boolean result = context.get(BindingContext.VARIABLE_REASSIGNMENT, expression);
172 assert result != null : message(expression);
173 return result;
174 }
175
176
177 @Nullable
178 public static FunctionDescriptor getFunctionDescriptorForOperationExpression(@NotNull BindingContext context,
179 @NotNull JetOperationExpression expression) {
180 DeclarationDescriptor descriptorForReferenceExpression = getNullableDescriptorForReferenceExpression
181 (context, expression.getOperationReference());
182
183 if (descriptorForReferenceExpression == null) return null;
184
185 assert descriptorForReferenceExpression instanceof FunctionDescriptor
186 : message(expression.getOperationReference(), "Operation should resolve to function descriptor");
187 return (FunctionDescriptor) descriptorForReferenceExpression;
188 }
189
190 @NotNull
191 public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
192 @NotNull PsiElement element) {
193 DeclarationDescriptor descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
194
195 assert descriptor != null : message(element, element + " doesn't have a descriptor");
196 return descriptor;
197 }
198
199 @Nullable
200 public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression) {
201 CompileTimeConstant<?> compileTimeValue = context.get(BindingContext.COMPILE_TIME_VALUE, expression);
202 if (compileTimeValue != null) {
203 return compileTimeValue.getValue();
204 }
205 return null;
206 }
207
208 @NotNull
209 public static JetExpression getDefaultArgument(@NotNull BindingContext context,
210 @NotNull ValueParameterDescriptor parameterDescriptor) {
211 ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
212 getOriginalDescriptorWhichDeclaresDefaultValue(context, parameterDescriptor);
213 JetParameter psiParameter = getParameterForDescriptor(context, descriptorWhichDeclaresDefaultValue);
214 JetExpression defaultValue = psiParameter.getDefaultValue();
215 assert defaultValue != null : message(context, parameterDescriptor, "No default value found in PSI");
216 return defaultValue;
217 }
218
219 private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
220 BindingContext context, @NotNull ValueParameterDescriptor parameterDescriptor) {
221 ValueParameterDescriptor result = parameterDescriptor;
222 assert result.hasDefaultValue() :
223 message(context, parameterDescriptor, "Unsupplied parameter must have default value");
224 while (!result.declaresDefaultValue()) {
225 result = result.getOverriddenDescriptors().iterator().next();
226 }
227 return result;
228 }
229
230 @NotNull
231 public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
232 @NotNull JetExpression rangeExpression) {
233 ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
234 assert resolvedCall != null :
235 message(rangeExpression, "Range expression must have a descriptor for iterator function");
236 return resolvedCall;
237 }
238
239 @NotNull
240 public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
241 @NotNull JetExpression rangeExpression) {
242 ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
243 assert resolvedCall != null : ErrorReportingUtils
244 .message(rangeExpression, "Range expression must have a descriptor for next function");
245 return resolvedCall;
246 }
247
248 @NotNull
249 public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
250 @NotNull JetExpression rangeExpression) {
251 ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
252 assert resolvedCall != null
253 : message(rangeExpression, "Range expression must have a descriptor for hasNext function or property");
254 return resolvedCall;
255 }
256
257 @NotNull
258 public static PropertyDescriptor getPropertyDescriptorForObjectDeclaration(@NotNull BindingContext context,
259 @NotNull JetObjectDeclarationName name) {
260 PropertyDescriptor propertyDescriptor = context.get(BindingContext.OBJECT_DECLARATION, name);
261 assert propertyDescriptor != null : message(name);
262 return propertyDescriptor;
263 }
264
265 @NotNull
266 public static JetType getTypeForExpression(@NotNull BindingContext context,
267 @NotNull JetExpression expression) {
268 JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
269 assert type != null : message(expression);
270 return type;
271 }
272
273 @NotNull
274 public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
275 @NotNull JetArrayAccessExpression arrayAccessExpression,
276 boolean isGet) {
277 ResolvedCall<FunctionDescriptor> resolvedCall = context.get(isGet
278 ? INDEXED_LVALUE_GET
279 : INDEXED_LVALUE_SET, arrayAccessExpression);
280 assert resolvedCall != null : message(arrayAccessExpression);
281 return resolvedCall;
282 }
283
284 public static ConstructorDescriptor getConstructor(@NotNull BindingContext bindingContext,
285 @NotNull JetClassOrObject declaration) {
286 ConstructorDescriptor primaryConstructor = getClassDescriptor(bindingContext, declaration).getUnsubstitutedPrimaryConstructor();
287 assert primaryConstructor != null : message(declaration, "Traits do not have initialize methods");
288 return primaryConstructor;
289 }
290
291 @Nullable
292 public static SimpleFunctionDescriptor getNullableDescriptorForFunction(@NotNull BindingContext bindingContext,
293 @NotNull JetNamedFunction function) {
294 return bindingContext.get(BindingContext.FUNCTION, function);
295 }
296
297 public static boolean isObjectDeclaration(
298 @NotNull BindingContext bindingContext,
299 @NotNull PropertyDescriptor propertyDescriptor
300 ) {
301 return bindingContext.get(BindingContext.OBJECT_DECLARATION_CLASS, propertyDescriptor) != null;
302 }
303 }