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