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 return BindingContextUtils.getNotNull(context, BindingContext.STATEMENT, expression);
102 }
103
104 @NotNull
105 public static JetType getTypeByReference(@NotNull BindingContext context,
106 @NotNull JetTypeReference typeReference) {
107 return BindingContextUtils.getNotNull(context, BindingContext.TYPE, typeReference);
108 }
109
110 @NotNull
111 public static ClassDescriptor getClassDescriptorForTypeReference(@NotNull BindingContext context,
112 @NotNull JetTypeReference typeReference) {
113 return DescriptorUtils.getClassDescriptorForType(getTypeByReference(context, typeReference));
114 }
115
116 @Nullable
117 public static PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
118 @NotNull JetParameter parameter) {
119 return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
120 }
121
122 @Nullable
123 public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
124 @NotNull JetReferenceExpression reference) {
125 if (BindingContextUtils.isExpressionWithValidReference(reference, context)) {
126 return BindingContextUtils.getNotNull(context, BindingContext.REFERENCE_TARGET, reference);
127 }
128 return null;
129 }
130
131 @Nullable
132 public static DeclarationDescriptor getNullableDescriptorForReferenceExpression(@NotNull BindingContext context,
133 @NotNull JetReferenceExpression reference) {
134 return context.get(BindingContext.REFERENCE_TARGET, reference);
135 }
136
137 @NotNull
138 public static ResolvedCall<?> getResolvedCall(@NotNull BindingContext context,
139 @NotNull JetExpression expression) {
140 ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
141 assert resolvedCall != null : message(expression, expression.getText() + " must resolve to a call");
142 return resolvedCall;
143 }
144
145 @NotNull
146 public static ResolvedCall<?> getResolvedCallForProperty(@NotNull BindingContext context,
147 @NotNull JetExpression expression) {
148 ResolvedCall<? extends CallableDescriptor> 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<?> getResolvedCallForCallExpression(@NotNull BindingContext context,
158 @NotNull JetCallExpression expression) {
159 JetExpression calleeExpression = PsiUtils.getCallee(expression);
160 return getResolvedCall(context, calleeExpression);
161 }
162
163 public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {
164 return BindingContextUtils.getNotNull(context, BindingContext.VARIABLE_REASSIGNMENT, expression);
165 }
166
167 @Nullable
168 public static FunctionDescriptor getFunctionDescriptorForOperationExpression(@NotNull BindingContext context,
169 @NotNull JetOperationExpression expression) {
170 DeclarationDescriptor descriptorForReferenceExpression = getNullableDescriptorForReferenceExpression
171 (context, expression.getOperationReference());
172
173 if (descriptorForReferenceExpression == null) return null;
174
175 assert descriptorForReferenceExpression instanceof FunctionDescriptor
176 : message(expression.getOperationReference(), "Operation should resolve to function descriptor");
177 return (FunctionDescriptor) descriptorForReferenceExpression;
178 }
179
180 @NotNull
181 public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
182 @NotNull PsiElement element) {
183 return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, element);
184 }
185
186 @Nullable
187 public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression) {
188 CompileTimeConstant<?> compileTimeValue = context.get(BindingContext.COMPILE_TIME_VALUE, expression);
189 if (compileTimeValue != null) {
190 return compileTimeValue.getValue();
191 }
192 return null;
193 }
194
195 @NotNull
196 public static JetExpression getDefaultArgument(@NotNull BindingContext context,
197 @NotNull ValueParameterDescriptor parameterDescriptor) {
198 ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
199 getOriginalDescriptorWhichDeclaresDefaultValue(context, parameterDescriptor);
200 JetParameter psiParameter = getParameterForDescriptor(context, descriptorWhichDeclaresDefaultValue);
201 JetExpression defaultValue = psiParameter.getDefaultValue();
202 assert defaultValue != null : message(context, parameterDescriptor, "No default value found in PSI");
203 return defaultValue;
204 }
205
206 private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
207 BindingContext context, @NotNull ValueParameterDescriptor parameterDescriptor) {
208 ValueParameterDescriptor result = parameterDescriptor;
209 assert result.hasDefaultValue() :
210 message(context, parameterDescriptor, "Unsupplied parameter must have default value");
211 while (!result.declaresDefaultValue()) {
212 result = result.getOverriddenDescriptors().iterator().next();
213 }
214 return result;
215 }
216
217 @NotNull
218 public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
219 @NotNull JetExpression rangeExpression) {
220 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
221 }
222
223 @NotNull
224 public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
225 @NotNull JetExpression rangeExpression) {
226 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
227 }
228
229 @NotNull
230 public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
231 @NotNull JetExpression rangeExpression) {
232 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
233 }
234
235 @NotNull
236 public static PropertyDescriptor getPropertyDescriptorForObjectDeclaration(@NotNull BindingContext context,
237 @NotNull JetObjectDeclarationName name) {
238 return BindingContextUtils.getNotNull(context, BindingContext.OBJECT_DECLARATION, name);
239 }
240
241 @NotNull
242 public static JetType getTypeForExpression(@NotNull BindingContext context,
243 @NotNull JetExpression expression) {
244 return BindingContextUtils.getNotNull(context, BindingContext.EXPRESSION_TYPE, expression);
245 }
246
247 @NotNull
248 public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
249 @NotNull JetArrayAccessExpression arrayAccessExpression,
250 boolean isGet) {
251 return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression);
252 }
253
254 public static ConstructorDescriptor getConstructor(@NotNull BindingContext bindingContext,
255 @NotNull JetClassOrObject declaration) {
256 ConstructorDescriptor primaryConstructor = getClassDescriptor(bindingContext, declaration).getUnsubstitutedPrimaryConstructor();
257 assert primaryConstructor != null : message(declaration, "Traits do not have initialize methods");
258 return primaryConstructor;
259 }
260
261 @Nullable
262 public static SimpleFunctionDescriptor getNullableDescriptorForFunction(@NotNull BindingContext bindingContext,
263 @NotNull JetNamedFunction function) {
264 return bindingContext.get(BindingContext.FUNCTION, function);
265 }
266
267 public static boolean isObjectDeclaration(
268 @NotNull BindingContext bindingContext,
269 @NotNull PropertyDescriptor propertyDescriptor
270 ) {
271 return bindingContext.get(BindingContext.OBJECT_DECLARATION_CLASS, propertyDescriptor) != null;
272 }
273 }