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