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    }