ModuleDescriptor: invert "friends" relation
Fixes memory leak caused by modules storing their friends (which can be potentially recreated many times)
This commit is contained in:
@@ -169,37 +169,33 @@ abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
|
||||
fun computeDependencyDescriptors(module: M): List<ModuleDescriptorImpl> {
|
||||
val orderedDependencies = firstDependency.singletonOrEmptyList() + module.dependencies()
|
||||
val dependenciesDescriptors = orderedDependencies.mapTo(ArrayList<ModuleDescriptorImpl>()) {
|
||||
dependencyInfo ->
|
||||
resolverForProject.descriptorForModule(dependencyInfo as M)
|
||||
}
|
||||
dependencyInfo ->
|
||||
resolverForProject.descriptorForModule(dependencyInfo as M)
|
||||
}
|
||||
module.dependencyOnBuiltIns().adjustDependencies(
|
||||
resolverForProject.descriptorForModule(module).builtIns.builtInsModule, dependenciesDescriptors)
|
||||
return dependenciesDescriptors
|
||||
}
|
||||
|
||||
fun computeModulesWhoseInternalsAreVisible(module: M): Set<ModuleDescriptorImpl> {
|
||||
return module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) { resolverForProject.descriptorForModule(it as M) }
|
||||
}
|
||||
|
||||
fun setupModuleDependencies() {
|
||||
modules.forEach {
|
||||
module ->
|
||||
resolverForProject.descriptorForModule(module).setDependencies(
|
||||
LazyModuleDependencies(storageManager) { computeDependencyDescriptors(module) }
|
||||
LazyModuleDependencies(
|
||||
storageManager,
|
||||
{ computeDependencyDescriptors(module) },
|
||||
{ computeModulesWhoseInternalsAreVisible(module) }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
setupModuleDependencies()
|
||||
|
||||
fun addFriends() {
|
||||
modules.forEach {
|
||||
module ->
|
||||
val descriptor = resolverForProject.descriptorForModule(module)
|
||||
module.modulesWhoseInternalsAreVisible().forEach {
|
||||
resolverForProject.descriptorForModule(it as M).addFriend(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addFriends()
|
||||
|
||||
fun initializeResolverForProject() {
|
||||
modules.forEach {
|
||||
module ->
|
||||
|
||||
@@ -28,7 +28,7 @@ interface ModuleDescriptor : DeclarationDescriptor, ModuleParameters {
|
||||
|
||||
val builtIns: KotlinBuiltIns
|
||||
|
||||
fun isFriend(other: ModuleDescriptor): Boolean
|
||||
fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean
|
||||
|
||||
override fun substitute(substitutor: TypeSubstitutor): ModuleDescriptor {
|
||||
return this
|
||||
|
||||
@@ -207,7 +207,7 @@ public class Visibilities {
|
||||
@Override
|
||||
public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
|
||||
DeclarationDescriptor fromOrModule = from instanceof PackageViewDescriptor ? ((PackageViewDescriptor) from).getModule() : from;
|
||||
if (!DescriptorUtils.getContainingModule(what).isFriend(DescriptorUtils.getContainingModule(fromOrModule))) return false;
|
||||
if (!DescriptorUtils.getContainingModule(fromOrModule).shouldSeeInternalsOf(DescriptorUtils.getContainingModule(what))) return false;
|
||||
|
||||
return MODULE_VISIBILITY_HELPER.isInFriendModule(what, from);
|
||||
}
|
||||
|
||||
+19
-18
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import java.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
moduleName: Name,
|
||||
@@ -56,8 +56,8 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
|
||||
private val packageFragmentProviderForWholeModuleWithDependencies by lazy {
|
||||
val moduleDependencies = dependencies.sure { "Dependencies of module $id were not set before querying module content" }
|
||||
val dependenciesDescriptors = moduleDependencies.descriptors
|
||||
assert(this in dependenciesDescriptors) { "Module ${id} is not contained in his own dependencies, this is probably a misconfiguration" }
|
||||
val dependenciesDescriptors = moduleDependencies.allDependencies
|
||||
assert(this in dependenciesDescriptors) { "Module $id is not contained in his own dependencies, this is probably a misconfiguration" }
|
||||
dependenciesDescriptors.forEach {
|
||||
dependency ->
|
||||
assert(dependency.isInitialized) {
|
||||
@@ -82,7 +82,11 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun setDependencies(descriptors: List<ModuleDescriptorImpl>) {
|
||||
setDependencies(ModuleDependenciesImpl(descriptors))
|
||||
setDependencies(ModuleDependenciesImpl(descriptors, emptySet()))
|
||||
}
|
||||
|
||||
override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean {
|
||||
return this == targetModule || targetModule in dependencies!!.modulesWhoseInternalsAreVisible
|
||||
}
|
||||
|
||||
private val id: String
|
||||
@@ -99,31 +103,28 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
val packageFragmentProvider: PackageFragmentProvider
|
||||
get() = packageFragmentProviderForWholeModuleWithDependencies
|
||||
|
||||
private val friendModules = LinkedHashSet<ModuleDescriptor>()
|
||||
|
||||
override fun isFriend(other: ModuleDescriptor) = other == this || other in friendModules
|
||||
|
||||
fun addFriend(friend: ModuleDescriptorImpl): Unit {
|
||||
assert(friend != this) { "Attempt to make module $id a friend to itself" }
|
||||
friendModules.add(friend)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T> getCapability(capability: ModuleDescriptor.Capability<T>) = capabilities[capability] as? T
|
||||
}
|
||||
|
||||
interface ModuleDependencies {
|
||||
val descriptors: List<ModuleDescriptorImpl>
|
||||
val allDependencies: List<ModuleDescriptorImpl>
|
||||
val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
|
||||
}
|
||||
|
||||
class ModuleDependenciesImpl(override val descriptors: List<ModuleDescriptorImpl>) : ModuleDependencies
|
||||
class ModuleDependenciesImpl(
|
||||
override val allDependencies: List<ModuleDescriptorImpl>,
|
||||
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
|
||||
) : ModuleDependencies
|
||||
|
||||
class LazyModuleDependencies(
|
||||
storageManager: StorageManager,
|
||||
computeDependencies: () -> List<ModuleDescriptorImpl>
|
||||
computeDependencies: () -> List<ModuleDescriptorImpl>,
|
||||
computeModulesWhoseInternalsAreVisible: () -> Set<ModuleDescriptorImpl>
|
||||
) : ModuleDependencies {
|
||||
private val dependencies = storageManager.createLazyValue(computeDependencies)
|
||||
private val visibleInternals = storageManager.createLazyValue(computeModulesWhoseInternalsAreVisible)
|
||||
|
||||
override val descriptors: List<ModuleDescriptorImpl>
|
||||
get() = dependencies()
|
||||
override val allDependencies: List<ModuleDescriptorImpl> get() = dependencies()
|
||||
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl> get() = visibleInternals()
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public class ErrorUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFriend(@NotNull ModuleDescriptor other) {
|
||||
public boolean shouldSeeInternalsOf(@NotNull ModuleDescriptor targetModule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user