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.KotlinTypeInfo;
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 KotlinTypeInfo 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 KotlinTypeInfo 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 }