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
This commit is contained in:
Alexey Andreev
2016-06-16 15:15:29 +03:00
parent 1dcb037aee
commit 33daf83f14
16 changed files with 84 additions and 433 deletions
@@ -47,7 +47,7 @@ public abstract class JsScope {
private final String description;
private Map<String, JsName> 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 <code>null</code> 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 <code>null</code> 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++;
}
@@ -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)
@@ -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
}
@@ -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) {
@@ -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)
@@ -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
}
}
@@ -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), ".");
}
@@ -110,6 +110,9 @@ public final class StaticContext {
@NotNull
private final Map<DeclarationDescriptor, JsName> nameCache = new HashMap<DeclarationDescriptor, JsName>();
@NotNull
private final Map<PropertyDescriptor, JsName> backingFieldNameCache = new HashMap<PropertyDescriptor, JsName>();
private final Map<JsScope, Map<String, JsName>> persistentNames = new HashMap<JsScope, Map<String, JsName>>();
@NotNull
@@ -120,6 +123,9 @@ public final class StaticContext {
private Map<String, JsName> 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>", "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<JsName> 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();
@@ -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);
@@ -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)
@@ -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<KtDelegatedSuperTypeEntry>()
private class Field (val name: String, val generateField: Boolean)
private class Field (val name: JsName, val generateField: Boolean)
private val fields = mutableMapOf<KtDelegatedSuperTypeEntry, Field>()
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<JsPropertyInitializer>
) {
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<JsPropertyInitializer>
) {
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()))
}
}
@@ -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()
@@ -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<CallableDescriptor> 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<String> parts = new ArrayList<String>();
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<DeclarationDescriptor> declarations = DescriptorUtils.getAllDescriptors(jetScope);
List<CallableDescriptor> overloadedFunctions =
CollectionsKt.flatMap(declarations, new Function1<DeclarationDescriptor, Iterable<? extends CallableDescriptor>>() {
@Override
public Iterable<? extends CallableDescriptor> invoke(DeclarationDescriptor declarationDescriptor) {
if (declarationDescriptor instanceof ClassDescriptor && finalNameToCompare.equals(declarationDescriptor.getName().asString())) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
Collection<ClassConstructorDescriptor> 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<ValueParameterDescriptor, String>() {
@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<SimpleFunctionDescriptor> functions =
descriptor.getDefaultType().getMemberScope().getContributedFunctions(Name.identifier(functionName), NoLookupLocation.FROM_BACKEND);
Collection<SimpleFunctionDescriptor> 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<CallableDescriptor> {
@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<CallableMemberDescriptor> 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);
}
}
@@ -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();
@@ -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))
}
@@ -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$