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.codegen.binding; 018 019 import com.intellij.openapi.vfs.VirtualFile; 020 import com.intellij.psi.PsiElement; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.annotations.Nullable; 023 import org.jetbrains.asm4.Type; 024 import org.jetbrains.jet.lang.descriptors.*; 025 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 026 import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl; 027 import org.jetbrains.jet.lang.psi.*; 028 import org.jetbrains.jet.lang.resolve.BindingContext; 029 import org.jetbrains.jet.lang.resolve.BindingTrace; 030 import org.jetbrains.jet.lang.resolve.java.JvmAbi; 031 import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor; 032 import org.jetbrains.jet.lang.resolve.name.FqName; 033 import org.jetbrains.jet.lang.resolve.name.Name; 034 import org.jetbrains.jet.lang.resolve.scopes.JetScope; 035 import org.jetbrains.jet.lang.types.JetType; 036 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 037 import org.jetbrains.jet.util.slicedmap.Slices; 038 import org.jetbrains.jet.util.slicedmap.WritableSlice; 039 040 import java.util.*; 041 042 import static org.jetbrains.jet.codegen.CodegenUtil.isInterface; 043 import static org.jetbrains.jet.lang.resolve.BindingContext.*; 044 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; 045 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass; 046 047 public class CodegenBinding { 048 public static final WritableSlice<ClassDescriptor, MutableClosure> CLOSURE = Slices.createSimpleSlice(); 049 050 public static final WritableSlice<FunctionDescriptor, ClassDescriptor> CLASS_FOR_FUNCTION = Slices.createSimpleSlice(); 051 052 public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice(); 053 054 public static final WritableSlice<DeclarationDescriptor, Type> ASM_TYPE = Slices.createSimpleSlice(); 055 056 public static final WritableSlice<ClassDescriptor, Boolean> ENUM_ENTRY_CLASS_NEED_SUBCLASS = Slices.createSimpleSetSlice(); 057 058 public static final WritableSlice<ClassDescriptor, Collection<ClassDescriptor>> INNER_CLASSES = Slices.createSimpleSlice(); 059 060 public static final WritableSlice<JetExpression, JavaClassDescriptor> SAM_VALUE = Slices.createSimpleSlice(); 061 062 private CodegenBinding() { 063 } 064 065 public static void initTrace(BindingTrace bindingTrace, Collection<JetFile> files) { 066 CodegenAnnotatingVisitor visitor = new CodegenAnnotatingVisitor(bindingTrace); 067 for (JetFile file : allFilesInNamespaces(bindingTrace.getBindingContext(), files)) { 068 file.accept(visitor); 069 } 070 } 071 072 public static boolean enumEntryNeedSubclass(BindingContext bindingContext, JetEnumEntry enumEntry) { 073 return enumEntryNeedSubclass(bindingContext, bindingContext.get(CLASS, enumEntry)); 074 } 075 076 public static boolean enumEntryNeedSubclass(BindingContext bindingContext, ClassDescriptor classDescriptor) { 077 return Boolean.TRUE.equals(bindingContext.get(ENUM_ENTRY_CLASS_NEED_SUBCLASS, classDescriptor)); 078 } 079 080 @NotNull 081 public static Type asmTypeForScriptDescriptor(BindingContext bindingContext, @NotNull ScriptDescriptor scriptDescriptor) { 082 ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor); 083 //noinspection ConstantConditions 084 return asmType(bindingContext, classDescriptor); 085 } 086 087 @NotNull 088 public static Type asmTypeForScriptPsi(BindingContext bindingContext, @NotNull JetScript script) { 089 ScriptDescriptor scriptDescriptor = bindingContext.get(SCRIPT, script); 090 if (scriptDescriptor == null) { 091 throw new IllegalStateException("Script descriptor not found by PSI " + script); 092 } 093 return asmTypeForScriptDescriptor(bindingContext, scriptDescriptor); 094 } 095 096 public static ClassDescriptor enclosingClassDescriptor(BindingContext bindingContext, ClassDescriptor descriptor) { 097 CalculatedClosure closure = bindingContext.get(CLOSURE, descriptor); 098 return closure == null ? null : closure.getEnclosingClass(); 099 } 100 101 @NotNull 102 public static ClassDescriptor anonymousClassForFunction( 103 @NotNull BindingContext bindingContext, 104 @NotNull FunctionDescriptor descriptor 105 ) { 106 //noinspection ConstantConditions 107 return bindingContext.get(CLASS_FOR_FUNCTION, descriptor); 108 } 109 110 @NotNull 111 private static Type asmType(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor descriptor) { 112 //noinspection ConstantConditions 113 return bindingContext.get(ASM_TYPE, descriptor); 114 } 115 116 @NotNull 117 public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull JetElement expression) { 118 if (expression instanceof JetObjectLiteralExpression) { 119 JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression; 120 expression = jetObjectLiteralExpression.getObjectDeclaration(); 121 } 122 123 ClassDescriptor descriptor = bindingContext.get(CLASS, expression); 124 if (descriptor == null) { 125 SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); 126 assert functionDescriptor != null; 127 return asmTypeForAnonymousClass(bindingContext, functionDescriptor); 128 } 129 130 return asmType(bindingContext, descriptor); 131 } 132 133 @NotNull 134 public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) { 135 ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, descriptor); 136 return asmType(bindingContext, classDescriptor); 137 } 138 139 public static void registerClassNameForScript( 140 BindingTrace bindingTrace, 141 @NotNull ScriptDescriptor scriptDescriptor, 142 @NotNull Type asmType 143 ) { 144 ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl( 145 scriptDescriptor, 146 Collections.<AnnotationDescriptor>emptyList(), 147 Modality.FINAL, 148 Name.special("<script-" + asmType.getInternalName() + ">")); 149 classDescriptor.initialize( 150 false, 151 Collections.<TypeParameterDescriptor>emptyList(), 152 Collections.singletonList(KotlinBuiltIns.getInstance().getAnyType()), 153 JetScope.EMPTY, 154 Collections.<ConstructorDescriptor>emptySet(), 155 null, 156 false); 157 158 recordClosure(bindingTrace, null, classDescriptor, null, asmType); 159 160 bindingTrace.record(CLASS_FOR_SCRIPT, scriptDescriptor, classDescriptor); 161 } 162 163 public static boolean canHaveOuter(BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) { 164 if (isSingleton(bindingContext, classDescriptor)) { 165 return false; 166 } 167 168 ClassDescriptor enclosing = enclosingClassDescriptor(bindingContext, classDescriptor); 169 if (enclosing == null) { 170 return false; 171 } 172 173 ClassKind kind = classDescriptor.getKind(); 174 if (kind == ClassKind.CLASS) { 175 return classDescriptor.isInner() || !(classDescriptor.getContainingDeclaration() instanceof ClassDescriptor); 176 } 177 else if (kind == ClassKind.OBJECT) { 178 return !isSingleton(bindingContext, enclosing); 179 } 180 else { 181 return false; 182 } 183 } 184 185 public static boolean isSingleton(BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) { 186 if (isObjectDeclaration(bindingContext, classDescriptor)) { 187 return true; 188 } 189 190 if (classDescriptor.getKind() == ClassKind.ENUM_ENTRY) { 191 return true; 192 } 193 194 return false; 195 } 196 197 static void recordClosure( 198 BindingTrace bindingTrace, 199 @Nullable JetElement element, 200 ClassDescriptor classDescriptor, 201 @Nullable ClassDescriptor enclosing, 202 Type asmType 203 ) { 204 JetDelegatorToSuperCall superCall = findSuperCall(bindingTrace.getBindingContext(), element); 205 206 CallableDescriptor enclosingReceiver = null; 207 if (classDescriptor.getContainingDeclaration() instanceof CallableDescriptor) { 208 enclosingReceiver = (CallableDescriptor) classDescriptor.getContainingDeclaration(); 209 enclosingReceiver = enclosingReceiver instanceof PropertyAccessorDescriptor 210 ? ((PropertyAccessorDescriptor) enclosingReceiver).getCorrespondingProperty() 211 : enclosingReceiver; 212 213 if (enclosingReceiver.getReceiverParameter() == null) { 214 enclosingReceiver = null; 215 } 216 } 217 218 MutableClosure closure = new MutableClosure(superCall, enclosing, enclosingReceiver); 219 220 assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, classDescriptor, asmType); 221 bindingTrace.record(ASM_TYPE, classDescriptor, asmType); 222 bindingTrace.record(CLOSURE, classDescriptor, closure); 223 224 if (classDescriptor.isInner()) { 225 closure.setCaptureThis(); 226 } 227 228 if (enclosing != null) { 229 recordInnerClass(bindingTrace, enclosing, classDescriptor); 230 } 231 } 232 233 private static void recordInnerClass( 234 @NotNull BindingTrace bindingTrace, 235 @NotNull ClassDescriptor outer, 236 @NotNull ClassDescriptor inner 237 ) { 238 Collection<ClassDescriptor> innerClasses = bindingTrace.get(INNER_CLASSES, outer); 239 if (innerClasses == null) { 240 innerClasses = new ArrayList<ClassDescriptor>(); 241 bindingTrace.record(INNER_CLASSES, outer, innerClasses); 242 } 243 innerClasses.add(inner); 244 } 245 246 public static void registerClassNameForScript( 247 BindingTrace bindingTrace, 248 @NotNull JetScript jetScript, 249 @NotNull Type asmType 250 ) { 251 ScriptDescriptor descriptor = bindingTrace.getBindingContext().get(SCRIPT, jetScript); 252 if (descriptor == null) { 253 throw new IllegalStateException("Descriptor is not found for PSI " + jetScript); 254 } 255 registerClassNameForScript(bindingTrace, descriptor, asmType); 256 } 257 258 @NotNull 259 public static Collection<JetFile> allFilesInNamespaces(BindingContext bindingContext, Collection<JetFile> files) { 260 // todo: we use Set and add given files but ignoring other scripts because something non-clear kept in binding 261 // for scripts especially in case of REPL 262 263 HashSet<FqName> names = new HashSet<FqName>(); 264 for (JetFile file : files) { 265 if (!file.isScript()) { 266 names.add(JetPsiUtil.getFQName(file)); 267 } 268 } 269 270 HashSet<JetFile> answer = new HashSet<JetFile>(); 271 answer.addAll(files); 272 273 for (FqName name : names) { 274 NamespaceDescriptor namespaceDescriptor = bindingContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, name); 275 Collection<JetFile> jetFiles = bindingContext.get(NAMESPACE_TO_FILES, namespaceDescriptor); 276 if (jetFiles != null) { 277 answer.addAll(jetFiles); 278 } 279 } 280 281 List<JetFile> sortedAnswer = new ArrayList<JetFile>(answer); 282 Collections.sort(sortedAnswer, new Comparator<JetFile>() { 283 @NotNull 284 private String path(JetFile file) { 285 VirtualFile virtualFile = file.getVirtualFile(); 286 assert virtualFile != null : "VirtualFile is null for JetFile: " + file.getName(); 287 return virtualFile.getPath(); 288 } 289 290 @Override 291 public int compare(JetFile first, JetFile second) { 292 return path(first).compareTo(path(second)); 293 } 294 }); 295 296 return sortedAnswer; 297 } 298 299 public static boolean isObjectLiteral(BindingContext bindingContext, ClassDescriptor declaration) { 300 PsiElement psiElement = descriptorToDeclaration(bindingContext, declaration); 301 if (psiElement instanceof JetObjectDeclaration && ((JetObjectDeclaration) psiElement).isObjectLiteral()) { 302 return true; 303 } 304 return false; 305 } 306 307 public static boolean isObjectDeclaration(BindingContext bindingContext, ClassDescriptor declaration) { 308 PsiElement psiElement = descriptorToDeclaration(bindingContext, declaration); 309 if (psiElement instanceof JetObjectDeclaration && !((JetObjectDeclaration) psiElement).isObjectLiteral()) { 310 return true; 311 } 312 return false; 313 } 314 315 public static boolean isLocalNamedFun(DeclarationDescriptor fd) { 316 if (fd instanceof FunctionDescriptor) { 317 FunctionDescriptor descriptor = (FunctionDescriptor) fd; 318 return descriptor.getVisibility() == Visibilities.LOCAL && !descriptor.getName().isSpecial(); 319 } 320 return false; 321 } 322 323 @NotNull 324 public static Type getAsmType(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) { 325 descriptor = descriptor.getOriginal(); 326 Type alreadyComputedType = bindingTrace.getBindingContext().get(ASM_TYPE, descriptor); 327 if (alreadyComputedType != null) { 328 return alreadyComputedType; 329 } 330 331 Type asmType = Type.getObjectType(getAsmTypeImpl(bindingTrace, descriptor)); 332 333 assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType); 334 bindingTrace.record(ASM_TYPE, descriptor, asmType); 335 return asmType; 336 } 337 338 @NotNull 339 private static String getAsmTypeImpl(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) { 340 if (descriptor instanceof FunctionDescriptor) { 341 throw new IllegalStateException("requested fq name for function: " + descriptor); 342 } 343 344 if (descriptor instanceof ModuleDescriptor) { 345 throw new IllegalStateException("missed something"); 346 } 347 348 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 349 if (container == null) { 350 throw new IllegalStateException("descriptor has no container: " + descriptor); 351 } 352 353 if (container.getContainingDeclaration() instanceof ModuleDescriptor || container instanceof ScriptDescriptor) { 354 return descriptor.getName().getIdentifier(); 355 } 356 357 String containerInternalName = getAsmType(bindingTrace, container).getInternalName(); 358 359 if (descriptor instanceof ClassDescriptor && container instanceof ClassDescriptor) { 360 ClassDescriptor klass = (ClassDescriptor) descriptor; 361 if (klass.getKind() == ClassKind.OBJECT || klass.getKind() == ClassKind.CLASS_OBJECT) { 362 if (isEnumClass(container)) { 363 return containerInternalName; 364 } 365 else if (klass.getKind() == ClassKind.OBJECT) { 366 return containerInternalName + "$" + klass.getName(); 367 } 368 else { 369 return containerInternalName + JvmAbi.CLASS_OBJECT_SUFFIX; 370 } 371 } 372 } 373 374 return containerInternalName + (container instanceof NamespaceDescriptor ? "/" : "$") + descriptor.getName().getIdentifier(); 375 } 376 377 public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) { 378 if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false; 379 VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; 380 return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar(); 381 } 382 383 public static boolean hasThis0(BindingContext bindingContext, ClassDescriptor classDescriptor) { 384 //noinspection SuspiciousMethodCalls 385 CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor); 386 return closure != null && closure.getCaptureThis() != null; 387 } 388 389 private static JetDelegatorToSuperCall findSuperCall( 390 BindingContext bindingContext, 391 JetElement classOrObject 392 ) { 393 if (!(classOrObject instanceof JetClassOrObject)) { 394 return null; 395 } 396 397 if (classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait()) { 398 return null; 399 } 400 for (JetDelegationSpecifier specifier : ((JetClassOrObject) classOrObject).getDelegationSpecifiers()) { 401 if (specifier instanceof JetDelegatorToSuperCall) { 402 JetType superType = bindingContext.get(TYPE, specifier.getTypeReference()); 403 assert superType != null; 404 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); 405 assert superClassDescriptor != null; 406 if (!isInterface(superClassDescriptor)) { 407 return (JetDelegatorToSuperCall) specifier; 408 } 409 } 410 } 411 412 return null; 413 } 414 }