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 org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.descriptors.*;
026    import org.jetbrains.kotlin.psi.*;
027    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
028    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
029    import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
030    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
031    import org.jetbrains.kotlin.types.JetType;
032    import org.jetbrains.kotlin.types.TypeUtils;
033    import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
034    import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
035    import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice;
036    
037    import java.util.Collection;
038    
039    import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
040    import static org.jetbrains.kotlin.diagnostics.Errors.AMBIGUOUS_LABEL;
041    import static org.jetbrains.kotlin.resolve.BindingContext.*;
042    
043    public class BindingContextUtils {
044        private BindingContextUtils() {
045        }
046    
047        @Nullable
048        public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
049            DeclarationDescriptor descriptor = null;
050            if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) {
051                descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
052            }
053            else if (element instanceof JetSimpleNameExpression) {
054                descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
055            }
056            else if (element instanceof JetQualifiedExpression) {
057                descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
058            }
059            if (descriptor instanceof VariableDescriptor) {
060                return (VariableDescriptor) descriptor;
061            }
062            return null;
063        }
064    
065        public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
066                @NotNull PsiElement psiElement, @NotNull SimpleFunctionDescriptor function) {
067    
068            if (function.getKind() != DECLARATION) {
069                throw new IllegalArgumentException("function of kind " + function.getKind() + " cannot have declaration");
070            }
071    
072            trace.record(BindingContext.FUNCTION, psiElement, function);
073        }
074    
075        @NotNull
076        public static <K, V> V getNotNull(
077            @NotNull BindingContext bindingContext,
078            @NotNull ReadOnlySlice<K, V> slice,
079            @NotNull K key
080        ) {
081            return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
082        }
083    
084        @NotNull
085        public static JetType getTypeNotNull(
086                @NotNull BindingContext bindingContext,
087                @NotNull JetExpression expression
088        ) {
089            JetType result = bindingContext.getType(expression);
090            if (result == null) {
091                throw new IllegalStateException("Type must be not null for " + expression);
092            }
093            return result;
094        }
095    
096        @NotNull
097        public static <K, V> V getNotNull(
098                @NotNull BindingContext bindingContext,
099                @NotNull ReadOnlySlice<K, V> slice,
100                @NotNull K key,
101                @NotNull String messageIfNull
102        ) {
103            V value = bindingContext.get(slice, key);
104            if (value == null) {
105                throw new IllegalStateException(messageIfNull);
106            }
107            return value;
108        }
109    
110        @NotNull
111        public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
112            JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
113            if (declaration instanceof JetFunctionLiteral) {
114                return getEnclosingDescriptor(context, declaration);
115            }
116            DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
117            assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
118            return descriptor;
119        }
120    
121        public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
122            JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
123            return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
124        }
125    
126        public static void reportAmbiguousLabel(
127                @NotNull BindingTrace trace,
128                @NotNull JetSimpleNameExpression targetLabel,
129                @NotNull Collection<DeclarationDescriptor> declarationsByLabel
130        ) {
131            Collection<PsiElement> targets = Lists.newArrayList();
132            for (DeclarationDescriptor descriptor : declarationsByLabel) {
133                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
134                assert element != null : "Label can only point to something in the same lexical scope";
135                targets.add(element);
136            }
137            if (!targets.isEmpty()) {
138                trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
139            }
140            trace.report(AMBIGUOUS_LABEL.on(targetLabel));
141        }
142    
143        @Nullable
144        public static JetType updateRecordedType(
145                @Nullable JetType type,
146                @NotNull JetExpression expression,
147                @NotNull BindingTrace trace,
148                boolean shouldBeMadeNullable
149        ) {
150            if (type == null) return null;
151            if (shouldBeMadeNullable) {
152                type = TypeUtils.makeNullable(type);
153            }
154            trace.recordType(expression, type);
155            return type;
156        }
157    
158        @Nullable
159        public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
160            // noinspection ConstantConditions
161            if (!context.get(BindingContext.PROCESSED, expression)) return null;
162            // NB: should never return null if expression is already processed
163            JetTypeInfo result = context.get(BindingContext.EXPRESSION_TYPE_INFO, expression);
164            return result != null ? result : TypeInfoFactoryPackage.noTypeInfo(DataFlowInfo.EMPTY);
165        }
166    
167        public static boolean isExpressionWithValidReference(
168                @NotNull JetExpression expression,
169                @NotNull BindingContext context
170        ) {
171            if (expression instanceof JetCallExpression) {
172                ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context);
173                return resolvedCall instanceof VariableAsFunctionResolvedCall;
174            }
175            return expression instanceof JetReferenceExpression;
176        }
177    
178        public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
179            if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
180            VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
181            return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
182        }
183    
184        @NotNull
185        public static Pair<FunctionDescriptor, PsiElement> getContainingFunctionSkipFunctionLiterals(
186                @Nullable DeclarationDescriptor startDescriptor,
187                boolean strict
188        ) {
189            FunctionDescriptor containingFunctionDescriptor = DescriptorUtils.getParentOfType(startDescriptor, FunctionDescriptor.class, strict);
190            PsiElement containingFunction =
191                    containingFunctionDescriptor != null ? DescriptorToSourceUtils.getSourceFromDescriptor(containingFunctionDescriptor) : null;
192            while (containingFunction instanceof JetFunctionLiteral) {
193                containingFunctionDescriptor = DescriptorUtils.getParentOfType(containingFunctionDescriptor, FunctionDescriptor.class);
194                containingFunction = containingFunctionDescriptor != null ? DescriptorToSourceUtils
195                        .getSourceFromDescriptor(containingFunctionDescriptor) : null;
196            }
197    
198            return new Pair<FunctionDescriptor, PsiElement>(containingFunctionDescriptor, containingFunction);
199        }
200    
201        @Nullable
202        public static ResolvedCall<ConstructorDescriptor> getDelegationConstructorCall(
203                @NotNull BindingContext bindingContext,
204                @NotNull ConstructorDescriptor constructorDescriptor
205        ) {
206            return bindingContext.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructorDescriptor);
207        }
208    }