001 /*
002 * Copyright 2010-2015 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.kotlin.js.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.kotlin.descriptors.*;
023 import org.jetbrains.kotlin.psi.*;
024 import org.jetbrains.kotlin.resolve.BindingContext;
025 import org.jetbrains.kotlin.resolve.BindingContextUtils;
026 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
027 import org.jetbrains.kotlin.resolve.DescriptorUtils;
028 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
029 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
030 import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
031 import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
032 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
033 import org.jetbrains.kotlin.types.KotlinType;
034 import org.jetbrains.kotlin.types.TypeUtils;
035
036 import java.util.List;
037
038 import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
039 import static org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_GET;
040 import static org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_SET;
041
042 /**
043 * This class contains some code related to BindingContext use. Intention is not to pollute other classes.
044 * Every call to BindingContext.get() is supposed to be wrapped by this utility class.
045 */
046 public final class BindingUtils {
047
048 private BindingUtils() {
049 }
050
051 @NotNull
052 static private <E extends PsiElement, D extends DeclarationDescriptor>
053 D getDescriptorForExpression(@NotNull BindingContext context, @NotNull E expression, Class<D> descriptorClass) {
054 DeclarationDescriptor descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression);
055 assert descriptor != null;
056 assert descriptorClass.isInstance(descriptor)
057 : message(expression, expression.toString() + " expected to have of type" + descriptorClass.toString());
058 //noinspection unchecked
059 return (D) descriptor;
060 }
061
062 @NotNull
063 public static ClassDescriptor getClassDescriptor(@NotNull BindingContext context,
064 @NotNull KtClassOrObject declaration) {
065 return BindingContextUtils.getNotNull(context, BindingContext.CLASS, declaration);
066 }
067
068 @NotNull
069 public static FunctionDescriptor getFunctionDescriptor(@NotNull BindingContext context,
070 @NotNull KtDeclarationWithBody declaration) {
071 return getDescriptorForExpression(context, declaration, FunctionDescriptor.class);
072 }
073
074 @NotNull
075 public static PropertyDescriptor getPropertyDescriptor(@NotNull BindingContext context,
076 @NotNull KtProperty declaration) {
077 return getDescriptorForExpression(context, declaration, PropertyDescriptor.class);
078 }
079
080 @NotNull
081 private static KtParameter getParameterForDescriptor(@NotNull ValueParameterDescriptor descriptor) {
082 PsiElement result = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
083 assert result instanceof KtParameter : message(descriptor, "ValueParameterDescriptor should have corresponding JetParameter");
084 return (KtParameter) result;
085 }
086
087 public static boolean hasAncestorClass(@NotNull BindingContext context, @NotNull KtClassOrObject classDeclaration) {
088 ClassDescriptor classDescriptor = getClassDescriptor(context, classDeclaration);
089 List<ClassDescriptor> superclassDescriptors = DescriptorUtils.getSuperclassDescriptors(classDescriptor);
090 return (JsDescriptorUtils.findAncestorClass(superclassDescriptors) != null);
091 }
092
093 @NotNull
094 public static KotlinType getTypeByReference(@NotNull BindingContext context,
095 @NotNull KtTypeReference typeReference) {
096 return BindingContextUtils.getNotNull(context, BindingContext.TYPE, typeReference);
097 }
098
099 @Nullable
100 public static PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
101 @NotNull KtParameter parameter) {
102 return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
103 }
104
105 @Nullable
106 public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
107 @NotNull KtReferenceExpression reference) {
108 if (BindingContextUtils.isExpressionWithValidReference(reference, context)) {
109 return resolveObjectViaTypeAlias(BindingContextUtils.getNotNull(context, BindingContext.REFERENCE_TARGET, reference));
110 }
111 return null;
112 }
113
114 @Nullable
115 private static DeclarationDescriptor getNullableDescriptorForReferenceExpression(@NotNull BindingContext context,
116 @NotNull KtReferenceExpression reference) {
117 DeclarationDescriptor descriptor = context.get(BindingContext.REFERENCE_TARGET, reference);
118 return descriptor != null ? resolveObjectViaTypeAlias(descriptor) : null;
119 }
120
121 @NotNull
122 private static DeclarationDescriptor resolveObjectViaTypeAlias(@NotNull DeclarationDescriptor descriptor) {
123 if (descriptor instanceof TypeAliasDescriptor) {
124 ClassDescriptor classDescriptor = ((TypeAliasDescriptor) descriptor).getClassDescriptor();
125 assert classDescriptor != null : "Class descriptor must be non-null in resolved typealias: " + descriptor;
126 if (classDescriptor.getKind() != ClassKind.OBJECT && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
127 classDescriptor = classDescriptor.getCompanionObjectDescriptor();
128 assert classDescriptor != null : "Resolved typealias must have non-null class descriptor: " + descriptor;
129 }
130 return classDescriptor;
131 }
132 else {
133 return descriptor;
134 }
135 }
136
137 public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull KtExpression expression) {
138 return BindingContextUtils.getNotNull(context, BindingContext.VARIABLE_REASSIGNMENT, expression);
139 }
140
141 @Nullable
142 public static CallableDescriptor getCallableDescriptorForOperationExpression(
143 @NotNull BindingContext context,
144 @NotNull KtOperationExpression expression
145 ) {
146 KtSimpleNameExpression operationReference = expression.getOperationReference();
147 DeclarationDescriptor descriptorForReferenceExpression =
148 getNullableDescriptorForReferenceExpression(context, operationReference);
149
150 if (descriptorForReferenceExpression == null) return null;
151
152 assert descriptorForReferenceExpression instanceof CallableDescriptor :
153 message(operationReference, "Operation should resolve to callable descriptor");
154 return (CallableDescriptor) descriptorForReferenceExpression;
155 }
156
157 @NotNull
158 public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
159 @NotNull PsiElement element) {
160 return BindingContextUtils.getNotNull(context, BindingContext.DECLARATION_TO_DESCRIPTOR, element);
161 }
162
163 @Nullable
164 public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull KtExpression expression) {
165 CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, context);
166 if (compileTimeValue != null) {
167 return getCompileTimeValue(context, expression, compileTimeValue);
168 }
169 return null;
170 }
171
172 @Nullable
173 public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull KtExpression expression, @NotNull CompileTimeConstant<?> constant) {
174 KotlinType expectedType = context.getType(expression);
175 return constant.getValue(expectedType == null ? TypeUtils.NO_EXPECTED_TYPE : expectedType);
176 }
177
178 @NotNull
179 public static KtExpression getDefaultArgument(@NotNull ValueParameterDescriptor parameterDescriptor) {
180 ValueParameterDescriptor descriptorWhichDeclaresDefaultValue =
181 getOriginalDescriptorWhichDeclaresDefaultValue(parameterDescriptor);
182 KtParameter psiParameter = getParameterForDescriptor(descriptorWhichDeclaresDefaultValue);
183 KtExpression defaultValue = psiParameter.getDefaultValue();
184 assert defaultValue != null : message(parameterDescriptor, "No default value found in PSI");
185 return defaultValue;
186 }
187
188 private static ValueParameterDescriptor getOriginalDescriptorWhichDeclaresDefaultValue(
189 @NotNull ValueParameterDescriptor parameterDescriptor
190 ) {
191 ValueParameterDescriptor result = parameterDescriptor;
192 assert DescriptorUtilsKt.hasDefaultValue(result) : message(parameterDescriptor, "Unsupplied parameter must have default value");
193 // TODO: this seems incorrect, as the default value may come from _not the first_ overridden parameter
194 while (!result.declaresDefaultValue()) {
195 result = result.getOverriddenDescriptors().iterator().next();
196 }
197 return result;
198 }
199
200 @NotNull
201 public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
202 @NotNull KtExpression rangeExpression) {
203 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
204 }
205
206 @NotNull
207 public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
208 @NotNull KtExpression rangeExpression) {
209 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
210 }
211
212 @NotNull
213 public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
214 @NotNull KtExpression rangeExpression) {
215 return BindingContextUtils.getNotNull(context, BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
216 }
217
218 @NotNull
219 public static KotlinType getTypeForExpression(@NotNull BindingContext context,
220 @NotNull KtExpression expression) {
221 return BindingContextUtils.getTypeNotNull(context, expression);
222 }
223
224 @NotNull
225 public static ResolvedCall<FunctionDescriptor> getResolvedCallForArrayAccess(@NotNull BindingContext context,
226 @NotNull KtArrayAccessExpression arrayAccessExpression,
227 boolean isGet) {
228 return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression);
229 }
230
231
232 @Nullable
233 @SuppressWarnings("unchecked")
234 public static ResolvedCall<FunctionDescriptor> getSuperCall(@NotNull BindingContext context, KtClassOrObject classDeclaration) {
235 for (KtSuperTypeListEntry specifier : classDeclaration.getSuperTypeListEntries()) {
236 if (specifier instanceof KtSuperTypeCallEntry) {
237 KtSuperTypeCallEntry superCall = (KtSuperTypeCallEntry) specifier;
238 return (ResolvedCall<FunctionDescriptor>) CallUtilKt.getResolvedCallWithAssert(superCall, context);
239 }
240 }
241 return null;
242 }
243 }