KT-2752: refactor generation of FQN in JS. Move backend-independent code to generic code in frontend.
This commit is contained in:
@@ -19,69 +19,74 @@ package org.jetbrains.kotlin.js.naming
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.isEnumValueOfMethod
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
|
||||
class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
private val cache = mutableMapOf<DeclarationDescriptor, List<FQNPart>>()
|
||||
class FQNGenerator {
|
||||
private val cache = mutableMapOf<DeclarationDescriptor, FQNPart>()
|
||||
|
||||
fun generate(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generateCacheMiss(descriptor) }
|
||||
fun generate(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generateCacheMiss(descriptor.original) }
|
||||
|
||||
private fun generateCacheMiss(descriptor: DeclarationDescriptor): List<FQNPart> {
|
||||
for (participant in participants) {
|
||||
val result = participant.participate(descriptor, this)
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
private fun generateCacheMiss(descriptor: DeclarationDescriptor): FQNPart {
|
||||
if (isNativeObject(descriptor) && isCompanionObject(descriptor)) {
|
||||
return generate(descriptor.containingDeclaration!!)
|
||||
}
|
||||
|
||||
when (descriptor) {
|
||||
is ModuleDescriptor -> return listOf(FQNPart(descriptor.name.asString(), FQNPartType.MODULE, descriptor))
|
||||
is ModuleDescriptor -> return FQNPart(listOf(descriptor.name.asString()), true, descriptor, descriptor)
|
||||
is PackageFragmentDescriptor -> {
|
||||
val result = generate(descriptor.containingDeclaration).toMutableList()
|
||||
if (!descriptor.name.isSpecial) {
|
||||
result += descriptor.fqName.pathSegments().map { FQNPart(it.asString(), FQNPartType.PUBLIC, descriptor) }
|
||||
return if (!descriptor.name.isSpecial) {
|
||||
FQNPart(descriptor.fqName.pathSegments().map { it.asString() }, true, descriptor,
|
||||
descriptor.containingDeclaration)
|
||||
}
|
||||
else {
|
||||
generate(descriptor.containingDeclaration)
|
||||
}
|
||||
return result
|
||||
}
|
||||
is ConstructorDescriptor -> if (descriptor.isPrimary) return generate(descriptor.containingDeclaration)
|
||||
is CallableMemberDescriptor ->
|
||||
is FakeCallableDescriptorForObject -> return generate(descriptor.getReferencedDescriptor())
|
||||
is ConstructorDescriptor -> {
|
||||
if (descriptor.isPrimary || isNativeObject(descriptor)) {
|
||||
return generate(descriptor.containingDeclaration)
|
||||
}
|
||||
}
|
||||
is CallableDescriptor ->
|
||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) {
|
||||
val name = getMangledName(getSuggestedName(descriptor), descriptor)
|
||||
return listOf(FQNPart(name, FQNPartType.PRIVATE, descriptor))
|
||||
return FQNPart(listOf(name.first), false, descriptor, descriptor.containingDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
val (localName, shared, parent) = getLocalName(descriptor)
|
||||
val localPart = FQNPart(localName, if (shared) FQNPartType.PUBLIC else FQNPartType.PRIVATE, descriptor)
|
||||
|
||||
val qualifier = if (parent != null) generate(parent) else listOf()
|
||||
return qualifier + localPart
|
||||
return FQNPart(listOf(localName), shared, descriptor, parent)
|
||||
}
|
||||
|
||||
private fun getLocalName(descriptor: DeclarationDescriptor): LocalName {
|
||||
if (descriptor.isDynamic()) {
|
||||
return LocalName(descriptor.name.asString(), true, descriptor.containingDeclaration!!)
|
||||
}
|
||||
|
||||
val parts = mutableListOf<String>()
|
||||
var current: DeclarationDescriptor? = descriptor
|
||||
var current: DeclarationDescriptor = descriptor
|
||||
do {
|
||||
current!!
|
||||
parts += getSuggestedName(current)
|
||||
var last = current
|
||||
current = current.containingDeclaration
|
||||
current = current.containingDeclaration!!
|
||||
if (last is ConstructorDescriptor && !last.isPrimary) {
|
||||
last = current
|
||||
parts[parts.lastIndex] = getSuggestedName(current!!) + "_init"
|
||||
current = current.containingDeclaration
|
||||
parts[parts.lastIndex] = getSuggestedName(current) + "_init"
|
||||
current = current.containingDeclaration!!
|
||||
}
|
||||
} while (current != null && DescriptorUtils.isDescriptorWithLocalVisibility(last) && current !is ClassDescriptor)
|
||||
} while (DescriptorUtils.isDescriptorWithLocalVisibility(last) && current !is ClassDescriptor)
|
||||
|
||||
parts.reverse()
|
||||
return LocalName(getMangledName(parts.joinToString("$"), descriptor), needsStableMangling(descriptor), current)
|
||||
val (id, shared) = getMangledName(parts.joinToString("$"), descriptor)
|
||||
return LocalName(id, shared, current)
|
||||
}
|
||||
|
||||
private data class LocalName(val id: String, val shared: Boolean, val parent: DeclarationDescriptor?)
|
||||
private data class LocalName(val id: String, val shared: Boolean, val parent: DeclarationDescriptor)
|
||||
|
||||
private fun getSuggestedName(descriptor: DeclarationDescriptor): String {
|
||||
val name = descriptor.name
|
||||
@@ -97,17 +102,49 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMangledName(baseName: String, descriptor: DeclarationDescriptor): String {
|
||||
if (needsStableMangling(descriptor)) {
|
||||
return if (descriptor is CallableMemberDescriptor) {
|
||||
getStableMangledName(baseName, getArgumentTypesAsString(descriptor))
|
||||
private fun getMangledName(baseName: String, descriptor: DeclarationDescriptor): Pair<String, Boolean> {
|
||||
if (descriptor !is CallableDescriptor) {
|
||||
if (isNativeObject(descriptor) || isLibraryObject(descriptor)) {
|
||||
return Pair(getNameForAnnotatedObjectWithOverrides(descriptor) ?: descriptor.name.asString(), true)
|
||||
}
|
||||
else {
|
||||
baseName
|
||||
return Pair(baseName, needsStableMangling(descriptor))
|
||||
}
|
||||
|
||||
var resolvedDescriptor: CallableDescriptor = descriptor
|
||||
var overriddenDescriptor: CallableDescriptor? = descriptor
|
||||
while (overriddenDescriptor != null) {
|
||||
resolvedDescriptor = overriddenDescriptor
|
||||
if (isNativeObject(resolvedDescriptor) || isLibraryObject(resolvedDescriptor)) {
|
||||
val explicitName = getNameForAnnotatedObjectWithOverrides(resolvedDescriptor)
|
||||
if (explicitName != null) {
|
||||
return Pair(explicitName, true)
|
||||
}
|
||||
}
|
||||
overriddenDescriptor = getOverriddenDescriptor(overriddenDescriptor)?.original
|
||||
}
|
||||
|
||||
when {
|
||||
isNativeObject(resolvedDescriptor) || isLibraryObject(resolvedDescriptor) -> {
|
||||
return Pair(getNameForAnnotatedObjectWithOverrides(resolvedDescriptor) ?: resolvedDescriptor.name.asString(), true)
|
||||
}
|
||||
}
|
||||
|
||||
return baseName
|
||||
return if (needsStableMangling(resolvedDescriptor)) {
|
||||
Pair(getStableMangledName(baseName, getArgumentTypesAsString(resolvedDescriptor)), true)
|
||||
}
|
||||
else {
|
||||
Pair(baseName, false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOverriddenDescriptor(functionDescriptor: CallableDescriptor): CallableDescriptor? {
|
||||
val overriddenDescriptors = functionDescriptor.overriddenDescriptors
|
||||
if (overriddenDescriptors.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
//TODO: for now translator can't deal with multiple inheritance good enough
|
||||
return overriddenDescriptors.iterator().next()
|
||||
}
|
||||
|
||||
private fun getArgumentTypesAsString(descriptor: CallableDescriptor): String {
|
||||
@@ -130,6 +167,7 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
}
|
||||
|
||||
private fun needsStableMangling(descriptor: DeclarationDescriptor): Boolean {
|
||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) return false
|
||||
if (descriptor is ClassOrPackageFragmentDescriptor) return true
|
||||
if (descriptor !is CallableMemberDescriptor) return false
|
||||
|
||||
@@ -138,12 +176,12 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
if (DescriptorUtils.isOverride(descriptor)) return true
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
if (isNativeObject(containingDeclaration) || isLibraryObject(containingDeclaration)) return true
|
||||
|
||||
return when (containingDeclaration) {
|
||||
is PackageFragmentDescriptor -> descriptor.visibility.isPublicAPI
|
||||
is ClassDescriptor -> {
|
||||
// Use stable mangling when it's inside an overridable declaration to avoid clashing names on inheritance.
|
||||
if (!containingDeclaration.isFinalOrEnum) return true
|
||||
if (descriptor.modality == Modality.OPEN || descriptor.modality == Modality.ABSTRACT) return true
|
||||
|
||||
// valueOf() is created in the library with a mangled name for every enum class
|
||||
if (descriptor is FunctionDescriptor && descriptor.isEnumValueOfMethod()) return true
|
||||
@@ -166,34 +204,4 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object NativeParticipant : FQNPartipcipant {
|
||||
override fun participate(descriptor: DeclarationDescriptor, generator: FQNGenerator): List<FQNPart>? {
|
||||
return when {
|
||||
isNativeObject(descriptor) && isCompanionObject(descriptor) -> {
|
||||
generator.generate(descriptor.containingDeclaration!!)
|
||||
}
|
||||
descriptor is PropertyAccessorDescriptor && isNativeObject(descriptor.correspondingProperty) -> {
|
||||
generator.generate(descriptor.correspondingProperty)
|
||||
}
|
||||
isNativeObject(descriptor) || isLibraryObject(descriptor) -> {
|
||||
if (descriptor is ConstructorDescriptor) {
|
||||
generator.generate(descriptor.containingDeclaration)
|
||||
}
|
||||
else {
|
||||
val name = AnnotationsUtils.getNameForAnnotatedObjectWithOverrides(descriptor)
|
||||
val qualifier = when {
|
||||
descriptor is CallableDescriptor && DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) -> listOf()
|
||||
descriptor is ClassDescriptor && descriptor.containingDeclaration is PackageFragmentDescriptor -> listOf()
|
||||
descriptor is ClassDescriptor && isNativeObject(descriptor) &&
|
||||
!isNativeObject(descriptor.containingDeclaration) -> listOf()
|
||||
else -> generator.generate(descriptor.containingDeclaration!!)
|
||||
}
|
||||
qualifier + listOf(FQNPart(name ?: descriptor.name.asString(), FQNPartType.PUBLIC, descriptor))
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@ package org.jetbrains.kotlin.js.naming
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
|
||||
data class FQNPart(val name: String, val type: FQNPartType, val descriptor: DeclarationDescriptor)
|
||||
class FQNPart(val names: List<String>, val shared: Boolean, val descriptor: DeclarationDescriptor, val scope: DeclarationDescriptor)
|
||||
|
||||
@@ -1,23 +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.naming
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
|
||||
interface FQNPartipcipant {
|
||||
fun participate(descriptor: DeclarationDescriptor, generator: FQNGenerator): List<FQNPart>?
|
||||
}
|
||||
Reference in New Issue
Block a user