diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt index 0d863821b06..fa93509029a 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt @@ -41,7 +41,7 @@ import kotlin.math.abs * A new instance of this class can be created for each request, however, it's recommended to use stable instance, since * [NameSuggestion] supports caching. */ -class NameSuggestion(val bindingContext: BindingContext) { +class NameSuggestion { private val cache: MutableMap = Collections.synchronizedMap(WeakHashMap()) /** @@ -63,12 +63,15 @@ class NameSuggestion(val bindingContext: BindingContext) { * list consists of exactly one string for any declaration except for package. Package name lists * have at least one string. */ - fun suggest(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generate(descriptor.original) } + fun suggest(descriptor: DeclarationDescriptor, bindingContext: BindingContext) = + cache.getOrPut(descriptor) { generate(descriptor.original, bindingContext) } - private fun generate(descriptor: DeclarationDescriptor): SuggestedName? { - // Members of companion objects of classes are treated as static members of these classes + private fun generate(descriptor: DeclarationDescriptor, bindingContext: BindingContext): SuggestedName? { + fun suggest(d: DeclarationDescriptor) = suggest(d, bindingContext) + + // Members of companion objects of classes are treated as static members of these classes if (isNativeObject(descriptor) && isCompanionObject(descriptor)) { - return suggest(descriptor.containingDeclaration!!) + return suggest(descriptor.containingDeclaration!!, bindingContext) } if (descriptor is FunctionDescriptor && descriptor.isSuspend) { @@ -139,10 +142,10 @@ class NameSuggestion(val bindingContext: BindingContext) { } } - return generateDefault(descriptor) + return generateDefault(descriptor, bindingContext) } - private fun generateDefault(descriptor: DeclarationDescriptor): SuggestedName { + private fun generateDefault(descriptor: DeclarationDescriptor, bindingContext: BindingContext): SuggestedName { // For any non-local declaration suggest its own suggested name and put it in scope of its containing declaration. // For local declaration get a sequence for names of all containing functions and join their names with '$' symbol, // and use container of topmost function, i.e. @@ -180,7 +183,7 @@ class NameSuggestion(val bindingContext: BindingContext) { getSuggestedName(fixedDescriptor) } if (current.containingDeclaration is FunctionDescriptor && current !is TypeParameterDescriptor) { - val outerFunctionName = suggest(current.containingDeclaration as FunctionDescriptor)!! + val outerFunctionName = suggest(current.containingDeclaration as FunctionDescriptor, bindingContext)!! parts += outerFunctionName.names.single() current = outerFunctionName.scope } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt index 0d349ace3d8..050122ad9be 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt @@ -48,6 +48,7 @@ object JsPlatformConfigurator : PlatformConfiguratorBase( identifierChecker = JsIdentifierChecker ) { override fun configureModuleComponents(container: StorageComponentContainer) { + container.useInstance(NameSuggestion()) container.useImpl() container.useImpl() container.useImpl() diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsBuiltinNameClashChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsBuiltinNameClashChecker.kt index 74d5d5dd7ed..770c8bb9e09 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsBuiltinNameClashChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsBuiltinNameClashChecker.kt @@ -22,16 +22,15 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor 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.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext -class JsBuiltinNameClashChecker : DeclarationChecker { +class JsBuiltinNameClashChecker(private val nameSuggestion: NameSuggestion) : DeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { - val nameSuggestion = NameSuggestion(context.trace.bindingContext) if (AnnotationsUtils.isNativeObject(descriptor)) return if (descriptor.containingDeclaration !is ClassDescriptor) return - val suggestedName = nameSuggestion.suggest(descriptor)!! + val suggestedName = nameSuggestion.suggest(descriptor, context.trace.bindingContext)!! if (!suggestedName.stable) return val simpleName = suggestedName.names.single() diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameCharsChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameCharsChecker.kt index 761637c5daa..083e301215a 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameCharsChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameCharsChecker.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext -class JsNameCharsChecker : DeclarationChecker { +class JsNameCharsChecker(private val suggestion: NameSuggestion) : DeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { val bindingContext = context.trace.bindingContext @@ -27,8 +27,7 @@ class JsNameCharsChecker : DeclarationChecker { AnnotationsUtils.isExportedObject(descriptor, bindingContext) ) return - val suggestion = NameSuggestion(bindingContext) - val suggestedName = suggestion.suggest(descriptor) ?: return + val suggestedName = suggestion.suggest(descriptor, bindingContext) ?: return if (suggestedName.stable && suggestedName.names.any { NameSuggestion.sanitizeName(it) != it }) { context.trace.report(ErrorsJs.NAME_CONTAINS_ILLEGAL_CHARS.on(declaration)) } 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 2137a94e51c..e8472ca9141 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 @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty import org.jetbrains.kotlin.resolve.scopes.MemberScope class JsNameClashChecker( + private val nameSuggestion: NameSuggestion, private val languageVersionSettings: LanguageVersionSettings ) : DeclarationChecker { companion object { @@ -44,7 +45,6 @@ class JsNameClashChecker( Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION) } - lateinit var nameSuggestion: NameSuggestion private val scopes = mutableMapOf>() private val clashedFakeOverrides = mutableMapOf>() private val clashedDescriptors = mutableSetOf>() @@ -62,12 +62,10 @@ class JsNameClashChecker( diagnosticHolder: DiagnosticSink, bindingContext: BindingContext ) { if (descriptor is ConstructorDescriptor && descriptor.isPrimary) return - if (!this::nameSuggestion.isInitialized || nameSuggestion.bindingContext !== bindingContext) - nameSuggestion = NameSuggestion(bindingContext) - for (suggested in nameSuggestion.suggestAllPossibleNames(descriptor)) { + for (suggested in nameSuggestion.suggestAllPossibleNames(descriptor, bindingContext)) { if (suggested.stable && suggested.scope is ClassOrPackageFragmentDescriptor && presentsInGeneratedCode(suggested.descriptor)) { - val scope = getScope(suggested.scope) + val scope = getScope(suggested.scope, bindingContext) val name = suggested.names.last() val existing = scope[name] if (existing != null && @@ -91,8 +89,8 @@ class JsNameClashChecker( .mapNotNull { it as? CallableMemberDescriptor } .filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } for (override in fakeOverrides) { - val overrideFqn = nameSuggestion.suggest(override)!! - val scope = getScope(overrideFqn.scope) + val overrideFqn = nameSuggestion.suggest(override, bindingContext)!! + val scope = getScope(overrideFqn.scope, bindingContext) val name = overrideFqn.names.last() val existing = scope[name] as? CallableMemberDescriptor val overrideDescriptor = overrideFqn.descriptor as? CallableMemberDescriptor @@ -131,12 +129,12 @@ class JsNameClashChecker( } } - private fun NameSuggestion.suggestAllPossibleNames(descriptor: DeclarationDescriptor): Collection = + private fun NameSuggestion.suggestAllPossibleNames(descriptor: DeclarationDescriptor, bindingContext: BindingContext): Collection = if (descriptor is CallableMemberDescriptor) { - val primary = suggest(descriptor) + val primary = suggest(descriptor, bindingContext) if (primary != null) { val overriddenNames = descriptor.overriddenDescriptors.flatMap { - suggestAllPossibleNames(it).map { overridden -> + suggestAllPossibleNames(it, bindingContext).map { overridden -> SuggestedName(overridden.names, overridden.stable, primary.descriptor, primary.scope) } } @@ -147,7 +145,7 @@ class JsNameClashChecker( } } else { - listOfNotNull(suggest(descriptor)) + listOfNotNull(suggest(descriptor, bindingContext)) } private fun BindingContext.isCommonDiagnosticReported(declaration: KtDeclaration): Boolean { @@ -165,46 +163,46 @@ class JsNameClashChecker( descriptor.overriddenDescriptors.all { !presentsInGeneratedCode(it) } } - private fun getScope(descriptor: DeclarationDescriptor) = scopes.getOrPut(descriptor) { + private fun getScope(descriptor: DeclarationDescriptor, bindingContext: BindingContext) = scopes.getOrPut(descriptor) { val scope = mutableMapOf() when (descriptor) { is PackageFragmentDescriptor -> { - collect(descriptor.getMemberScope(), scope) + collect(descriptor.getMemberScope(), scope, bindingContext) val module = DescriptorUtils.getContainingModule(descriptor) module.getSubPackagesOf(descriptor.fqName) { true } .flatMap { module.getPackage(it).fragments } - .forEach { collect(it, scope) } + .forEach { collect(it, scope, bindingContext) } } - is ClassDescriptor -> collect(descriptor.defaultType.memberScope, scope) + is ClassDescriptor -> collect(descriptor.defaultType.memberScope, scope, bindingContext) } scope } - private fun collect(scope: MemberScope, target: MutableMap) { + private fun collect(scope: MemberScope, target: MutableMap, bindingContext: BindingContext) { for (descriptor in scope.getContributedDescriptors()) { - collect(descriptor, target) + collect(descriptor, target, bindingContext) } } - private fun collect(descriptor: DeclarationDescriptor, target: MutableMap) { + private fun collect(descriptor: DeclarationDescriptor, target: MutableMap, bindingContext: BindingContext) { if (descriptor is PropertyDescriptor) { if (descriptor.isExtension || AnnotationsUtils.hasJsNameInAccessors(descriptor)) { - descriptor.accessors.forEach { collect(it, target) } + descriptor.accessors.forEach { collect(it, target, bindingContext) } return } } - for (fqn in nameSuggestion.suggestAllPossibleNames(descriptor)) { + for (fqn in nameSuggestion.suggestAllPossibleNames(descriptor, bindingContext)) { if (fqn.stable && presentsInGeneratedCode(fqn.descriptor)) { target[fqn.names.last()] = fqn.descriptor - (fqn.descriptor as? CallableMemberDescriptor)?.let { checkOverrideClashes(it, target) } + (fqn.descriptor as? CallableMemberDescriptor)?.let { checkOverrideClashes(it, target, bindingContext) } } } } - private fun checkOverrideClashes(descriptor: CallableMemberDescriptor, target: MutableMap) { + private fun checkOverrideClashes(descriptor: CallableMemberDescriptor, target: MutableMap, bindingContext: BindingContext) { for (overriddenDescriptor in DescriptorUtils.getAllOverriddenDeclarations(descriptor)) { - val overriddenFqn = nameSuggestion.suggest(overriddenDescriptor)!! + val overriddenFqn = nameSuggestion.suggest(overriddenDescriptor, bindingContext)!! if (overriddenFqn.stable) { val existing = target[overriddenFqn.names.last()] if (existing != null) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt index 66deb7a5466..d1c7b32b608 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt @@ -46,7 +46,7 @@ internal class DeclarationExporter(val context: StaticContext) { if (isNativeObject(descriptor) || isLibraryObject(descriptor)) return if (descriptor.isEffectivelyInlineOnly()) return - val suggestedName = context.nameSuggestion.suggest(descriptor) ?: return + val suggestedName = context.nameSuggestion.suggest(descriptor, context.bindingContext) ?: return val container = suggestedName.scope if (!descriptor.shouldBeExported(force)) return 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 020a5e0cb92..9820d835e06 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 @@ -151,7 +151,7 @@ public final class Namer { qualifier = fqNameParent.asString(); } - SuggestedName suggestedName = new NameSuggestion(bindingContext).suggest(functionDescriptor); + SuggestedName suggestedName = new NameSuggestion().suggest(functionDescriptor, bindingContext); assert suggestedName != null : "Suggested name can be null only for module descriptors: " + functionDescriptor; String mangledName = suggestedName.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 41fc0e87dd3..4f6d47d3edc 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 @@ -169,7 +169,7 @@ public final class StaticContext { fragment = new JsProgramFragment(rootFunction.getScope(), packageFqn); this.bindingTrace = bindingTrace; - this.nameSuggestion = new NameSuggestion(bindingTrace.getBindingContext()); + this.nameSuggestion = new NameSuggestion(); this.namer = Namer.newInstance(program.getRootScope()); this.intrinsics = new Intrinsics(); this.rootScope = fragment.getScope(); @@ -271,7 +271,7 @@ public final class StaticContext { @Nullable public SuggestedName suggestName(@NotNull DeclarationDescriptor descriptor) { - return nameSuggestion.suggest(descriptor); + return nameSuggestion.suggest(descriptor, getBindingContext()); } @NotNull @@ -368,7 +368,7 @@ public final class StaticContext { MetadataProperties.setDescriptor(result, descriptor); return result; } - SuggestedName suggested = nameSuggestion.suggest(descriptor); + SuggestedName suggested = nameSuggestion.suggest(descriptor, getBindingContext()); if (suggested == null) { throw new IllegalArgumentException("Can't generate name for root declarations: " + descriptor); } @@ -380,7 +380,7 @@ public final class StaticContext { JsName name = backingFieldNameCache.get(property); if (name == null) { - SuggestedName fqn = nameSuggestion.suggest(property); + SuggestedName fqn = nameSuggestion.suggest(property, getBindingContext()); assert fqn != null : "Properties are non-root declarations: " + property; assert fqn.getNames().size() == 1 : "Private names must always consist of exactly one name"; @@ -741,7 +741,7 @@ public final class StaticContext { @NotNull private String getPlainId(@NotNull DeclarationDescriptor declaration) { - SuggestedName suggestedName = nameSuggestion.suggest(declaration); + SuggestedName suggestedName = nameSuggestion.suggest(declaration, getBindingContext()); assert suggestedName != null : "Declaration should not be ModuleDescriptor, therefore suggestedName should be non-null"; return suggestedName.getNames().get(0); } 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 6fe041d5b05..0e7ab25d584 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 @@ -177,7 +177,7 @@ class UsageTracker( // Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes else -> { - val mangled = NameSuggestion.sanitizeName(NameSuggestion(bindingContext).suggest(this)!!.names.last()) + val mangled = NameSuggestion.sanitizeName(NameSuggestion().suggest(this, bindingContext)!!.names.last()) "closure\$$mangled" } }