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 }