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.jet.lang.resolve;
018
019 import com.google.common.collect.Lists;
020 import com.google.common.collect.Sets;
021 import com.intellij.openapi.util.text.StringUtil;
022 import com.intellij.psi.PsiElement;
023 import com.intellij.psi.PsiFile;
024 import com.intellij.psi.util.PsiTreeUtil;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.jet.lang.descriptors.*;
028 import org.jetbrains.jet.lang.psi.*;
029 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
030 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
031 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
032 import org.jetbrains.jet.lang.types.JetType;
033 import org.jetbrains.jet.lang.types.JetTypeInfo;
034 import org.jetbrains.jet.lang.types.TypeUtils;
035 import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
036 import org.jetbrains.jet.util.slicedmap.Slices;
037
038 import java.util.*;
039
040 import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.*;
041 import static org.jetbrains.jet.lang.diagnostics.Errors.AMBIGUOUS_LABEL;
042 import static org.jetbrains.jet.lang.resolve.BindingContext.*;
043
044 public class BindingContextUtils {
045 private BindingContextUtils() {
046 }
047
048 private static final Slices.KeyNormalizer<DeclarationDescriptor> DECLARATION_DESCRIPTOR_NORMALIZER = new Slices.KeyNormalizer<DeclarationDescriptor>() {
049 @Override
050 public DeclarationDescriptor normalize(DeclarationDescriptor declarationDescriptor) {
051 if (declarationDescriptor instanceof CallableMemberDescriptor) {
052 CallableMemberDescriptor callable = (CallableMemberDescriptor) declarationDescriptor;
053 if (callable.getKind() != DECLARATION) {
054 throw new IllegalStateException("non-declaration descriptors should be filtered out earlier: " + callable);
055 }
056 }
057 //if (declarationDescriptor instanceof VariableAsFunctionDescriptor) {
058 // VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) declarationDescriptor;
059 // if (descriptor.getOriginal() != descriptor) {
060 // throw new IllegalStateException("original should be resolved earlier: " + descriptor);
061 // }
062 //}
063 return declarationDescriptor.getOriginal();
064 }
065 };
066
067 /*package*/ static final ReadOnlySlice<DeclarationDescriptor, PsiElement> DESCRIPTOR_TO_DECLARATION =
068 Slices.<DeclarationDescriptor, PsiElement>sliceBuilder().setKeyNormalizer(DECLARATION_DESCRIPTOR_NORMALIZER).setDebugName("DESCRIPTOR_TO_DECLARATION").build();
069
070 @Nullable
071 public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
072 DeclarationDescriptor descriptor = null;
073 if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) {
074 descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
075 }
076 else if (element instanceof JetSimpleNameExpression) {
077 descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
078 }
079 else if (element instanceof JetQualifiedExpression) {
080 descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
081 }
082 if (descriptor instanceof VariableDescriptor) {
083 return (VariableDescriptor) descriptor;
084 }
085 return null;
086 }
087
088 @Nullable
089 public static JetFile getContainingFile(@NotNull BindingContext context, @NotNull DeclarationDescriptor declarationDescriptor) {
090 // declarationDescriptor may describe a synthesized element which doesn't have PSI
091 // To workaround that, we find a top-level parent (which is inside a PackageFragmentDescriptor), which is guaranteed to have PSI
092 DeclarationDescriptor descriptor = DescriptorUtils.findTopLevelParent(declarationDescriptor);
093 if (descriptor == null) return null;
094
095 PsiElement declaration = descriptorToDeclaration(context, descriptor);
096 if (declaration == null) return null;
097
098 PsiFile containingFile = declaration.getContainingFile();
099 if (!(containingFile instanceof JetFile)) return null;
100 return (JetFile) containingFile;
101 }
102
103 @Nullable
104 private static PsiElement doGetDescriptorToDeclaration(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
105 return context.get(DESCRIPTOR_TO_DECLARATION, descriptor);
106 }
107
108 // NOTE this is also used by KDoc
109 @Nullable
110 public static PsiElement descriptorToDeclaration(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
111 if (descriptor instanceof CallableMemberDescriptor) {
112 return callableDescriptorToDeclaration(context, (CallableMemberDescriptor) descriptor);
113 }
114 else if (descriptor instanceof ClassDescriptor) {
115 return classDescriptorToDeclaration(context, (ClassDescriptor) descriptor);
116 }
117 else {
118 return doGetDescriptorToDeclaration(context, descriptor);
119 }
120 }
121
122 @NotNull
123 public static List<PsiElement> descriptorToDeclarations(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
124 if (descriptor instanceof CallableMemberDescriptor) {
125 return callableDescriptorToDeclarations(context, (CallableMemberDescriptor) descriptor);
126 }
127 else {
128 PsiElement psiElement = descriptorToDeclaration(context, descriptor);
129 if (psiElement != null) {
130 return Lists.newArrayList(psiElement);
131 } else {
132 return Lists.newArrayList();
133 }
134 }
135 }
136
137 @Nullable
138 public static PsiElement callableDescriptorToDeclaration(@NotNull BindingContext context, @NotNull CallableMemberDescriptor callable) {
139 if (callable.getKind() == SYNTHESIZED) {
140 CallableMemberDescriptor original = callable.getOriginal();
141 if (original instanceof SynthesizedCallableMemberDescriptor<?>) {
142 DeclarationDescriptor base = ((SynthesizedCallableMemberDescriptor<?>) original).getBaseForSynthesized();
143 return descriptorToDeclaration(context, base);
144 }
145 return null;
146 }
147
148 if (callable.getKind() == DECLARATION) {
149 return doGetDescriptorToDeclaration(context, callable.getOriginal());
150 }
151
152 Set<? extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
153 if (overriddenDescriptors.size() != 1) {
154 throw new IllegalStateException(
155 "Cannot find declaration: fake descriptor " + callable + " has more than one overridden descriptor:\n" +
156 StringUtil.join(overriddenDescriptors, ",\n"));
157 }
158
159 return callableDescriptorToDeclaration(context, overriddenDescriptors.iterator().next());
160 }
161
162 @NotNull
163 public static List<PsiElement> callableDescriptorToDeclarations(
164 @NotNull BindingContext context,
165 @NotNull CallableMemberDescriptor callable
166 ) {
167 if (callable.getKind() == SYNTHESIZED) {
168 CallableMemberDescriptor original = callable.getOriginal();
169 if (original instanceof SynthesizedCallableMemberDescriptor<?>) {
170 DeclarationDescriptor base = ((SynthesizedCallableMemberDescriptor<?>) original).getBaseForSynthesized();
171 return descriptorToDeclarations(context, base);
172 }
173 return Collections.emptyList();
174 }
175
176 if (callable.getKind() == DECLARATION) {
177 PsiElement psiElement = doGetDescriptorToDeclaration(context, callable);
178 return psiElement != null ? Lists.newArrayList(psiElement) : Lists.<PsiElement>newArrayList();
179 }
180
181 List<PsiElement> r = new ArrayList<PsiElement>();
182 Set<? extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
183 for (CallableMemberDescriptor overridden : overriddenDescriptors) {
184 r.addAll(callableDescriptorToDeclarations(context, overridden));
185 }
186 return r;
187 }
188
189 @Nullable
190 public static PsiElement classDescriptorToDeclaration(@NotNull BindingContext context, @NotNull ClassDescriptor clazz) {
191 return doGetDescriptorToDeclaration(context, clazz);
192 }
193
194 public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
195 @NotNull PsiElement psiElement, @NotNull SimpleFunctionDescriptor function) {
196
197 if (function.getKind() != DECLARATION) {
198 throw new IllegalArgumentException("function of kind " + function.getKind() + " cannot have declaration");
199 }
200
201 trace.record(BindingContext.FUNCTION, psiElement, function);
202 }
203
204 @NotNull
205 public static <K, V> V getNotNull(
206 @NotNull BindingContext bindingContext,
207 @NotNull ReadOnlySlice<K, V> slice,
208 @NotNull K key
209 ) {
210 return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
211 }
212
213 @NotNull
214 public static <K, V> V getNotNull(
215 @NotNull BindingContext bindingContext,
216 @NotNull ReadOnlySlice<K, V> slice,
217 @NotNull K key,
218 @NotNull String messageIfNull
219 ) {
220 V value = bindingContext.get(slice, key);
221 if (value == null) {
222 throw new IllegalStateException(messageIfNull);
223 }
224 return value;
225 }
226
227 @NotNull
228 public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
229 JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
230 if (declaration instanceof JetFunctionLiteral) {
231 return getEnclosingDescriptor(context, declaration);
232 }
233 DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
234 assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
235 return descriptor;
236 }
237
238 public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
239 JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
240 return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
241 }
242
243 public static void reportAmbiguousLabel(
244 @NotNull BindingTrace trace,
245 @NotNull JetSimpleNameExpression targetLabel,
246 @NotNull Collection<DeclarationDescriptor> declarationsByLabel
247 ) {
248 Collection<PsiElement> targets = Lists.newArrayList();
249 for (DeclarationDescriptor descriptor : declarationsByLabel) {
250 PsiElement element = descriptorToDeclaration(trace.getBindingContext(), descriptor);
251 assert element != null : "Label can only point to something in the same lexical scope";
252 targets.add(element);
253 }
254 if (!targets.isEmpty()) {
255 trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
256 }
257 trace.report(AMBIGUOUS_LABEL.on(targetLabel));
258 }
259
260 @Nullable
261 public static JetType updateRecordedType(
262 @Nullable JetType type,
263 @NotNull JetExpression expression,
264 @NotNull BindingTrace trace,
265 boolean shouldBeMadeNullable
266 ) {
267 if (type == null) return null;
268 if (shouldBeMadeNullable) {
269 type = TypeUtils.makeNullable(type);
270 }
271 trace.record(BindingContext.EXPRESSION_TYPE, expression, type);
272 return type;
273 }
274
275 @Nullable
276 public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
277 if (!context.get(BindingContext.PROCESSED, expression)) return null;
278 DataFlowInfo dataFlowInfo = context.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression);
279 if (dataFlowInfo == null) {
280 dataFlowInfo = DataFlowInfo.EMPTY;
281 }
282 JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
283 return JetTypeInfo.create(type, dataFlowInfo);
284 }
285
286 public static boolean isExpressionWithValidReference(
287 @NotNull JetExpression expression,
288 @NotNull BindingContext context
289 ) {
290 if (expression instanceof JetCallExpression) {
291 return isCallExpressionWithValidReference(expression, context);
292 }
293
294 return expression instanceof JetReferenceExpression;
295 }
296
297 public static boolean isCallExpressionWithValidReference(
298 @NotNull JetExpression expression,
299 @NotNull BindingContext context
300 ) {
301 if (expression instanceof JetCallExpression) {
302 JetExpression calleeExpression = ((JetCallExpression) expression).getCalleeExpression();
303 ResolvedCall<?> resolvedCall = context.get(BindingContext.RESOLVED_CALL, calleeExpression);
304 if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
305 return true;
306 }
307 }
308 return false;
309 }
310
311 @NotNull
312 public static Set<CallableMemberDescriptor> getDirectlyOverriddenDeclarations(@NotNull CallableMemberDescriptor descriptor) {
313 Set<CallableMemberDescriptor> result = Sets.newHashSet();
314 Set<? extends CallableMemberDescriptor> overriddenDescriptors = descriptor.getOverriddenDescriptors();
315 for (CallableMemberDescriptor overriddenDescriptor : overriddenDescriptors) {
316 CallableMemberDescriptor.Kind kind = overriddenDescriptor.getKind();
317 if (kind == DECLARATION) {
318 result.add(overriddenDescriptor);
319 }
320 else if (kind == FAKE_OVERRIDE || kind == DELEGATION) {
321 result.addAll(getDirectlyOverriddenDeclarations(overriddenDescriptor));
322 }
323 else if (kind == SYNTHESIZED) {
324 //do nothing
325 }
326 else {
327 throw new AssertionError("Unexpected callable kind " + kind);
328 }
329 }
330 return OverridingUtil.filterOutOverridden(result);
331 }
332
333 @NotNull
334 public static Set<FunctionDescriptor> getDirectlyOverriddenDeclarations(@NotNull FunctionDescriptor descriptor) {
335 //noinspection unchecked
336 return (Set) getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor);
337 }
338
339 @NotNull
340 public static Set<PropertyDescriptor> getDirectlyOverriddenDeclarations(@NotNull PropertyDescriptor descriptor) {
341 //noinspection unchecked
342 return (Set) getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor);
343 }
344
345 @NotNull
346 public static <T extends CallableMemberDescriptor> Set<T> getAllOverriddenDeclarations(@NotNull T memberDescriptor) {
347 Set<T> result = Sets.newHashSet();
348 for (CallableMemberDescriptor overriddenDeclaration : memberDescriptor.getOverriddenDescriptors()) {
349 CallableMemberDescriptor.Kind kind = overriddenDeclaration.getKind();
350 if (kind == DECLARATION) {
351 //noinspection unchecked
352 result.add((T) overriddenDeclaration);
353 }
354 else if (kind == DELEGATION || kind == FAKE_OVERRIDE || kind == SYNTHESIZED) {
355 //do nothing
356 }
357 else {
358 throw new AssertionError("Unexpected callable kind " + kind);
359 }
360 //noinspection unchecked
361 result.addAll(getAllOverriddenDeclarations((T) overriddenDeclaration));
362 }
363 return result;
364 }
365
366 public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
367 if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
368 VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
369 return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
370 }
371 }