Write proper enclosingMethod/enclosingClass information to bytecode

This commit is contained in:
Mikhael Bogdanov
2013-02-11 17:16:46 +04:00
parent 1a54e42eb7
commit 1b2da6b558
8 changed files with 283 additions and 13 deletions
@@ -39,12 +39,14 @@ import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.OverridingUtil;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
@@ -184,9 +186,50 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void writeOuterClass() {
ClassDescriptor container = getContainingClassDescriptor(descriptor);
//JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
DeclarationDescriptor parentDescriptor = descriptor.getContainingDeclaration();
boolean isObjectLiteral = descriptor.getName().isSpecial() && descriptor.getKind() == ClassKind.OBJECT;
boolean isLocalOrAnonymousClass = isObjectLiteral ||
!(parentDescriptor instanceof NamespaceDescriptor || parentDescriptor instanceof ClassDescriptor);
if (isLocalOrAnonymousClass) {
String outerClassName = getOuterClassName(descriptor, typeMapper, bindingContext, state);
FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
//Function descriptor could be null only for object literal in package namespace
assert (!isObjectLiteral && function != null) || isObjectLiteral:
"Function descriptor should be present: " + descriptor.getName();
Name functionName = function != null ? function.getName() : null;
v.visitOuterClass(outerClassName,
functionName != null ? functionName.getName() : null,
functionName != null ? typeMapper.mapSignature(functionName, function).getAsmMethod().getDescriptor() : null);
}
}
@NotNull
public static String getOuterClassName(
@NotNull ClassDescriptor classDescriptor,
@NotNull JetTypeMapper typeMapper,
@NotNull BindingContext bindingContext,
@NotNull GenerationState state
) {
ClassDescriptor container = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
if (container != null) {
v.visitOuterClass(typeMapper.mapType(container.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName(), null, null);
return typeMapper.mapType(container.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
}
else {
NamespaceDescriptor namespaceDescriptor = DescriptorUtils.getParentOfType(classDescriptor, NamespaceDescriptor.class);
assert namespaceDescriptor != null : "Namespace descriptor should be present: " + classDescriptor.getName();
FqName namespaceQN = namespaceDescriptor.getQualifiedName();
boolean isMultiFile = CodegenBinding.isMultiFileNamespace(state.getBindingContext(), namespaceQN);
return isMultiFile
? NamespaceCodegen.getNamespacePartInternalName(
BindingContextUtils.getContainingFile(bindingContext, classDescriptor))
: NamespaceCodegen.getJVMClassNameForKotlinNs(namespaceQN).getInternalName();
}
}
@@ -242,16 +285,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
annotationVisitor.visitEnd();
}
@Nullable
private static ClassDescriptor getContainingClassDescriptor(ClassDescriptor decl) {
DeclarationDescriptor container = decl.getContainingDeclaration();
while (container != null && !(container instanceof NamespaceDescriptor)) {
if (container instanceof ClassDescriptor) return (ClassDescriptor) container;
container = container.getContainingDeclaration();
}
return null;
}
private JvmClassSignature signature() {
List<String> superInterfaces;