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