From 025a21761b326767207b4a373593a3c2d24b8056 Mon Sep 17 00:00:00 2001 From: Artem Kobzar Date: Thu, 28 Apr 2022 15:54:50 +0000 Subject: [PATCH] fix: change logic of calculation fqName for export model. --- .../backend/js/export/ExportModelGenerator.kt | 19 +++---------- .../kotlin/ir/backend/js/utils/IrJsUtils.kt | 18 ++++++++++--- .../declarations/declarations.d.ts | 15 +++++++++++ .../declarations/declarations.kt | 27 +++++++++++++++++++ .../declarations/declarations__main.js | 6 +++++ .../declarations/declarations__main.ts | 10 +++++++ 6 files changed, 77 insertions(+), 18 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt index f9ca28e810b..379acfbb10b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt @@ -504,8 +504,10 @@ class ExportModelGenerator( classifier is IrClassSymbol -> { val klass = classifier.owner - val isImplicitlyExported = !klass.isExported(context) && !klass.isExternal - val name = klass.getExportableName() + val isExported = klass.isExported(context) + val isImplicitlyExported = !isExported && !klass.isExternal + val isNonExportedExternal = klass.isExternal && !isExported + val name = klass.getFqNameWithJsNameWhenAvailable(!isNonExportedExternal && generateNamespacesForPackages).asString() when (klass.kind) { ClassKind.ANNOTATION_CLASS, @@ -531,19 +533,6 @@ class ExportModelGenerator( return exportedType.withNullability(isMarkedNullable) } - private fun IrClass.getExportableName(): String { - val qualifier = (parent as? IrFile)?.getJsQualifier() - val supQualifier = (parent as? IrClass)?.getExportableName() - val name = getJsNameOrKotlinName() - - return when { - qualifier != null -> "$qualifier.$name" - isExternal && !isExported(context) -> "${supQualifier?.plus(".") ?: ""}$name" - generateNamespacesForPackages -> fqNameWhenAvailable!!.asString() - else -> name.asString() - } - } - private fun IrDeclarationWithName.getExportedIdentifier(): String = with(getJsNameOrKotlinName()) { if (isSpecial) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt index 20c130c5449..1c8b7ed579b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/IrJsUtils.kt @@ -9,12 +9,11 @@ import org.jetbrains.kotlin.descriptors.isClass import org.jetbrains.kotlin.descriptors.isInterface import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.export.isExported -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrReturn import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol import org.jetbrains.kotlin.ir.util.parentClassOrNull +import org.jetbrains.kotlin.name.FqName fun IrDeclaration.isExportedMember(context: JsIrBackendContext) = (this is IrDeclarationWithVisibility && visibility.isPublicAPI) && @@ -29,3 +28,16 @@ fun IrDeclaration?.isExportedInterface(context: JsIrBackendContext) = fun IrReturn.isTheLastReturnStatementIn(target: IrReturnableBlockSymbol): Boolean { return target.owner.statements.lastOrNull() === this } + +fun IrDeclarationWithName.getFqNameWithJsNameWhenAvailable(shouldIncludePackage: Boolean): FqName { + val name = getJsNameOrKotlinName() + return when (val parent = parent) { + is IrDeclarationWithName -> parent.getFqNameWithJsNameWhenAvailable(shouldIncludePackage).child(name) + is IrPackageFragment -> getKotlinOrJsQualifier(parent, shouldIncludePackage)?.child(name) ?: FqName(name.identifier) + else -> FqName(name.identifier) + } +} + +private fun getKotlinOrJsQualifier(parent: IrPackageFragment, shouldIncludePackage: Boolean): FqName? { + return (parent as? IrFile)?.getJsQualifier()?.let { FqName(it) } ?: parent.fqName.takeIf { shouldIncludePackage } +} diff --git a/js/js.translator/testData/typescript-export/declarations/declarations.d.ts b/js/js.translator/testData/typescript-export/declarations/declarations.d.ts index 30d43fb1a76..4c657fde1ce 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations.d.ts +++ b/js/js.translator/testData/typescript-export/declarations/declarations.d.ts @@ -167,5 +167,20 @@ declare namespace JS_TESTS { then(): number; catch(): number; } + class JsNameTest { + private constructor(); + get value(): number; + runTest(): string; + static get Companion(): { + create(): foo.JsNameTest; + createChild(value: number): foo.JsNameTest.NestedJsName; + }; + } + namespace JsNameTest { + class NestedJsName { + constructor(__value: number); + get value(): number; + } + } } } diff --git a/js/js.translator/testData/typescript-export/declarations/declarations.kt b/js/js.translator/testData/typescript-export/declarations/declarations.kt index c6fe3cfc3a0..e303e357190 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations.kt +++ b/js/js.translator/testData/typescript-export/declarations/declarations.kt @@ -219,4 +219,31 @@ class OuterClass { class KT38262 { fun then(): Int = 42 fun catch(): Int = 24 +} + +@JsExport +@JsName("JsNameTest") +class __JsNameTest private constructor() { + @JsName("value") + val __value = 4 + + @JsName("runTest") + fun __runTest(): String { + return "JsNameTest" + } + + companion object { + @JsName("create") + fun __create(): __JsNameTest { + return __JsNameTest() + } + + @JsName("createChild") + fun __createChild(value: Int): __NestJsNameTest { + return __NestJsNameTest(value) + } + } + + @JsName("NestedJsName") + class __NestJsNameTest(@JsName("value") val __value: Int) } \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/declarations/declarations__main.js b/js/js.translator/testData/typescript-export/declarations/declarations__main.js index abdfaa20d01..aa17238e03e 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations__main.js +++ b/js/js.translator/testData/typescript-export/declarations/declarations__main.js @@ -31,6 +31,7 @@ var TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl; var processInterface = JS_TESTS.foo.processInterface; var OuterClass = JS_TESTS.foo.OuterClass; var KT38262 = JS_TESTS.foo.KT38262; +var JsNameTest = JS_TESTS.foo.JsNameTest; function assert(condition) { if (!condition) { throw "Assertion failed"; @@ -129,5 +130,10 @@ function box() { assert(OuterClass.NestedEnum.B.ordinal === 1); assert(new KT38262().then() == 42); assert(new KT38262().catch() == 24); + var jsNameTest = JsNameTest.Companion.create(); + assert(jsNameTest.value === 4); + assert(jsNameTest.runTest() === "JsNameTest"); + var jsNameNestedTest = JsNameTest.Companion.createChild(42); + assert(jsNameNestedTest.value === 42); return "OK"; } diff --git a/js/js.translator/testData/typescript-export/declarations/declarations__main.ts b/js/js.translator/testData/typescript-export/declarations/declarations__main.ts index 3d1d4050029..ba23d890a51 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations__main.ts +++ b/js/js.translator/testData/typescript-export/declarations/declarations__main.ts @@ -31,6 +31,7 @@ import TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl; import processInterface = JS_TESTS.foo.processInterface; import OuterClass = JS_TESTS.foo.OuterClass; import KT38262 = JS_TESTS.foo.KT38262; +import JsNameTest = JS_TESTS.foo.JsNameTest; function assert(condition: boolean) { if (!condition) { @@ -156,5 +157,14 @@ function box(): string { assert(new KT38262().then() == 42) assert(new KT38262().catch() == 24) + const jsNameTest = JsNameTest.Companion.create(); + + assert(jsNameTest.value === 4) + assert(jsNameTest.runTest() === "JsNameTest") + + const jsNameNestedTest = JsNameTest.Companion.createChild(42); + + assert(jsNameNestedTest.value === 42) + return "OK"; } \ No newline at end of file