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 }