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