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