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