[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 isStatic: Boolean = false,
|
||||
val isAbstract: Boolean = false,
|
||||
val isProtected: Boolean,
|
||||
val ir: IrSimpleFunction
|
||||
) : ExportedDeclaration()
|
||||
|
||||
class ExportedConstructor(
|
||||
val parameters: List<ExportedParameter>
|
||||
val parameters: List<ExportedParameter>,
|
||||
val isProtected: Boolean
|
||||
) : ExportedDeclaration()
|
||||
|
||||
class ExportedProperty(
|
||||
@@ -45,6 +47,7 @@ class ExportedProperty(
|
||||
val isMember: Boolean = false,
|
||||
val isStatic: Boolean = false,
|
||||
val isAbstract: Boolean,
|
||||
val isProtected: Boolean,
|
||||
val irGetter: IrFunction?,
|
||||
val irSetter: IrFunction?,
|
||||
) : ExportedDeclaration()
|
||||
|
||||
+9
-2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
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.JsLoweredDeclarationOrigin
|
||||
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,
|
||||
isStatic = function.isStaticMethodOfClass,
|
||||
isAbstract = parent is IrClass && !parent.isInterface && function.modality == Modality.ABSTRACT,
|
||||
isProtected = function.visibility == DescriptorVisibilities.PROTECTED,
|
||||
ir = function
|
||||
)
|
||||
}
|
||||
@@ -84,7 +86,10 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
||||
if (!constructor.isPrimary) return null
|
||||
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) +
|
||||
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 {
|
||||
@@ -115,6 +120,7 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
||||
isMember = parentClass != null,
|
||||
isStatic = false,
|
||||
isAbstract = parentClass?.isInterface == false && property.modality == Modality.ABSTRACT,
|
||||
isProtected = property.visibility == DescriptorVisibilities.PROTECTED,
|
||||
irGetter = property.getter,
|
||||
irSetter = property.setter
|
||||
)
|
||||
@@ -217,6 +223,7 @@ class ExportModelGenerator(val context: JsIrBackendContext) {
|
||||
isMember = klass.parent is IrClass,
|
||||
isStatic = true,
|
||||
isAbstract = false,
|
||||
isProtected = klass.visibility == DescriptorVisibilities.PROTECTED,
|
||||
irGetter = context.mapping.objectToGetInstanceFunction[klass]!!,
|
||||
irSetter = null
|
||||
)
|
||||
@@ -372,7 +379,7 @@ private fun getExportCandidate(declaration: IrDeclaration): IrDeclarationWithNam
|
||||
// Only actual public declarations with name can be exported
|
||||
if (declaration !is IrDeclarationWithVisibility ||
|
||||
declaration !is IrDeclarationWithName ||
|
||||
declaration.visibility != DescriptorVisibilities.PUBLIC ||
|
||||
!declaration.visibility.isPublicAPI ||
|
||||
declaration.isExpect
|
||||
) {
|
||||
return null
|
||||
|
||||
+10
-4
@@ -41,6 +41,8 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin
|
||||
"${prefix}namespace $name {\n" + declarations.toTypeScript("$indent ") + "$indent}"
|
||||
|
||||
is ExportedFunction -> {
|
||||
val visibility = if (isProtected) "protected " else ""
|
||||
|
||||
val keyword: String = when {
|
||||
isMember -> when {
|
||||
isStatic -> "static "
|
||||
@@ -60,17 +62,21 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin
|
||||
|
||||
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 -> {
|
||||
val visibility = if (isProtected) "protected " else ""
|
||||
val keyword = when {
|
||||
isMember -> (if (isAbstract) "abstract " else "") + (if (!mutable) "readonly " else "")
|
||||
else -> if (mutable) "let " else "const "
|
||||
}
|
||||
prefix + keyword + name + ": " + type.toTypeScript(indent) + ";"
|
||||
"$prefix$visibility$keyword$name: ${type.toTypeScript(indent)};"
|
||||
}
|
||||
|
||||
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)
|
||||
continue
|
||||
|
||||
if (property.visibility != DescriptorVisibilities.PUBLIC)
|
||||
if (!property.visibility.isPublicAPI)
|
||||
continue
|
||||
|
||||
if (property.isFakeOverride)
|
||||
|
||||
Generated
+5
@@ -1632,6 +1632,11 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
||||
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")
|
||||
public void testNonIndetifierModuleName() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("exportProtectedMembers.kt")
|
||||
public void testExportProtectedMembers() throws Exception {
|
||||
runTest("js/js.translator/testData/box/export/exportProtectedMembers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonIndetifierModuleName.kt")
|
||||
public void testNonIndetifierModuleName() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("exportProtectedMembers.kt")
|
||||
public void testExportProtectedMembers() throws Exception {
|
||||
runTest("js/js.translator/testData/box/export/exportProtectedMembers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonIndetifierModuleName.kt")
|
||||
public void testNonIndetifierModuleName() throws Exception {
|
||||
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 {
|
||||
constructor();
|
||||
protected readonly protectedVal: number;
|
||||
protected protectedFun(): number;
|
||||
protected readonly protectedNestedObject: {
|
||||
};
|
||||
protected readonly Companion: {
|
||||
readonly companionObjectProp: number;
|
||||
};
|
||||
readonly publicVal: number;
|
||||
publicFun(): number;
|
||||
}
|
||||
namespace Class {
|
||||
class protectedClass {
|
||||
constructor();
|
||||
}
|
||||
class classWithProtectedConstructors {
|
||||
protected constructor();
|
||||
protected static createWithString(arg: string): Class.classWithProtectedConstructors;
|
||||
}
|
||||
class publicClass {
|
||||
constructor();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,17 @@ open class Class {
|
||||
|
||||
protected val protectedVal = 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
|
||||
@JsName("publicFun") // TODO: Should work without JsName
|
||||
|
||||
Reference in New Issue
Block a user