diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNGenerator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt similarity index 93% rename from js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNGenerator.kt rename to js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt index 30a276e9bb0..f5cfe6d367f 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNGenerator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt @@ -33,10 +33,10 @@ import java.util.* * fully-qualified names for static declarations. * * A new instance of this class can be created for each request, however, it's recommended to use shared instance, since - * [FQNGenerator] supports caching. + * [NameSuggestion] supports caching. */ -class FQNGenerator { - private val cache: MutableMap = WeakHashMap() +class NameSuggestion { + private val cache: MutableMap = WeakHashMap() /** * Generates names for declarations. Name consist of the following parts: @@ -57,12 +57,12 @@ class FQNGenerator { * list consists of exactly one string for any declaration except for package. Package name lists * have at least one string. */ - fun generate(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generateCacheMiss(descriptor.original) } + fun suggest(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generate(descriptor.original) } - private fun generateCacheMiss(descriptor: DeclarationDescriptor): FQNPart? { + private fun generate(descriptor: DeclarationDescriptor): SuggestedName? { // Members of companion objects of classes are treated as static members of these classes if (isNativeObject(descriptor) && isCompanionObject(descriptor)) { - return generate(descriptor.containingDeclaration!!) + return suggest(descriptor.containingDeclaration!!) } when (descriptor) { @@ -71,7 +71,7 @@ class FQNGenerator { is PackageFragmentDescriptor -> { return if (!descriptor.name.isSpecial) { - FQNPart(descriptor.fqName.pathSegments().map { it.asString() }, true, descriptor, descriptor.containingDeclaration) + SuggestedName(descriptor.fqName.pathSegments().map { it.asString() }, true, descriptor, descriptor.containingDeclaration) } else { // Root packages are similar to modules @@ -80,12 +80,12 @@ class FQNGenerator { } // It's a special case when an object has `invoke` operator defined, in this case we simply generate object itself - is FakeCallableDescriptorForObject -> return generate(descriptor.getReferencedDescriptor()) + is FakeCallableDescriptorForObject -> return suggest(descriptor.getReferencedDescriptor()) // For primary constructors and constructors of native classes we generate references to containing classes is ConstructorDescriptor -> { if (descriptor.isPrimary || isNativeObject(descriptor)) { - return generate(descriptor.containingDeclaration) + return suggest(descriptor.containingDeclaration) } } @@ -93,12 +93,12 @@ class FQNGenerator { is CallableDescriptor -> if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) { val name = getMangledName(getSuggestedName(descriptor), descriptor) - return FQNPart(listOf(name.first), false, descriptor, descriptor.containingDeclaration) + return SuggestedName(listOf(name.first), false, descriptor, descriptor.containingDeclaration) } } val (localName, shared, parent) = getLocalName(descriptor) - return FQNPart(listOf(localName), shared, descriptor, fixParent(parent)) + return SuggestedName(listOf(localName), shared, descriptor, fixParent(parent)) } // Getters and setters have generation strategy similar to common declarations, except for they are declared as diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNPart.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/SuggestedName.kt similarity index 83% rename from js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNPart.kt rename to js/js.frontend/src/org/jetbrains/kotlin/js/naming/SuggestedName.kt index 13d223667ef..d4b8419d561 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/FQNPart.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/SuggestedName.kt @@ -18,4 +18,4 @@ package org.jetbrains.kotlin.js.naming import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -class FQNPart(val names: List, val shared: Boolean, val descriptor: DeclarationDescriptor, val scope: DeclarationDescriptor) +class SuggestedName(val names: List, val stable: Boolean, val descriptor: DeclarationDescriptor, val scope: DeclarationDescriptor) 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 5c9aed331a0..1faffe235c1 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 @@ -18,7 +18,7 @@ package org.jetbrains.kotlin.js.resolve.diagnostics import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.DiagnosticSink -import org.jetbrains.kotlin.js.naming.FQNGenerator +import org.jetbrains.kotlin.js.naming.NameSuggestion import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtProperty @@ -29,7 +29,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.scopes.MemberScope class JsNameClashChecker : SimpleDeclarationChecker { - private val fqnGenerator = FQNGenerator() + private val nameSuggestion = NameSuggestion() private val scopes = mutableMapOf>() private val clashedFakeOverrides = mutableMapOf>() private val clashedDescriptors = mutableSetOf() @@ -46,12 +46,12 @@ class JsNameClashChecker : SimpleDeclarationChecker { } private fun checkDescriptor(descriptor: DeclarationDescriptor, declaration: KtDeclaration, diagnosticHolder: DiagnosticSink) { - val fqn = fqnGenerator.generate(descriptor)!! - if (fqn.shared && fqn.scope is ClassOrPackageFragmentDescriptor && isOpaque(fqn.descriptor)) { - val scope = getScope(fqn.scope) - val name = fqn.names.last() + val suggested = nameSuggestion.suggest(descriptor)!! + if (suggested.stable && suggested.scope is ClassOrPackageFragmentDescriptor && isOpaque(suggested.descriptor)) { + val scope = getScope(suggested.scope) + val name = suggested.names.last() val existing = scope[name] - if (existing != null && existing != fqn.descriptor) { + if (existing != null && existing != suggested.descriptor) { diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(declaration, name, existing)) val existingDeclaration = existing.findPsi() ?: declaration if (clashedDescriptors.add(existing) && existingDeclaration is KtDeclaration && existingDeclaration != declaration) { @@ -60,13 +60,13 @@ class JsNameClashChecker : SimpleDeclarationChecker { } } - val fqnDescriptor = fqn.descriptor + val fqnDescriptor = suggested.descriptor if (fqnDescriptor is ClassDescriptor) { val fakeOverrides = fqnDescriptor.defaultType.memberScope.getContributedDescriptors().asSequence() .mapNotNull { it as? CallableMemberDescriptor } .filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } for (override in fakeOverrides) { - val overrideFqn = fqnGenerator.generate(override)!! + val overrideFqn = nameSuggestion.suggest(override)!! val scope = getScope(overrideFqn.scope) val name = overrideFqn.names.last() val existing = scope[name] @@ -114,8 +114,8 @@ class JsNameClashChecker : SimpleDeclarationChecker { } } - val fqn = fqnGenerator.generate(descriptor) ?: return - if (fqn.shared && isOpaque(fqn.descriptor)) { + val fqn = nameSuggestion.suggest(descriptor) ?: return + if (fqn.stable && isOpaque(fqn.descriptor)) { target[fqn.names.last()] = fqn.descriptor (fqn.descriptor as? CallableMemberDescriptor)?.let { checkOverrideClashes(it, target) } } @@ -125,8 +125,8 @@ class JsNameClashChecker : SimpleDeclarationChecker { var overridden = descriptor.overriddenDescriptors while (overridden.isNotEmpty()) { for (overridenDescriptor in overridden) { - val overriddenFqn = fqnGenerator.generate(overridenDescriptor)!! - if (overriddenFqn.shared) { + val overriddenFqn = nameSuggestion.suggest(overridenDescriptor)!! + if (overriddenFqn.stable) { val existing = target[overriddenFqn.names.last()] if (existing != null) { if (existing != descriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { 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 dda2b1cb181..650ee05a4f8 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,7 +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.naming.NameSuggestion; import org.jetbrains.kotlin.js.resolve.JsPlatform; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; @@ -128,7 +128,7 @@ public final class Namer { qualifier = fqNameParent.asString(); } - String mangledName = new FQNGenerator().generate(functionDescriptor).getNames().get(0); + String mangledName = new NameSuggestion().suggest(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 7f9ae518690..e3b350d88b4 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 @@ -29,8 +29,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.js.config.JsConfig; -import org.jetbrains.kotlin.js.naming.FQNGenerator; -import org.jetbrains.kotlin.js.naming.FQNPart; +import org.jetbrains.kotlin.js.naming.NameSuggestion; +import org.jetbrains.kotlin.js.naming.SuggestedName; import org.jetbrains.kotlin.js.translate.context.generator.Generator; import org.jetbrains.kotlin.js.translate.context.generator.Rule; import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; @@ -105,7 +105,7 @@ public final class StaticContext { private final ModuleDescriptor currentModule; @NotNull - private final FQNGenerator fqnGenerator = new FQNGenerator(); + private final NameSuggestion nameSuggestion = new NameSuggestion(); @NotNull private final Map nameCache = new HashMap(); @@ -221,8 +221,8 @@ public final class StaticContext { @NotNull private JsExpression buildQualifiedExpression(@NotNull DeclarationDescriptor descriptor) { - FQNPart part = fqnGenerator.generate(descriptor); - if (part == null) { + SuggestedName suggested = nameSuggestion.suggest(descriptor); + if (suggested == null) { ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor); if (currentModule == module) { return pureFqn(Namer.getRootPackageName(), null); @@ -235,30 +235,30 @@ public final class StaticContext { JsExpression expression; List partNames; - if (standardClasses.isStandardObject(part.getDescriptor())) { + if (standardClasses.isStandardObject(suggested.getDescriptor())) { expression = Namer.kotlinObject(); - partNames = Collections.singletonList(standardClasses.getStandardObjectName(part.getDescriptor())); + partNames = Collections.singletonList(standardClasses.getStandardObjectName(suggested.getDescriptor())); } - else if (isLibraryObject(part.getDescriptor())) { + else if (isLibraryObject(suggested.getDescriptor())) { expression = Namer.kotlinObject(); - partNames = getNameForFQNPart(part); + partNames = getActualNameFromSuggested(suggested); } - else if (isNative(part.getDescriptor()) && !isNativeObject(part.getScope())) { + else if (isNative(suggested.getDescriptor()) && !isNativeObject(suggested.getScope())) { expression = null; - partNames = getNameForFQNPart(part); + partNames = getActualNameFromSuggested(suggested); } else { - if (part.getDescriptor() instanceof CallableDescriptor && part.getScope() instanceof FunctionDescriptor) { + if (suggested.getDescriptor() instanceof CallableDescriptor && suggested.getScope() instanceof FunctionDescriptor) { expression = null; } else { - expression = getQualifiedExpression(part.getScope()); + expression = getQualifiedExpression(suggested.getScope()); } - partNames = getNameForFQNPart(part); + partNames = getActualNameFromSuggested(suggested); } for (JsName partName : partNames) { expression = new JsNameRef(partName, expression); - applySideEffects(expression, part.getDescriptor()); + applySideEffects(expression, suggested.getDescriptor()); } assert expression != null : "Since partNames is not empty, expression must be non-null"; return expression; @@ -283,11 +283,11 @@ public final class StaticContext { @NotNull public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) { - FQNPart fqn = fqnGenerator.generate(descriptor); - if (fqn == null) { + SuggestedName suggested = nameSuggestion.suggest(descriptor); + if (suggested == null) { throw new IllegalArgumentException("Can't generate name for root declarations: " + descriptor); } - return getNameForFQNPart(fqn).get(0); + return getActualNameFromSuggested(suggested).get(0); } @NotNull @@ -295,7 +295,7 @@ public final class StaticContext { JsName name = backingFieldNameCache.get(property); if (name == null) { - FQNPart fqn = fqnGenerator.generate(property); + SuggestedName fqn = nameSuggestion.suggest(property); assert fqn != null : "Properties are non-root declarations: " + property; assert fqn.getNames().size() == 1 : "Private names must always consist of exactly one name"; @@ -313,21 +313,21 @@ public final class StaticContext { } @NotNull - private List getNameForFQNPart(@NotNull FQNPart part) { - JsScope scope = getScopeForDescriptor(part.getScope()); + private List getActualNameFromSuggested(@NotNull SuggestedName suggested) { + JsScope scope = getScopeForDescriptor(suggested.getScope()); - if (DynamicCallsKt.isDynamic(part.getDescriptor())) { + if (DynamicCallsKt.isDynamic(suggested.getDescriptor())) { scope = JsDynamicScope.INSTANCE; } List names = new ArrayList(); - if (part.getShared()) { + if (suggested.getStable()) { Map scopeNames = persistentNames.get(scope); if (scopeNames == null) { scopeNames = new HashMap(); persistentNames.put(scope, scopeNames); } - for (String namePart : part.getNames()) { + for (String namePart : suggested.getNames()) { JsName name = scopeNames.get(namePart); if (name == null) { name = scope.declareName(namePart); @@ -338,16 +338,16 @@ public final class StaticContext { } else { // TODO: consider using sealed class to represent FQNs - assert part.getNames().size() == 1 : "Private names must always consist of exactly one name"; - JsName name = nameCache.get(part.getDescriptor()); + assert suggested.getNames().size() == 1 : "Private names must always consist of exactly one name"; + JsName name = nameCache.get(suggested.getDescriptor()); if (name == null) { - String baseName = part.getNames().get(0); - if (!DescriptorUtils.isDescriptorWithLocalVisibility(part.getDescriptor())) { + String baseName = suggested.getNames().get(0); + if (!DescriptorUtils.isDescriptorWithLocalVisibility(suggested.getDescriptor())) { baseName += "_0"; } name = scope.declareFreshName(baseName); } - nameCache.put(part.getDescriptor(), name); + nameCache.put(suggested.getDescriptor(), name); names.add(name); } @@ -501,7 +501,6 @@ public final class StaticContext { return JsAstUtils.pureFqn(moduleId, null); } - private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) { if (expression instanceof HasMetadata) { if (descriptor instanceof FunctionDescriptor || 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 68b76944f6c..728bca0b7f8 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 @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.js.translate.context import org.jetbrains.kotlin.descriptors.* import com.google.dart.compiler.backend.js.ast.JsName import com.google.dart.compiler.backend.js.ast.JsScope -import org.jetbrains.kotlin.js.naming.FQNGenerator +import org.jetbrains.kotlin.js.naming.NameSuggestion import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils.* import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject @@ -170,7 +170,7 @@ class UsageTracker( // Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes else -> { - val mangled = FQNGenerator().generate(this)!!.names.last() + val mangled = NameSuggestion().suggest(this)!!.names.last() "closure\$$mangled" } } 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 c392f8f05c5..2db77831c64 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,7 +20,7 @@ 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.naming.NameSuggestion import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.general.AbstractTranslator @@ -63,7 +63,7 @@ class DelegationTranslator( else { val classFqName = DescriptorUtils.getFqName(classDescriptor) val typeFqName = DescriptorUtils.getFqName(descriptor) - val suffix = FQNGenerator.mangledId("${classFqName.asString()}:${typeFqName.asString()}") + val suffix = NameSuggestion.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) 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 ee695b5bb08..747a1085fba 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 @@ -20,7 +20,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; -import org.jetbrains.kotlin.js.naming.FQNGenerator; +import org.jetbrains.kotlin.js.naming.NameSuggestion; +import org.jetbrains.kotlin.js.naming.SuggestedName; import org.jetbrains.kotlin.name.Name; import java.util.Collection; @@ -33,6 +34,8 @@ public class ManglingUtils { 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 new FQNGenerator().generate(functions.iterator().next()).getNames().get(0); + SuggestedName suggested = new NameSuggestion().suggest(functions.iterator().next()); + assert suggested != null : "Suggested name for class members is always non-null: " + functions.iterator().next(); + return suggested.getNames().get(0); } }