Fix initialization of object's INSTANCE$ field
Call object's constructor in <clinit> and ignore the result, but in the first line of <init> save the current "this" to INSTANCE$ #KT-4516 Fixed #KT-4543 Fixed #KT-5291 Fixed #KT-5523 Fixed #KT-5582 Fixed
This commit is contained in:
@@ -641,7 +641,7 @@ public class AsmUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
|
public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
|
||||||
return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS);
|
return isClassObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
|
public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
|
||||||
@@ -668,13 +668,13 @@ public class AsmUtil {
|
|||||||
public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
|
public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
|
||||||
boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
|
boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
|
||||||
return !propertyDescriptor.isVar() && !isExtensionProperty
|
return !propertyDescriptor.isVar() && !isExtensionProperty
|
||||||
&& isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT)
|
&& isClassObjectOfClassWithKind(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT)
|
||||||
&& areBothAccessorDefault(propertyDescriptor)
|
&& areBothAccessorDefault(propertyDescriptor)
|
||||||
&& getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
|
&& getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
|
public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
|
||||||
return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS);
|
return isClassObjectOfClassWithKind(classObject, ClassKind.CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
|
private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
|
||||||
@@ -686,7 +686,7 @@ public class AsmUtil {
|
|||||||
return accessorDescriptor == null || !accessorDescriptor.hasBody();
|
return accessorDescriptor == null || !accessorDescriptor.hasBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) {
|
private static boolean isClassObjectOfClassWithKind(@NotNull DeclarationDescriptor classObject, @NotNull ClassKind kind) {
|
||||||
return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind);
|
return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,36 +17,35 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
|
||||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassKind;
|
import org.jetbrains.jet.lang.descriptors.ClassKind;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
public class FieldInfo {
|
public class FieldInfo {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static FieldInfo createForSingleton(@NotNull ClassDescriptor fieldClassDescriptor, @NotNull JetTypeMapper typeMapper) {
|
public static FieldInfo createForSingleton(@NotNull ClassDescriptor classDescriptor, @NotNull JetTypeMapper typeMapper) {
|
||||||
ClassKind kind = fieldClassDescriptor.getKind();
|
ClassKind kind = classDescriptor.getKind();
|
||||||
if (kind != ClassKind.OBJECT && kind != ClassKind.CLASS_OBJECT && kind != ClassKind.ENUM_ENTRY) {
|
if (!kind.isSingleton()) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException("Can't create singleton field for class: " + classDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type fieldType = typeMapper.mapType(fieldClassDescriptor);
|
|
||||||
|
|
||||||
ClassDescriptor ownerDescriptor = kind == ClassKind.OBJECT
|
ClassDescriptor ownerDescriptor = kind == ClassKind.OBJECT
|
||||||
? fieldClassDescriptor: DescriptorUtils.getParentOfType(fieldClassDescriptor, ClassDescriptor.class);
|
? classDescriptor
|
||||||
assert ownerDescriptor != null;
|
: DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
|
||||||
|
assert ownerDescriptor != null : "Owner not found for class: " + classDescriptor;
|
||||||
Type ownerType = typeMapper.mapType(ownerDescriptor);
|
Type ownerType = typeMapper.mapType(ownerDescriptor);
|
||||||
|
|
||||||
String fieldName = kind == ClassKind.ENUM_ENTRY
|
String fieldName = kind == ClassKind.ENUM_ENTRY
|
||||||
? fieldClassDescriptor.getName().asString()
|
? classDescriptor.getName().asString()
|
||||||
: fieldClassDescriptor.getKind() == ClassKind.CLASS_OBJECT ? JvmAbi.CLASS_OBJECT_FIELD : JvmAbi.INSTANCE_FIELD;
|
: classDescriptor.getKind() == ClassKind.CLASS_OBJECT ? JvmAbi.CLASS_OBJECT_FIELD : JvmAbi.INSTANCE_FIELD;
|
||||||
return new FieldInfo(ownerType, fieldType, fieldName, true);
|
return new FieldInfo(ownerType, typeMapper.mapType(classDescriptor), fieldName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldInfo createForHiddenField(@NotNull Type owner, Type fieldType, String fieldName) {
|
@NotNull
|
||||||
|
public static FieldInfo createForHiddenField(@NotNull Type owner, @NotNull Type fieldType, @NotNull String fieldName) {
|
||||||
return new FieldInfo(owner, fieldType, fieldName, false);
|
return new FieldInfo(owner, fieldType, fieldName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1091,8 +1091,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
v.newField(OtherOrigin(original), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
|
v.newField(OtherOrigin(original), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
|
||||||
|
|
||||||
if (!AsmUtil.isClassObjectWithBackingFieldsInOuter(fieldTypeDescriptor)) {
|
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
||||||
genInitSingleton(fieldTypeDescriptor, field);
|
|
||||||
|
if (isObject(descriptor)) {
|
||||||
|
// Invoke the object constructor but ignore the result because INSTANCE$ will be initialized in the first line of <init>
|
||||||
|
InstructionAdapter v = createOrGetClInitCodegen().v;
|
||||||
|
v.anew(classAsmType);
|
||||||
|
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
|
||||||
|
}
|
||||||
|
else if (!isClassObjectWithBackingFieldsInOuter(fieldTypeDescriptor)) {
|
||||||
|
generateClassObjectInitializer(fieldTypeDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1142,16 +1150,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
field.store(field.type, codegen.v);
|
field.store(field.type, codegen.v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void genInitSingleton(ClassDescriptor fieldTypeDescriptor, StackValue.Field field) {
|
private void generateClassObjectInitializer(@NotNull ClassDescriptor classObject) {
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
ExpressionCodegen codegen = createOrGetClInitCodegen();
|
||||||
Collection<ConstructorDescriptor> constructors = fieldTypeDescriptor.getConstructors();
|
FunctionDescriptor constructor = codegen.accessibleFunctionDescriptor(KotlinPackage.single(classObject.getConstructors()));
|
||||||
assert constructors.size() == 1 : "Class of singleton object must have only one constructor: " + constructors;
|
generateMethodCallTo(constructor, codegen.v);
|
||||||
|
StackValue.singleton(classObject, typeMapper).store(typeMapper.mapClass(classObject), codegen.v);
|
||||||
ExpressionCodegen codegen = createOrGetClInitCodegen();
|
|
||||||
FunctionDescriptor fd = codegen.accessibleFunctionDescriptor(constructors.iterator().next());
|
|
||||||
generateMethodCallTo(fd, codegen.v);
|
|
||||||
field.store(field.type, codegen.v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generatePrimaryConstructor(final DelegationFieldsInfo delegationFieldsInfo) {
|
private void generatePrimaryConstructor(final DelegationFieldsInfo delegationFieldsInfo) {
|
||||||
@@ -1211,6 +1214,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor);
|
generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isObject(descriptor)) {
|
||||||
|
iv.load(0, classAsmType);
|
||||||
|
StackValue.singleton(descriptor, typeMapper).store(classAsmType, iv);
|
||||||
|
}
|
||||||
|
|
||||||
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
|
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
|
||||||
if (specifier instanceof JetDelegatorByExpressionSpecifier) {
|
if (specifier instanceof JetDelegatorByExpressionSpecifier) {
|
||||||
genCallToDelegatorByExpressionSpecifier(iv, codegen, (JetDelegatorByExpressionSpecifier) specifier, fieldsInfo);
|
genCallToDelegatorByExpressionSpecifier(iv, codegen, (JetDelegatorByExpressionSpecifier) specifier, fieldsInfo);
|
||||||
@@ -1232,18 +1240,18 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
curParam++;
|
curParam++;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean generateInitializerInOuter = isClassObjectWithBackingFieldsInOuter(descriptor);
|
if (isClassObjectWithBackingFieldsInOuter(descriptor)) {
|
||||||
if (generateInitializerInOuter) {
|
|
||||||
final ImplementationBodyCodegen parentCodegen = getParentBodyCodegen(this);
|
final ImplementationBodyCodegen parentCodegen = getParentBodyCodegen(this);
|
||||||
//generate OBJECT$
|
//generate OBJECT$
|
||||||
parentCodegen.genInitSingleton(descriptor, StackValue.singleton(descriptor, typeMapper));
|
parentCodegen.generateClassObjectInitializer(descriptor);
|
||||||
generateInitializers(new Function0<ExpressionCodegen>() {
|
generateInitializers(new Function0<ExpressionCodegen>() {
|
||||||
@Override
|
@Override
|
||||||
public ExpressionCodegen invoke() {
|
public ExpressionCodegen invoke() {
|
||||||
return parentCodegen.createOrGetClInitCodegen();
|
return parentCodegen.createOrGetClInitCodegen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
generateInitializers(new Function0<ExpressionCodegen>() {
|
generateInitializers(new Function0<ExpressionCodegen>() {
|
||||||
@Override
|
@Override
|
||||||
public ExpressionCodegen invoke() {
|
public ExpressionCodegen invoke() {
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
trait T {
|
||||||
|
fun foo(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
val o = object : T {
|
||||||
|
val a = "OK"
|
||||||
|
val f = {
|
||||||
|
a
|
||||||
|
}()
|
||||||
|
|
||||||
|
override fun foo() = f
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = o.foo()
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
|
object O {
|
||||||
|
val mmmap = HashMap<String, Int>();
|
||||||
|
|
||||||
|
{
|
||||||
|
fun doStuff() {
|
||||||
|
mmmap.put("two", 2)
|
||||||
|
}
|
||||||
|
doStuff()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val r = O.mmmap["two"]
|
||||||
|
if (r != 2) return "Fail: $r"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
object A {
|
||||||
|
val a = "OK"
|
||||||
|
val b = A.a
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = A.b
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
public inline fun <T> T.with(f: T.() -> Unit): T {
|
||||||
|
this.f()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Cls {
|
||||||
|
val string = "Cls"
|
||||||
|
val buffer = StringBuilder().with {
|
||||||
|
append(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Obj {
|
||||||
|
val string = "Obj"
|
||||||
|
val buffer = StringBuilder().with {
|
||||||
|
append(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (Cls().buffer.toString() != "Cls") return "Fail class"
|
||||||
|
if (Obj.buffer.toString() != "Obj") return "Fail object"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
class A(val result: String)
|
||||||
|
|
||||||
|
fun a(body: A.() -> String): String {
|
||||||
|
val r = A("OK")
|
||||||
|
return r.body()
|
||||||
|
}
|
||||||
|
|
||||||
|
object C {
|
||||||
|
private fun A.f() = result
|
||||||
|
|
||||||
|
val g = a {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = C.g
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
trait T
|
||||||
|
|
||||||
|
object Foo {
|
||||||
|
private fun foo(p: T) = p
|
||||||
|
|
||||||
|
private val v: Int = {
|
||||||
|
val x = foo(O)
|
||||||
|
42
|
||||||
|
}()
|
||||||
|
|
||||||
|
private object O : T
|
||||||
|
|
||||||
|
val result = v
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val foo = Foo
|
||||||
|
if (foo.result != 42) return "Fail: ${foo.result}"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -4654,6 +4654,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/objects"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/objects"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousObjectPropertyInitialization.kt")
|
||||||
|
public void testAnonymousObjectPropertyInitialization() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/anonymousObjectPropertyInitialization.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("flist.kt")
|
@TestMetadata("flist.kt")
|
||||||
public void testFlist() throws Exception {
|
public void testFlist() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/flist.kt");
|
||||||
@@ -4768,6 +4774,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localFunctionInObjectInitializer_kt4516.kt")
|
||||||
|
public void testLocalFunctionInObjectInitializer_kt4516() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/localFunctionInObjectInitializer_kt4516.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("methodOnObject.kt")
|
@TestMetadata("methodOnObject.kt")
|
||||||
public void testMethodOnObject() throws Exception {
|
public void testMethodOnObject() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/methodOnObject.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/methodOnObject.kt");
|
||||||
@@ -4786,6 +4798,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("objectInitialization_kt5523.kt")
|
||||||
|
public void testObjectInitialization_kt5523() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectInitialization_kt5523.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("objectLiteral.kt")
|
@TestMetadata("objectLiteral.kt")
|
||||||
public void testObjectLiteral() throws Exception {
|
public void testObjectLiteral() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectLiteral.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectLiteral.kt");
|
||||||
@@ -4798,6 +4816,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("objectVsClassInitialization_kt5291.kt")
|
||||||
|
public void testObjectVsClassInitialization_kt5291() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectVsClassInitialization_kt5291.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("objectWithSuperclass.kt")
|
@TestMetadata("objectWithSuperclass.kt")
|
||||||
public void testObjectWithSuperclass() throws Exception {
|
public void testObjectWithSuperclass() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectWithSuperclass.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/objectWithSuperclass.kt");
|
||||||
@@ -4810,6 +4834,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("privateExtensionFromInitializer_kt4543.kt")
|
||||||
|
public void testPrivateExtensionFromInitializer_kt4543() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/privateExtensionFromInitializer_kt4543.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("privateFunctionFromClosureInInitializer_kt5582.kt")
|
||||||
|
public void testPrivateFunctionFromClosureInInitializer_kt5582() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/privateFunctionFromClosureInInitializer_kt5582.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("receiverInConstructor.kt")
|
@TestMetadata("receiverInConstructor.kt")
|
||||||
public void testReceiverInConstructor() throws Exception {
|
public void testReceiverInConstructor() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/receiverInConstructor.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/receiverInConstructor.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user