Move object initialization from <init> to <clinit>

Codegen generates static backing fields for object properties.
  They are initialized in class constructor but some of them are final static
  and such access is prohibited in specification but it's allowed in
  java bytecode <= 1.8. Such access in 1.9 bytecode cause
  "IllegalAccessError: Update to static final field Object.INSTANCE
  attempted from a different method (<init>) than the initializer method <clinit>"

  Added additional hidden field in interface companion to pass out
  companion instance from <clinit>.

 #KT-15894 Fixed
This commit is contained in:
Mikhael Bogdanov
2017-03-14 13:52:07 +01:00
committed by Ilya Gorbunov
parent de004337a2
commit b73be50e5b
13 changed files with 223 additions and 47 deletions
@@ -34,7 +34,7 @@ public class FieldInfo {
}
if (isNonCompanionObject(classDescriptor) || CompanionObjectMapping.INSTANCE.isMappedIntrinsicCompanionObject(classDescriptor)) {
return createSingletonViaInstance(classDescriptor, typeMapper);
return createSingletonViaInstance(classDescriptor, typeMapper, JvmAbi.INSTANCE_FIELD);
}
ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
@@ -46,10 +46,11 @@ public class FieldInfo {
@NotNull
public static FieldInfo createSingletonViaInstance(
@NotNull ClassDescriptor classDescriptor,
@NotNull KotlinTypeMapper typeMapper
@NotNull KotlinTypeMapper typeMapper,
@NotNull String name
) {
Type type = typeMapper.mapType(classDescriptor);
return new FieldInfo(type, type, JvmAbi.INSTANCE_FIELD, true);
return new FieldInfo(type, type, name, true);
}
@NotNull
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode;
import org.jetbrains.kotlin.name.ClassId;
@@ -77,6 +76,7 @@ import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isNonGenericToArray;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtils2Kt.initDefaultSourceMappingIfNeeded;
import static org.jetbrains.kotlin.load.java.JvmAbi.*;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull;
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
@@ -354,6 +354,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
protected void generateSyntheticPartsAfterBody() {
generateFieldForSingleton();
initializeObjects();
generateCompanionObjectBackingFieldCopies();
generateTraitMethods();
@@ -811,21 +813,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateFieldForSingleton() {
if (isCompanionObjectInInterfaceNotIntrinsic(descriptor)) {
StackValue.Field field = StackValue.createSingletonViaInstance(descriptor, typeMapper, HIDDEN_INSTANCE_FIELD);
//hidden instance in interface companion
v.newField(JvmDeclarationOriginKt.OtherOrigin(descriptor),
ACC_SYNTHETIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
}
if (isEnumEntry(descriptor) || isCompanionObject(descriptor)) return;
if (isNonCompanionObject(descriptor)) {
StackValue.Field field = StackValue.singletonViaInstance(descriptor, typeMapper);
StackValue.Field field = StackValue.createSingletonViaInstance(descriptor, typeMapper, INSTANCE_FIELD);
v.newField(JvmDeclarationOriginKt.OtherOriginFromPure(myClass),
ACC_PUBLIC | ACC_STATIC | ACC_FINAL,
field.name, field.type.getDescriptor(), null, null);
if (!state.getClassBuilderMode().generateBodies) return;
// Invoke the object constructor but ignore the result because INSTANCE will be initialized in the first line of <init>
InstructionAdapter v = createOrGetClInitCodegen().v;
markLineNumberForElement(element.getPsiOrParent(), v);
v.anew(classAsmType);
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
return;
}
@@ -853,6 +855,60 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
private void initializeObjects() {
if (!DescriptorUtils.isObject(descriptor)) return;
if (!state.getClassBuilderMode().generateBodies) return;
boolean isNonCompanionObject = isNonCompanionObject(descriptor);
boolean isInterfaceCompanion = isCompanionObjectInInterfaceNotIntrinsic(descriptor);
boolean isMappedIntrinsicCompanionObject = isMappedIntrinsicCompanionObject(descriptor);
if (isNonCompanionObject || isInterfaceCompanion || isMappedIntrinsicCompanionObject) {
ExpressionCodegen clInitCodegen = createOrGetClInitCodegen();
InstructionAdapter v = clInitCodegen.v;
markLineNumberForElement(element.getPsiOrParent(), v);
v.anew(classAsmType);
v.dup();
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
//local0 emulates this in object constructor
int local0Index = clInitCodegen.getFrameMap().enterTemp(classAsmType);
assert local0Index == 0 : "Local variable with index 0 in clInit should be used only for singleton instance keeping";
StackValue.Local local0 = StackValue.local(0, classAsmType);
local0.store(StackValue.onStack(classAsmType), clInitCodegen.v);
StackValue.Field singleton =
StackValue.createSingletonViaInstance(
descriptor, typeMapper, isInterfaceCompanion ? HIDDEN_INSTANCE_FIELD : INSTANCE_FIELD
);
singleton.store(local0, clInitCodegen.v);
generateInitializers(clInitCodegen);
if (isInterfaceCompanion) {
//initialize singleton instance in outer by hidden instance
StackValue.singleton(descriptor, typeMapper).store(
singleton, getParentCodegen().createOrGetClInitCodegen().v, true
);
}
}
else if (isCompanionObjectWithBackingFieldsInOuter(descriptor)) {
ImplementationBodyCodegen parentCodegen = (ImplementationBodyCodegen) getParentCodegen();
ExpressionCodegen parentClInitCodegen = parentCodegen.createOrGetClInitCodegen();
InstructionAdapter parentVisitor = parentClInitCodegen.v;
FunctionDescriptor constructor = (FunctionDescriptor) parentCodegen.context.accessibleDescriptor(
CollectionsKt.single(descriptor.getConstructors()), /* superCallExpression = */ null
);
parentCodegen.generateMethodCallTo(constructor, null, parentVisitor);
StackValue instance = StackValue.onStack(parentCodegen.typeMapper.mapClass(descriptor));
StackValue.singleton(descriptor, parentCodegen.typeMapper).store(instance, parentVisitor, true);
generateInitializers(parentClInitCodegen);
}
else {
assert false : "Unknown object type: " + descriptor;
}
}
private void generateCompanionObjectBackingFieldCopies() {
if (companionObjectPropertiesToCopy == null) return;
@@ -900,17 +956,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
field.store(property, codegen.v);
}
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
ExpressionCodegen codegen = createOrGetClInitCodegen();
FunctionDescriptor constructor = (FunctionDescriptor) context.accessibleDescriptor(
CollectionsKt.single(companionObject.getConstructors()), /* superCallExpression = */ null
);
generateMethodCallTo(constructor, null, codegen.v);
StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject));
StackValue.singleton(companionObject, typeMapper).store(instance, codegen.v, true);
}
private void generatePrimaryConstructor(DelegationFieldsInfo delegationFieldsInfo) {
if (isInterface(descriptor) || isAnnotationClass(descriptor)) return;
@@ -978,10 +1023,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor,
getDelegationConstructorCall(bindingContext, constructorDescriptor));
if (isNonCompanionObject(descriptor)) {
StackValue.singletonViaInstance(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
}
for (KtSuperTypeListEntry specifier : myClass.getSuperTypeListEntries()) {
if (specifier instanceof KtDelegatedSuperTypeEntry) {
genCallToDelegatorByExpressionSpecifier(iv, codegen, (KtDelegatedSuperTypeEntry) specifier, fieldsInfo);
@@ -1003,18 +1044,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
curParam++;
}
if (isCompanionObject(descriptor)) {
ImplementationBodyCodegen parentCodegen = (ImplementationBodyCodegen) getParentCodegen();
parentCodegen.generateCompanionObjectInitializer(descriptor);
}
if (JvmAbi.isCompanionObjectWithBackingFieldsInOuter(descriptor)) {
generateInitializers(((ImplementationBodyCodegen) getParentCodegen())::createOrGetClInitCodegen);
}
else {
//object initialization was moved to initializeObjects()
if (!isObject(descriptor)) {
generateInitializers(codegen);
}
iv.visitInsn(RETURN);
}
@@ -1159,7 +1192,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (asmType == null) continue;
result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, JvmAbi.DELEGATE_SUPER_FIELD_PREFIX + n);
result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, DELEGATE_SUPER_FIELD_PREFIX + n);
}
n++;
}
@@ -621,8 +621,8 @@ public abstract class StackValue {
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper), none());
}
public static Field singletonViaInstance(ClassDescriptor classDescriptor, KotlinTypeMapper typeMapper) {
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper), none());
public static Field createSingletonViaInstance(@NotNull ClassDescriptor classDescriptor, @NotNull KotlinTypeMapper typeMapper, @NotNull String name) {
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper, name), none());
}
public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {
+19
View File
@@ -0,0 +1,19 @@
var result = ""
class A {
companion object {
val prop = test()
fun test(): String {
result += "OK"
return result
}
}
}
fun box(): String {
if (A.prop != "OK") return "fail ${A.prop}"
return result
}
@@ -0,0 +1,19 @@
var result = ""
interface A {
companion object {
val prop = test()
fun test(): String {
result += "OK"
return result
}
}
}
fun box(): String {
if (A.prop != "OK") return "fail ${A.prop}"
return result
}
+15
View File
@@ -0,0 +1,15 @@
var result = ""
object A {
val prop = test()
fun test(): String {
result += "OK"
return result
}
}
fun box(): String {
if (A.prop != "OK") return "fail ${A.prop}"
return result
}
@@ -14,7 +14,7 @@ fun box(): String {
if (enclosingMethod != null) return "method: $enclosingMethod"
val enclosingConstructor = javaClass.getEnclosingConstructor()
if (enclosingConstructor == null) return "no enclosing constructor"
if (enclosingConstructor != null) return "field should be initialized in clInit"
val enclosingClass = javaClass.getEnclosingClass()
if (enclosingClass?.getName() != "O") return "enclosing class: $enclosingClass"
+10 -5
View File
@@ -49,7 +49,8 @@
"class": "PublicInterface$Companion",
"members": [
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "()V"},
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V"}
{"visibility": "public", "declaration": "companion object", "name": "$$INSTANCE", "desc": "LPublicInterface$Companion;"},
{"visibility": "public", "declaration": "companion object", "name": "<clinit>", "desc": "()V"}
]
},
{
@@ -75,7 +76,8 @@
"class": "InternalInterface$Companion",
"members": [
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "()V"},
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V"}
{"visibility": "public", "declaration": "companion object", "name": "$$INSTANCE", "desc": "LInternalInterface$Companion;"},
{"visibility": "public", "declaration": "companion object", "name": "<clinit>", "desc": "()V"}
]
},
{
@@ -101,7 +103,8 @@
"class": "InternalInterfacePrivateCompanion$Companion",
"members": [
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "()V"},
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V"}
{"visibility": "private", "declaration": "companion object", "name": "$$INSTANCE", "desc": "LInternalInterfacePrivateCompanion$Companion;"},
{"visibility": "private", "declaration": "companion object", "name": "<clinit>", "desc": "()V"}
]
},
{
@@ -163,7 +166,8 @@
"class": "PrivateInterface$Companion",
"members": [
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "()V"},
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V"}
{"visibility": "public", "declaration": "companion object", "name": "$$INSTANCE", "desc": "LPrivateInterface$Companion;"},
{"visibility": "public", "declaration": "companion object", "name": "<clinit>", "desc": "()V"}
]
},
{
@@ -189,7 +193,8 @@
"class": "PrivateInterfacePrivateCompanion$Companion",
"members": [
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "()V"},
{"visibility": "private", "declaration": "constructor Companion()", "name": "<init>", "desc": "(Lkotlin/jvm/internal/DefaultConstructorMarker;)V"}
{"visibility": "private", "declaration": "companion object", "name": "$$INSTANCE", "desc": "LPrivateInterfacePrivateCompanion$Companion;"},
{"visibility": "private", "declaration": "companion object", "name": "<clinit>", "desc": "()V"}
]
},
{
@@ -11993,6 +11993,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("classCompanion.kt")
public void testClassCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/classCompanion.kt");
doTest(fileName);
}
@TestMetadata("flist.kt")
public void testFlist() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt");
@@ -12011,6 +12017,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("interfaceCompanion.kt")
public void testInterfaceCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanion.kt");
doTest(fileName);
}
@TestMetadata("kt1047.kt")
public void testKt1047() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
@@ -12149,6 +12161,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/object.kt");
doTest(fileName);
}
@TestMetadata("objectExtendsInnerAndReferencesOuterMember.kt")
public void testObjectExtendsInnerAndReferencesOuterMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectExtendsInnerAndReferencesOuterMember.kt");
@@ -11993,6 +11993,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("classCompanion.kt")
public void testClassCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/classCompanion.kt");
doTest(fileName);
}
@TestMetadata("flist.kt")
public void testFlist() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt");
@@ -12011,6 +12017,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("interfaceCompanion.kt")
public void testInterfaceCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanion.kt");
doTest(fileName);
}
@TestMetadata("kt1047.kt")
public void testKt1047() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
@@ -12149,6 +12161,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/object.kt");
doTest(fileName);
}
@TestMetadata("objectExtendsInnerAndReferencesOuterMember.kt")
public void testObjectExtendsInnerAndReferencesOuterMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectExtendsInnerAndReferencesOuterMember.kt");
@@ -11993,6 +11993,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("classCompanion.kt")
public void testClassCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/classCompanion.kt");
doTest(fileName);
}
@TestMetadata("flist.kt")
public void testFlist() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt");
@@ -12011,6 +12017,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("interfaceCompanion.kt")
public void testInterfaceCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanion.kt");
doTest(fileName);
}
@TestMetadata("kt1047.kt")
public void testKt1047() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
@@ -12149,6 +12161,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/object.kt");
doTest(fileName);
}
@TestMetadata("objectExtendsInnerAndReferencesOuterMember.kt")
public void testObjectExtendsInnerAndReferencesOuterMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectExtendsInnerAndReferencesOuterMember.kt");
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.CapitalizeDecapitalizeKt
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassOrEnumClass;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
public final class JvmAbi {
public static final String DEFAULT_IMPLS_CLASS_NAME = "DefaultImpls";
@@ -54,6 +55,7 @@ public final class JvmAbi {
private static final String ANNOTATED_TYPEALIAS_METHOD_NAME_SUFFIX = ANNOTATIONS_SUFFIX;
public static final String INSTANCE_FIELD = "INSTANCE";
public static final String HIDDEN_INSTANCE_FIELD = "$$" + INSTANCE_FIELD;
public static final String DEFAULT_MODULE_NAME = "main";
public static final ClassId REFLECTION_FACTORY_IMPL = ClassId.topLevel(new FqName("kotlin.reflect.jvm.internal.ReflectionFactoryImpl"));
@@ -110,6 +112,16 @@ public final class JvmAbi {
public static boolean isCompanionObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor companionObject) {
return isCompanionObject(companionObject) &&
isClassOrEnumClass(companionObject.getContainingDeclaration()) &&
!CompanionObjectMapping.INSTANCE.isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject);
!isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject);
}
public static boolean isMappedIntrinsicCompanionObject(@NotNull ClassDescriptor companionObject) {
return CompanionObjectMapping.INSTANCE.isMappedIntrinsicCompanionObject(companionObject);
}
public static boolean isCompanionObjectInInterfaceNotIntrinsic(@NotNull DeclarationDescriptor companionObject) {
return isCompanionObject(companionObject) &&
isInterface(companionObject.getContainingDeclaration()) &&
!isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject);
}
}
@@ -13163,6 +13163,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("classCompanion.kt")
public void testClassCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/classCompanion.kt");
doTest(fileName);
}
@TestMetadata("flist.kt")
public void testFlist() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt");
@@ -13181,6 +13187,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("interfaceCompanion.kt")
public void testInterfaceCompanion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanion.kt");
doTest(fileName);
}
@TestMetadata("kt1047.kt")
public void testKt1047() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
@@ -13349,6 +13361,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/object.kt");
doTest(fileName);
}
@TestMetadata("objectExtendsInnerAndReferencesOuterMember.kt")
public void testObjectExtendsInnerAndReferencesOuterMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectExtendsInnerAndReferencesOuterMember.kt");