[JS IR] Export protected members too
#KT-47524 Fixed #KT-47525 Fixed
This commit is contained in:
@@ -31,11 +31,13 @@ class ExportedFunction(
|
|||||||
val isMember: Boolean = false,
|
val isMember: Boolean = false,
|
||||||
val isStatic: Boolean = false,
|
val isStatic: Boolean = false,
|
||||||
val isAbstract: Boolean = false,
|
val isAbstract: Boolean = false,
|
||||||
|
val isProtected: Boolean,
|
||||||
val ir: IrSimpleFunction
|
val ir: IrSimpleFunction
|
||||||
) : ExportedDeclaration()
|
) : ExportedDeclaration()
|
||||||
|
|
||||||
class ExportedConstructor(
|
class ExportedConstructor(
|
||||||
val parameters: List<ExportedParameter>
|
val parameters: List<ExportedParameter>,
|
||||||
|
val isProtected: Boolean
|
||||||
) : ExportedDeclaration()
|
) : ExportedDeclaration()
|
||||||
|
|
||||||
class ExportedProperty(
|
class ExportedProperty(
|
||||||
@@ -45,6 +47,7 @@ class ExportedProperty(
|
|||||||
val isMember: Boolean = false,
|
val isMember: Boolean = false,
|
||||||
val isStatic: Boolean = false,
|
val isStatic: Boolean = false,
|
||||||
val isAbstract: Boolean,
|
val isAbstract: Boolean,
|
||||||
|
val isProtected: Boolean,
|
||||||
val irGetter: IrFunction?,
|
val irGetter: IrFunction?,
|
||||||
val irSetter: IrFunction?,
|
val irSetter: IrFunction?,
|
||||||
) : ExportedDeclaration()
|
) : ExportedDeclaration()
|
||||||
|
|||||||
+9
-2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER
|
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER
|
||||||
@@ -75,6 +76,7 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
|||||||
isMember = parent is IrClass,
|
isMember = parent is IrClass,
|
||||||
isStatic = function.isStaticMethodOfClass,
|
isStatic = function.isStaticMethodOfClass,
|
||||||
isAbstract = parent is IrClass && !parent.isInterface && function.modality == Modality.ABSTRACT,
|
isAbstract = parent is IrClass && !parent.isInterface && function.modality == Modality.ABSTRACT,
|
||||||
|
isProtected = function.visibility == DescriptorVisibilities.PROTECTED,
|
||||||
ir = function
|
ir = function
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,10 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
|||||||
if (!constructor.isPrimary) return null
|
if (!constructor.isPrimary) return null
|
||||||
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) +
|
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) +
|
||||||
constructor.valueParameters.filterNot { it.origin === ES6_RESULT_TYPE_PARAMETER || it.origin === ES6_INIT_BOX_PARAMETER }
|
constructor.valueParameters.filterNot { it.origin === ES6_RESULT_TYPE_PARAMETER || it.origin === ES6_INIT_BOX_PARAMETER }
|
||||||
return ExportedConstructor(allValueParameters.map { exportParameter(it) })
|
return ExportedConstructor(
|
||||||
|
parameters = allValueParameters.map { exportParameter(it) },
|
||||||
|
isProtected = constructor.visibility == DescriptorVisibilities.PROTECTED
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exportParameter(parameter: IrValueParameter): ExportedParameter {
|
private fun exportParameter(parameter: IrValueParameter): ExportedParameter {
|
||||||
@@ -115,6 +120,7 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
|||||||
isMember = parentClass != null,
|
isMember = parentClass != null,
|
||||||
isStatic = false,
|
isStatic = false,
|
||||||
isAbstract = parentClass?.isInterface == false && property.modality == Modality.ABSTRACT,
|
isAbstract = parentClass?.isInterface == false && property.modality == Modality.ABSTRACT,
|
||||||
|
isProtected = property.visibility == DescriptorVisibilities.PROTECTED,
|
||||||
irGetter = property.getter,
|
irGetter = property.getter,
|
||||||
irSetter = property.setter
|
irSetter = property.setter
|
||||||
)
|
)
|
||||||
@@ -217,6 +223,7 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
|||||||
isMember = klass.parent is IrClass,
|
isMember = klass.parent is IrClass,
|
||||||
isStatic = true,
|
isStatic = true,
|
||||||
isAbstract = false,
|
isAbstract = false,
|
||||||
|
isProtected = klass.visibility == DescriptorVisibilities.PROTECTED,
|
||||||
irGetter = context.mapping.objectToGetInstanceFunction[klass]!!,
|
irGetter = context.mapping.objectToGetInstanceFunction[klass]!!,
|
||||||
irSetter = null
|
irSetter = null
|
||||||
)
|
)
|
||||||
@@ -372,7 +379,7 @@ private fun getExportCandidate(declaration: IrDeclaration): IrDeclarationWithNam
|
|||||||
// Only actual public declarations with name can be exported
|
// Only actual public declarations with name can be exported
|
||||||
if (declaration !is IrDeclarationWithVisibility ||
|
if (declaration !is IrDeclarationWithVisibility ||
|
||||||
declaration !is IrDeclarationWithName ||
|
declaration !is IrDeclarationWithName ||
|
||||||
declaration.visibility != DescriptorVisibilities.PUBLIC ||
|
!declaration.visibility.isPublicAPI ||
|
||||||
declaration.isExpect
|
declaration.isExpect
|
||||||
) {
|
) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
+10
-4
@@ -41,6 +41,8 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin
|
|||||||
"${prefix}namespace $name {\n" + declarations.toTypeScript("$indent ") + "$indent}"
|
"${prefix}namespace $name {\n" + declarations.toTypeScript("$indent ") + "$indent}"
|
||||||
|
|
||||||
is ExportedFunction -> {
|
is ExportedFunction -> {
|
||||||
|
val visibility = if (isProtected) "protected " else ""
|
||||||
|
|
||||||
val keyword: String = when {
|
val keyword: String = when {
|
||||||
isMember -> when {
|
isMember -> when {
|
||||||
isStatic -> "static "
|
isStatic -> "static "
|
||||||
@@ -60,17 +62,21 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin
|
|||||||
|
|
||||||
val renderedReturnType = returnType.toTypeScript(indent)
|
val renderedReturnType = returnType.toTypeScript(indent)
|
||||||
|
|
||||||
"${prefix}$keyword$name$renderedTypeParameters($renderedParameters): $renderedReturnType;"
|
"${prefix}$visibility$keyword$name$renderedTypeParameters($renderedParameters): $renderedReturnType;"
|
||||||
|
}
|
||||||
|
is ExportedConstructor -> {
|
||||||
|
val visibility = if (isProtected) "protected " else ""
|
||||||
|
val renderedParameters = parameters.joinToString(", ") { it.toTypeScript(indent) }
|
||||||
|
"${visibility}constructor($renderedParameters);"
|
||||||
}
|
}
|
||||||
is ExportedConstructor ->
|
|
||||||
"constructor(${parameters.joinToString(", ") { it.toTypeScript(indent) }});"
|
|
||||||
|
|
||||||
is ExportedProperty -> {
|
is ExportedProperty -> {
|
||||||
|
val visibility = if (isProtected) "protected " else ""
|
||||||
val keyword = when {
|
val keyword = when {
|
||||||
isMember -> (if (isAbstract) "abstract " else "") + (if (!mutable) "readonly " else "")
|
isMember -> (if (isAbstract) "abstract " else "") + (if (!mutable) "readonly " else "")
|
||||||
else -> if (mutable) "let " else "const "
|
else -> if (mutable) "let " else "const "
|
||||||
}
|
}
|
||||||
prefix + keyword + name + ": " + type.toTypeScript(indent) + ";"
|
"$prefix$visibility$keyword$name: ${type.toTypeScript(indent)};"
|
||||||
}
|
}
|
||||||
|
|
||||||
is ExportedClass -> {
|
is ExportedClass -> {
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null)
|
if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (property.visibility != DescriptorVisibilities.PUBLIC)
|
if (!property.visibility.isPublicAPI)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (property.isFakeOverride)
|
if (property.isFakeOverride)
|
||||||
|
|||||||
Generated
+5
@@ -1632,6 +1632,11 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
|||||||
runTest("js/js.translator/testData/box/export/exportNestedObject.kt");
|
runTest("js/js.translator/testData/box/export/exportNestedObject.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("exportProtectedMembers.kt")
|
||||||
|
public void testExportProtectedMembers() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/export/exportProtectedMembers.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/export/nonIndetifierModuleName.kt");
|
runTest("js/js.translator/testData/box/export/nonIndetifierModuleName.kt");
|
||||||
|
|||||||
+5
@@ -1632,6 +1632,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/export/exportNestedObject.kt");
|
runTest("js/js.translator/testData/box/export/exportNestedObject.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("exportProtectedMembers.kt")
|
||||||
|
public void testExportProtectedMembers() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/export/exportProtectedMembers.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/export/nonIndetifierModuleName.kt");
|
runTest("js/js.translator/testData/box/export/nonIndetifierModuleName.kt");
|
||||||
|
|||||||
+5
@@ -1637,6 +1637,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/export/exportNestedObject.kt");
|
runTest("js/js.translator/testData/box/export/exportNestedObject.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("exportProtectedMembers.kt")
|
||||||
|
public void testExportProtectedMembers() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/export/exportProtectedMembers.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonIndetifierModuleName.kt")
|
@TestMetadata("nonIndetifierModuleName.kt")
|
||||||
public void testNonIndetifierModuleName() throws Exception {
|
public void testNonIndetifierModuleName() throws Exception {
|
||||||
runTest("js/js.translator/testData/box/export/nonIndetifierModuleName.kt");
|
runTest("js/js.translator/testData/box/export/nonIndetifierModuleName.kt");
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// EXPECTED_REACHABLE_NODES: 1265
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
// SKIP_MINIFICATION
|
||||||
|
// SKIP_NODE_JS
|
||||||
|
// SKIP_DCE_DRIVEN
|
||||||
|
|
||||||
|
// MODULE: exportProtectedMembers
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
open class Foo protected constructor() {
|
||||||
|
protected fun bar(): String = "protected method"
|
||||||
|
|
||||||
|
private var _baz: String = "baz"
|
||||||
|
|
||||||
|
protected var baz: String
|
||||||
|
get() = _baz
|
||||||
|
set(value) {
|
||||||
|
_baz = value
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class NestedClass {
|
||||||
|
val prop: String = "nested class property"
|
||||||
|
}
|
||||||
|
protected object NestedObject {
|
||||||
|
val prop: String = "nested object property"
|
||||||
|
}
|
||||||
|
|
||||||
|
protected companion object {
|
||||||
|
val prop: String = "companion object property"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.js
|
||||||
|
function box() {
|
||||||
|
foo = new exportProtectedMembers.Foo();
|
||||||
|
|
||||||
|
if (foo.bar() != 'protected method') return 'failed to call protected method';
|
||||||
|
if (foo.baz != 'baz') return 'failed to read protected property';
|
||||||
|
foo.baz = 'beer';
|
||||||
|
if (foo.baz != 'beer') return 'failed to write protected property';
|
||||||
|
|
||||||
|
nestedClass = new exportProtectedMembers.Foo.NestedClass()
|
||||||
|
if (nestedClass.prop != 'nested class property')
|
||||||
|
return 'failed to read protected class property'
|
||||||
|
if (exportProtectedMembers.Foo.NestedObject.prop != 'nested object property')
|
||||||
|
return 'failed to read protected nested object property'
|
||||||
|
if (exportProtectedMembers.Foo.Companion.prop != 'companion object property')
|
||||||
|
return 'failed to read protected companion object property'
|
||||||
|
|
||||||
|
return 'OK';
|
||||||
|
}
|
||||||
@@ -9,10 +9,24 @@ declare namespace JS_TESTS {
|
|||||||
}
|
}
|
||||||
class Class {
|
class Class {
|
||||||
constructor();
|
constructor();
|
||||||
|
protected readonly protectedVal: number;
|
||||||
|
protected protectedFun(): number;
|
||||||
|
protected readonly protectedNestedObject: {
|
||||||
|
};
|
||||||
|
protected readonly Companion: {
|
||||||
|
readonly companionObjectProp: number;
|
||||||
|
};
|
||||||
readonly publicVal: number;
|
readonly publicVal: number;
|
||||||
publicFun(): number;
|
publicFun(): number;
|
||||||
}
|
}
|
||||||
namespace Class {
|
namespace Class {
|
||||||
|
class protectedClass {
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
|
class classWithProtectedConstructors {
|
||||||
|
protected constructor();
|
||||||
|
protected static createWithString(arg: string): Class.classWithProtectedConstructors;
|
||||||
|
}
|
||||||
class publicClass {
|
class publicClass {
|
||||||
constructor();
|
constructor();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,17 @@ open class Class {
|
|||||||
|
|
||||||
protected val protectedVal = 10
|
protected val protectedVal = 10
|
||||||
protected fun protectedFun() = 10
|
protected fun protectedFun() = 10
|
||||||
protected class protectedClass
|
protected class protectedClass {}
|
||||||
|
protected object protectedNestedObject {}
|
||||||
|
protected companion object {
|
||||||
|
val companionObjectProp = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
public class classWithProtectedConstructors protected constructor() {
|
||||||
|
|
||||||
|
@JsName("createWithString")
|
||||||
|
protected constructor(arg: String): this()
|
||||||
|
}
|
||||||
|
|
||||||
public val publicVal = 10
|
public val publicVal = 10
|
||||||
@JsName("publicFun") // TODO: Should work without JsName
|
@JsName("publicFun") // TODO: Should work without JsName
|
||||||
|
|||||||
Reference in New Issue
Block a user