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 }