001    /*
002     * Copyright 2010-2014 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.intellij.openapi.util.Pair;
021    import com.intellij.psi.PsiElement;
022    import com.intellij.psi.util.PsiTreeUtil;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.jet.lang.descriptors.*;
026    import org.jetbrains.jet.lang.psi.*;
027    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
028    import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
029    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
030    import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
031    import org.jetbrains.jet.lang.types.JetType;
032    import org.jetbrains.jet.lang.types.JetTypeInfo;
033    import org.jetbrains.jet.lang.types.TypeUtils;
034    import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
035    
036    import java.util.Collection;
037    
038    import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
039    import static org.jetbrains.jet.lang.diagnostics.Errors.AMBIGUOUS_LABEL;
040    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
041    
042    public class BindingContextUtils {
043        private BindingContextUtils() {
044        }
045    
046        @Nullable
047        public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
048            DeclarationDescriptor descriptor = null;
049            if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) {
050                descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
051            }
052            else if (element instanceof JetSimpleNameExpression) {
053                descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
054            }
055            else if (element instanceof JetQualifiedExpression) {
056                descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
057            }
058            if (descriptor instanceof VariableDescriptor) {
059                return (VariableDescriptor) descriptor;
060            }
061            return null;
062        }
063    
064        public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
065                @NotNull PsiElement psiElement, @NotNull SimpleFunctionDescriptor function) {
066    
067            if (function.getKind() != DECLARATION) {
068                throw new IllegalArgumentException("function of kind " + function.getKind() + " cannot have declaration");
069            }
070    
071            trace.record(BindingContext.FUNCTION, psiElement, function);
072        }
073    
074        @NotNull
075        public static <K, V> V getNotNull(
076            @NotNull BindingContext bindingContext,
077            @NotNull ReadOnlySlice<K, V> slice,
078            @NotNull K key
079        ) {
080            return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
081        }
082    
083        @NotNull
084        public static <K, V> V getNotNull(
085                @NotNull BindingContext bindingContext,
086                @NotNull ReadOnlySlice<K, V> slice,
087                @NotNull K key,
088                @NotNull String messageIfNull
089        ) {
090            V value = bindingContext.get(slice, key);
091            if (value == null) {
092                throw new IllegalStateException(messageIfNull);
093            }
094            return value;
095        }
096    
097        @NotNull
098        public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
099            JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
100            if (declaration instanceof JetFunctionLiteral) {
101                return getEnclosingDescriptor(context, declaration);
102            }
103            DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
104            assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
105            return descriptor;
106        }
107    
108        public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
109            JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
110            return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
111        }
112    
113        public static void reportAmbiguousLabel(
114                @NotNull BindingTrace trace,
115                @NotNull JetSimpleNameExpression targetLabel,
116                @NotNull Collection<DeclarationDescriptor> declarationsByLabel
117        ) {
118            Collection<PsiElement> targets = Lists.newArrayList();
119            for (DeclarationDescriptor descriptor : declarationsByLabel) {
120                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
121                assert element != null : "Label can only point to something in the same lexical scope";
122                targets.add(element);
123            }
124            if (!targets.isEmpty()) {
125                trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
126            }
127            trace.report(AMBIGUOUS_LABEL.on(targetLabel));
128        }
129    
130        @Nullable
131        public static JetType updateRecordedType(
132                @Nullable JetType type,
133                @NotNull JetExpression expression,
134                @NotNull BindingTrace trace,
135                boolean shouldBeMadeNullable
136        ) {
137            if (type == null) return null;
138            if (shouldBeMadeNullable) {
139                type = TypeUtils.makeNullable(type);
140            }
141            trace.record(BindingContext.EXPRESSION_TYPE, expression, type);
142            return type;
143        }
144    
145        @Nullable
146        public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
147            if (!context.get(BindingContext.PROCESSED, expression)) return null;
148            DataFlowInfo dataFlowInfo = context.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression);
149            if (dataFlowInfo == null) {
150                dataFlowInfo = DataFlowInfo.EMPTY;
151            }
152            JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
153            return JetTypeInfo.create(type, dataFlowInfo);
154        }
155    
156        public static boolean isExpressionWithValidReference(
157                @NotNull JetExpression expression,
158                @NotNull BindingContext context
159        ) {
160            if (expression instanceof JetCallExpression) {
161                ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
162                return resolvedCall instanceof VariableAsFunctionResolvedCall;
163            }
164            return expression instanceof JetReferenceExpression;
165        }
166    
167        public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
168            if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
169            VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
170            return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
171        }
172    
173        @NotNull
174        public static Pair<FunctionDescriptor, PsiElement> getContainingFunctionSkipFunctionLiterals(
175                @Nullable DeclarationDescriptor startDescriptor,
176                boolean strict
177        ) {
178            FunctionDescriptor containingFunctionDescriptor = DescriptorUtils.getParentOfType(startDescriptor, FunctionDescriptor.class, strict);
179            PsiElement containingFunction =
180                    containingFunctionDescriptor != null ? DescriptorToSourceUtils.callableDescriptorToDeclaration(containingFunctionDescriptor) : null;
181            while (containingFunction instanceof JetFunctionLiteral) {
182                containingFunctionDescriptor = DescriptorUtils.getParentOfType(containingFunctionDescriptor, FunctionDescriptor.class);
183                containingFunction = containingFunctionDescriptor != null ? DescriptorToSourceUtils
184                        .callableDescriptorToDeclaration(containingFunctionDescriptor) : null;
185            }
186    
187            return new Pair<FunctionDescriptor, PsiElement>(containingFunctionDescriptor, containingFunction);
188        }
189    
190    }