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 }