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