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:
@@ -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) {
|
||||
|
||||
+1
-4
@@ -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)
|
||||
|
||||
-77
@@ -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)
|
||||
|
||||
+16
-17
@@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -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$
|
||||
|
||||
Reference in New Issue
Block a user