Fix generation of InnerClasses/EnclosingMethod attributes
Generate InnerClasses for each outer class and each direct inner class in all inheritors of MemberCodegen, i.e. for classes, objects, lambdas, local classes, etc. Also skip lambdas which will be inlined when calculating outer class for EnclosingMethod #KT-5447 Fixed #KT-5478 Fixed
This commit is contained in:
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
@@ -61,6 +62,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
|
||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME;
|
||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
@@ -863,15 +865,16 @@ public class AsmUtil {
|
||||
@NotNull DeclarationDescriptor originalDescriptor,
|
||||
@NotNull JetTypeMapper typeMapper
|
||||
) {
|
||||
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||
|
||||
DeclarationDescriptor container = classDescriptor.getContainingDeclaration();
|
||||
while (container != null) {
|
||||
if (container instanceof ClassDescriptor) {
|
||||
return typeMapper.mapClass((ClassDescriptor) container).getInternalName();
|
||||
}
|
||||
else if (CodegenBinding.isLocalFunOrLambda(container)) {
|
||||
ClassDescriptor descriptor =
|
||||
CodegenBinding.anonymousClassForFunction(typeMapper.getBindingContext(), (FunctionDescriptor) container);
|
||||
return typeMapper.mapClass(descriptor).getInternalName();
|
||||
else if (CodegenBinding.isLocalFunOrLambda(container) &&
|
||||
!JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, container)) {
|
||||
return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) container).getInternalName();
|
||||
}
|
||||
|
||||
container = container.getContainingDeclaration();
|
||||
|
||||
@@ -128,4 +128,10 @@ public abstract class ClassBodyCodegen extends MemberCodegen<JetClassOrObject> {
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected ClassDescriptor classForInnerClassRecord() {
|
||||
return DescriptorUtils.isTopLevelDeclaration(descriptor) ? null : descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,12 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
superInterfaceAsmTypes
|
||||
);
|
||||
v.visitSource(element.getContainingFile().getName(), null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected ClassDescriptor classForInnerClassRecord() {
|
||||
return JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, funDescriptor) ? null : classDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -204,7 +209,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
AsmUtil.writeOuterClassAndEnclosingMethod(classDescriptor, funDescriptor, typeMapper, v);
|
||||
writeOuterClassAndEnclosingMethod(classDescriptor, funDescriptor, typeMapper, v);
|
||||
super.done();
|
||||
}
|
||||
|
||||
@@ -297,7 +302,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
|
||||
int k = 1;
|
||||
for (FieldInfo fieldInfo : args) {
|
||||
k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, iv);
|
||||
k = genAssignInstanceFieldFromParam(fieldInfo, k, iv);
|
||||
}
|
||||
|
||||
iv.load(0, superClassAsmType);
|
||||
|
||||
@@ -69,7 +69,8 @@ import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.isLocalNamedFun;
|
||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.classDescriptorToDeclaration;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
@@ -209,10 +210,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
writeEnclosingMethod();
|
||||
|
||||
writeOuterClasses();
|
||||
|
||||
writeInnerClasses();
|
||||
|
||||
AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null);
|
||||
|
||||
generateReflectionObjectFieldIfNeeded();
|
||||
@@ -265,43 +262,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInnerClasses() {
|
||||
Collection<ClassDescriptor> result = bindingContext.get(INNER_CLASSES, descriptor);
|
||||
if (result != null) {
|
||||
for (ClassDescriptor innerClass : result) {
|
||||
writeInnerClass(innerClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOuterClasses() {
|
||||
// JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
|
||||
// for each enclosing class and for each immediate member
|
||||
DeclarationDescriptor inner = descriptor;
|
||||
while (true) {
|
||||
if (inner == null || isTopLevelDeclaration(inner)) {
|
||||
break;
|
||||
}
|
||||
if (inner instanceof ClassDescriptor) {
|
||||
writeInnerClass((ClassDescriptor) inner);
|
||||
}
|
||||
inner = inner.getContainingDeclaration();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
|
||||
DeclarationDescriptor containing = innerClass.getContainingDeclaration();
|
||||
String outerClassInternalName =
|
||||
containing instanceof ClassDescriptor ? typeMapper.mapClass((ClassDescriptor) containing).getInternalName() : null;
|
||||
|
||||
String innerName = isClassObject(innerClass)
|
||||
? JvmAbi.CLASS_OBJECT_CLASS_NAME
|
||||
: innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
|
||||
|
||||
String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName();
|
||||
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JvmClassSignature signature() {
|
||||
BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS);
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -34,9 +35,13 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass;
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass;
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteral;
|
||||
import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression;
|
||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.InlineDescriptorUtils;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
|
||||
@@ -224,4 +229,11 @@ public class JvmCodegenUtil {
|
||||
? ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()
|
||||
: descriptor;
|
||||
}
|
||||
|
||||
public static boolean isLambdaWhichWillBeInlined(@NotNull BindingContext bindingContext, @NotNull DeclarationDescriptor descriptor) {
|
||||
PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
|
||||
return declaration instanceof JetFunctionLiteral &&
|
||||
declaration.getParent() instanceof JetFunctionLiteralExpression &&
|
||||
InlineDescriptorUtils.isInlineLambda((JetFunctionLiteralExpression) declaration.getParent(), bindingContext, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,14 +48,14 @@ import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.calculateInnerClassAccessFlags;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
import static org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassObject;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.TraitImpl;
|
||||
@@ -73,6 +73,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
protected final BindingContext bindingContext;
|
||||
private final MemberCodegen<?> parentCodegen;
|
||||
private final ReifiedTypeParametersUsages reifiedTypeParametersUsages = new ReifiedTypeParametersUsages();
|
||||
protected final Collection<ClassDescriptor> innerClasses = new LinkedHashSet<ClassDescriptor>();
|
||||
|
||||
protected ExpressionCodegen clInit;
|
||||
private NameGenerator inlineNameGenerator;
|
||||
@@ -120,12 +121,19 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
|
||||
protected abstract void generateKotlinAnnotation();
|
||||
|
||||
@Nullable
|
||||
protected ClassDescriptor classForInnerClassRecord() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void done() {
|
||||
if (clInit != null) {
|
||||
clInit.v.visitInsn(RETURN);
|
||||
FunctionCodegen.endVisit(clInit.v, "static initializer", element);
|
||||
}
|
||||
|
||||
writeInnerClasses();
|
||||
|
||||
v.done();
|
||||
}
|
||||
|
||||
@@ -203,6 +211,41 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
genClassOrObject(context, aClass, state, this);
|
||||
}
|
||||
|
||||
private void writeInnerClasses() {
|
||||
// JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
|
||||
// for each enclosing class and for each immediate member
|
||||
ClassDescriptor classDescriptor = classForInnerClassRecord();
|
||||
if (classDescriptor != null) {
|
||||
if (parentCodegen != null) {
|
||||
parentCodegen.innerClasses.add(classDescriptor);
|
||||
}
|
||||
|
||||
for (MemberCodegen<?> codegen = this; codegen != null; codegen = codegen.getParentCodegen()) {
|
||||
ClassDescriptor outerClass = codegen.classForInnerClassRecord();
|
||||
if (outerClass != null) {
|
||||
innerClasses.add(outerClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassDescriptor innerClass : innerClasses) {
|
||||
writeInnerClass(innerClass);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
|
||||
DeclarationDescriptor containing = innerClass.getContainingDeclaration();
|
||||
String outerClassInternalName =
|
||||
containing instanceof ClassDescriptor ? typeMapper.mapClass((ClassDescriptor) containing).getInternalName() : null;
|
||||
|
||||
String innerName = isClassObject(innerClass)
|
||||
? JvmAbi.CLASS_OBJECT_CLASS_NAME
|
||||
: innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
|
||||
|
||||
String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName();
|
||||
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NameGenerator getInlineNameGenerator() {
|
||||
if (inlineNameGenerator == null) {
|
||||
@@ -403,4 +446,9 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
public MemberCodegen<?> getParentCodegen() {
|
||||
return parentCodegen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return context.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.SamType;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
||||
@@ -60,8 +61,8 @@ public class CodegenBinding {
|
||||
|
||||
public static final WritableSlice<JetExpression, SamType> SAM_VALUE = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<JetWhenExpression, WhenByEnumsMapping> MAPPING_FOR_WHEN_BY_ENUM = Slices.
|
||||
<JetWhenExpression, WhenByEnumsMapping>sliceBuilder().build();
|
||||
public static final WritableSlice<JetWhenExpression, WhenByEnumsMapping> MAPPING_FOR_WHEN_BY_ENUM =
|
||||
Slices.<JetWhenExpression, WhenByEnumsMapping>sliceBuilder().build();
|
||||
|
||||
public static final WritableSlice<String, List<WhenByEnumsMapping>> MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE =
|
||||
Slices.<String, List<WhenByEnumsMapping>>sliceBuilder().build();
|
||||
@@ -169,9 +170,9 @@ public class CodegenBinding {
|
||||
trace.record(ASM_TYPE, classDescriptor, asmType);
|
||||
trace.record(CLOSURE, classDescriptor, closure);
|
||||
|
||||
//TEMPORARY EAT INNER CLASS INFO FOR FUNCTION LITERALS
|
||||
//TODO: we should understand that lambda/closure would be inlined and don't generate inner class record
|
||||
if (enclosing != null && !(element instanceof JetFunctionLiteral)) {
|
||||
// Note: at the moment this is needed for light classes only
|
||||
// TODO: refactor this out
|
||||
if (enclosing != null && !JvmCodegenUtil.isLambdaWhichWillBeInlined(trace.getBindingContext(), classDescriptor)) {
|
||||
recordInnerClass(trace, enclosing, classDescriptor);
|
||||
}
|
||||
}
|
||||
@@ -183,7 +184,7 @@ public class CodegenBinding {
|
||||
) {
|
||||
Collection<ClassDescriptor> innerClasses = bindingTrace.get(INNER_CLASSES, outer);
|
||||
if (innerClasses == null) {
|
||||
innerClasses = new ArrayList<ClassDescriptor>();
|
||||
innerClasses = new ArrayList<ClassDescriptor>(1);
|
||||
bindingTrace.record(INNER_CLASSES, outer, innerClasses);
|
||||
}
|
||||
innerClasses.add(inner);
|
||||
|
||||
Reference in New Issue
Block a user