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.ClassDescriptorFromJvmBytecode; 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, ClassDescriptorFromJvmBytecode> 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, false); 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 boolean functionLiteral 204 ) { 205 JetDelegatorToSuperCall superCall = findSuperCall(bindingTrace.getBindingContext(), element); 206 207 CallableDescriptor enclosingReceiver = null; 208 if (classDescriptor.getContainingDeclaration() instanceof CallableDescriptor) { 209 enclosingReceiver = (CallableDescriptor) classDescriptor.getContainingDeclaration(); 210 enclosingReceiver = enclosingReceiver instanceof PropertyAccessorDescriptor 211 ? ((PropertyAccessorDescriptor) enclosingReceiver).getCorrespondingProperty() 212 : enclosingReceiver; 213 214 if (enclosingReceiver.getReceiverParameter() == null) { 215 enclosingReceiver = null; 216 } 217 } 218 219 MutableClosure closure = new MutableClosure(superCall, enclosing, enclosingReceiver); 220 221 assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, classDescriptor, asmType); 222 bindingTrace.record(ASM_TYPE, classDescriptor, asmType); 223 bindingTrace.record(CLOSURE, classDescriptor, closure); 224 225 // TODO: this is temporary before we have proper inner classes 226 if (canHaveOuter(bindingTrace.getBindingContext(), classDescriptor) && !functionLiteral) { 227 closure.setCaptureThis(); 228 } 229 230 if (enclosing != null) { 231 recordInnerClass(bindingTrace, enclosing, classDescriptor); 232 } 233 } 234 235 private static void recordInnerClass( 236 @NotNull BindingTrace bindingTrace, 237 @NotNull ClassDescriptor outer, 238 @NotNull ClassDescriptor inner 239 ) { 240 Collection<ClassDescriptor> innerClasses = bindingTrace.get(INNER_CLASSES, outer); 241 if (innerClasses == null) { 242 innerClasses = new ArrayList<ClassDescriptor>(); 243 bindingTrace.record(INNER_CLASSES, outer, innerClasses); 244 } 245 innerClasses.add(inner); 246 } 247 248 public static void registerClassNameForScript( 249 BindingTrace bindingTrace, 250 @NotNull JetScript jetScript, 251 @NotNull Type asmType 252 ) { 253 ScriptDescriptor descriptor = bindingTrace.getBindingContext().get(SCRIPT, jetScript); 254 if (descriptor == null) { 255 throw new IllegalStateException("Descriptor is not found for PSI " + jetScript); 256 } 257 registerClassNameForScript(bindingTrace, descriptor, asmType); 258 } 259 260 @NotNull 261 public static Collection<JetFile> allFilesInNamespaces(BindingContext bindingContext, Collection<JetFile> files) { 262 // todo: we use Set and add given files but ignoring other scripts because something non-clear kept in binding 263 // for scripts especially in case of REPL 264 265 HashSet<FqName> names = new HashSet<FqName>(); 266 for (JetFile file : files) { 267 if (!file.isScript()) { 268 names.add(JetPsiUtil.getFQName(file)); 269 } 270 } 271 272 HashSet<JetFile> answer = new HashSet<JetFile>(); 273 answer.addAll(files); 274 275 for (FqName name : names) { 276 NamespaceDescriptor namespaceDescriptor = bindingContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, name); 277 Collection<JetFile> jetFiles = bindingContext.get(NAMESPACE_TO_FILES, namespaceDescriptor); 278 if (jetFiles != null) { 279 answer.addAll(jetFiles); 280 } 281 } 282 283 List<JetFile> sortedAnswer = new ArrayList<JetFile>(answer); 284 Collections.sort(sortedAnswer, new Comparator<JetFile>() { 285 @NotNull 286 private String path(JetFile file) { 287 VirtualFile virtualFile = file.getVirtualFile(); 288 assert virtualFile != null : "VirtualFile is null for JetFile: " + file.getName(); 289 return virtualFile.getPath(); 290 } 291 292 @Override 293 public int compare(JetFile first, JetFile second) { 294 return path(first).compareTo(path(second)); 295 } 296 }); 297 298 return sortedAnswer; 299 } 300 301 public static boolean isObjectLiteral(BindingContext bindingContext, ClassDescriptor declaration) { 302 PsiElement psiElement = descriptorToDeclaration(bindingContext, declaration); 303 if (psiElement instanceof JetObjectDeclaration && ((JetObjectDeclaration) psiElement).isObjectLiteral()) { 304 return true; 305 } 306 return false; 307 } 308 309 public static boolean isObjectDeclaration(BindingContext bindingContext, ClassDescriptor declaration) { 310 PsiElement psiElement = descriptorToDeclaration(bindingContext, declaration); 311 if (psiElement instanceof JetObjectDeclaration && !((JetObjectDeclaration) psiElement).isObjectLiteral()) { 312 return true; 313 } 314 return false; 315 } 316 317 public static boolean isLocalNamedFun(DeclarationDescriptor fd) { 318 if (fd instanceof FunctionDescriptor) { 319 FunctionDescriptor descriptor = (FunctionDescriptor) fd; 320 return descriptor.getVisibility() == Visibilities.LOCAL && !descriptor.getName().isSpecial(); 321 } 322 return false; 323 } 324 325 @NotNull 326 public static Type getAsmType(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) { 327 descriptor = descriptor.getOriginal(); 328 Type alreadyComputedType = bindingTrace.getBindingContext().get(ASM_TYPE, descriptor); 329 if (alreadyComputedType != null) { 330 return alreadyComputedType; 331 } 332 333 Type asmType = Type.getObjectType(getAsmTypeImpl(bindingTrace, descriptor)); 334 335 assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType); 336 bindingTrace.record(ASM_TYPE, descriptor, asmType); 337 return asmType; 338 } 339 340 @NotNull 341 private static String getAsmTypeImpl(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) { 342 if (descriptor instanceof FunctionDescriptor) { 343 throw new IllegalStateException("requested fq name for function: " + descriptor); 344 } 345 346 if (descriptor instanceof ModuleDescriptor) { 347 throw new IllegalStateException("missed something"); 348 } 349 350 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 351 if (container == null) { 352 throw new IllegalStateException("descriptor has no container: " + descriptor); 353 } 354 355 if (container.getContainingDeclaration() instanceof ModuleDescriptor || container instanceof ScriptDescriptor) { 356 return descriptor.getName().getIdentifier(); 357 } 358 359 String containerInternalName = getAsmType(bindingTrace, container).getInternalName(); 360 361 if (descriptor instanceof ClassDescriptor && container instanceof ClassDescriptor) { 362 ClassDescriptor klass = (ClassDescriptor) descriptor; 363 if (klass.getKind() == ClassKind.OBJECT || klass.getKind() == ClassKind.CLASS_OBJECT) { 364 if (isEnumClass(container)) { 365 return containerInternalName; 366 } 367 else if (klass.getKind() == ClassKind.OBJECT) { 368 return containerInternalName + "$" + klass.getName(); 369 } 370 else { 371 return containerInternalName + JvmAbi.CLASS_OBJECT_SUFFIX; 372 } 373 } 374 } 375 376 return containerInternalName + (container instanceof NamespaceDescriptor ? "/" : "$") + descriptor.getName().getIdentifier(); 377 } 378 379 public static boolean isVarCapturedInClosure(BindingContext bindingContext, DeclarationDescriptor descriptor) { 380 if (!(descriptor instanceof VariableDescriptor) || descriptor instanceof PropertyDescriptor) return false; 381 VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; 382 return bindingContext.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null && variableDescriptor.isVar(); 383 } 384 385 public static boolean hasThis0(BindingContext bindingContext, ClassDescriptor classDescriptor) { 386 //noinspection SuspiciousMethodCalls 387 CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor); 388 return closure != null && closure.getCaptureThis() != null; 389 } 390 391 private static JetDelegatorToSuperCall findSuperCall( 392 BindingContext bindingContext, 393 JetElement classOrObject 394 ) { 395 if (!(classOrObject instanceof JetClassOrObject)) { 396 return null; 397 } 398 399 if (classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait()) { 400 return null; 401 } 402 for (JetDelegationSpecifier specifier : ((JetClassOrObject) classOrObject).getDelegationSpecifiers()) { 403 if (specifier instanceof JetDelegatorToSuperCall) { 404 JetType superType = bindingContext.get(TYPE, specifier.getTypeReference()); 405 assert superType != null; 406 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); 407 assert superClassDescriptor != null; 408 if (!isInterface(superClassDescriptor)) { 409 return (JetDelegatorToSuperCall) specifier; 410 } 411 } 412 } 413 414 return null; 415 } 416 }