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        public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull KtElement element) {
129            KtFunction function = PsiTreeUtil.getParentOfType(element, KtFunction.class);
130            return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
131        }
132    
133        public static void reportAmbiguousLabel(
134                @NotNull BindingTrace trace,
135                @NotNull KtSimpleNameExpression targetLabel,
136                @NotNull Collection<DeclarationDescriptor> declarationsByLabel
137        ) {
138            Collection<PsiElement> targets = Lists.newArrayList();
139            for (DeclarationDescriptor descriptor : declarationsByLabel) {
140                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
141                assert element != null : "Label can only point to something in the same lexical scope";
142                targets.add(element);
143            }
144            if (!targets.isEmpty()) {
145                trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
146            }
147            trace.report(AMBIGUOUS_LABEL.on(targetLabel));
148        }
149    
150        @Nullable
151        public static KotlinType updateRecordedType(
152                @Nullable KotlinType type,
153                @NotNull KtExpression expression,
154                @NotNull BindingTrace trace,
155                boolean shouldBeMadeNullable
156        ) {
157            if (type == null) return null;
158            if (shouldBeMadeNullable) {
159                type = TypeUtils.makeNullable(type);
160            }
161            trace.recordType(expression, type);
162            return type;
163        }
164    
165        @Nullable
166        public static KotlinTypeInfo getRecordedTypeInfo(@NotNull KtExpression expression, @NotNull BindingContext context) {
167            // noinspection ConstantConditions
168            if (!context.get(BindingContext.PROCESSED, expression)) return null;
169            // NB: should never return null if expression is already processed
170            KotlinTypeInfo result = context.get(BindingContext.EXPRESSION_TYPE_INFO, expression);
171            return result != null ? result : TypeInfoFactoryKt.noTypeInfo(DataFlowInfoFactory.EMPTY);
172        }
173    
174        public static boolean isExpressionWithValidReference(
175                @NotNull KtExpression expression,
176                @NotNull BindingContext context
177        ) {
178            if (expression instanceof KtCallExpression) {
179                ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, context);
180                return resolvedCall instanceof VariableAsFunctionResolvedCall;
181            }
182            return expression instanceof KtReferenceExpression;
183        }
184    
185        public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
186            if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
187            VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
188            return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
189        }
190    
191        @NotNull
192        public static Pair<FunctionDescriptor, PsiElement> getContainingFunctionSkipFunctionLiterals(
193                @Nullable DeclarationDescriptor startDescriptor,
194                boolean strict
195        ) {
196            FunctionDescriptor containingFunctionDescriptor = DescriptorUtils.getParentOfType(startDescriptor, FunctionDescriptor.class, strict);
197            PsiElement containingFunction =
198                    containingFunctionDescriptor != null ? DescriptorToSourceUtils.getSourceFromDescriptor(containingFunctionDescriptor) : null;
199            while (containingFunction instanceof KtFunctionLiteral) {
200                containingFunctionDescriptor = DescriptorUtils.getParentOfType(containingFunctionDescriptor, FunctionDescriptor.class);
201                containingFunction = containingFunctionDescriptor != null ? DescriptorToSourceUtils
202                        .getSourceFromDescriptor(containingFunctionDescriptor) : null;
203            }
204    
205            return new Pair<FunctionDescriptor, PsiElement>(containingFunctionDescriptor, containingFunction);
206        }
207    
208        @Nullable
209        public static ResolvedCall<ConstructorDescriptor> getDelegationConstructorCall(
210                @NotNull BindingContext bindingContext,
211                @NotNull ConstructorDescriptor constructorDescriptor
212        ) {
213            return bindingContext.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructorDescriptor);
214        }
215    
216        static void addOwnDataTo(
217                @NotNull final BindingTrace trace, @Nullable final TraceEntryFilter filter, boolean commitDiagnostics,
218                @NotNull MutableSlicedMap map, MutableDiagnosticsWithSuppression diagnostics
219        ) {
220            map.forEach(new Function3<WritableSlice, Object, Object, Void>() {
221                @Override
222                public Void invoke(WritableSlice slice, Object key, Object value) {
223                    if (filter == null || filter.accept(slice, key)) {
224                        trace.record(slice, key, value);
225                    }
226    
227                    return null;
228                }
229            });
230    
231            if (!commitDiagnostics) return;
232    
233            for (Diagnostic diagnostic : diagnostics.getOwnDiagnostics()) {
234                if (filter == null || filter.accept(null, diagnostic.getPsiElement())) {
235                    trace.report(diagnostic);
236                }
237            }
238    
239        }
240    }