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