001 /*
002 * Copyright 2010-2014 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.jet.lang.resolve;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.openapi.util.text.StringUtil;
021 import com.intellij.psi.PsiElement;
022 import com.intellij.psi.PsiFile;
023 import com.intellij.psi.util.PsiTreeUtil;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.*;
027 import org.jetbrains.jet.lang.psi.*;
028 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
029 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
030 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
031 import org.jetbrains.jet.lang.types.JetType;
032 import org.jetbrains.jet.lang.types.JetTypeInfo;
033 import org.jetbrains.jet.lang.types.TypeUtils;
034 import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
035 import org.jetbrains.jet.util.slicedmap.Slices;
036
037 import java.util.*;
038
039 import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
040 import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
041 import static org.jetbrains.jet.lang.diagnostics.Errors.AMBIGUOUS_LABEL;
042 import static org.jetbrains.jet.lang.resolve.BindingContext.*;
043
044 public class BindingContextUtils {
045 private BindingContextUtils() {
046 }
047
048 private static final Slices.KeyNormalizer<DeclarationDescriptor> DECLARATION_DESCRIPTOR_NORMALIZER = new Slices.KeyNormalizer<DeclarationDescriptor>() {
049 @Override
050 public DeclarationDescriptor normalize(DeclarationDescriptor declarationDescriptor) {
051 if (declarationDescriptor instanceof CallableMemberDescriptor) {
052 CallableMemberDescriptor callable = (CallableMemberDescriptor) declarationDescriptor;
053 if (callable.getKind() != DECLARATION) {
054 throw new IllegalStateException("non-declaration descriptors should be filtered out earlier: " + callable);
055 }
056 }
057 //if (declarationDescriptor instanceof VariableAsFunctionDescriptor) {
058 // VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) declarationDescriptor;
059 // if (descriptor.getOriginal() != descriptor) {
060 // throw new IllegalStateException("original should be resolved earlier: " + descriptor);
061 // }
062 //}
063 return declarationDescriptor.getOriginal();
064 }
065 };
066
067 /*package*/ static final ReadOnlySlice<DeclarationDescriptor, PsiElement> DESCRIPTOR_TO_DECLARATION =
068 Slices.<DeclarationDescriptor, PsiElement>sliceBuilder().setKeyNormalizer(DECLARATION_DESCRIPTOR_NORMALIZER).setDebugName("DESCRIPTOR_TO_DECLARATION").build();
069
070 @Nullable
071 public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
072 DeclarationDescriptor descriptor = null;
073 if (!onlyReference && (element instanceof JetVariableDeclaration || element instanceof JetParameter)) {
074 descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
075 }
076 else if (element instanceof JetSimpleNameExpression) {
077 descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
078 }
079 else if (element instanceof JetQualifiedExpression) {
080 descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
081 }
082 if (descriptor instanceof VariableDescriptor) {
083 return (VariableDescriptor) descriptor;
084 }
085 return null;
086 }
087
088 @Nullable
089 public static JetFile getContainingFile(@NotNull BindingContext context, @NotNull DeclarationDescriptor declarationDescriptor) {
090 // declarationDescriptor may describe a synthesized element which doesn't have PSI
091 // To workaround that, we find a top-level parent (which is inside a PackageFragmentDescriptor), which is guaranteed to have PSI
092 DeclarationDescriptor descriptor = findTopLevelParent(declarationDescriptor);
093 if (descriptor == null) return null;
094
095 PsiElement declaration = descriptorToDeclaration(context, descriptor);
096 if (declaration == null) return null;
097
098 PsiFile containingFile = declaration.getContainingFile();
099 if (!(containingFile instanceof JetFile)) return null;
100 return (JetFile) containingFile;
101 }
102
103 @Nullable
104 private static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) {
105 DeclarationDescriptor descriptor = declarationDescriptor;
106 if (declarationDescriptor instanceof PropertyAccessorDescriptor) {
107 descriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
108 }
109 while (!(descriptor == null || DescriptorUtils.isTopLevelDeclaration(descriptor))) {
110 descriptor = descriptor.getContainingDeclaration();
111 }
112 return descriptor;
113 }
114
115 @Nullable
116 private static PsiElement doGetDescriptorToDeclaration(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
117 return context.get(DESCRIPTOR_TO_DECLARATION, descriptor);
118 }
119
120 // NOTE this is also used by KDoc
121 @Nullable
122 public static PsiElement descriptorToDeclaration(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
123 if (descriptor instanceof CallableMemberDescriptor) {
124 return callableDescriptorToDeclaration(context, (CallableMemberDescriptor) descriptor);
125 }
126 else if (descriptor instanceof ClassDescriptor) {
127 return classDescriptorToDeclaration(context, (ClassDescriptor) descriptor);
128 }
129 else {
130 return doGetDescriptorToDeclaration(context, descriptor);
131 }
132 }
133
134 @NotNull
135 public static List<PsiElement> descriptorToDeclarations(@NotNull BindingContext context, @NotNull DeclarationDescriptor descriptor) {
136 if (descriptor instanceof CallableMemberDescriptor) {
137 return callableDescriptorToDeclarations(context, (CallableMemberDescriptor) descriptor);
138 }
139 else {
140 PsiElement psiElement = descriptorToDeclaration(context, descriptor);
141 if (psiElement != null) {
142 return Lists.newArrayList(psiElement);
143 } else {
144 return Lists.newArrayList();
145 }
146 }
147 }
148
149 @Nullable
150 public static PsiElement callableDescriptorToDeclaration(@NotNull BindingContext context, @NotNull CallableMemberDescriptor callable) {
151 if (callable.getKind() == SYNTHESIZED) {
152 CallableMemberDescriptor original = callable.getOriginal();
153 if (original instanceof SynthesizedCallableMemberDescriptor<?>) {
154 DeclarationDescriptor base = ((SynthesizedCallableMemberDescriptor<?>) original).getBaseForSynthesized();
155 return descriptorToDeclaration(context, base);
156 }
157 return null;
158 }
159
160 if (callable.getKind() == DECLARATION) {
161 return doGetDescriptorToDeclaration(context, callable.getOriginal());
162 }
163
164 Set<? extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
165 if (overriddenDescriptors.size() != 1) {
166 throw new IllegalStateException(
167 "Cannot find declaration: fake descriptor " + callable + " has more than one overridden descriptor:\n" +
168 StringUtil.join(overriddenDescriptors, ",\n"));
169 }
170
171 return callableDescriptorToDeclaration(context, overriddenDescriptors.iterator().next());
172 }
173
174 @NotNull
175 public static List<PsiElement> callableDescriptorToDeclarations(
176 @NotNull BindingContext context,
177 @NotNull CallableMemberDescriptor callable
178 ) {
179 if (callable.getKind() == SYNTHESIZED) {
180 CallableMemberDescriptor original = callable.getOriginal();
181 if (original instanceof SynthesizedCallableMemberDescriptor<?>) {
182 DeclarationDescriptor base = ((SynthesizedCallableMemberDescriptor<?>) original).getBaseForSynthesized();
183 return descriptorToDeclarations(context, base);
184 }
185 return Collections.emptyList();
186 }
187
188 if (callable.getKind() == DECLARATION) {
189 PsiElement psiElement = doGetDescriptorToDeclaration(context, callable);
190 return psiElement != null ? Lists.newArrayList(psiElement) : Lists.<PsiElement>newArrayList();
191 }
192
193 List<PsiElement> r = new ArrayList<PsiElement>();
194 Set<? extends CallableMemberDescriptor> overriddenDescriptors = callable.getOverriddenDescriptors();
195 for (CallableMemberDescriptor overridden : overriddenDescriptors) {
196 r.addAll(callableDescriptorToDeclarations(context, overridden));
197 }
198 return r;
199 }
200
201 @Nullable
202 public static PsiElement classDescriptorToDeclaration(@NotNull BindingContext context, @NotNull ClassDescriptor clazz) {
203 return doGetDescriptorToDeclaration(context, clazz);
204 }
205
206 public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
207 @NotNull PsiElement psiElement, @NotNull SimpleFunctionDescriptor function) {
208
209 if (function.getKind() != DECLARATION) {
210 throw new IllegalArgumentException("function of kind " + function.getKind() + " cannot have declaration");
211 }
212
213 trace.record(BindingContext.FUNCTION, psiElement, function);
214 }
215
216 @NotNull
217 public static <K, V> V getNotNull(
218 @NotNull BindingContext bindingContext,
219 @NotNull ReadOnlySlice<K, V> slice,
220 @NotNull K key
221 ) {
222 return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key);
223 }
224
225 @NotNull
226 public static <K, V> V getNotNull(
227 @NotNull BindingContext bindingContext,
228 @NotNull ReadOnlySlice<K, V> slice,
229 @NotNull K key,
230 @NotNull String messageIfNull
231 ) {
232 V value = bindingContext.get(slice, key);
233 if (value == null) {
234 throw new IllegalStateException(messageIfNull);
235 }
236 return value;
237 }
238
239 @NotNull
240 public static DeclarationDescriptor getEnclosingDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
241 JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
242 if (declaration instanceof JetFunctionLiteral) {
243 return getEnclosingDescriptor(context, declaration);
244 }
245 DeclarationDescriptor descriptor = context.get(DECLARATION_TO_DESCRIPTOR, declaration);
246 assert descriptor != null : "No descriptor for named declaration: " + declaration.getText() + "\n(of type " + declaration.getClass() + ")";
247 return descriptor;
248 }
249
250 public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
251 JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
252 return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
253 }
254
255 public static void reportAmbiguousLabel(
256 @NotNull BindingTrace trace,
257 @NotNull JetSimpleNameExpression targetLabel,
258 @NotNull Collection<DeclarationDescriptor> declarationsByLabel
259 ) {
260 Collection<PsiElement> targets = Lists.newArrayList();
261 for (DeclarationDescriptor descriptor : declarationsByLabel) {
262 PsiElement element = descriptorToDeclaration(trace.getBindingContext(), descriptor);
263 assert element != null : "Label can only point to something in the same lexical scope";
264 targets.add(element);
265 }
266 if (!targets.isEmpty()) {
267 trace.record(AMBIGUOUS_LABEL_TARGET, targetLabel, targets);
268 }
269 trace.report(AMBIGUOUS_LABEL.on(targetLabel));
270 }
271
272 @Nullable
273 public static JetType updateRecordedType(
274 @Nullable JetType type,
275 @NotNull JetExpression expression,
276 @NotNull BindingTrace trace,
277 boolean shouldBeMadeNullable
278 ) {
279 if (type == null) return null;
280 if (shouldBeMadeNullable) {
281 type = TypeUtils.makeNullable(type);
282 }
283 trace.record(BindingContext.EXPRESSION_TYPE, expression, type);
284 return type;
285 }
286
287 @Nullable
288 public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) {
289 if (!context.get(BindingContext.PROCESSED, expression)) return null;
290 DataFlowInfo dataFlowInfo = context.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression);
291 if (dataFlowInfo == null) {
292 dataFlowInfo = DataFlowInfo.EMPTY;
293 }
294 JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
295 return JetTypeInfo.create(type, dataFlowInfo);
296 }
297
298 public static boolean isExpressionWithValidReference(
299 @NotNull JetExpression expression,
300 @NotNull BindingContext context
301 ) {
302 if (expression instanceof JetCallExpression) {
303 return isCallExpressionWithValidReference(expression, context);
304 }
305
306 return expression instanceof JetReferenceExpression;
307 }
308
309 public static boolean isCallExpressionWithValidReference(
310 @NotNull JetExpression expression,
311 @NotNull BindingContext context
312 ) {
313 if (expression instanceof JetCallExpression) {
314 JetExpression calleeExpression = ((JetCallExpression) expression).getCalleeExpression();
315 ResolvedCall<?> resolvedCall = context.get(BindingContext.RESOLVED_CALL, calleeExpression);
316 if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
317 return true;
318 }
319 }
320 return false;
321 }
322
323 public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) {
324 if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false;
325 VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
326 return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar();
327 }
328 }