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 }