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