[JS] Remove binding context from NameSuggestion instance

Pass bindingContext to suggest method instead.
Revert creating multiple instances of NameSuggestion in checkers.
This commit is contained in:
Svyatoslav Kuzmich
2020-05-22 13:37:04 +03:00
parent 104352b313
commit c9adf22697
9 changed files with 46 additions and 46 deletions
@@ -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 * A new instance of this class can be created for each request, however, it's recommended to use stable instance, since
* [NameSuggestion] supports caching. * [NameSuggestion] supports caching.
*/ */
class NameSuggestion(val bindingContext: BindingContext) { class NameSuggestion {
private val cache: MutableMap<DeclarationDescriptor, SuggestedName?> = Collections.synchronizedMap(WeakHashMap()) private val cache: MutableMap<DeclarationDescriptor, SuggestedName?> = 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 * list consists of exactly one string for any declaration except for package. Package name lists
* have at least one string. * 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? { private fun generate(descriptor: DeclarationDescriptor, bindingContext: BindingContext): SuggestedName? {
// Members of companion objects of classes are treated as static members of these classes 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)) { if (isNativeObject(descriptor) && isCompanionObject(descriptor)) {
return suggest(descriptor.containingDeclaration!!) return suggest(descriptor.containingDeclaration!!, bindingContext)
} }
if (descriptor is FunctionDescriptor && descriptor.isSuspend) { 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 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, // 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. // and use container of topmost function, i.e.
@@ -180,7 +183,7 @@ class NameSuggestion(val bindingContext: BindingContext) {
getSuggestedName(fixedDescriptor) getSuggestedName(fixedDescriptor)
} }
if (current.containingDeclaration is FunctionDescriptor && current !is TypeParameterDescriptor) { 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() parts += outerFunctionName.names.single()
current = outerFunctionName.scope current = outerFunctionName.scope
} }
@@ -48,6 +48,7 @@ object JsPlatformConfigurator : PlatformConfiguratorBase(
identifierChecker = JsIdentifierChecker identifierChecker = JsIdentifierChecker
) { ) {
override fun configureModuleComponents(container: StorageComponentContainer) { override fun configureModuleComponents(container: StorageComponentContainer) {
container.useInstance(NameSuggestion())
container.useImpl<JsCallChecker>() container.useImpl<JsCallChecker>()
container.useImpl<JsTypeSpecificityComparator>() container.useImpl<JsTypeSpecificityComparator>()
container.useImpl<JsNameClashChecker>() container.useImpl<JsNameClashChecker>()
@@ -22,16 +22,15 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.js.naming.NameSuggestion import org.jetbrains.kotlin.js.naming.NameSuggestion
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.psi.KtDeclaration 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.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) { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val nameSuggestion = NameSuggestion(context.trace.bindingContext)
if (AnnotationsUtils.isNativeObject(descriptor)) return if (AnnotationsUtils.isNativeObject(descriptor)) return
if (descriptor.containingDeclaration !is ClassDescriptor) return if (descriptor.containingDeclaration !is ClassDescriptor) return
val suggestedName = nameSuggestion.suggest(descriptor)!! val suggestedName = nameSuggestion.suggest(descriptor, context.trace.bindingContext)!!
if (!suggestedName.stable) return if (!suggestedName.stable) return
val simpleName = suggestedName.names.single() val simpleName = suggestedName.names.single()
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext 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) { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val bindingContext = context.trace.bindingContext val bindingContext = context.trace.bindingContext
@@ -27,8 +27,7 @@ class JsNameCharsChecker : DeclarationChecker {
AnnotationsUtils.isExportedObject(descriptor, bindingContext) AnnotationsUtils.isExportedObject(descriptor, bindingContext)
) return ) return
val suggestion = NameSuggestion(bindingContext) val suggestedName = suggestion.suggest(descriptor, bindingContext) ?: return
val suggestedName = suggestion.suggest(descriptor) ?: return
if (suggestedName.stable && suggestedName.names.any { NameSuggestion.sanitizeName(it) != it }) { if (suggestedName.stable && suggestedName.names.any { NameSuggestion.sanitizeName(it) != it }) {
context.trace.report(ErrorsJs.NAME_CONTAINS_ILLEGAL_CHARS.on(declaration)) context.trace.report(ErrorsJs.NAME_CONTAINS_ILLEGAL_CHARS.on(declaration))
} }
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
class JsNameClashChecker( class JsNameClashChecker(
private val nameSuggestion: NameSuggestion,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings
) : DeclarationChecker { ) : DeclarationChecker {
companion object { companion object {
@@ -44,7 +45,6 @@ class JsNameClashChecker(
Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION) Errors.PACKAGE_OR_CLASSIFIER_REDECLARATION)
} }
lateinit var nameSuggestion: NameSuggestion
private val scopes = mutableMapOf<DeclarationDescriptor, MutableMap<String, DeclarationDescriptor>>() private val scopes = mutableMapOf<DeclarationDescriptor, MutableMap<String, DeclarationDescriptor>>()
private val clashedFakeOverrides = mutableMapOf<DeclarationDescriptor, Pair<DeclarationDescriptor, DeclarationDescriptor>>() private val clashedFakeOverrides = mutableMapOf<DeclarationDescriptor, Pair<DeclarationDescriptor, DeclarationDescriptor>>()
private val clashedDescriptors = mutableSetOf<Pair<DeclarationDescriptor, String>>() private val clashedDescriptors = mutableSetOf<Pair<DeclarationDescriptor, String>>()
@@ -62,12 +62,10 @@ class JsNameClashChecker(
diagnosticHolder: DiagnosticSink, bindingContext: BindingContext diagnosticHolder: DiagnosticSink, bindingContext: BindingContext
) { ) {
if (descriptor is ConstructorDescriptor && descriptor.isPrimary) return 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)) { 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 name = suggested.names.last()
val existing = scope[name] val existing = scope[name]
if (existing != null && if (existing != null &&
@@ -91,8 +89,8 @@ class JsNameClashChecker(
.mapNotNull { it as? CallableMemberDescriptor } .mapNotNull { it as? CallableMemberDescriptor }
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } .filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
for (override in fakeOverrides) { for (override in fakeOverrides) {
val overrideFqn = nameSuggestion.suggest(override)!! val overrideFqn = nameSuggestion.suggest(override, bindingContext)!!
val scope = getScope(overrideFqn.scope) val scope = getScope(overrideFqn.scope, bindingContext)
val name = overrideFqn.names.last() val name = overrideFqn.names.last()
val existing = scope[name] as? CallableMemberDescriptor val existing = scope[name] as? CallableMemberDescriptor
val overrideDescriptor = overrideFqn.descriptor as? CallableMemberDescriptor val overrideDescriptor = overrideFqn.descriptor as? CallableMemberDescriptor
@@ -131,12 +129,12 @@ class JsNameClashChecker(
} }
} }
private fun NameSuggestion.suggestAllPossibleNames(descriptor: DeclarationDescriptor): Collection<SuggestedName> = private fun NameSuggestion.suggestAllPossibleNames(descriptor: DeclarationDescriptor, bindingContext: BindingContext): Collection<SuggestedName> =
if (descriptor is CallableMemberDescriptor) { if (descriptor is CallableMemberDescriptor) {
val primary = suggest(descriptor) val primary = suggest(descriptor, bindingContext)
if (primary != null) { if (primary != null) {
val overriddenNames = descriptor.overriddenDescriptors.flatMap { val overriddenNames = descriptor.overriddenDescriptors.flatMap {
suggestAllPossibleNames(it).map { overridden -> suggestAllPossibleNames(it, bindingContext).map { overridden ->
SuggestedName(overridden.names, overridden.stable, primary.descriptor, primary.scope) SuggestedName(overridden.names, overridden.stable, primary.descriptor, primary.scope)
} }
} }
@@ -147,7 +145,7 @@ class JsNameClashChecker(
} }
} }
else { else {
listOfNotNull(suggest(descriptor)) listOfNotNull(suggest(descriptor, bindingContext))
} }
private fun BindingContext.isCommonDiagnosticReported(declaration: KtDeclaration): Boolean { private fun BindingContext.isCommonDiagnosticReported(declaration: KtDeclaration): Boolean {
@@ -165,46 +163,46 @@ class JsNameClashChecker(
descriptor.overriddenDescriptors.all { !presentsInGeneratedCode(it) } 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<String, DeclarationDescriptor>() val scope = mutableMapOf<String, DeclarationDescriptor>()
when (descriptor) { when (descriptor) {
is PackageFragmentDescriptor -> { is PackageFragmentDescriptor -> {
collect(descriptor.getMemberScope(), scope) collect(descriptor.getMemberScope(), scope, bindingContext)
val module = DescriptorUtils.getContainingModule(descriptor) val module = DescriptorUtils.getContainingModule(descriptor)
module.getSubPackagesOf(descriptor.fqName) { true } module.getSubPackagesOf(descriptor.fqName) { true }
.flatMap { module.getPackage(it).fragments } .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 scope
} }
private fun collect(scope: MemberScope, target: MutableMap<String, DeclarationDescriptor>) { private fun collect(scope: MemberScope, target: MutableMap<String, DeclarationDescriptor>, bindingContext: BindingContext) {
for (descriptor in scope.getContributedDescriptors()) { for (descriptor in scope.getContributedDescriptors()) {
collect(descriptor, target) collect(descriptor, target, bindingContext)
} }
} }
private fun collect(descriptor: DeclarationDescriptor, target: MutableMap<String, DeclarationDescriptor>) { private fun collect(descriptor: DeclarationDescriptor, target: MutableMap<String, DeclarationDescriptor>, bindingContext: BindingContext) {
if (descriptor is PropertyDescriptor) { if (descriptor is PropertyDescriptor) {
if (descriptor.isExtension || AnnotationsUtils.hasJsNameInAccessors(descriptor)) { if (descriptor.isExtension || AnnotationsUtils.hasJsNameInAccessors(descriptor)) {
descriptor.accessors.forEach { collect(it, target) } descriptor.accessors.forEach { collect(it, target, bindingContext) }
return return
} }
} }
for (fqn in nameSuggestion.suggestAllPossibleNames(descriptor)) { for (fqn in nameSuggestion.suggestAllPossibleNames(descriptor, bindingContext)) {
if (fqn.stable && presentsInGeneratedCode(fqn.descriptor)) { if (fqn.stable && presentsInGeneratedCode(fqn.descriptor)) {
target[fqn.names.last()] = 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<String, DeclarationDescriptor>) { private fun checkOverrideClashes(descriptor: CallableMemberDescriptor, target: MutableMap<String, DeclarationDescriptor>, bindingContext: BindingContext) {
for (overriddenDescriptor in DescriptorUtils.getAllOverriddenDeclarations(descriptor)) { for (overriddenDescriptor in DescriptorUtils.getAllOverriddenDeclarations(descriptor)) {
val overriddenFqn = nameSuggestion.suggest(overriddenDescriptor)!! val overriddenFqn = nameSuggestion.suggest(overriddenDescriptor, bindingContext)!!
if (overriddenFqn.stable) { if (overriddenFqn.stable) {
val existing = target[overriddenFqn.names.last()] val existing = target[overriddenFqn.names.last()]
if (existing != null) { if (existing != null) {
@@ -46,7 +46,7 @@ internal class DeclarationExporter(val context: StaticContext) {
if (isNativeObject(descriptor) || isLibraryObject(descriptor)) return if (isNativeObject(descriptor) || isLibraryObject(descriptor)) return
if (descriptor.isEffectivelyInlineOnly()) 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 val container = suggestedName.scope
if (!descriptor.shouldBeExported(force)) return if (!descriptor.shouldBeExported(force)) return
@@ -151,7 +151,7 @@ public final class Namer {
qualifier = fqNameParent.asString(); 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; assert suggestedName != null : "Suggested name can be null only for module descriptors: " + functionDescriptor;
String mangledName = suggestedName.getNames().get(0); String mangledName = suggestedName.getNames().get(0);
return StringUtil.join(Arrays.asList(moduleName, qualifier, mangledName), "."); return StringUtil.join(Arrays.asList(moduleName, qualifier, mangledName), ".");
@@ -169,7 +169,7 @@ public final class StaticContext {
fragment = new JsProgramFragment(rootFunction.getScope(), packageFqn); fragment = new JsProgramFragment(rootFunction.getScope(), packageFqn);
this.bindingTrace = bindingTrace; this.bindingTrace = bindingTrace;
this.nameSuggestion = new NameSuggestion(bindingTrace.getBindingContext()); this.nameSuggestion = new NameSuggestion();
this.namer = Namer.newInstance(program.getRootScope()); this.namer = Namer.newInstance(program.getRootScope());
this.intrinsics = new Intrinsics(); this.intrinsics = new Intrinsics();
this.rootScope = fragment.getScope(); this.rootScope = fragment.getScope();
@@ -271,7 +271,7 @@ public final class StaticContext {
@Nullable @Nullable
public SuggestedName suggestName(@NotNull DeclarationDescriptor descriptor) { public SuggestedName suggestName(@NotNull DeclarationDescriptor descriptor) {
return nameSuggestion.suggest(descriptor); return nameSuggestion.suggest(descriptor, getBindingContext());
} }
@NotNull @NotNull
@@ -368,7 +368,7 @@ public final class StaticContext {
MetadataProperties.setDescriptor(result, descriptor); MetadataProperties.setDescriptor(result, descriptor);
return result; return result;
} }
SuggestedName suggested = nameSuggestion.suggest(descriptor); SuggestedName suggested = nameSuggestion.suggest(descriptor, getBindingContext());
if (suggested == null) { if (suggested == null) {
throw new IllegalArgumentException("Can't generate name for root declarations: " + descriptor); throw new IllegalArgumentException("Can't generate name for root declarations: " + descriptor);
} }
@@ -380,7 +380,7 @@ public final class StaticContext {
JsName name = backingFieldNameCache.get(property); JsName name = backingFieldNameCache.get(property);
if (name == null) { 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 != null : "Properties are non-root declarations: " + property;
assert fqn.getNames().size() == 1 : "Private names must always consist of exactly one name"; assert fqn.getNames().size() == 1 : "Private names must always consist of exactly one name";
@@ -741,7 +741,7 @@ public final class StaticContext {
@NotNull @NotNull
private String getPlainId(@NotNull DeclarationDescriptor declaration) { 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"; assert suggestedName != null : "Declaration should not be ModuleDescriptor, therefore suggestedName should be non-null";
return suggestedName.getNames().get(0); return suggestedName.getNames().get(0);
} }
@@ -177,7 +177,7 @@ class UsageTracker(
// Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes // Append 'closure$' prefix to avoid name clash between closure and member fields in case of local classes
else -> { else -> {
val mangled = NameSuggestion.sanitizeName(NameSuggestion(bindingContext).suggest(this)!!.names.last()) val mangled = NameSuggestion.sanitizeName(NameSuggestion().suggest(this, bindingContext)!!.names.last())
"closure\$$mangled" "closure\$$mangled"
} }
} }