[JS IR] Add to IR keep possibility similar to legacy-dce one
It helps to: - keep declarations even if they are not reachable and not exported - not minify names of not exported declarations Compiler argument: -Xir-keep=A,B Can be used for top-level declarations or for member ^KT-54118 fixed
This commit is contained in:
+7
@@ -100,6 +100,13 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
|||||||
@Argument(value = "-target", valueDescription = "{ v5 }", description = "Generate JS files for specific ECMA version")
|
@Argument(value = "-target", valueDescription = "{ v5 }", description = "Generate JS files for specific ECMA version")
|
||||||
var target: String? by NullableStringFreezableVar(null)
|
var target: String? by NullableStringFreezableVar(null)
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
value = "-Xir-keep",
|
||||||
|
description = "Comma-separated list of fully-qualified names to not be eliminated by DCE (if it can be reached), " +
|
||||||
|
"and for which to keep non-minified names."
|
||||||
|
)
|
||||||
|
var irKeep: String? by NullableStringFreezableVar(null)
|
||||||
|
|
||||||
@GradleOption(
|
@GradleOption(
|
||||||
value = DefaultValues.JsModuleKinds::class,
|
value = DefaultValues.JsModuleKinds::class,
|
||||||
gradleInputType = GradleInputTypes.INPUT
|
gradleInputType = GradleInputTypes.INPUT
|
||||||
|
|||||||
@@ -100,6 +100,10 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
module,
|
module,
|
||||||
phaseConfig,
|
phaseConfig,
|
||||||
irFactory,
|
irFactory,
|
||||||
|
keep = arguments.irKeep?.split(",")
|
||||||
|
?.filterNot { it.isEmpty() }
|
||||||
|
?.toSet()
|
||||||
|
?: emptySet(),
|
||||||
dceRuntimeDiagnostic = RuntimeDiagnostic.resolve(
|
dceRuntimeDiagnostic = RuntimeDiagnostic.resolve(
|
||||||
arguments.irDceRuntimeDiagnostic,
|
arguments.irDceRuntimeDiagnostic,
|
||||||
messageCollector
|
messageCollector
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class JsIrBackendContext(
|
|||||||
val symbolTable: SymbolTable,
|
val symbolTable: SymbolTable,
|
||||||
irModuleFragment: IrModuleFragment,
|
irModuleFragment: IrModuleFragment,
|
||||||
val additionalExportedDeclarationNames: Set<FqName>,
|
val additionalExportedDeclarationNames: Set<FqName>,
|
||||||
|
keep: Set<String>,
|
||||||
override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context
|
override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context
|
||||||
override val scriptMode: Boolean = false,
|
override val scriptMode: Boolean = false,
|
||||||
override val es6mode: Boolean = false,
|
override val es6mode: Boolean = false,
|
||||||
@@ -86,6 +87,9 @@ class JsIrBackendContext(
|
|||||||
val minimizedNameGenerator: MinimizedNameGenerator =
|
val minimizedNameGenerator: MinimizedNameGenerator =
|
||||||
MinimizedNameGenerator()
|
MinimizedNameGenerator()
|
||||||
|
|
||||||
|
val keeper: Keeper =
|
||||||
|
Keeper(keep)
|
||||||
|
|
||||||
val fieldDataCache = mutableMapOf<IrClass, Map<IrField, String>>()
|
val fieldDataCache = mutableMapOf<IrClass, Map<IrField, String>>()
|
||||||
|
|
||||||
override val builtIns = module.builtIns
|
override val builtIns = module.builtIns
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ fun compile(
|
|||||||
phaseConfig: PhaseConfig,
|
phaseConfig: PhaseConfig,
|
||||||
irFactory: IrFactory,
|
irFactory: IrFactory,
|
||||||
exportedDeclarations: Set<FqName> = emptySet(),
|
exportedDeclarations: Set<FqName> = emptySet(),
|
||||||
|
keep: Set<String> = emptySet(),
|
||||||
dceRuntimeDiagnostic: RuntimeDiagnostic? = null,
|
dceRuntimeDiagnostic: RuntimeDiagnostic? = null,
|
||||||
es6mode: Boolean = false,
|
es6mode: Boolean = false,
|
||||||
verifySignatures: Boolean = true,
|
verifySignatures: Boolean = true,
|
||||||
@@ -76,6 +77,7 @@ fun compile(
|
|||||||
deserializer,
|
deserializer,
|
||||||
phaseConfig,
|
phaseConfig,
|
||||||
exportedDeclarations,
|
exportedDeclarations,
|
||||||
|
keep,
|
||||||
dceRuntimeDiagnostic,
|
dceRuntimeDiagnostic,
|
||||||
es6mode,
|
es6mode,
|
||||||
baseClassIntoMetadata,
|
baseClassIntoMetadata,
|
||||||
@@ -97,6 +99,7 @@ fun compileIr(
|
|||||||
irLinker: JsIrLinker,
|
irLinker: JsIrLinker,
|
||||||
phaseConfig: PhaseConfig,
|
phaseConfig: PhaseConfig,
|
||||||
exportedDeclarations: Set<FqName>,
|
exportedDeclarations: Set<FqName>,
|
||||||
|
keep: Set<String>,
|
||||||
dceRuntimeDiagnostic: RuntimeDiagnostic?,
|
dceRuntimeDiagnostic: RuntimeDiagnostic?,
|
||||||
es6mode: Boolean,
|
es6mode: Boolean,
|
||||||
baseClassIntoMetadata: Boolean,
|
baseClassIntoMetadata: Boolean,
|
||||||
@@ -119,6 +122,7 @@ fun compileIr(
|
|||||||
symbolTable,
|
symbolTable,
|
||||||
allModules.first(),
|
allModules.first(),
|
||||||
exportedDeclarations,
|
exportedDeclarations,
|
||||||
|
keep,
|
||||||
configuration,
|
configuration,
|
||||||
es6mode = es6mode,
|
es6mode = es6mode,
|
||||||
dceRuntimeDiagnostic = dceRuntimeDiagnostic,
|
dceRuntimeDiagnostic = dceRuntimeDiagnostic,
|
||||||
@@ -126,7 +130,7 @@ fun compileIr(
|
|||||||
safeExternalBoolean = safeExternalBoolean,
|
safeExternalBoolean = safeExternalBoolean,
|
||||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
||||||
granularity = granularity,
|
granularity = granularity,
|
||||||
icCompatibleIr2Js = if (icCompatibleIr2Js) IcCompatibleIr2Js.COMPATIBLE else IcCompatibleIr2Js.DISABLED
|
icCompatibleIr2Js = if (icCompatibleIr2Js) IcCompatibleIr2Js.COMPATIBLE else IcCompatibleIr2Js.DISABLED,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Load declarations referenced during `context` initialization
|
// Load declarations referenced during `context` initialization
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ fun compileWithIC(
|
|||||||
filesToLower: Collection<IrFile>,
|
filesToLower: Collection<IrFile>,
|
||||||
mainArguments: List<String>? = null,
|
mainArguments: List<String>? = null,
|
||||||
exportedDeclarations: Set<FqName> = emptySet(),
|
exportedDeclarations: Set<FqName> = emptySet(),
|
||||||
|
keep: Set<String> = emptySet(),
|
||||||
generateFullJs: Boolean = true,
|
generateFullJs: Boolean = true,
|
||||||
generateDceJs: Boolean = false,
|
generateDceJs: Boolean = false,
|
||||||
dceDriven: Boolean = false,
|
dceDriven: Boolean = false,
|
||||||
@@ -42,7 +43,7 @@ fun compileWithIC(
|
|||||||
baseClassIntoMetadata: Boolean = false,
|
baseClassIntoMetadata: Boolean = false,
|
||||||
lowerPerModule: Boolean = false,
|
lowerPerModule: Boolean = false,
|
||||||
safeExternalBoolean: Boolean = false,
|
safeExternalBoolean: Boolean = false,
|
||||||
safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null
|
safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null,
|
||||||
): List<JsIrFragmentAndBinaryAst> {
|
): List<JsIrFragmentAndBinaryAst> {
|
||||||
val irBuiltIns = mainModule.irBuiltins
|
val irBuiltIns = mainModule.irBuiltins
|
||||||
val symbolTable = (irBuiltIns as IrBuiltInsOverDescriptors).symbolTable
|
val symbolTable = (irBuiltIns as IrBuiltInsOverDescriptors).symbolTable
|
||||||
@@ -53,13 +54,14 @@ fun compileWithIC(
|
|||||||
symbolTable,
|
symbolTable,
|
||||||
mainModule,
|
mainModule,
|
||||||
exportedDeclarations,
|
exportedDeclarations,
|
||||||
|
keep,
|
||||||
configuration,
|
configuration,
|
||||||
es6mode = es6mode,
|
es6mode = es6mode,
|
||||||
dceRuntimeDiagnostic = dceRuntimeDiagnostic,
|
dceRuntimeDiagnostic = dceRuntimeDiagnostic,
|
||||||
baseClassIntoMetadata = baseClassIntoMetadata,
|
baseClassIntoMetadata = baseClassIntoMetadata,
|
||||||
safeExternalBoolean = safeExternalBoolean,
|
safeExternalBoolean = safeExternalBoolean,
|
||||||
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic,
|
||||||
icCompatibleIr2Js = IcCompatibleIr2Js.IC_MODE
|
icCompatibleIr2Js = IcCompatibleIr2Js.IC_MODE,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Load declarations referenced during `context` initialization
|
// Load declarations referenced during `context` initialization
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ private fun IrDeclaration.addRootsTo(
|
|||||||
getter?.addRootsTo(nestedVisitor, context)
|
getter?.addRootsTo(nestedVisitor, context)
|
||||||
setter?.addRootsTo(nestedVisitor, context)
|
setter?.addRootsTo(nestedVisitor, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
isEffectivelyExternal() -> {
|
isEffectivelyExternal() -> {
|
||||||
val correspondingProperty = when (this) {
|
val correspondingProperty = when (this) {
|
||||||
is IrField -> correspondingPropertySymbol?.owner
|
is IrField -> correspondingPropertySymbol?.owner
|
||||||
@@ -68,15 +69,18 @@ private fun IrDeclaration.addRootsTo(
|
|||||||
acceptVoid(nestedVisitor)
|
acceptVoid(nestedVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isExported(context) -> {
|
isExported(context) -> {
|
||||||
acceptVoid(nestedVisitor)
|
acceptVoid(nestedVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
this is IrField -> {
|
this is IrField -> {
|
||||||
// TODO: simplify
|
// TODO: simplify
|
||||||
if ((initializer != null && !isKotlinPackage() || correspondingPropertySymbol?.owner?.isExported(context) == true) && !isConstant()) {
|
if ((initializer != null && !isKotlinPackage() || correspondingPropertySymbol?.owner?.isExported(context) == true) && !isConstant()) {
|
||||||
acceptVoid(nestedVisitor)
|
acceptVoid(nestedVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this is IrSimpleFunction -> {
|
this is IrSimpleFunction -> {
|
||||||
val correspondingProperty = correspondingPropertySymbol?.owner ?: return
|
val correspondingProperty = correspondingPropertySymbol?.owner ?: return
|
||||||
if (correspondingProperty.isExported(context)) {
|
if (correspondingProperty.isExported(context)) {
|
||||||
|
|||||||
+18
@@ -43,6 +43,7 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
val constructor = inlineClass.declarations.filterIsInstance<IrConstructor>().single { it.isPrimary }
|
val constructor = inlineClass.declarations.filterIsInstance<IrConstructor>().single { it.isPrimary }
|
||||||
constructor.enqueue(data, "intrinsic: jsBoxIntrinsic")
|
constructor.enqueue(data, "intrinsic: jsBoxIntrinsic")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsClass -> {
|
context.intrinsics.jsClass -> {
|
||||||
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
||||||
ref.enqueue(data, "intrinsic: jsClass")
|
ref.enqueue(data, "intrinsic: jsClass")
|
||||||
@@ -63,34 +64,42 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.reflectionSymbols.getKClassFromExpression -> {
|
context.reflectionSymbols.getKClassFromExpression -> {
|
||||||
val ref = expression.getTypeArgument(0)?.classOrNull ?: context.irBuiltIns.anyClass
|
val ref = expression.getTypeArgument(0)?.classOrNull ?: context.irBuiltIns.anyClass
|
||||||
referencedJsClassesFromExpressions += ref.owner
|
referencedJsClassesFromExpressions += ref.owner
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsObjectCreateSymbol -> {
|
context.intrinsics.jsObjectCreateSymbol -> {
|
||||||
val classToCreate = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
val classToCreate = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
||||||
classToCreate.enqueue(data, "intrinsic: jsObjectCreateSymbol")
|
classToCreate.enqueue(data, "intrinsic: jsObjectCreateSymbol")
|
||||||
constructedClasses += classToCreate
|
constructedClasses += classToCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsEquals -> {
|
context.intrinsics.jsEquals -> {
|
||||||
equalsMethod.enqueue(data, "intrinsic: jsEquals")
|
equalsMethod.enqueue(data, "intrinsic: jsEquals")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsToString -> {
|
context.intrinsics.jsToString -> {
|
||||||
toStringMethod.enqueue(data, "intrinsic: jsToString")
|
toStringMethod.enqueue(data, "intrinsic: jsToString")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsHashCode -> {
|
context.intrinsics.jsHashCode -> {
|
||||||
hashCodeMethod.enqueue(data, "intrinsic: jsHashCode")
|
hashCodeMethod.enqueue(data, "intrinsic: jsHashCode")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsPlus -> {
|
context.intrinsics.jsPlus -> {
|
||||||
if (expression.getValueArgument(0)?.type?.classOrNull == context.irBuiltIns.stringClass) {
|
if (expression.getValueArgument(0)?.type?.classOrNull == context.irBuiltIns.stringClass) {
|
||||||
toStringMethod.enqueue(data, "intrinsic: jsPlus")
|
toStringMethod.enqueue(data, "intrinsic: jsPlus")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsConstruct -> {
|
context.intrinsics.jsConstruct -> {
|
||||||
val callType = expression.getTypeArgument(0)!!
|
val callType = expression.getTypeArgument(0)!!
|
||||||
val constructor = callType.getClass()!!.primaryConstructor
|
val constructor = callType.getClass()!!.primaryConstructor
|
||||||
constructor!!.enqueue(data, "ctor call from jsConstruct-intrinsic")
|
constructor!!.enqueue(data, "ctor call from jsConstruct-intrinsic")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.es6DefaultType -> {
|
context.intrinsics.es6DefaultType -> {
|
||||||
//same as jsClass
|
//same as jsClass
|
||||||
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
||||||
@@ -104,6 +113,7 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
constructedClasses.add(klass)
|
constructedClasses.add(klass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsInvokeSuspendSuperType,
|
context.intrinsics.jsInvokeSuspendSuperType,
|
||||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiver,
|
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiver,
|
||||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam -> {
|
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam -> {
|
||||||
@@ -126,6 +136,14 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
override fun processClass(irClass: IrClass) {
|
override fun processClass(irClass: IrClass) {
|
||||||
super.processClass(irClass)
|
super.processClass(irClass)
|
||||||
|
|
||||||
|
if (context.keeper.shouldKeep(irClass)) {
|
||||||
|
irClass.declarations
|
||||||
|
.filter { context.keeper.shouldKeep(it) }
|
||||||
|
.forEach { declaration ->
|
||||||
|
declaration.enqueue(irClass, "kept declaration")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (irClass.containsMetadata()) {
|
if (irClass.containsMetadata()) {
|
||||||
when {
|
when {
|
||||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||||
|
|||||||
+12
@@ -114,6 +114,18 @@ class IrModuleToJsTransformerTmp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun doStaticMembersLowering(modules: Iterable<IrModuleFragment>) {
|
private fun doStaticMembersLowering(modules: Iterable<IrModuleFragment>) {
|
||||||
|
modules.forEach { module ->
|
||||||
|
module.files.forEach {
|
||||||
|
it.accept(
|
||||||
|
backendContext.keeper,
|
||||||
|
Keeper.KeepData(
|
||||||
|
classInKeep = false,
|
||||||
|
classShouldBeKept = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
modules.forEach { module ->
|
modules.forEach { module ->
|
||||||
module.files.forEach { StaticMembersLowering(backendContext).lower(it) }
|
module.files.forEach { StaticMembersLowering(backendContext).lower(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -86,10 +86,15 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
|||||||
override fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
override fun getNameForMemberFunction(function: IrSimpleFunction): JsName {
|
||||||
require(function.dispatchReceiverParameter != null)
|
require(function.dispatchReceiverParameter != null)
|
||||||
val signature = jsFunctionSignature(function, context)
|
val signature = jsFunctionSignature(function, context)
|
||||||
|
if (context.keeper.shouldKeep(function)) {
|
||||||
|
context.minimizedNameGenerator.keepName(signature)
|
||||||
|
}
|
||||||
val result = if (minimizedMemberNames && !function.hasStableJsName(context)) {
|
val result = if (minimizedMemberNames && !function.hasStableJsName(context)) {
|
||||||
function.parentAsClass.fieldData()
|
function.parentAsClass.fieldData()
|
||||||
context.minimizedNameGenerator.nameBySignature(signature)
|
context.minimizedNameGenerator.nameBySignature(signature)
|
||||||
} else signature
|
} else {
|
||||||
|
signature
|
||||||
|
}
|
||||||
return result.toJsName()
|
return result.toJsName()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +130,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
|||||||
context.minimizedNameGenerator.reserveName(signature)
|
context.minimizedNameGenerator.reserveName(signature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declaration is IrProperty -> {
|
declaration is IrProperty -> {
|
||||||
if (declaration.isExported(context)) {
|
if (declaration.isExported(context)) {
|
||||||
context.minimizedNameGenerator.reserveName(declaration.getJsNameOrKotlinName().identifier)
|
context.minimizedNameGenerator.reserveName(declaration.getJsNameOrKotlinName().identifier)
|
||||||
@@ -146,7 +152,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
|||||||
correspondingProperty.isSimpleProperty
|
correspondingProperty.isSimpleProperty
|
||||||
val safeName = when {
|
val safeName = when {
|
||||||
hasStableName -> (correspondingProperty ?: it).getJsNameOrKotlinName().identifier
|
hasStableName -> (correspondingProperty ?: it).getJsNameOrKotlinName().identifier
|
||||||
minimizedMemberNames -> context.minimizedNameGenerator.generateNextName()
|
minimizedMemberNames && !context.keeper.shouldKeep(it) -> context.minimizedNameGenerator.generateNextName()
|
||||||
else -> it.safeName()
|
else -> it.safeName()
|
||||||
}
|
}
|
||||||
val resultName = if (!hasStableName) {
|
val resultName = if (!hasStableName) {
|
||||||
@@ -156,6 +162,7 @@ class JsNameLinkingNamer(private val context: JsIrBackendContext, private val mi
|
|||||||
} else safeName
|
} else safeName
|
||||||
result[it] = resultName
|
result[it] = resultName
|
||||||
}
|
}
|
||||||
|
|
||||||
it is IrFunction && it.dispatchReceiverParameter != null -> {
|
it is IrFunction && it.dispatchReceiverParameter != null -> {
|
||||||
nameCnt[jsFunctionSignature(it, context)] = 1 // avoid clashes with member functions
|
nameCnt[jsFunctionSignature(it, context)] = 1 // avoid clashes with member functions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|
||||||
|
class Keeper(private val keep: Set<String>) : IrElementVisitor<Unit, Keeper.KeepData> {
|
||||||
|
private val keptDeclarations: MutableSet<IrDeclaration> = mutableSetOf()
|
||||||
|
|
||||||
|
fun shouldKeep(declaration: IrDeclaration): Boolean {
|
||||||
|
return declaration in keptDeclarations
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement, data: KeepData) {
|
||||||
|
element.acceptChildren(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Keep declarations can work both ways
|
||||||
|
* if member of a class is in keep, the class should be also kept
|
||||||
|
* if a class is kept, members of the class should be also kept
|
||||||
|
* but there can be nested classes, and for nested classes we need only to propagate "keep" from top-level to nested (not vice versa)
|
||||||
|
* because we have 2 directions, we need 2 boolean flags
|
||||||
|
* [KeepData.classInKeep] responsible to propagate "keep" from class level to members direction
|
||||||
|
* [KeepData.classShouldBeKept] responsible to bubble "keep" from members to class level direction
|
||||||
|
*/
|
||||||
|
override fun visitClass(declaration: IrClass, data: KeepData) {
|
||||||
|
val prevShouldBeKept = data.classShouldBeKept
|
||||||
|
val prevClassInKeep = data.classInKeep
|
||||||
|
data.classShouldBeKept = false
|
||||||
|
val keptClass = data.classInKeep || isInKeep(declaration)
|
||||||
|
if (keptClass) {
|
||||||
|
keptDeclarations.add(declaration)
|
||||||
|
}
|
||||||
|
data.classInKeep = keptClass
|
||||||
|
super.visitClass(declaration, data)
|
||||||
|
if (data.classShouldBeKept) {
|
||||||
|
keptDeclarations.add(declaration)
|
||||||
|
}
|
||||||
|
data.classShouldBeKept = prevShouldBeKept
|
||||||
|
data.classInKeep = prevClassInKeep
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclarationBase, data: KeepData) {
|
||||||
|
super.visitDeclaration(declaration, data)
|
||||||
|
if (declaration in keptDeclarations) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (declaration is IrDeclarationWithName && isInKeep(declaration) || data.classInKeep) {
|
||||||
|
keptDeclarations.add(declaration)
|
||||||
|
data.classShouldBeKept = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isInKeep(declaration: IrDeclarationWithName): Boolean {
|
||||||
|
return declaration.fqNameWhenAvailable?.asString() in keep
|
||||||
|
}
|
||||||
|
|
||||||
|
class KeepData(var classInKeep: Boolean, var classShouldBeKept: Boolean)
|
||||||
|
}
|
||||||
+6
@@ -9,6 +9,7 @@ class MinimizedNameGenerator {
|
|||||||
private var index = 0
|
private var index = 0
|
||||||
private val functionSignatureToName = mutableMapOf<String, String>()
|
private val functionSignatureToName = mutableMapOf<String, String>()
|
||||||
private val reservedNames = mutableSetOf<String>()
|
private val reservedNames = mutableSetOf<String>()
|
||||||
|
private val keptNames = mutableSetOf<String>()
|
||||||
|
|
||||||
fun generateNextName(): String {
|
fun generateNextName(): String {
|
||||||
var candidate = index++.toJsIdentifier()
|
var candidate = index++.toJsIdentifier()
|
||||||
@@ -19,11 +20,16 @@ class MinimizedNameGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun nameBySignature(signature: String): String {
|
fun nameBySignature(signature: String): String {
|
||||||
|
if (signature in keptNames) return signature
|
||||||
return functionSignatureToName.getOrPut(signature) {
|
return functionSignatureToName.getOrPut(signature) {
|
||||||
generateNextName()
|
generateNextName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun keepName(signature: String): Boolean {
|
||||||
|
return keptNames.add(signature)
|
||||||
|
}
|
||||||
|
|
||||||
fun reserveName(signature: String) {
|
fun reserveName(signature: String) {
|
||||||
reservedNames.add(signature)
|
reservedNames.add(signature)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -19,6 +19,7 @@ where advanced options include:
|
|||||||
Enable runtime diagnostics when performing DCE instead of removing declarations
|
Enable runtime diagnostics when performing DCE instead of removing declarations
|
||||||
-Xir-generate-inline-anonymous-functions
|
-Xir-generate-inline-anonymous-functions
|
||||||
Lambda expressions that capture values are translated into in-line anonymous JavaScript functions
|
Lambda expressions that capture values are translated into in-line anonymous JavaScript functions
|
||||||
|
-Xir-keep Comma-separated list of fully-qualified names to not be eliminated by DCE (if it can be reached), and for which to keep non-minified names.
|
||||||
-Xir-minimized-member-names Perform minimization for names of members
|
-Xir-minimized-member-names Perform minimization for names of members
|
||||||
-Xir-module-name=<name> Specify a compilation module name for IR backend
|
-Xir-module-name=<name> Specify a compilation module name for IR backend
|
||||||
-Xir-new-ir2js New fragment-based ir2js
|
-Xir-new-ir2js New fragment-based ir2js
|
||||||
|
|||||||
+10
@@ -210,6 +210,11 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
|
|||||||
applicability = DirectiveApplicability.Global
|
applicability = DirectiveApplicability.Global
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val ONLY_IR_DCE by directive(
|
||||||
|
description = "Disable non DCE build",
|
||||||
|
applicability = DirectiveApplicability.Global
|
||||||
|
)
|
||||||
|
|
||||||
val RUN_IC by directive(
|
val RUN_IC by directive(
|
||||||
description = "",
|
description = "",
|
||||||
applicability = DirectiveApplicability.Global
|
applicability = DirectiveApplicability.Global
|
||||||
@@ -251,4 +256,9 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
|
|||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
applicability = DirectiveApplicability.Global,
|
applicability = DirectiveApplicability.Global,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val KEEP by stringDirective(
|
||||||
|
description = "Keep declarations",
|
||||||
|
applicability = DirectiveApplicability.Global
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -593,7 +593,15 @@ class GenerateIrRuntime {
|
|||||||
private fun doBackEnd(
|
private fun doBackEnd(
|
||||||
module: IrModuleFragment, symbolTable: SymbolTable, irBuiltIns: IrBuiltIns, jsLinker: JsIrLinker
|
module: IrModuleFragment, symbolTable: SymbolTable, irBuiltIns: IrBuiltIns, jsLinker: JsIrLinker
|
||||||
): CompilerResult {
|
): CompilerResult {
|
||||||
val context = JsIrBackendContext(module.descriptor, irBuiltIns, symbolTable, module, emptySet(), configuration)
|
val context = JsIrBackendContext(
|
||||||
|
module.descriptor,
|
||||||
|
irBuiltIns,
|
||||||
|
symbolTable,
|
||||||
|
module,
|
||||||
|
additionalExportedDeclarationNames = emptySet(),
|
||||||
|
keep = emptySet(),
|
||||||
|
configuration
|
||||||
|
)
|
||||||
|
|
||||||
ExternalDependenciesGenerator(symbolTable, listOf(jsLinker)).generateUnboundSymbolsAsDependencies()
|
ExternalDependenciesGenerator(symbolTable, listOf(jsLinker)).generateUnboundSymbolsAsDependencies()
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ class JsIrBackendFacade(
|
|||||||
val splitPerFile = JsEnvironmentConfigurationDirectives.SPLIT_PER_FILE in module.directives
|
val splitPerFile = JsEnvironmentConfigurationDirectives.SPLIT_PER_FILE in module.directives
|
||||||
val perModule = JsEnvironmentConfigurationDirectives.PER_MODULE in module.directives
|
val perModule = JsEnvironmentConfigurationDirectives.PER_MODULE in module.directives
|
||||||
val runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
val runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
||||||
|
val keep = module.directives[JsEnvironmentConfigurationDirectives.KEEP].toSet()
|
||||||
|
|
||||||
val granularity = when {
|
val granularity = when {
|
||||||
!firstTimeCompilation -> JsGenerationGranularity.WHOLE_PROGRAM
|
!firstTimeCompilation -> JsGenerationGranularity.WHOLE_PROGRAM
|
||||||
@@ -145,6 +146,7 @@ class JsIrBackendFacade(
|
|||||||
deserializer,
|
deserializer,
|
||||||
phaseConfig,
|
phaseConfig,
|
||||||
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))),
|
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))),
|
||||||
|
keep = keep,
|
||||||
dceRuntimeDiagnostic = null,
|
dceRuntimeDiagnostic = null,
|
||||||
es6mode = false,
|
es6mode = false,
|
||||||
baseClassIntoMetadata = false,
|
baseClassIntoMetadata = false,
|
||||||
@@ -166,6 +168,7 @@ class JsIrBackendFacade(
|
|||||||
val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module)
|
val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module)
|
||||||
.run { if (shouldBeGenerated()) arguments() else null }
|
.run { if (shouldBeGenerated()) arguments() else null }
|
||||||
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives
|
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives
|
||||||
|
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in module.directives
|
||||||
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in module.directives
|
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in module.directives
|
||||||
val runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
val runNewIr2Js = JsEnvironmentConfigurationDirectives.RUN_NEW_IR_2_JS in module.directives
|
||||||
val perModuleOnly = JsEnvironmentConfigurationDirectives.SPLIT_PER_MODULE in module.directives
|
val perModuleOnly = JsEnvironmentConfigurationDirectives.SPLIT_PER_MODULE in module.directives
|
||||||
@@ -180,7 +183,7 @@ class JsIrBackendFacade(
|
|||||||
// If perModuleOnly then skip whole program
|
// If perModuleOnly then skip whole program
|
||||||
// (it.dce => runIrDce) && (perModuleOnly => it.perModule)
|
// (it.dce => runIrDce) && (perModuleOnly => it.perModule)
|
||||||
val translationModes = TranslationMode.values()
|
val translationModes = TranslationMode.values()
|
||||||
.filter { (!it.dce || runIrDce) && (!perModuleOnly || it.perModule) }
|
.filter { (it.dce || !onlyIrDce) && (!it.dce || runIrDce) && (!perModuleOnly || it.perModule) }
|
||||||
.filter { it.dce == it.minimizedMemberNames }
|
.filter { it.dce == it.minimizedMemberNames }
|
||||||
.toSet()
|
.toSet()
|
||||||
val compilationOut = transformer.generateModule(loweredIr.allModules, translationModes, false)
|
val compilationOut = transformer.generateModule(loweredIr.allModules, translationModes, false)
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ class JsMinifierRunner(testServices: TestServices) : AbstractJsArtifactsCollecto
|
|||||||
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
|
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
|
||||||
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
|
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
|
||||||
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
|
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
|
||||||
|
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in globalDirectives
|
||||||
|
|
||||||
if (dontRunGeneratedCode || esModules) return
|
if (dontRunGeneratedCode || esModules || onlyIrDce) return
|
||||||
|
|
||||||
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
|
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import java.io.File
|
|||||||
class NodeJsGeneratorHandler(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
|
class NodeJsGeneratorHandler(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
|
||||||
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||||
if (someAssertionWasFailed) return
|
if (someAssertionWasFailed) return
|
||||||
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
|
|
||||||
|
|
||||||
val globalDirectives = testServices.moduleStructure.allDirectives
|
val globalDirectives = testServices.moduleStructure.allDirectives
|
||||||
|
|
||||||
@@ -31,8 +30,11 @@ class NodeJsGeneratorHandler(testServices: TestServices) : AbstractJsArtifactsCo
|
|||||||
val generateNodeJsRunner = JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER in globalDirectives
|
val generateNodeJsRunner = JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER in globalDirectives
|
||||||
val skipNodeJs = JsEnvironmentConfigurationDirectives.SKIP_NODE_JS in globalDirectives
|
val skipNodeJs = JsEnvironmentConfigurationDirectives.SKIP_NODE_JS in globalDirectives
|
||||||
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
|
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
|
||||||
|
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in globalDirectives
|
||||||
|
|
||||||
if (dontRunGeneratedCode || !generateNodeJsRunner || skipNodeJs || esModules) return
|
if (dontRunGeneratedCode || !generateNodeJsRunner || skipNodeJs || esModules || onlyIrDce) return
|
||||||
|
|
||||||
|
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
|
||||||
|
|
||||||
val mainModuleName = getMainModuleName(testServices)
|
val mainModuleName = getMainModuleName(testServices)
|
||||||
val outputDir = File(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).absolutePath)
|
val outputDir = File(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).absolutePath)
|
||||||
|
|||||||
@@ -136,10 +136,14 @@ fun getAllFilesForRunner(
|
|||||||
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }.filter { !File(it).isDirectory }
|
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }.filter { !File(it).isDirectory }
|
||||||
val allJsFiles = additionalFiles + inputJsFilesBefore +artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
|
val allJsFiles = additionalFiles + inputJsFilesBefore +artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
|
||||||
|
|
||||||
val result = mutableMapOf(TranslationMode.FULL to allJsFiles)
|
val result = mutableMapOf<TranslationMode, List<String>>()
|
||||||
|
|
||||||
val globalDirectives = testServices.moduleStructure.allDirectives
|
val globalDirectives = testServices.moduleStructure.allDirectives
|
||||||
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in globalDirectives
|
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in globalDirectives
|
||||||
|
val onlyIrDce = JsEnvironmentConfigurationDirectives.ONLY_IR_DCE in globalDirectives
|
||||||
|
if (!onlyIrDce) {
|
||||||
|
result[TranslationMode.FULL] = allJsFiles
|
||||||
|
}
|
||||||
if (runIrDce) {
|
if (runIrDce) {
|
||||||
val dceJsFiles = artifactsPaths.map { it.replace(outputDir.absolutePath, dceOutputDir.absolutePath) }
|
val dceJsFiles = artifactsPaths.map { it.replace(outputDir.absolutePath, dceOutputDir.absolutePath) }
|
||||||
val dceAllJsFiles = additionalFiles + inputJsFilesBefore + dceJsFiles + commonFiles + additionalMainFiles + inputJsFilesAfter
|
val dceAllJsFiles = additionalFiles + inputJsFilesBefore + dceJsFiles + commonFiles + additionalMainFiles + inputJsFilesAfter
|
||||||
|
|||||||
@@ -6797,6 +6797,16 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("js/js.translator/testData/box/keep")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Keep {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInKeep() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/keep"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+40
@@ -7269,6 +7269,46 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("js/js.translator/testData/box/keep")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Keep {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInKeep() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/keep"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepClass.kt")
|
||||||
|
public void testKeepClass() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepMethod.kt")
|
||||||
|
public void testKeepMethod() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepMethod.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepNestedClass.kt")
|
||||||
|
public void testKeepNestedClass() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepNestedClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepNestedClassIfKeptTopLevelClass.kt")
|
||||||
|
public void testKeepNestedClassIfKeptTopLevelClass() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepNestedClassIfKeptTopLevelClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepOverriddenMethod.kt")
|
||||||
|
public void testKeepOverriddenMethod() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepOverriddenMethod.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+40
@@ -7269,6 +7269,46 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("js/js.translator/testData/box/keep")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Keep {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInKeep() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/keep"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepClass.kt")
|
||||||
|
public void testKeepClass() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepMethod.kt")
|
||||||
|
public void testKeepMethod() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepMethod.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepNestedClass.kt")
|
||||||
|
public void testKeepNestedClass() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepNestedClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepNestedClassIfKeptTopLevelClass.kt")
|
||||||
|
public void testKeepNestedClassIfKeptTopLevelClass() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepNestedClassIfKeptTopLevelClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("keepOverriddenMethod.kt")
|
||||||
|
public void testKeepOverriddenMethod() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/box/keep/keepOverriddenMethod.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
@TestMetadata("js/js.translator/testData/box/kotlin.test")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
// TARGET_BACKEND: JS_IR
|
||||||
|
// ONLY_IR_DCE
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
// KEEP: A
|
||||||
|
|
||||||
|
// MODULE: keep_class
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun foo(): String {
|
||||||
|
return "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String {
|
||||||
|
return "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun bar(): A {
|
||||||
|
return A()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.js
|
||||||
|
function box() {
|
||||||
|
var a = this["keep_class"].bar()
|
||||||
|
|
||||||
|
if (a.foo_26di_k$() != "foo") return "fail 1"
|
||||||
|
if (a.bar_232r_k$() != "bar") return "fail 2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// TARGET_BACKEND: JS_IR
|
||||||
|
// ONLY_IR_DCE
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
// KEEP: A.foo
|
||||||
|
|
||||||
|
// MODULE: keep_method
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun foo(): String {
|
||||||
|
return "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String {
|
||||||
|
return "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun bar(): A {
|
||||||
|
return A()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.js
|
||||||
|
function box() {
|
||||||
|
var a = this["keep_method"].bar()
|
||||||
|
|
||||||
|
if (a.foo_26di_k$() != "foo") return "fail 1"
|
||||||
|
if (typeof a.bar_232r_k$ !== "undefined") return "fail 2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// TARGET_BACKEND: JS_IR
|
||||||
|
// ONLY_IR_DCE
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
// KEEP: A.B
|
||||||
|
|
||||||
|
// MODULE: keep_nested_class
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun foo(): String {
|
||||||
|
return "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String {
|
||||||
|
return "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
fun baz() = "baz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun barA(): A {
|
||||||
|
return A()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun bar(): A.B {
|
||||||
|
return A.B()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.js
|
||||||
|
function box() {
|
||||||
|
var a = this["keep_nested_class"].barA()
|
||||||
|
var b = this["keep_nested_class"].bar()
|
||||||
|
|
||||||
|
if (typeof a.foo_26di_k$ !== "undefined") return "fail 1"
|
||||||
|
if (typeof a.bar_232r_k$ !== "undefined") return "fail 2"
|
||||||
|
if (b.baz_232z_k$() != "baz") return "fail 3"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// TARGET_BACKEND: JS_IR
|
||||||
|
// ONLY_IR_DCE
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
// KEEP: A
|
||||||
|
|
||||||
|
// MODULE: keep_nested_class_if_kept_top_level_class
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun foo(): String {
|
||||||
|
return "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String {
|
||||||
|
return "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
fun baz() = "baz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun barA(): A {
|
||||||
|
return A()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun bar(): A.B {
|
||||||
|
return A.B()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.js
|
||||||
|
function box() {
|
||||||
|
var a = this["keep_nested_class_if_kept_top_level_class"].barA()
|
||||||
|
var b = this["keep_nested_class_if_kept_top_level_class"].bar()
|
||||||
|
|
||||||
|
if (a.foo_26di_k$() != "foo") return "fail 1"
|
||||||
|
if (a.bar_232r_k$() != "bar") return "fail 2"
|
||||||
|
if (b.baz_232z_k$() != "baz") return "fail 3"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// TARGET_BACKEND: JS_IR
|
||||||
|
// ONLY_IR_DCE
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
// KEEP: A.foo
|
||||||
|
|
||||||
|
// MODULE: keep_overridden_method
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
open fun foo(): String {
|
||||||
|
return "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun bar(): String {
|
||||||
|
return "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class B : A() {
|
||||||
|
override fun foo(): String {
|
||||||
|
return super.foo() + "!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun bar(): B {
|
||||||
|
return B()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.js
|
||||||
|
function box() {
|
||||||
|
var b = this["keep_overridden_method"].bar()
|
||||||
|
|
||||||
|
if (b.foo_26di_k$() != "foo!") return "fail 1"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+2
-1
@@ -92,7 +92,8 @@ class JsCoreScriptingCompiler(
|
|||||||
psi2irContext.irBuiltIns,
|
psi2irContext.irBuiltIns,
|
||||||
psi2irContext.symbolTable,
|
psi2irContext.symbolTable,
|
||||||
irModuleFragment,
|
irModuleFragment,
|
||||||
emptySet(),
|
additionalExportedDeclarationNames = emptySet(),
|
||||||
|
keep = emptySet(),
|
||||||
environment.configuration,
|
environment.configuration,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-1
@@ -62,7 +62,8 @@ class JsScriptDependencyCompiler(
|
|||||||
irBuiltIns,
|
irBuiltIns,
|
||||||
symbolTable,
|
symbolTable,
|
||||||
moduleFragment,
|
moduleFragment,
|
||||||
emptySet(),
|
additionalExportedDeclarationNames = emptySet(),
|
||||||
|
keep = emptySet(),
|
||||||
configuration,
|
configuration,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user