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 017package org.jetbrains.k2js.translate.utils; 018 019import com.intellij.psi.PsiElement; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.*; 023import org.jetbrains.jet.lang.psi.*; 024import org.jetbrains.jet.lang.resolve.BindingContext; 025import org.jetbrains.jet.lang.resolve.BindingContextUtils; 026import org.jetbrains.jet.lang.resolve.DescriptorUtils; 027import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 028import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; 029import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 030import org.jetbrains.jet.lang.types.JetType; 031 032import java.util.List; 033 034import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET; 035import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET; 036import 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 */ 042public 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}