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