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$