KT-5524 Support [platformName] annotation for class members

@platformName is now supported for final non-overriding class member functions
(including property accessors).
Front-end provides diagnostics for inapplicable annotation cases.
Code generation updated:
- ignore kotlin.platform.platformName annotation for Java class methods;
- bridges generation generates proper JVM declarations in case of methods renamed with @platformName.
@platformName-related tests added.

#KT-5524 Fixed
This commit is contained in:
dnpetrov
2015-06-04 15:48:10 +03:00
parent 0bf249d6ae
commit 50ea67ba13
16 changed files with 392 additions and 30 deletions
@@ -760,7 +760,7 @@ public class FunctionCodegen {
int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
MethodVisitor mv =
v.newMethod(DiagnosticsPackage.Bridge(descriptor, origin), flags, delegateTo.getName(), bridge.getDescriptor(), null, null);
v.newMethod(DiagnosticsPackage.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null);
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
mv.visitCode();
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
@@ -663,8 +664,10 @@ public class JetTypeMapper {
@NotNull
private String mapFunctionName(@NotNull FunctionDescriptor descriptor) {
String platformName = getPlatformName(descriptor);
if (platformName != null) return platformName;
if (!(descriptor instanceof JavaCallableMemberDescriptor)) {
String platformName = getPlatformName(descriptor);
if (platformName != null) return platformName;
}
if (descriptor instanceof PropertyAccessorDescriptor) {
PropertyDescriptor property = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
@@ -113,6 +113,7 @@ public interface Errors {
DiagnosticFactory1<PsiElement, JetModifierKeywordToken> REPEATED_MODIFIER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, JetModifierKeywordToken> REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory0<PsiElement> INAPPLICABLE_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_PLATFORM_NAME = DiagnosticFactory0.create(ERROR);
// Annotations
@@ -121,6 +121,7 @@ public class DefaultErrorMessages {
MAP.put(ILLEGAL_MODIFIER, "Illegal modifier ''{0}''", TO_STRING);
MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING);
MAP.put(INAPPLICABLE_ANNOTATION, "This annotation is only applicable to top level functions");
MAP.put(INAPPLICABLE_PLATFORM_NAME, "platformName annotation is not applicable to this declaration");
MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING);
MAP.put(ABSTRACT_MODIFIER_IN_TRAIT, "Modifier ''abstract'' is redundant in interface");
@@ -295,21 +295,37 @@ public class ModifiersChecker {
JetAnnotationEntry annotationEntry = trace.get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation);
if (annotationEntry == null) return;
if (!DescriptorUtils.isTopLevelDeclaration(descriptor) || !(descriptor instanceof FunctionDescriptor) ||
descriptor instanceof ConstructorDescriptor) {
trace.report(INAPPLICABLE_ANNOTATION.on(annotationEntry));
if (!isRenamableDeclaration(descriptor)) {
trace.report(INAPPLICABLE_PLATFORM_NAME.on(annotationEntry));
}
String value = null;
Collection<CompileTimeConstant<?>> values = annotation.getAllValueArguments().values();
if (!values.isEmpty()) {
CompileTimeConstant<?> name = values.iterator().next();
if (name instanceof StringValue) {
String value = ((StringValue) name).getValue();
if (value == null || !Name.isValidIdentifier(value)) {
trace.report(ILLEGAL_PLATFORM_NAME.on(annotationEntry, String.valueOf(value)));
}
value = ((StringValue) name).getValue();
}
}
if (value == null || !Name.isValidIdentifier(value)) {
trace.report(ILLEGAL_PLATFORM_NAME.on(annotationEntry, String.valueOf(value)));
}
if (descriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) descriptor;
if (DescriptorUtils.isOverride(callableMemberDescriptor) || callableMemberDescriptor.getModality().isOverridable()) {
trace.report(INAPPLICABLE_PLATFORM_NAME.on(annotationEntry));
}
}
}
private static boolean isRenamableDeclaration(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
return (descriptor instanceof PropertyAccessorDescriptor)
|| (containingDescriptor instanceof PackageFragmentDescriptor || containingDescriptor instanceof ClassDescriptor)
&& descriptor instanceof FunctionDescriptor && !(descriptor instanceof ConstructorDescriptor);
}
private void checkCompatibility(@Nullable JetModifierList modifierList, Collection<JetModifierKeywordToken> availableModifiers, Collection<JetModifierKeywordToken>... availableCombinations) {
@@ -0,0 +1,12 @@
import kotlin.platform.platformName;
public class FakePlatformName {
@platformName(name = "fake")
public String foo() {
return "foo";
}
public String fake() {
return "fake";
}
}
@@ -0,0 +1,6 @@
fun box(): String {
val test1 = FakePlatformName().foo()
if (test1 != "foo") return "Failed: FakePlatformName().foo()==$test1"
return "OK"
}
@@ -0,0 +1,121 @@
import kotlin.platform.*
// See:
// http://kotlinlang.org/docs/reference/java-interop.html#handling-signature-clashes-with-platformname
// https://youtrack.jetbrains.com/issue/KT-5524
val strs = listOf("abc", "def")
val ints = listOf(1, 2, 3)
class C {
// Instance methods
@platformName("instMethodStr")
fun instMethod(list: List<String>): String = "instMethodStr"
@platformName("instMethodInt")
fun instMethod(list: List<Int>): String = "instMethodInt"
// Properties
var rwProperty: Int
@platformName("get_rwProperty")
get() = 123
@platformName("set_rwProperty")
set(v) {}
var rwValue = 111
fun getRwProperty(): Int = rwValue
fun setRwProperty(v: Int) {
rwValue = v
}
// Extension methods
class Inner
@platformName("extMethodWithGenericParamStr")
fun Inner.extMethodWithGenericParam(list: List<String>): String = "extMethodWithGenericParamStr"
@platformName("extMethodWithGenericParamInt")
fun Inner.extMethodWithGenericParam(list: List<Int>): String = "extMethodWithGenericParamInt"
// This is already covered by extMethodWithGenericParam(), but might be relevant for a platform
// with extension method code generation strategy different from Java 6.
@platformName("extMethodWithGenericReceiverStr")
fun List<String>.extMethodWithGenericReceiver(): String = "extMethodWithGenericReceiverStr"
@platformName("extMethodWithGenericReceiverInt")
fun List<Int>.extMethodWithGenericReceiver(): String = "extMethodWithGenericReceiverInt"
// Extension method vs instance method
@platformName("ambigMethod1")
fun ambigMethod(str: String): String = "ambigMethod1"
@platformName("ambigMethod2")
fun String.ambigMethod(): String = "ambigMethod2"
}
fun box(): String {
val c = C()
// Instance methods:
// method signatures with erased types SHOULD NOT clash
val test1 = c.instMethod(strs)
if (test1 != "instMethodStr") return "Fail: c.instMethod(strs)==$test1"
val test2 = c.instMethod(ints)
if (test2 != "instMethodInt") return "Fail: c.instMethod(ints)==$test2"
// Properties:
// property accessors SHOULD NOT clash with class methods
val test3 = c.rwProperty
if (test3 != 123) return "Fail: c.rwProperty==$test3"
val test3a = c.getRwProperty()
if (test3a != 111) return "Fail: c.getRwProperty()==$test3a"
c.setRwProperty(444)
val test3b = c.rwProperty
if (test3b != 123) return "Fail: c.rwProperty==$test3b after c.setRwProperty(1234)"
val test3c = c.getRwProperty()
if (test3c != 444) return "Fail: c.getRwProperty()==$test3c after c.setRwProperty(1234)"
// Extension methods:
// method signatures with erased types SHOULD NOT clash
val test4 = with(c) { C.Inner().extMethodWithGenericParam(strs) }
if (test4 != "extMethodWithGenericParamStr") return "Fail: with(c) { C.Inner().extMethodWithGenericParam(strs) }==$test4"
val test5 = with(c) { C.Inner().extMethodWithGenericParam(ints) }
if (test5 != "extMethodWithGenericParamInt") return "Fail: with(c) { C.Inner().extMethodWithGenericParam(ints) }==$test5"
val test6 = with(c) { strs.extMethodWithGenericReceiver() }
if (test6 != "extMethodWithGenericReceiverStr") return "Fail: with(c) { strs.extMethodWithGenericReceiver() }==$test6"
val test7 = with(c) { ints.extMethodWithGenericReceiver() }
if (test7 != "extMethodWithGenericReceiverInt") return "Fail: with(c) { ints.extMethodWithGenericReceiver() }==$test7"
// Extension method SHOULD NOT clash with instance method with the same Java signature.
val str = "abc"
val test8 = with(c) { ambigMethod(str) }
if (test8 != "ambigMethod1") return "Fail: with(c) { ambigMethod(str) }==$test8"
val test9 = with(c) { str.ambigMethod() }
if (test9 != "ambigMethod2") return "Fail: with(c) { str.ambigMethod() }==$test9"
// Everything is fine.
return "OK"
}
@@ -8,10 +8,10 @@ fun foo() {}
@platformName("b")
fun Any.foo() {}
<!INAPPLICABLE_ANNOTATION!>@platformName("c")<!>
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("c")<!>
val px = 1
<!INAPPLICABLE_ANNOTATION!>@platformName("d")<!>
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("d")<!>
val Any.px : Int
get() = 1
@@ -31,37 +31,61 @@ var vardef: Int = 1
@platformName("i")
set
<!INAPPLICABLE_ANNOTATION!>@platformName("C")<!>
class C <!INAPPLICABLE_ANNOTATION!>platformName("primary")<!> constructor() {
<!INAPPLICABLE_ANNOTATION!>platformName("ctr")<!> constructor(x: Int): this() {}
<!INAPPLICABLE_ANNOTATION!>@platformName("a")<!>
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("C")<!>
class C <!INAPPLICABLE_PLATFORM_NAME!>platformName("primary")<!> constructor() {
<!INAPPLICABLE_PLATFORM_NAME!>platformName("ctr")<!> constructor(x: Int): this() {}
@platformName("a")
fun foo() {}
<!INAPPLICABLE_ANNOTATION!>@platformName("b")<!>
@platformName("b")
fun Any.foo() {}
<!INAPPLICABLE_ANNOTATION!>@platformName("c")<!>
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("c")<!>
val px = 1
<!INAPPLICABLE_ANNOTATION!>@platformName("d")<!>
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("d")<!>
val Any.px : Int
get() = 1
val valx: Int
<!INAPPLICABLE_ANNOTATION!>@platformName("e")<!>
@platformName("e")
get() = 1
var varx: Int
<!INAPPLICABLE_ANNOTATION!>@platformName("f")<!>
@platformName("f")
get() = 1
<!INAPPLICABLE_ANNOTATION!>@platformName("g")<!>
@platformName("g")
set(v) {}
}
fun foo1() {
<!INAPPLICABLE_ANNOTATION!>@platformName("a")<!>
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("a")<!>
fun foo() {}
<!INAPPLICABLE_ANNOTATION!>@platformName("a")<!>
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("a")<!>
val x = 1
}
}
abstract class AB {
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("AB_absFun1")<!>
abstract fun absFun1()
abstract fun absFun2()
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("AB_openFun")<!>
open fun openFun() {}
}
class D: AB() {
override fun absFun1() {}
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("D_absFun2")<!>
override fun absFun2() {}
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("D_openFun")<!>
final override fun openFun() {}
@platformName("D_finalFun")
fun finalFun() {}
}
@@ -1,4 +1,4 @@
package
package
kotlin.platform.platformName(name = "c": kotlin.String) internal val px: kotlin.Int = 1
internal val valx: kotlin.Int
@@ -9,6 +9,16 @@ kotlin.platform.platformName(name = "a": kotlin.String) internal fun foo(): kotl
internal fun foo1(): kotlin.Unit
kotlin.platform.platformName(name = "b": kotlin.String) internal fun kotlin.Any.foo(): kotlin.Unit
internal abstract class AB {
public constructor AB()
kotlin.platform.platformName(name = "AB_absFun1": kotlin.String) internal abstract fun absFun1(): kotlin.Unit
internal abstract fun absFun2(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
kotlin.platform.platformName(name = "AB_openFun": kotlin.String) internal open fun openFun(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
kotlin.platform.platformName(name = "C": kotlin.String) internal final class C {
kotlin.platform.platformName(name = "primary": kotlin.String) public constructor C()
kotlin.platform.platformName(name = "ctr": kotlin.String) public constructor C(/*0*/ x: kotlin.Int)
@@ -22,3 +32,14 @@ kotlin.platform.platformName(name = "C": kotlin.String) internal final class C {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
kotlin.platform.platformName(name = "b": kotlin.String) internal final fun kotlin.Any.foo(): kotlin.Unit
}
internal final class D : AB {
public constructor D()
internal open override /*1*/ fun absFun1(): kotlin.Unit
kotlin.platform.platformName(name = "D_absFun2": kotlin.String) internal open override /*1*/ fun absFun2(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "D_finalFun": kotlin.String) internal final fun finalFun(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
kotlin.platform.platformName(name = "D_openFun": kotlin.String) internal final override /*1*/ fun openFun(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -4,4 +4,21 @@ import kotlin.platform.*
@platformName("bar")
fun foo(a: Any) {}
fun Any.foo() {}
fun Any.foo() {}
@platformName("barInt")
fun bar(x: List<Int>) {}
@platformName("barStr")
fun bar(x: List<String>) {}
class C {
var rwProp: Int
@platformName("get_rwProp")
get() = 0
@platformName("set_rwProp")
set(v) {}
fun getRwProp(): Int = 123
fun setRwProp(v: Int) {}
}
@@ -1,4 +1,16 @@
package
package
kotlin.platform.platformName(name = "barInt": kotlin.String) internal fun bar(/*0*/ x: kotlin.List<kotlin.Int>): kotlin.Unit
kotlin.platform.platformName(name = "barStr": kotlin.String) internal fun bar(/*0*/ x: kotlin.List<kotlin.String>): kotlin.Unit
kotlin.platform.platformName(name = "bar": kotlin.String) internal fun foo(/*0*/ a: kotlin.Any): kotlin.Unit
internal fun kotlin.Any.foo(): kotlin.Unit
internal final class C {
public constructor C()
internal final var rwProp: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
internal final fun getRwProp(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
internal final fun setRwProp(/*0*/ v: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -4,4 +4,52 @@ import kotlin.platform.*
<!CONFLICTING_JVM_DECLARATIONS!>@platformName("bar")
fun foo(a: Any)<!> {}
<!CONFLICTING_JVM_DECLARATIONS!>fun bar(a: Any)<!> {}
<!CONFLICTING_JVM_DECLARATIONS!>fun bar(a: Any)<!> {}
class C {
<!CONFLICTING_JVM_DECLARATIONS!>@platformName("foo1")
fun foo(list: List<Int>)<!> {}
<!CONFLICTING_JVM_DECLARATIONS!>@platformName("foo1")
fun foo(list: List<String>)<!> {}
}
// Conflicts in inheritance.
// A1 -> B1 with accidental override
open class A1 {
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("bar")<!>
open fun foo() {}
}
class B1 : A1() {
<!ACCIDENTAL_OVERRIDE!>fun bar()<!> {}
}
// A2 -> B2 with intended override and conflicting JVM declarations
open class A2 {
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("bar")<!>
open fun foo() {}
}
class <!CONFLICTING_JVM_DECLARATIONS!>B2<!> : A2() {
override fun foo() {}
<!CONFLICTING_JVM_DECLARATIONS!>fun bar()<!> {}
}
// A3 -> B3 -> C3 with accidental override
open class A3 {
<!INAPPLICABLE_PLATFORM_NAME!>@platformName("bar")<!>
open fun foo() {}
}
open class B3: A3() {
}
class C3: B3() {
<!ACCIDENTAL_OVERRIDE!>fun bar()<!> {}
}
@@ -1,4 +1,72 @@
package
package
internal fun bar(/*0*/ a: kotlin.Any): kotlin.Unit
kotlin.platform.platformName(name = "bar": kotlin.String) internal fun foo(/*0*/ a: kotlin.Any): kotlin.Unit
internal open class A1 {
public constructor A1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "bar": kotlin.String) internal open fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal open class A2 {
public constructor A2()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "bar": kotlin.String) internal open fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal open class A3 {
public constructor A3()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "bar": kotlin.String) internal open fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class B1 : A1 {
public constructor B1()
internal final fun bar(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "bar": kotlin.String) internal open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class B2 : A2 {
public constructor B2()
internal final fun bar(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
internal open override /*1*/ fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal open class B3 : A3 {
public constructor B3()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "bar": kotlin.String) internal open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "foo1": kotlin.String) internal final fun foo(/*0*/ list: kotlin.List<kotlin.Int>): kotlin.Unit
kotlin.platform.platformName(name = "foo1": kotlin.String) internal final fun foo(/*0*/ list: kotlin.List<kotlin.String>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class C3 : B3 {
public constructor C3()
internal final fun bar(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
kotlin.platform.platformName(name = "bar": kotlin.String) internal open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -59,6 +59,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName);
}
@TestMetadata("platformName")
public void testPlatformName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/platformName/");
doTestWithJava(fileName);
}
@TestMetadata("referenceToJavaFieldOfKotlinSubclass")
public void testReferenceToJavaFieldOfKotlinSubclass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/referenceToJavaFieldOfKotlinSubclass/");
@@ -2194,6 +2194,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("classMembers.kt")
public void testClassMembers() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/platformNames/classMembers.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("functionName.kt")
public void testFunctionName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/platformNames/functionName.kt");