- InnerClasses & EnclosingMethod attributes for local classes

in multifile part members
- invocation of multifile part/facade members
(TODO: deserialized descriptor case)
- inlining of multifile part/facade members
(TODO: inline against binaries case)
This commit is contained in:
Dmitry Petrov
2015-09-10 16:43:56 +03:00
parent 6a3cd50a70
commit 2931e474e1
27 changed files with 259 additions and 82 deletions
@@ -27,9 +27,6 @@ import java.util.*
public class CodegenFileClassesProvider() : JvmFileClassesProvider {
private val fileParts = hashMapOf<JetFile, JvmFileClassInfo>()
override fun getFileClassFqName(file: JetFile): FqName =
getFileClassInfo(file).fileClassFqName
public fun getFileClassInfo(file: JetFile): JvmFileClassInfo =
override public fun getFileClassInfo(file: JetFile): JvmFileClassInfo =
fileParts.getOrPut(file) { JvmFileClassUtil.getFileClassInfoNoResolve(file) }
}
@@ -148,9 +148,8 @@ public class FunctionCodegen {
int flags = getMethodAsmFlags(functionDescriptor, contextKind);
boolean isNative = NativeDeclarationsPackage.hasNativeAnnotation(functionDescriptor);
//TODO: generate native method only in new mini facades (now it equals to package part)
if (isNative && owner instanceof PackageFacadeContext) {
// Native methods are only defined in package facades and do not need package part implementations
if (isNative && owner instanceof DelegatingFacadeContext) {
// Native methods are only defined in facades and do not need package part implementations
return;
}
MethodVisitor mv = v.newMethod(origin,
@@ -160,7 +159,7 @@ public class FunctionCodegen {
jvmSignature.getGenericsSignature(),
getThrownExceptions(functionDescriptor, typeMapper));
String implClassName = CodegenContextUtil.getImplClassNameByOwnerIfRequired(owner);
String implClassName = CodegenContextUtil.getImplementationClassShortName(owner);
if (implClassName != null) {
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, implClassName);
}
@@ -329,8 +328,8 @@ public class FunctionCodegen {
JetTypeMapper typeMapper = parentCodegen.typeMapper;
Label methodEnd;
if (context.getParentContext() instanceof PackageFacadeContext) {
generatePackageDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext());
if (context.getParentContext() instanceof DelegatingFacadeContext) {
generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (DelegatingFacadeContext) context.getParentContext());
methodEnd = new Label();
}
else {
@@ -402,10 +401,10 @@ public class FunctionCodegen {
}
}
private static void generatePackageDelegateMethodBody(
private static void generateFacadeDelegateMethodBody(
@NotNull MethodVisitor mv,
@NotNull Method asmMethod,
@NotNull PackageFacadeContext context
@NotNull DelegatingFacadeContext context
) {
generateDelegateToMethodBody(true, mv, asmMethod, context.getDelegateToClassType().getInternalName());
}
@@ -596,9 +595,9 @@ public class FunctionCodegen {
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType());
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
if (this.owner instanceof PackageFacadeContext) {
if (this.owner instanceof DelegatingFacadeContext) {
mv.visitCode();
generatePackageDelegateMethodBody(mv, defaultMethod, (PackageFacadeContext) this.owner);
generateFacadeDelegateMethodBody(mv, defaultMethod, (DelegatingFacadeContext) this.owner);
endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
}
else {
@@ -289,9 +289,16 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
if (outermost instanceof ClassContext) {
return typeMapper.mapType(((ClassContext) outermost).getContextDescriptor());
}
else if (outermost instanceof PackageContext && !(outermost instanceof PackageFacadeContext)) {
return fileClassesProvider.getFileClassType(element.getContainingJetFile());
}/*disabled cause of KT-7775
else if (outermost instanceof DelegatingFacadeContext || outermost instanceof DelegatingToPartContext) {
Type implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(outermost);
if (implementationOwnerType != null) {
return implementationOwnerType;
}
else {
return fileClassesProvider.getFileClassType(element.getContainingJetFile());
}
}
/*disabled cause of KT-7775
else if (outermost instanceof ScriptContext) {
return asmTypeForScriptDescriptor(bindingContext, ((ScriptContext) outermost).getScriptDescriptor());
}*/
@@ -110,7 +110,7 @@ public class PropertyCodegen {
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
Type implClassType = CodegenContextUtil.getImplClassTypeByOwnerIfRequired(context);
Type implClassType = CodegenContextUtil.getImplementationOwnerClassType(context);
if (implClassType != null) {
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, shortNameByAsmType(implClassType));
}
@@ -493,6 +493,9 @@ public class PropertyCodegen {
else if (ownerContext instanceof PackageContext) {
owner = ((PackageContext) ownerContext).getPackagePartType();
}
else if (ownerContext instanceof MultifileClassContextBase) {
owner = ((MultifileClassContextBase) ownerContext).getFilePartType();
}
else {
throw new UnsupportedOperationException("Unknown context: " + ownerContext);
}
@@ -204,7 +204,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
@NotNull Type multifileClassType,
@NotNull Type filePartType
) {
return new MultifileClassContext(descriptor, this, multifileClassType, filePartType);
return new MultifileClassFacadeContext(descriptor, this, multifileClassType, filePartType);
}
@NotNull
@@ -21,21 +21,19 @@ import org.jetbrains.org.objectweb.asm.Type
public object CodegenContextUtil {
public @JvmStatic fun getImplClassTypeByOwnerIfRequired(owner: CodegenContext<*>): Type? =
public @JvmStatic fun getImplementationOwnerClassType(owner: CodegenContext<*>): Type? =
when (owner) {
is PackageFacadeContext ->
is DelegatingFacadeContext ->
owner.delegateToClassType
is PackageContext ->
owner.packagePartType
is MultifileClassOrPartContext ->
owner.filePartType
is DelegatingToPartContext ->
owner.implementationOwnerClassType
else ->
null
}
public @JvmStatic fun getImplClassNameByOwnerIfRequired(owner: CodegenContext<*>): String? =
getImplClassTypeByOwnerIfRequired(owner)?.let{ AsmUtil.shortNameByAsmType(it) }
public @JvmStatic fun getImplementationClassShortName(owner: CodegenContext<*>): String? =
getImplementationOwnerClassType(owner)?.let { AsmUtil.shortNameByAsmType(it) }
public @JvmStatic fun isImplClassOwner(owner: CodegenContext<*>): Boolean =
!(owner is PackageFacadeContext || owner is MultifileClassContext)
owner !is DelegatingFacadeContext
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.org.objectweb.asm.Type;
public interface DelegatingFacadeContext {
@Nullable
public Type getDelegateToClassType();
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.org.objectweb.asm.Type;
public interface DelegatingToPartContext {
@Nullable
Type getImplementationOwnerClassType();
}
@@ -20,11 +20,11 @@ import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.org.objectweb.asm.Type;
public class MultifileClassOrPartContext extends FieldOwnerContext<PackageFragmentDescriptor> {
public class MultifileClassContextBase extends FieldOwnerContext<PackageFragmentDescriptor> {
private final Type multifileClassType;
private final Type filePartType;
public MultifileClassOrPartContext(
public MultifileClassContextBase(
PackageFragmentDescriptor descriptor,
CodegenContext parent,
Type multifileClassType,
@@ -16,13 +16,12 @@
package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.org.objectweb.asm.Type;
public class MultifileClassContext extends MultifileClassOrPartContext {
public MultifileClassContext(
public class MultifileClassFacadeContext extends MultifileClassContextBase implements DelegatingFacadeContext {
public MultifileClassFacadeContext(
PackageFragmentDescriptor descriptor,
CodegenContext parent,
Type multifileClassType,
@@ -31,4 +30,9 @@ public class MultifileClassContext extends MultifileClassOrPartContext {
super(descriptor, parent, multifileClassType, filePartType);
}
@Nullable
@Override
public Type getDelegateToClassType() {
return getFilePartType();
}
}
@@ -16,12 +16,11 @@
package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.org.objectweb.asm.Type;
public class MultifileClassPartContext extends MultifileClassOrPartContext {
public class MultifileClassPartContext extends MultifileClassContextBase implements DelegatingToPartContext {
public MultifileClassPartContext(
PackageFragmentDescriptor descriptor,
CodegenContext parent,
@@ -31,4 +30,9 @@ public class MultifileClassPartContext extends MultifileClassOrPartContext {
super(descriptor, parent, multifileClassType, filePartType);
}
@Nullable
@Override
public Type getImplementationOwnerClassType() {
return getFilePartType();
}
}
@@ -17,14 +17,19 @@
package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.org.objectweb.asm.Type;
public class PackageContext extends FieldOwnerContext<PackageFragmentDescriptor> {
public class PackageContext extends FieldOwnerContext<PackageFragmentDescriptor> implements DelegatingToPartContext {
private final Type packagePartType;
public PackageContext(@NotNull PackageFragmentDescriptor contextDescriptor, @NotNull CodegenContext parent, Type packagePartType) {
public PackageContext(
@NotNull PackageFragmentDescriptor contextDescriptor,
@NotNull CodegenContext parent,
@Nullable Type packagePartType
) {
super(contextDescriptor, OwnerKind.PACKAGE, parent, null, null, null);
this.packagePartType = packagePartType;
}
@@ -34,7 +39,14 @@ public class PackageContext extends FieldOwnerContext<PackageFragmentDescriptor>
return "Package: " + getContextDescriptor().getName();
}
@Nullable
public Type getPackagePartType() {
return packagePartType;
}
@Nullable
@Override
public Type getImplementationOwnerClassType() {
return packagePartType;
}
}
@@ -17,20 +17,22 @@
package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.org.objectweb.asm.Type;
public class PackageFacadeContext extends PackageContext {
public class PackageFacadeContext extends PackageContext implements DelegatingFacadeContext {
public PackageFacadeContext(
@NotNull PackageFragmentDescriptor contextDescriptor,
@NotNull CodegenContext parent,
@NotNull Type delegateTo
@NotNull Type packagePartType
) {
super(contextDescriptor, parent, delegateTo);
super(contextDescriptor, parent, packagePartType);
}
@NotNull
@Override
@Nullable
public Type getDelegateToClassType() {
return getPackagePartType();
}
@@ -26,9 +26,7 @@ import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.codegen.MemberCodegen;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.PackageContext;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
@@ -221,22 +219,22 @@ public class InlineCodegenUtil {
if (currentDescriptor instanceof PackageFragmentDescriptor) {
PsiFile file = getContainingFile(codegenContext);
Type packagePartType;
Type implementationOwnerType;
if (file == null) {
//in case package fragment clinit
assert codegenContext instanceof PackageContext : "Expected package context but " + codegenContext;
packagePartType = ((PackageContext) codegenContext).getPackagePartType();
implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(codegenContext);
} else {
packagePartType = fileClassesManager.getFileClassType((JetFile) file);
implementationOwnerType = fileClassesManager.getFileClassType((JetFile) file);
}
if (packagePartType == null) {
if (implementationOwnerType == null) {
DeclarationDescriptor contextDescriptor = codegenContext.getContextDescriptor();
//noinspection ConstantConditions
throw new RuntimeException("Couldn't find declaration for " + contextDescriptor.getContainingDeclaration().getName() + "." + contextDescriptor.getName() );
throw new RuntimeException("Couldn't find declaration for " +
contextDescriptor.getContainingDeclaration().getName() + "." + contextDescriptor.getName() +
"; context: " + codegenContext);
}
return packagePartType.getInternalName();
return implementationOwnerType.getInternalName();
}
else if (currentDescriptor instanceof ClassifierDescriptor) {
Type type = typeMapper.mapType((ClassifierDescriptor) currentDescriptor);
@@ -144,9 +144,7 @@ public class JetTypeMapper {
if (container instanceof PackageFragmentDescriptor) {
boolean effectiveInsideModule = isInsideModule && !NativeDeclarationsPackage.hasNativeAnnotation(descriptor);
return Type.getObjectType(internalNameForPackage(
(PackageFragmentDescriptor) container,
(CallableMemberDescriptor) descriptor,
effectiveInsideModule
(CallableMemberDescriptor) descriptor
));
}
else if (container instanceof ClassDescriptor) {
@@ -161,25 +159,25 @@ public class JetTypeMapper {
}
@NotNull
private String internalNameForPackage(
@NotNull PackageFragmentDescriptor packageFragment,
@NotNull CallableMemberDescriptor descriptor,
boolean insideModule
) {
///if (insideModule) {
JetFile file = DescriptorToSourceUtils.getContainingFile(descriptor);
if (file != null) {
private String internalNameForPackage(@NotNull CallableMemberDescriptor descriptor) {
JetFile file = DescriptorToSourceUtils.getContainingFile(descriptor);
if (file != null) {
Visibility visibility = descriptor.getVisibility();
if (Visibilities.isPrivate(visibility)) {
return fileClassesProvider.getFileClassInternalName(file);
}
CallableMemberDescriptor directMember = getDirectMember(descriptor);
if (directMember instanceof DeserializedCallableMemberDescriptor) {
FqName packagePartFqName = PackagePartClassUtils.getPackagePartFqName((DeserializedCallableMemberDescriptor) directMember);
return internalNameByFqNameWithoutInnerClasses(packagePartFqName);
else {
return fileClassesProvider.getFacadeClassInternalName(file);
}
}
//}
CallableMemberDescriptor directMember = getDirectMember(descriptor);
if (directMember instanceof DeserializedCallableMemberDescriptor) {
// TODO private vs public
FqName packagePartFqName = PackagePartClassUtils.getPackagePartFqName((DeserializedCallableMemberDescriptor) directMember);
return internalNameByFqNameWithoutInnerClasses(packagePartFqName);
}
throw new RuntimeException("Unreachable state");
//return PackageClassUtils.getPackageClassInternalName(packageFragment.getFqName());
@@ -22,12 +22,29 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.org.objectweb.asm.Type
public interface JvmFileClassesProvider {
public fun getFileClassFqName(file: JetFile): FqName
public fun getFileClassInfo(file: JetFile): JvmFileClassInfo
public fun getFileClassFqName(file: JetFile): FqName =
getFileClassInfo(file).fileClassFqName
public fun getFileClassInternalName(file: JetFile): String =
JvmClassName.byFqNameWithoutInnerClasses(getFileClassFqName(file)).internalName
getFileClassFqName(file).getInternalName()
public fun getFileClassType(file: JetFile): Type =
Type.getObjectType(getFileClassInternalName(file))
getFileClassFqName(file).getClassType()
public fun getFacadeClassFqName(file: JetFile): FqName =
getFileClassInfo(file).facadeClassFqName
public fun getFacadeClassInternalName(file: JetFile): String =
getFacadeClassFqName(file).getInternalName()
public fun getFacadeClassType(file: JetFile): Type =
getFacadeClassFqName(file).getClassType()
}
private fun FqName.getInternalName(): String =
JvmClassName.byFqNameWithoutInnerClasses(this).internalName
private fun FqName.getClassType(): Type =
Type.getObjectType(getInternalName())
@@ -21,6 +21,6 @@ import org.jetbrains.kotlin.psi.JetFile
public object NoResolveFileClassesProvider : JvmFileClassesProvider {
override fun getFileClassFqName(file: JetFile): FqName =
JvmFileClassUtil.getFileClassInfo(file, JvmFileClassUtil.parseJvmNameOnFileNoResolve(file)).fileClassFqName
override fun getFileClassInfo(file: JetFile): JvmFileClassInfo =
JvmFileClassUtil.getFileClassInfo(file, JvmFileClassUtil.parseJvmNameOnFileNoResolve(file))
}
@@ -2,4 +2,4 @@
@file:JvmMultifileClass
public fun bar(): String = barx()
private fun foox(): String = "O"
public fun foox(): String = "O"
@@ -2,4 +2,4 @@
@file:JvmMultifileClass
public fun foo(): String = foox()
private fun barx(): String = "K"
public fun barx(): String = "K"
@@ -0,0 +1,11 @@
@file:JvmName("TestPackage")
@file:JvmMultifileClass
package test
fun foo(): String = bar()
fun bar(): String {
class Local(val x: String)
return Local("OK").x
}
fun box(): String = foo()
@@ -0,0 +1,5 @@
@file:[JvmName("Util") JvmMultifileClass]
package test
internal fun internalInOtherFile() {}
public fun publicInOtherFile() {}
@@ -0,0 +1,23 @@
@file:[JvmName("Util") JvmMultifileClass]
package test
fun foo() {
privateInThisFile()
internalInThisFile()
publicInThisFile()
internalInOtherFile()
publicInOtherFile()
}
private fun privateInThisFile() {}
internal fun internalInThisFile() {}
public fun publicInThisFile() {}
// @test/1ThisFileKt.class:
// 1 INVOKESTATIC test/1ThisFileKt.privateInThisFile
// 1 INVOKESTATIC test/1ThisFileKt.internalInThisFile
// 1 INVOKESTATIC test/1ThisFileKt.publicInThisFile
// 1 INVOKESTATIC test/1OtherFileKt.internalInOtherFile
// 1 INVOKESTATIC test/1OtherFileKt.publicInOtherFile
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.JetTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/bytecodeTextMultifile")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class BytecodeTextMultifileTestGenerated extends AbstractBytecodeTextTest {
public void testAllFilesPresentInBytecodeTextMultifile() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeTextMultifile"), Pattern.compile("^([^\\.]+)$"), false);
}
@TestMetadata("partMembersCall")
public void testPartMembersCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeTextMultifile/partMembersCall/");
doTestMultiFile(fileName);
}
}
@@ -141,9 +141,9 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName);
}
@TestMetadata("multifileClassWithCrossPrivate")
public void testMultifileClassWithCrossPrivate() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/fileClasses/multifileClassWithCrossPrivate/");
@TestMetadata("multifileClassWithCrossCall")
public void testMultifileClassWithCrossCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/fileClasses/multifileClassWithCrossCall/");
doTestWithJava(fileName);
}
@@ -2245,6 +2245,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("multifileClassWithLocalClass.kt")
public void testMultifileClassWithLocalClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/platformNames/multifileClassWithLocalClass.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("multifileClassWithLocalGeneric.kt")
public void testMultifileClassWithLocalGeneric() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/platformNames/multifileClassWithLocalGeneric.kt");