Implement ModuleSourceInfo.getDependentModules()
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.plugin.caches.resolve
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.ModuleOrderEntry
|
||||
import gnu.trove.THashSet
|
||||
import com.intellij.util.containers.Queue
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||
import java.util.HashSet
|
||||
|
||||
//NOTE: this is an approximation that may contain more module infos then the exact solution
|
||||
public fun ModuleSourceInfo.getDependentModules(): Set<ModuleSourceInfo> {
|
||||
val dependents = getDependents(module)
|
||||
if (isTests()) {
|
||||
return dependents.mapTo(HashSet<ModuleSourceInfo>()) { it.testSourceInfo() }
|
||||
}
|
||||
else {
|
||||
return dependents.flatMapTo(HashSet<ModuleSourceInfo>()) { listOf(it.productionSourceInfo(), it.testSourceInfo()) }
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: getDependents adapted from com.intellij.openapi.module.impl.scopes.ModuleWithDependentsScope#buildDependents()
|
||||
private fun getDependents(module: Module): Set<Module> {
|
||||
val result = THashSet<Module>()
|
||||
result.add(module)
|
||||
|
||||
val processedExporting = THashSet<Module>()
|
||||
|
||||
val index = getModuleIndex(module.getProject())
|
||||
|
||||
val walkingQueue = Queue<Module>(10)
|
||||
walkingQueue.addLast(module)
|
||||
|
||||
while (!walkingQueue.isEmpty()) {
|
||||
val current = walkingQueue.pullFirst()
|
||||
processedExporting.add(current!!)
|
||||
result.addAll(index.plainUsages[current])
|
||||
for (dependent in index.exportingUsages[current]) {
|
||||
result.add(dependent)
|
||||
if (processedExporting.add(dependent)) {
|
||||
walkingQueue.addLast(dependent)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private class ModuleIndex {
|
||||
val plainUsages = MultiMap.create<Module, Module>()
|
||||
val exportingUsages = MultiMap.create<Module, Module>()
|
||||
}
|
||||
|
||||
private fun getModuleIndex(project: Project): ModuleIndex {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(project) {
|
||||
val index = ModuleIndex()
|
||||
for (module in ModuleManager.getInstance(project).getModules()) {
|
||||
for (orderEntry in ModuleRootManager.getInstance(module).getOrderEntries()) {
|
||||
if (orderEntry is ModuleOrderEntry) {
|
||||
val referenced = orderEntry.getModule()
|
||||
if (referenced != null) {
|
||||
val map = if (orderEntry.isExported()) index.exportingUsages else index.plainUsages
|
||||
map.putValue(referenced, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CachedValueProvider.Result(index, ProjectRootModificationTracker.getInstance(project))
|
||||
}!!
|
||||
}
|
||||
@@ -21,10 +21,11 @@ import com.intellij.openapi.module.StdModuleTypes
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import junit.framework.Assert
|
||||
import org.junit.Assert
|
||||
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
|
||||
class IdeaModuleInfoTest : ModuleTestCase() {
|
||||
|
||||
@@ -182,6 +183,43 @@ class IdeaModuleInfoTest : ModuleTestCase() {
|
||||
c.test.assertDependenciesEqual(c.test, c.production, b.test, b.production, a.test, a.production)
|
||||
}
|
||||
|
||||
fun testDependents() {
|
||||
//NOTE: we do not differ between dependency kinds
|
||||
val (a, b, c) = modules(name1 = "a", name2 = "b", name3 = "c")
|
||||
val (d, e, f) = modules(name1 = "d", name2 = "e", name3 = "f")
|
||||
|
||||
b.addDependency(a, exported = true)
|
||||
|
||||
c.addDependency(a)
|
||||
|
||||
d.addDependency(c, exported = true)
|
||||
|
||||
e.addDependency(b)
|
||||
|
||||
f.addDependency(d)
|
||||
f.addDependency(e)
|
||||
|
||||
|
||||
a.test.assertDependentsEqual(a.test, b.test, c.test, e.test)
|
||||
a.production.assertDependentsEqual(a.production, a.test, b.production, b.test, c.production, c.test, e.production, e.test)
|
||||
|
||||
b.test.assertDependentsEqual(b.test, e.test)
|
||||
b.production.assertDependentsEqual(b.production, b.test, e.production, e.test)
|
||||
|
||||
|
||||
c.test.assertDependentsEqual(c.test, d.test, f.test)
|
||||
c.production.assertDependentsEqual(c.production, c.test, d.production, d.test, f.production, f.test)
|
||||
|
||||
d.test.assertDependentsEqual(d.test, f.test)
|
||||
d.production.assertDependentsEqual(d.production, d.test, f.production, f.test)
|
||||
|
||||
e.test.assertDependentsEqual(e.test, f.test)
|
||||
e.production.assertDependentsEqual(e.production, e.test, f.production, f.test)
|
||||
|
||||
f.test.assertDependentsEqual(f.test)
|
||||
f.production.assertDependentsEqual(f.production, f.test)
|
||||
}
|
||||
|
||||
private fun Module.addDependency(
|
||||
other: Module,
|
||||
dependencyScope: DependencyScope = DependencyScope.COMPILE,
|
||||
@@ -189,13 +227,13 @@ class IdeaModuleInfoTest : ModuleTestCase() {
|
||||
) = ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported)
|
||||
|
||||
private val Module.production: ModuleProductionSourceInfo
|
||||
get() = productionSourceInfo()
|
||||
get() = productionSourceInfo()
|
||||
|
||||
private val Module.test: ModuleTestSourceInfo
|
||||
get() = testSourceInfo()
|
||||
get() = testSourceInfo()
|
||||
|
||||
private val Library.classes: LibraryInfo
|
||||
get() = LibraryInfo(getProject()!!, this)
|
||||
get() = LibraryInfo(getProject()!!, this)
|
||||
|
||||
private fun Module.addDependency(
|
||||
lib: Library,
|
||||
@@ -213,6 +251,10 @@ class IdeaModuleInfoTest : ModuleTestCase() {
|
||||
Assert.assertEquals(dependencies.toList(), this.dependencies())
|
||||
}
|
||||
|
||||
private fun ModuleSourceInfo.assertDependentsEqual(vararg dependents: ModuleSourceInfo) {
|
||||
UsefulTestCase.assertSameElements(this.getDependentModules(), dependents.toList())
|
||||
}
|
||||
|
||||
private fun projectLibrary(name: String = "lib"): Library {
|
||||
val libraryTable = ProjectLibraryTable.getInstance(myProject)!!
|
||||
return WriteCommandAction.runWriteCommandAction<Library>(myProject) {
|
||||
|
||||
Reference in New Issue
Block a user