From 33daf83f141069ebb268b9231150de011d3bcff9 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 16 Jun 2016 15:15:29 +0300 Subject: [PATCH] KT-2752: refactoring: 1. Get rid of most of ManglingUtils 2. Use simple mangling for delegated properties instead of stable mangling 3. Use stable mangling for public declarations of open non-public classes 4. When generating a fresh name in a JsScope, check it for clashing against parent scopes 5. JsFunctionScope does not generate fresh name instead of stable names 6. Function scopes inherit directly from global scope 7. Generate simple mangled names for backing fields of properties --- .../dart/compiler/backend/js/ast/JsScope.java | 12 +- .../dart/compiler/backend/js/ast/jsScopes.kt | 2 - .../kotlin/js/naming/FQNGenerator.kt | 4 +- .../js/resolve/diagnostics/JsNameChecker.kt | 3 +- .../resolve/diagnostics/JsNameClashChecker.kt | 5 +- .../diagnostics/OverriddenJsNameChecker.kt | 77 ----- .../kotlin/js/translate/context/Namer.java | 4 +- .../js/translate/context/StaticContext.java | 33 +- .../translate/context/TranslationContext.java | 5 + .../js/translate/context/UsageTracker.kt | 7 +- .../declaration/DelegationTranslator.kt | 33 +- .../declaration/PropertyTranslator.kt | 3 +- .../js/translate/utils/ManglingUtils.java | 312 +----------------- .../js/translate/utils/TranslationUtils.java | 11 +- .../kotlin/js/translate/utils/utils.kt | 4 +- .../box/inline/metadataForPublicFunction.kt | 2 +- 16 files changed, 84 insertions(+), 433 deletions(-) delete mode 100644 js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/OverriddenJsNameChecker.kt diff --git a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsScope.java b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsScope.java index f2d305ddd09..7481c056cc3 100644 --- a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsScope.java +++ b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/JsScope.java @@ -47,7 +47,7 @@ public abstract class JsScope { private final String description; private Map names = Collections.emptyMap(); private final JsScope parent; - protected int tempIndex = 0; + private int tempIndex = 0; private final String scopeId; private static final Pattern FRESH_NAME_SUFFIX = Pattern.compile("[\\$_]\\d+$"); @@ -94,7 +94,6 @@ public abstract class JsScope { public JsName declareFreshName(@NotNull String suggestedName) { assert !suggestedName.isEmpty(); String ident = getFreshIdent(suggestedName); - assert !hasOwnName(ident); return doCreateName(ident); } @@ -121,7 +120,7 @@ public abstract class JsScope { * @return null if the identifier has no associated name */ @Nullable - public final JsName findName(String ident) { + public final JsName findName(@NotNull String ident) { JsName name = findOwnName(ident); if (name == null && parent != null) { return parent.findName(ident); @@ -133,6 +132,11 @@ public abstract class JsScope { return names.containsKey(name); } + @Nullable + public boolean hasName(@NotNull String name) { + return hasOwnName(name) || (parent != null && parent.hasName(name)); + } + /** * Returns the parent scope of this scope, or null if this is the * root scope. @@ -209,7 +213,7 @@ public abstract class JsScope { } String freshName = suggestedIdent; - while (hasOwnName(freshName)) { + while (hasName(freshName)) { freshName = baseName + sep + counter++; } diff --git a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt index 9d49f07ec14..210bc0369cb 100644 --- a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt +++ b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/jsScopes.kt @@ -32,8 +32,6 @@ open class JsFunctionScope(parent: JsScope, description: String) : JsScope(paren private val topLabelScope: LabelScope? get() = if (labelScopes.isNotEmpty()) labelScopes.peek() else null - override fun declareName(identifier: String): JsName = super.declareFreshName(identifier) - override fun hasOwnName(name: String): Boolean = RESERVED_WORDS.contains(name) || super.hasOwnName(name) open fun declareNameUnsafe(identifier: String): JsName = super.declareName(identifier) diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNGenerator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNGenerator.kt index ec758073c75..0ff5748399a 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNGenerator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNGenerator.kt @@ -187,7 +187,9 @@ class FQNGenerator { return when (containingDeclaration) { is PackageFragmentDescriptor -> descriptor.visibility.isPublicAPI is ClassDescriptor -> { - if (descriptor.modality == Modality.OPEN || descriptor.modality == Modality.ABSTRACT) { + if (descriptor.modality == Modality.OPEN || descriptor.modality == Modality.ABSTRACT || + containingDeclaration.modality == Modality.OPEN || containingDeclaration.modality == Modality.ABSTRACT + ) { return descriptor.visibility.isPublicAPI } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameChecker.kt index e5a32952828..65fe5b455d0 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameChecker.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.js.resolve.diagnostics -import org.jetbrains.kotlin.config.LanguageFeatureSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils @@ -26,7 +25,7 @@ import org.jetbrains.kotlin.resolve.SimpleDeclarationChecker object JsNameChecker : SimpleDeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink, - bindingContext: BindingContext, languageFeatureSettings: LanguageFeatureSettings) { + bindingContext: BindingContext) { if (descriptor is PropertyDescriptor) { val namedAccessorCount = descriptor.accessors.count { AnnotationsUtils.getJsName(it) != null } if (namedAccessorCount > 0 && namedAccessorCount < descriptor.accessors.size) { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt index 47b762fcf4b..3e665a14a1d 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.js.resolve.diagnostics -import org.jetbrains.kotlin.config.LanguageFeatureSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.js.naming.FQNGenerator @@ -24,7 +23,6 @@ import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DeclarationChecker import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.SimpleDeclarationChecker import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension @@ -40,8 +38,7 @@ class JsNameClashChecker : SimpleDeclarationChecker { declaration: KtDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink, - bindingContext: BindingContext, - languageFeatureSettings: LanguageFeatureSettings + bindingContext: BindingContext ) { if (declaration !is KtProperty || !descriptor.isExtension) { checkDescriptor(descriptor, declaration, diagnosticHolder) diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/OverriddenJsNameChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/OverriddenJsNameChecker.kt deleted file mode 100644 index ea81667011d..00000000000 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/OverriddenJsNameChecker.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.js.resolve.diagnostics - -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.diagnostics.DiagnosticSink -import org.jetbrains.kotlin.js.naming.FQNGenerator -import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DeclarationChecker - -class OverriddenJsNameChecker : DeclarationChecker { - private val fqnGenerator = FQNGenerator() - - override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink, - bindingContext: BindingContext) { - doCheck(descriptor) { first, second -> - val psi = descriptor.findPsi() ?: declaration - diagnosticHolder.report(ErrorsJs.JS_NAME_OVERRIDE_CLASH.on(psi, first, second)) - } - - if (descriptor is ClassDescriptor) { - val fakeOverrides = descriptor.defaultType.memberScope.getContributedDescriptors().asSequence() - .mapNotNull { it as? CallableMemberDescriptor } - .filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } - for (override in fakeOverrides) { - val errorFound = doCheck(override) { first, second -> - val psi = descriptor.findPsi() ?: declaration - diagnosticHolder.report(ErrorsJs.JS_NAME_OVERRIDE_CLASH.on(psi, first, second)) - } - if (errorFound) break - } - } - } - - private fun doCheck(descriptor: DeclarationDescriptor, onClash: (CallableMemberDescriptor, CallableMemberDescriptor) -> Unit): - Boolean { - if (descriptor !is CallableMemberDescriptor) return false - - var knownName: String? = null - var knownDescriptor: CallableMemberDescriptor? = null - for (overridden in descriptor.overriddenDescriptors) { - val fqn = fqnGenerator.generate(overridden) - if (!fqn.shared) continue - - val name = fqnGenerator.generate(overridden).names.last() - if (knownName == null) { - knownName = name - knownDescriptor = overridden - } - else if (knownName != name && - (AnnotationsUtils.getJsName(knownDescriptor!!) != null || AnnotationsUtils.getJsName(overridden) != null)) { - onClash(knownDescriptor, overridden) - return true - } - } - - return false - } -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index 97133e193ab..dda2b1cb181 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.idea.KotlinLanguage; +import org.jetbrains.kotlin.js.naming.FQNGenerator; import org.jetbrains.kotlin.js.resolve.JsPlatform; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; @@ -40,7 +41,6 @@ import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn; import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName; import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor; -import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName; /** * Encapsulates different types of constants and naming conventions. @@ -128,7 +128,7 @@ public final class Namer { qualifier = fqNameParent.asString(); } - String mangledName = getSuggestedName(functionDescriptor); + String mangledName = new FQNGenerator().generate(functionDescriptor).getNames().get(0); return StringUtil.join(Arrays.asList(moduleName, qualifier, mangledName), "."); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index 3185e1e64a4..d99227dd83f 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -110,6 +110,9 @@ public final class StaticContext { @NotNull private final Map nameCache = new HashMap(); + @NotNull + private final Map backingFieldNameCache = new HashMap(); + private final Map> persistentNames = new HashMap>(); @NotNull @@ -120,6 +123,9 @@ public final class StaticContext { private Map readOnlyImportedModules; + @NotNull + private final JsScope rootPackageScope; + //TODO: too many parameters in constructor private StaticContext( @NotNull JsProgram program, @@ -139,6 +145,7 @@ public final class StaticContext { this.standardClasses = standardClasses; this.config = config; currentModule = moduleDescriptor; + rootPackageScope = new JsObjectScope(rootScope, "", "root-package"); } @NotNull @@ -280,6 +287,27 @@ public final class StaticContext { return getNameForFQNPart(fqnGenerator.generate(descriptor)).get(0); } + @NotNull + public JsName getNameForBackingField(@NotNull PropertyDescriptor property) { + JsName name = backingFieldNameCache.get(property); + + if (name == null) { + FQNPart fqn = fqnGenerator.generate(property); + assert fqn.getNames().size() == 1 : "Private names must always consist of exactly one name"; + + JsScope scope = getScopeForDescriptor(fqn.getScope()); + + if (DynamicCallsKt.isDynamic(property)) { + scope = JsDynamicScope.INSTANCE; + } + String baseName = fqn.getNames().get(0) + "_0"; + name = scope.declareFreshName(baseName); + backingFieldNameCache.put(property, name); + } + + return name; + } + @NotNull private List getNameForFQNPart(@NotNull FQNPart part) { JsScope scope = getScopeForDescriptor(part.getScope()); @@ -328,7 +356,7 @@ public final class StaticContext { @Override public JsName create() { String name = Namer.generatePackageName(packageFqName); - return getRootScope().declareName(name); + return rootPackageScope.declareName(name); } }); } @@ -427,9 +455,8 @@ public final class StaticContext { if (!(descriptor instanceof CallableDescriptor)) { return null; } - JsScope enclosingScope = getEnclosingScope(descriptor); - JsFunction correspondingFunction = JsAstUtils.createFunctionWithEmptyBody(enclosingScope); + JsFunction correspondingFunction = JsAstUtils.createFunctionWithEmptyBody(getRootScope()); assert (!scopeToFunction.containsKey(correspondingFunction.getScope())) : "Scope to function value overridden for " + descriptor; scopeToFunction.put(correspondingFunction.getScope(), correspondingFunction); return correspondingFunction.getScope(); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 157932b3113..044ebfd42aa 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -229,6 +229,11 @@ public class TranslationContext { return staticContext.getQualifiedReference(packageFqName); } + @NotNull + public JsName getNameForBackingField(@NotNull PropertyDescriptor property) { + return staticContext.getNameForBackingField(property); + } + @NotNull public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) { return dynamicContext.declareTemporary(initExpression); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt index 55ffb5c7b41..9e7760218dc 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt @@ -18,8 +18,8 @@ package org.jetbrains.kotlin.js.translate.context import org.jetbrains.kotlin.descriptors.* import com.google.dart.compiler.backend.js.ast.JsName -import org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName import com.google.dart.compiler.backend.js.ast.JsScope +import org.jetbrains.kotlin.js.naming.FQNGenerator import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils.* import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject @@ -169,7 +169,10 @@ class UsageTracker( is TypeParameterDescriptor -> Namer.isInstanceSuggestedName(this) // Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes - else -> "closure\$${getSuggestedName(this)}" + else -> { + val mangled = FQNGenerator().generate(this).names.last() + "closure\$$mangled" + } } return scope.declareFreshName(suggestedName) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt index 2b18e368b02..c392f8f05c5 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt @@ -20,13 +20,13 @@ package org.jetbrains.kotlin.js.translate.declaration import com.google.dart.compiler.backend.js.ast.* import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.js.naming.FQNGenerator import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.general.Translation import org.jetbrains.kotlin.js.translate.utils.BindingUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils -import org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledMemberNameForExplicitDelegation import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateFunctionAsEcma5PropertyDescriptor import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall @@ -46,7 +46,7 @@ class DelegationTranslator( private val delegationBySpecifiers = classDeclaration.getSuperTypeListEntries().filterIsInstance() - private class Field (val name: String, val generateField: Boolean) + private class Field (val name: JsName, val generateField: Boolean) private val fields = mutableMapOf() init { @@ -57,12 +57,15 @@ class DelegationTranslator( val propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, classDescriptor, bindingContext()) if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext())) { - fields[specifier] = Field(propertyDescriptor!!.name.asString(), false) + val delegateName = context.getNameForDescriptor(propertyDescriptor!!) + fields[specifier] = Field(delegateName, false) } else { val classFqName = DescriptorUtils.getFqName(classDescriptor) val typeFqName = DescriptorUtils.getFqName(descriptor) - val delegateName = getMangledMemberNameForExplicitDelegation(Namer.getDelegatePrefix(), classFqName, typeFqName) + val suffix = FQNGenerator.mangledId("${classFqName.asString()}:${typeFqName.asString()}") + val suggestedName = Namer.getDelegatePrefix() + if (suffix.isNotEmpty()) "_$suffix\$" else "" + val delegateName = context.getScopeForDescriptor(classDescriptor).declareFreshName("${suggestedName}_0") fields[specifier] = Field(delegateName, true) } } @@ -76,7 +79,8 @@ class DelegationTranslator( val context = context().innerBlock() val delegateInitExpr = Translation.translateAsExpression(expression, context) statements += context.dynamicContext().jsBlock().statements - statements += JsAstUtils.defineSimpleProperty(field.name, delegateInitExpr) + val lhs = JsAstUtils.pureFqn(field.name, JsLiteral.THIS) + statements += JsAstUtils.assignment(lhs, delegateInitExpr).makeStmt() } } } @@ -105,15 +109,13 @@ class DelegationTranslator( private fun generateDelegateCallForPropertyMember( descriptor: PropertyDescriptor, - delegateName: String, + delegateName: JsName, properties: MutableList ) { val propertyName: String = descriptor.name.asString() fun generateDelegateGetterFunction(getterDescriptor: PropertyGetterDescriptor): JsFunction { - // TODO review: used wrong scope? - val delegateRefName = context().getScopeForDescriptor(getterDescriptor).declareName(delegateName) - val delegateRef = JsNameRef(delegateRefName, JsLiteral.THIS) + val delegateRef = JsNameRef(delegateName, JsLiteral.THIS) val returnExpression: JsExpression = if (DescriptorUtils.isExtension(descriptor)) { val getterName = context().getNameForDescriptor(getterDescriptor) @@ -121,8 +123,7 @@ class DelegationTranslator( JsInvocation(JsNameRef(getterName, delegateRef), JsNameRef(receiver)) } else { - @Suppress("USELESS_CAST") - (JsNameRef(propertyName, delegateRef) as JsExpression) // TODO remove explicit type specification after resolving KT-5569 + JsNameRef(propertyName, delegateRef) } val jsFunction = simpleReturnFunction(context().getScopeForDescriptor(getterDescriptor.containingDeclaration), returnExpression) @@ -134,15 +135,14 @@ class DelegationTranslator( } fun generateDelegateSetterFunction(setterDescriptor: PropertySetterDescriptor): JsFunction { - val jsFunction = JsFunction(context().getScopeForDescriptor(setterDescriptor.containingDeclaration), + val jsFunction = JsFunction(context().program().rootScope, "setter for " + setterDescriptor.name.asString()) assert(setterDescriptor.valueParameters.size == 1) { "Setter must have 1 parameter" } val defaultParameter = JsParameter(jsFunction.scope.declareTemporary()) val defaultParameterRef = defaultParameter.name.makeRef() - val delegateRefName = context().getScopeForDescriptor(setterDescriptor).declareName(delegateName) - val delegateRef = JsNameRef(delegateRefName, JsLiteral.THIS) + val delegateRef = JsNameRef(delegateName, JsLiteral.THIS) // TODO: remove explicit type annotation when Kotlin compiler works this out val setExpression: JsExpression = if (DescriptorUtils.isExtension(descriptor)) { @@ -182,11 +182,10 @@ class DelegationTranslator( private fun generateDelegateCallForFunctionMember( descriptor: FunctionDescriptor, overriddenDescriptor: FunctionDescriptor, - delegateName: String, + delegateName: JsName, properties: MutableList ) { - val delegateRefName = context().getScopeForDescriptor(descriptor).declareName(delegateName) - val delegateRef = JsNameRef(delegateRefName, JsLiteral.THIS) + val delegateRef = JsNameRef(delegateName, JsLiteral.THIS) properties.add(generateDelegateCall(descriptor, overriddenDescriptor, delegateRef, context())) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt index 722a83923d2..d38bb7acaa4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/PropertyTranslator.kt @@ -179,8 +179,7 @@ private class PropertyTranslator( } private fun generateDefaultSetterFunction(setterDescriptor: VariableAccessorDescriptor): JsFunction { - val containingScope = context().getScopeForDescriptor(setterDescriptor.containingDeclaration) - val function = JsFunction(containingScope, JsBlock(), accessorDescription(setterDescriptor)) + val function = JsFunction(context().program().rootScope, JsBlock(), accessorDescription(setterDescriptor)) assert(setterDescriptor.valueParameters.size == 1) { "Setter must have 1 parameter" } val correspondingPropertyName = setterDescriptor.correspondingVariable.name.asString() diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java index 7806f3f8888..ee695b5bb08 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java @@ -16,321 +16,23 @@ package org.jetbrains.kotlin.js.translate.utils; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; -import kotlin.collections.CollectionsKt; -import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.backend.common.CodegenUtil; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.annotations.Annotations; -import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl; +import org.jetbrains.kotlin.descriptors.ClassDescriptor; +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; -import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsKt; -import org.jetbrains.kotlin.name.FqNameUnsafe; +import org.jetbrains.kotlin.js.naming.FQNGenerator; import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.resolve.DescriptorUtils; -import org.jetbrains.kotlin.resolve.scopes.MemberScope; -import java.util.*; - -import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName; +import java.util.Collection; public class ManglingUtils { private ManglingUtils() {} - private static final Comparator CALLABLE_COMPARATOR = new CallableComparator(); - - @NotNull - public static String getMangledName(@NotNull PropertyDescriptor descriptor, @NotNull String suggestedName) { - return getStableMangledName(suggestedName, getFqName(descriptor).asString()); - } - - @NotNull - public static String getSuggestedName(@NotNull DeclarationDescriptor descriptor) { - String suggestedName = descriptor.getName().isSpecial() ? "f" : descriptor.getName().getIdentifier(); - - if (descriptor instanceof FunctionDescriptor || - descriptor instanceof PropertyDescriptor && DescriptorUtils.isExtension((PropertyDescriptor) descriptor) - ) { - suggestedName = getMangledName((CallableMemberDescriptor) descriptor); - } - - ClassifierDescriptorWithTypeParameters localClass = null; - if (descriptor instanceof ConstructorDescriptor) { - ConstructorDescriptor constructor = (ConstructorDescriptor) descriptor; - localClass = constructor.getContainingDeclaration(); - } - else if (descriptor instanceof ClassDescriptor) { - localClass = (ClassDescriptor) descriptor; - } - - if (DescriptorUtils.isDescriptorWithLocalVisibility(localClass)) { - suggestedName = getSuggestedLocalPrefix(localClass) + suggestedName; - } - - return suggestedName; - } - - @NotNull - private static String getSuggestedLocalPrefix(@NotNull DeclarationDescriptor descriptor) { - List parts = new ArrayList(); - while (true) { - descriptor = descriptor.getContainingDeclaration(); - if (descriptor == null || descriptor instanceof ClassOrPackageFragmentDescriptor) { - break; - } - parts.add(descriptor.getName().isSpecial() ? "f" : descriptor.getName().getIdentifier()); - } - - Collections.reverse(parts); - String result = StringUtil.join(parts, "$"); - return !result.isEmpty() ? result + "$" : ""; - } - - @NotNull - private static String getMangledName(@NotNull CallableMemberDescriptor descriptor) { - if (needsStableMangling(descriptor)) { - return getStableMangledName(descriptor); - } - - return getSimpleMangledName(descriptor); - } - - //TODO extend logic for nested/inner declarations - private static boolean needsStableMangling(CallableMemberDescriptor descriptor) { - // Use stable mangling for overrides because we use stable mangling when any function inside a overridable declaration - // for avoid clashing names when inheritance. - if (DescriptorUtils.isOverride(descriptor)) { - return true; - } - - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - - if (containingDeclaration instanceof PackageFragmentDescriptor) { - return descriptor.getVisibility().isPublicAPI(); - } - else if (containingDeclaration instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - - // Use stable mangling when it's inside an overridable declaration to avoid clashing names on inheritance. - if (!ModalityKt.isFinalOrEnum(classDescriptor)) { - return true; - } - - // valueOf() is created in the library with a mangled name for every enum class - if (descriptor instanceof FunctionDescriptor && CodegenUtil.isEnumValueOfMethod((FunctionDescriptor) descriptor)) { - return true; - } - - // Don't use stable mangling when it inside a non-public API declaration. - if (!classDescriptor.getVisibility().isPublicAPI()) { - return false; - } - - // Ignore the `protected` visibility because it can be use outside a containing declaration - // only when the containing declaration is overridable. - if (descriptor.getVisibility() == Visibilities.PUBLIC) { - return true; - } - - return false; - } - - assert containingDeclaration instanceof CallableMemberDescriptor : - "containingDeclaration for descriptor have unsupported type for mangling, " + - "descriptor: " + descriptor + ", containingDeclaration: " + containingDeclaration; - - return false; - } - - @NotNull - public static String getMangledMemberNameForExplicitDelegation( - @NotNull String suggestedName, - @NotNull FqNameUnsafe classFqName, - @NotNull FqNameUnsafe typeFqName - ) { - String forCalculateId = classFqName.asString() + ":" + typeFqName.asString(); - return getStableMangledName(suggestedName, forCalculateId); - } - - @NotNull - private static String getStableMangledName(@NotNull String suggestedName, String forCalculateId) { - int absHashCode = Math.abs(forCalculateId.hashCode()); - String suffix = absHashCode == 0 ? "" : ("_" + Integer.toString(absHashCode, Character.MAX_RADIX) + "$"); - return suggestedName + suffix; - } - - @NotNull - private static String getStableMangledName(@NotNull CallableDescriptor descriptor) { - String suggestedName = getSuggestedName(descriptor); - return getStableMangledName(suggestedName, getArgumentTypesAsString(descriptor)); - } - - @NotNull - private static String getSuggestedName(@NotNull CallableDescriptor descriptor) { - if (descriptor instanceof ConstructorDescriptor && !((ConstructorDescriptor) descriptor).isPrimary()) { - return descriptor.getContainingDeclaration().getName().asString() + "_init"; - } - else { - return descriptor.getName().asString(); - } - } - - @NotNull - private static String getSimpleMangledName(@NotNull CallableMemberDescriptor descriptor) { - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - - MemberScope jetScope = null; - - String nameToCompare = descriptor.getName().asString(); - - if (descriptor instanceof ConstructorDescriptor) { - nameToCompare = containingDeclaration.getName().asString(); - containingDeclaration = containingDeclaration.getContainingDeclaration(); - } - - if (containingDeclaration instanceof PackageFragmentDescriptor) { - jetScope = ((PackageFragmentDescriptor) containingDeclaration).getMemberScope(); - } - else if (containingDeclaration instanceof ClassDescriptor) { - jetScope = ((ClassDescriptor) containingDeclaration).getDefaultType().getMemberScope(); - } - - int counter = 0; - - if (jetScope != null) { - final String finalNameToCompare = nameToCompare; - - Collection declarations = DescriptorUtils.getAllDescriptors(jetScope); - List overloadedFunctions = - CollectionsKt.flatMap(declarations, new Function1>() { - @Override - public Iterable invoke(DeclarationDescriptor declarationDescriptor) { - if (declarationDescriptor instanceof ClassDescriptor && finalNameToCompare.equals(declarationDescriptor.getName().asString())) { - ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; - Collection constructors = classDescriptor.getConstructors(); - - if (!DescriptorUtilsKt.hasPrimaryConstructor(classDescriptor)) { - ClassConstructorDescriptorImpl fakePrimaryConstructor = - ClassConstructorDescriptorImpl - .create(classDescriptor, Annotations.Companion.getEMPTY(), true, SourceElement.NO_SOURCE); - return CollectionsKt.plus(constructors, fakePrimaryConstructor); - } - - return constructors; - } - - if (!(declarationDescriptor instanceof CallableMemberDescriptor)) return Collections.emptyList(); - - CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declarationDescriptor; - - String name = AnnotationsUtils.getNameForAnnotatedObjectWithOverrides(callableMemberDescriptor); - - // when name == null it's mean that it's not native. - if (name == null) { - // skip functions without arguments, because we don't use mangling for them - if (needsStableMangling(callableMemberDescriptor) && !callableMemberDescriptor.getValueParameters().isEmpty()) return Collections.emptyList(); - - // TODO add prefix for property: get_$name and set_$name - name = callableMemberDescriptor.getName().asString(); - } - - if (finalNameToCompare.equals(name)) return Collections.singletonList(callableMemberDescriptor); - - return Collections.emptyList(); - } - }); - - if (overloadedFunctions.size() > 1) { - Collections.sort(overloadedFunctions, CALLABLE_COMPARATOR); - counter = ContainerUtil.indexOfIdentity(overloadedFunctions, descriptor); - assert counter >= 0; - } - } - - String name = getSuggestedName(descriptor); - return counter == 0 ? name : name + '_' + counter; - } - - private static String getArgumentTypesAsString(CallableDescriptor descriptor) { - StringBuilder argTypes = new StringBuilder(); - - ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); - if (receiverParameter != null) { - argTypes.append(DescriptorUtilsKt.getJetTypeFqName(receiverParameter.getType(), true)).append("."); - } - - argTypes.append(StringUtil.join(descriptor.getValueParameters(), new Function() { - @Override - public String fun(ValueParameterDescriptor descriptor) { - return DescriptorUtilsKt.getJetTypeFqName(descriptor.getType(), true); - } - }, ",")); - - return argTypes.toString(); - } - @NotNull public static String getStableMangledNameForDescriptor(@NotNull ClassDescriptor descriptor, @NotNull String functionName) { - Collection functions = - descriptor.getDefaultType().getMemberScope().getContributedFunctions(Name.identifier(functionName), NoLookupLocation.FROM_BACKEND); + Collection functions = descriptor.getDefaultType().getMemberScope().getContributedFunctions( + Name.identifier(functionName), NoLookupLocation.FROM_BACKEND); assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor; - return getSuggestedName((DeclarationDescriptor) functions.iterator().next()); - } - - private static class CallableComparator implements Comparator { - @Override - public int compare(@NotNull CallableDescriptor a, @NotNull CallableDescriptor b) { - // primary constructors - if (a instanceof ConstructorDescriptor && ((ConstructorDescriptor) a).isPrimary()) { - if (!(b instanceof ConstructorDescriptor) || !((ConstructorDescriptor) b).isPrimary()) return -1; - } - else if (b instanceof ConstructorDescriptor && ((ConstructorDescriptor) b).isPrimary()) { - return 1; - } - - // native functions - if (isNativeOrOverrideNative(a)) { - if (!isNativeOrOverrideNative(b)) return -1; - } - else if (isNativeOrOverrideNative(b)) { - return 1; - } - - // be visibility - // Actually "internal" > "private", but we want to have less number for "internal", so compare b with a instead of a with b. - Integer result = Visibilities.compare(b.getVisibility(), a.getVisibility()); - if (result != null && result != 0) return result; - - // by arity - int aArity = arity(a); - int bArity = arity(b); - if (aArity != bArity) return aArity - bArity; - - // by stringify argument types - String aArguments = getArgumentTypesAsString(a); - String bArguments = getArgumentTypesAsString(b); - assert aArguments != bArguments; - - return aArguments.compareTo(bArguments); - } - - private static int arity(CallableDescriptor descriptor) { - return descriptor.getValueParameters().size() + (descriptor.getExtensionReceiverParameter() == null ? 0 : 1); - } - - private static boolean isNativeOrOverrideNative(CallableDescriptor descriptor) { - if (!(descriptor instanceof CallableMemberDescriptor)) return false; - - if (AnnotationsUtils.isNativeObject(descriptor)) return true; - - Set declarations = DescriptorUtils.getAllOverriddenDeclarations((CallableMemberDescriptor) descriptor); - for (CallableMemberDescriptor memberDescriptor : declarations) { - if (AnnotationsUtils.isNativeObject(memberDescriptor)) return true; - } - return false; - } + return new FQNGenerator().generate(functions.iterator().next()).getNames().get(0); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index d99f2b4af34..1569b243b0c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -38,11 +38,9 @@ import java.util.ArrayList; import java.util.List; import static com.google.dart.compiler.backend.js.ast.JsBinaryOperator.*; -import static org.jetbrains.kotlin.js.translate.context.Namer.getKotlinBackingFieldName; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.assignment; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.createDataDescriptor; -import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isAnonymousObject; public final class TranslationUtils { @@ -152,13 +150,8 @@ public final class TranslationUtils { @NotNull PropertyDescriptor descriptor) { JsName backingFieldName = context.getNameForDescriptor(descriptor); if(!JsDescriptorUtils.isSimpleFinalProperty(descriptor)) { - String backingFieldMangledName; - if (!Visibilities.isPrivate(descriptor.getVisibility())) { - backingFieldMangledName = getMangledName(descriptor, getKotlinBackingFieldName(backingFieldName.getIdent())); - } else { - backingFieldMangledName = getKotlinBackingFieldName(backingFieldName.getIdent()); - } - backingFieldName = context.declarePropertyOrPropertyAccessorName(descriptor, backingFieldMangledName, false); + JsName backingFieldMangledName = context.getNameForBackingField(descriptor); + backingFieldName = context.declarePropertyOrPropertyAccessorName(descriptor, backingFieldMangledName.getIdent(), false); } DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration(); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index f1673320cf7..106aa456423 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -43,14 +43,14 @@ fun generateDelegateCall( val functionScope = context.getScopeForDescriptor(fromDescriptor) if (DescriptorUtils.isExtension(fromDescriptor)) { - val extensionFunctionReceiverName = functionScope.declareName(Namer.getReceiverParameterName()) + val extensionFunctionReceiverName = functionScope.declareFreshName(Namer.getReceiverParameterName()) parameters.add(JsParameter(extensionFunctionReceiverName)) args.add(JsNameRef(extensionFunctionReceiverName)) } for (param in fromDescriptor.valueParameters) { val paramName = param.name.asString() - val jsParamName = functionScope.declareName(paramName) + val jsParamName = functionScope.declareFreshName(paramName) parameters.add(JsParameter(jsParamName)) args.add(JsNameRef(jsParamName)) } diff --git a/js/js.translator/testData/box/inline/metadataForPublicFunction.kt b/js/js.translator/testData/box/inline/metadataForPublicFunction.kt index 378fede11f1..0e4d7b68a72 100644 --- a/js/js.translator/testData/box/inline/metadataForPublicFunction.kt +++ b/js/js.translator/testData/box/inline/metadataForPublicFunction.kt @@ -6,7 +6,7 @@ package foo // CHECK_CONTAINS_NO_CALLS: test4_buocd8$ // CHECK_CONTAINS_NO_CALLS: test5_0 // CHECK_HAS_INLINE_METADATA: apply_hiyix$ -// CHECK_HAS_INLINE_METADATA: applyL_0 +// CHECK_HAS_INLINE_METADATA: applyL_hiyix$ // CHECK_HAS_INLINE_METADATA: applyM_hiyix$ // CHECK_HAS_NO_INLINE_METADATA: applyN_0 // CHECK_HAS_NO_INLINE_METADATA: applyO_hiyix$