001    /*
002     * Copyright 2010-2015 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.kotlin.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 kotlin.jvm.functions.Function3;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.kotlin.descriptors.*;
027    import org.jetbrains.kotlin.diagnostics.Diagnostic;
028    import org.jetbrains.kotlin.psi.*;
029    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
030    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
031    import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
032    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
033    import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression;
034    import org.jetbrains.kotlin.types.JetType;
035    import org.jetbrains.kotlin.types.TypeUtils;
036    import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
037    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
038    import org.jetbrains.kotlin.util.slicedMap.MutableSlicedMap;
039    import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
040    import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
041    
042    import java.util.Collection;
043    
044    import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
045    import static org.jetbrains.kotlin.diagnostics.Errors.AMBIGUOUS_LABEL;
046    import static org.jetbrains.kotlin.resolve.BindingContext.*;
047    
048    public class BindingContextUtils {
049        private BindingContextUtils() {
050        }
051    
052        @Nullable
053        public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
054            DeclarationDescriptor descriptor = null;
055            if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) {
056                descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
057            }
058            else if (element instanceof JetSimpleNameExpression) {
059                descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
060            }
061            else if (element instanceof JetQualifiedExpression) {
062                descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
063            }
064            if (descriptor instanceof VariableDescriptor) {
065                return (VariableDescriptor) descriptor;
066            }
067            return null;
068        }
069    
070        public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
071                @NotNull PsiElement psiElement, @NotNull SimpleFunctionDescriptor function) {
072    
073            if (function.getKind() != DECLARATION) {
074                throw new IllegalArgumentException("function of kind " + function.getKind() + " cannot have declaration");
075            }
076    
077            trace.record(BindingContext.FUNCTION, psiElement, function);
078        }
079    
080        @NotNull
081        public static <K, V> V getNotNull(
082            @NotNull BindingContext bindingContext,
083            @NotNull ReadOnlySlice<K, V> slice,
084            @NotNull K key
085        ) {
086            return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
087        }
088    
089        @NotNull
090        public static JetType getTypeNotNull(
091                @NotNull BindingContext bindingContext,
092                @NotNull JetExpression expression
093        ) {
094            JetType result = bindingContext.getType(expression);
095            if (result == null) {
096                throw new IllegalStateException("Type must be not null for " + expression);
097            }
098            return result;
099        }
100    
101        @NotNull
102        public static <K, V> V getNotNull(
103                @NotNull BindingContext bindingContext,
104                @NotNull ReadOnlySlice<K, V> slice,
105                @NotNull K key,
106                @NotNull String messageIfNull
107        ) {
108            V value = bindingContext.get(slice, key);
109            if (value == null) {
110                throw new IllegalStateException(messageIfNull);
111            }
112            return value;
113        }
114    
115        @NotNull
116        public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
117            JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
118            if (declaration instanceof JetFunctionLiteral) {
119                return getEnclosingDescriptor(context, declaration);
120            }
121            DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
122            assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
123            return descriptor;
124        }
125    
126        public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
127            JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
128            return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
129        }
130    
131        public static void reportAmbiguousLabel(
132                @NotNull BindingTrace trace,
133                @NotNull JetSimpleNameExpression targetLabel,
134                @NotNull Collection<DeclarationDescriptor> declarationsByLabel
135        ) {
136            Collection<PsiElement> targets = Lists.newArrayList();
137            for (DeclarationDescriptor descriptor : declarationsByLabel) {
138                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
139                assert element != null : "Label can only point to something in the same lexical scope";
140                targets.add(element);
141            }
142            if (!targets.isEmpty()) {
143                trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
144            }
145            trace.report(AMBIGUOUS_LABEL.on(targetLabel));
146        }
147    
148        @Nullable
149        public static JetType updateRecordedType(
150                @Nullable JetType type,
151                @NotNull JetExpression expression,
152                @NotNull BindingTrace trace,
153                boolean shouldBeMadeNullable
154        ) {
155            if (type == null) return null;
156            if (shouldBeMadeNullable) {
157                type = TypeUtils.makeNullable(type);
158            }
159            trace.recordType(expression, type);
160            return type;
161        }
162    
163        @Nullable
164        public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
165            // noinspection ConstantConditions
166            if (!context.get(BindingContext.PROCESSED, expression)) return null;
167            // NB: should never return null if expression is already processed
168            JetTypeInfo result = context.get(BindingContext.EXPRESSION_TYPE_INFO, expression);
169            return result != null ? result : TypeInfoFactoryPackage.noTypeInfo(DataFlowInfo.EMPTY);
170        }
171    
172        public static boolean isExpressionWithValidReference(
173                @NotNull JetExpression expression,
174                @NotNull BindingContext context
175        ) {
176            if (expression instanceof JetCallExpression) {
177                ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
178                return resolvedCall instanceof VariableAsFunctionResolvedCall;
179            }
180            return expression instanceof JetReferenceExpression;
181        }
182    
183        public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
184            if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
185            VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
186            return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
187        }
188    
189        @NotNull
190        public static Pair<FunctionDescriptor, PsiElement> getContainingFunctionSkipFunctionLiterals(
191                @Nullable DeclarationDescriptor startDescriptor,
192                boolean strict
193        ) {
194            FunctionDescriptor containingFunctionDescriptor = DescriptorUtils.getParentOfType(startDescriptor, FunctionDescriptor.class, strict);
195            PsiElement containingFunction =
196                    containingFunctionDescriptor != null ? DescriptorToSourceUtils.getSourceFromDescriptor(containingFunctionDescriptor) : null;
197            while (containingFunction instanceof JetFunctionLiteral) {
198                containingFunctionDescriptor = DescriptorUtils.getParentOfType(containingFunctionDescriptor, FunctionDescriptor.class);
199                containingFunction = containingFunctionDescriptor != null ? DescriptorToSourceUtils
200                        .getSourceFromDescriptor(containingFunctionDescriptor) : null;
201            }
202    
203            return new Pair<FunctionDescriptor, PsiElement>(containingFunctionDescriptor, containingFunction);
204        }
205    
206        @Nullable
207        public static ResolvedCall<ConstructorDescriptor> getDelegationConstructorCall(
208                @NotNull BindingContext bindingContext,
209                @NotNull ConstructorDescriptor constructorDescriptor
210        ) {
211            return bindingContext.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructorDescriptor);
212        }
213    
214        static void addOwnDataTo(
215                @NotNull final BindingTrace trace, @Nullable final TraceEntryFilter filter, boolean commitDiagnostics,
216                @NotNull MutableSlicedMap map, MutableDiagnosticsWithSuppression diagnostics
217        ) {
218            map.forEach(new Function3<WritableSlice, Object, Object, Void>() {
219                @Override
220                public Void invoke(WritableSlice slice, Object key, Object value) {
221                    if (filter == null || filter.accept(slice, key)) {
222                        trace.record(slice, key, value);
223                    }
224    
225                    return null;
226                }
227            });
228    
229            if (!commitDiagnostics) return;
230    
231            for (Diagnostic diagnostic : diagnostics.getOwnDiagnostics()) {
232                if (filter == null || filter.accept(null, diagnostic.getPsiElement())) {
233                    trace.report(diagnostic);
234                }
235            }
236    
237        }
238    }