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    }