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