diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt index df586de25c8..b7774f968e8 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt @@ -38,179 +38,182 @@ class SimpleNameGenerator : NameGenerator { override fun getNameForType(type: IrType, context: JsGenerationContext) = getNameForDeclaration(type.classifierOrFail.owner as IrDeclarationWithName, context) - private val RESERVED_IDENTIFIERS = setOf( - // keywords - "await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if", - "in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with", + private fun getNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName { + return nameCache.getOrPut(declaration) { getNewNameForDeclaration(declaration, context) } + } - // future reserved words - "class", "const", "enum", "export", "extends", "import", "super", + private fun getNewNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName { + var nameDeclarator: (String) -> JsName = context.currentScope::declareName - // as future reserved words in strict mode - "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield", + val declarationName = declaration.getJsNameOrKotlinName().asString() - // additional reserved words - // "null", "true", "false", + if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) { + return nameDeclarator(declarationName) + } - // disallowed as variable names in strict mode - "eval", "arguments", + if (declaration.isEffectivelyExternal()) { + if (declaration is IrConstructor) + return getNameForDeclaration(declaration.parentAsClass, context) - // global identifiers usually declared in a typical JS interpreter - "NaN", "isNaN", "Infinity", "undefined", - - "Error", "Object", "Number", - - // "Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON", - - // global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc) - // "require", "define", "module", "window", "self", - - // the special Kotlin object - "Kotlin" - ) - - private fun getNameForDeclaration(declaration: IrDeclarationWithName, context: JsGenerationContext): JsName = - nameCache.getOrPut(declaration) { - var nameDeclarator: (String) -> JsName = context.currentScope::declareName - val nameBuilder = StringBuilder() - - val declarationName = declaration.getJsNameOrKotlinName().asString() - - if (declaration is IrSimpleFunction && declaration.origin == JsLoweredDeclarationOrigin.BRIDGE_TO_EXTERNAL_FUNCTION) { - return@getOrPut nameDeclarator(declarationName) - } - - if (declaration.isEffectivelyExternal()) { - if (declaration is IrConstructor) - return@getOrPut getNameForDeclaration(declaration.parentAsClass, context) - - if (declaration is IrClass && declaration.parent is IrClass) { - val parentName = getNameForDeclaration(declaration.parentAsClass, context) - if (declaration.isCompanion) { - // External companions are class references - return@getOrPut parentName - } - return@getOrPut context.currentScope.declareFreshName(parentName.ident + "$" + declarationName) + if (declaration is IrClass && declaration.parent is IrClass) { + val parentName = getNameForDeclaration(declaration.parentAsClass, context) + if (declaration.isCompanion) { + // External companions are class references + return parentName } - return@getOrPut nameDeclarator(declarationName) + return context.currentScope.declareFreshName(parentName.ident + "$" + declarationName) } + return nameDeclarator(declarationName) + } - val jsName = declaration.getJsName() - if (jsName != null) { - return@getOrPut context.currentScope.declareName(jsName) - } + val jsName = declaration.getJsName() + if (jsName != null) { + return context.currentScope.declareName(jsName) + } - when (declaration) { - is IrValueParameter -> { - if ((context.currentFunction is IrConstructor && declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) || - declaration == context.currentFunction?.dispatchReceiverParameter - ) - nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME) - else if (declaration == context.currentFunction?.extensionReceiverParameter) { - nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME) - } else { - val declaredName = declarationName - nameBuilder.append(declaredName) - if (declaredName.startsWith("\$")) { - nameBuilder.append('.') - nameBuilder.append(declaration.index) - } - nameDeclarator = context.currentScope::declareFreshName - } - } - is IrField -> { - nameBuilder.append(declarationName) - if (declaration.isTopLevel) { - nameDeclarator = context.staticContext.rootScope::declareFreshName - } else { + val nameBuilder = StringBuilder() + when (declaration) { + is IrValueParameter -> { + if ((context.currentFunction is IrConstructor && declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) || + declaration == context.currentFunction?.dispatchReceiverParameter + ) + nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME) + else if (declaration == context.currentFunction?.extensionReceiverParameter) { + nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME) + } else { + val declaredName = declarationName + nameBuilder.append(declaredName) + if (declaredName.startsWith("\$")) { nameBuilder.append('.') - nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context)) - if (declaration.visibility == Visibilities.PRIVATE) nameDeclarator = context.currentScope::declareFreshName + nameBuilder.append(declaration.index) } - } - is IrClass -> { - if (declaration.isCompanion) { - nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context)) - nameBuilder.append('.') - } - - nameBuilder.append(declarationName) - - (declaration.parent as? IrClass)?.let { - nameBuilder.append("$") - nameBuilder.append(getNameForDeclaration(it, context)) - } - - - if (declaration.kind == ClassKind.OBJECT || declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) { - if (declaration.descriptor !is DeserializedClassDescriptor) { - // TODO: temporary workaround for Unit instance - nameDeclarator = context.staticContext.rootScope::declareFreshName - } - val parent = declaration.parent - when (parent) { - is IrDeclarationWithName -> nameBuilder.append(getNameForDeclaration(parent, context)) - is IrPackageFragment -> nameBuilder.append(parent.fqName.asString()) - } - } - - // TODO: remove asap `NameGenerator` is implemented - (declaration.parent as? IrPackageFragment)?.let { - if (declaration.isInline && it.fqName.asString() != "kotlin") { - nameBuilder.append("_FIX") - } - } - - } - is IrConstructor -> { - nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context)) - } - is IrVariable -> { - nameBuilder.append(declaration.name.identifier) nameDeclarator = context.currentScope::declareFreshName } - is IrSimpleFunction -> { + } + is IrField -> { + nameBuilder.append(declarationName) + if (declaration.isTopLevel) { + nameDeclarator = context.staticContext.rootScope::declareFreshName + } else { + nameBuilder.append('.') + nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context)) + if (declaration.visibility == Visibilities.PRIVATE) nameDeclarator = context.currentScope::declareFreshName + } + } + is IrClass -> { + if (declaration.isCompanion) { + nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclarationWithName, context)) + nameBuilder.append('.') + } - if (declaration.isStaticMethodOfClass) { - nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context)) - nameBuilder.append('.') - } - if (declaration.dispatchReceiverParameter == null) { + nameBuilder.append(declarationName) + + (declaration.parent as? IrClass)?.let { + nameBuilder.append("$") + nameBuilder.append(getNameForDeclaration(it, context)) + } + + + if (declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) { + if (declaration.descriptor !is DeserializedClassDescriptor) { + // TODO: temporary workaround for Unit instance nameDeclarator = context.staticContext.rootScope::declareFreshName } + val parent = declaration.parent + when (parent) { + is IrDeclarationWithName -> nameBuilder.append(getNameForDeclaration(parent, context)) + is IrPackageFragment -> nameBuilder.append(parent.fqName.asString()) + } + } - nameBuilder.append(declarationName) - // TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters? - declaration.typeParameters.ifNotEmpty { - nameBuilder.append("_\$t") - joinTo(nameBuilder, "") { "_${it.name.asString()}" } - } - declaration.extensionReceiverParameter?.let { - nameBuilder.append("_r$${it.type.asString()}") - } - declaration.valueParameters.ifNotEmpty { - joinTo(nameBuilder, "") { "_${it.type.asString()}" } - } - declaration.returnType.let { - // Return type is only used in signature for inline class types because - // they are binary incompatible with supertypes. - if (it.isInlined()) { - nameBuilder.append("_ret$${it.asString()}") - } + // TODO: remove asap `NameGenerator` is implemented + (declaration.parent as? IrPackageFragment)?.let { + if (declaration.isInline && it.fqName.asString() != "kotlin") { + nameBuilder.append("_FIX") } } } - - if (nameBuilder.toString() in RESERVED_IDENTIFIERS) { - nameBuilder.append(0) + is IrConstructor -> { + nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context)) + } + is IrVariable -> { + nameBuilder.append(declaration.name.identifier) nameDeclarator = context.currentScope::declareFreshName } + is IrSimpleFunction -> { - nameDeclarator(sanitizeName(nameBuilder.toString())) + if (declaration.isStaticMethodOfClass) { + nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context)) + nameBuilder.append('.') + } + if (declaration.dispatchReceiverParameter == null) { + nameDeclarator = context.staticContext.rootScope::declareFreshName + } + + nameBuilder.append(declarationName) + // TODO should we skip type parameters and use upper bound of type parameter when print type of value parameters? + declaration.typeParameters.ifNotEmpty { + nameBuilder.append("_\$t") + joinTo(nameBuilder, "") { "_${it.name.asString()}" } + } + declaration.extensionReceiverParameter?.let { + nameBuilder.append("_r$${it.type.asString()}") + } + declaration.valueParameters.ifNotEmpty { + joinTo(nameBuilder, "") { "_${it.type.asString()}" } + } + declaration.returnType.let { + // Return type is only used in signature for inline class types because + // they are binary incompatible with supertypes. + if (it.isInlined()) { + nameBuilder.append("_ret$${it.asString()}") + } + } + } } + + if (nameBuilder.toString() in RESERVED_IDENTIFIERS) { + nameBuilder.append(0) + nameDeclarator = context.currentScope::declareFreshName + } + + return nameDeclarator(sanitizeName(nameBuilder.toString())) + } } +private val RESERVED_IDENTIFIERS = setOf( + // keywords + "await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if", + "in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with", + + // future reserved words + "class", "const", "enum", "export", "extends", "import", "super", + + // as future reserved words in strict mode + "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield", + + // additional reserved words + // "null", "true", "false", + + // disallowed as variable names in strict mode + "eval", "arguments", + + // global identifiers usually declared in a typical JS interpreter + "NaN", "isNaN", "Infinity", "undefined", + + "Error", "Object", "Number", + + // "Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON", + + // global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc) + // "require", "define", "module", "window", "self", + + // the special Kotlin object + "Kotlin" +) + + fun sanitizeName(name: String): String { if (name.isEmpty()) return "_"