Allow to use internal declarations from special modules in IDEA

(e.g. IDEA 16 gradle tests loaded in separate module)

 #KT-10595 Fixed
This commit is contained in:
Zalim Bashorov
2016-02-03 20:40:01 +03:00
parent 5968ce96df
commit 2c1d1e84a6
3 changed files with 53 additions and 10 deletions
@@ -98,7 +98,7 @@ class ResolverForProjectImpl<M : ModuleInfo>(
}
private fun doGetDescriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
return descriptorByModule[moduleInfo] ?: return delegateResolver.descriptorForModule(moduleInfo) as ModuleDescriptorImpl
return descriptorByModule[moduleInfo] ?: delegateResolver.descriptorForModule(moduleInfo) as ModuleDescriptorImpl
}
}
@@ -114,7 +114,7 @@ interface ModuleInfo {
get() = false
val name: Name
fun dependencies(): List<ModuleInfo>
fun friends(): Collection<ModuleInfo> = listOf()
fun modulesWhichInternalsAreVisible(): Collection<ModuleInfo> = listOf()
fun dependencyOnBuiltins(): DependencyOnBuiltins = DependenciesOnBuiltins.LAST
val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
get() = emptyMap()
@@ -193,8 +193,8 @@ abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
modules.forEach {
module ->
val descriptor = resolverForProject.descriptorForModule(module)
module.friends().forEach {
descriptor.addFriend(resolverForProject.descriptorForModule(it as M))
module.modulesWhichInternalsAreVisible().forEach {
resolverForProject.descriptorForModule(it as M).addFriend(descriptor)
}
}
}
@@ -249,4 +249,4 @@ private class DelegatingPackageFragmentProvider(
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> {
return delegate().getSubPackagesOf(fqName, nameFilter)
}
}
}
@@ -25,6 +25,10 @@ private val ALWAYS_TRUE: (Any?) -> Boolean = { true }
fun <T> alwaysTrue(): (T) -> Boolean = ALWAYS_TRUE
private val ALWAYS_NULL: (Any?) -> Any? = { null }
@Suppress("UNCHECKED_CAST")
fun <T, R: Any> alwaysNull(): (T) -> R? = ALWAYS_NULL as (T) -> R?
val DO_NOTHING: (Any?) -> Unit = { }
@@ -26,13 +26,44 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.util.SmartList
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.alwaysNull
import org.jetbrains.kotlin.utils.emptyOrSingletonList
import java.lang.reflect.Method
import java.util.*
val LIBRARY_NAME_PREFIX: String = "library "
private val LIBRARY_NAME_PREFIX: String = "library "
// TODO used reflection to be compatible with IDEA from both 143 and 144 branches,
// TODO switch to directly using when "since-build" will be >= 144.3357.4
private val getRelatedProductionModule: (Module) -> Module? = run {
val klass =
try {
Class.forName("com.intellij.openapi.roots.TestModuleProperties")
} catch (e: ClassNotFoundException) {
return@run alwaysNull()
}
val getInstanceMethod: Method
val getProductionModuleMethod: Method
try {
getInstanceMethod = klass.getDeclaredMethod("getInstance", Module::class.java)
getProductionModuleMethod = klass.getDeclaredMethod("getProductionModule")
}
catch (e: NoSuchMethodException) {
return@run alwaysNull()
}
return@run { module ->
val instance = getInstanceMethod(null, module)
getProductionModuleMethod(instance) as Module?
}
}
interface IdeaModuleInfo : ModuleInfo {
fun contentScope(): GlobalSearchScope
@@ -71,7 +102,7 @@ private fun <T> Module.cached(provider: CachedValueProvider<T>): T {
return CachedValuesManager.getManager(project).getCachedValue(this, provider)
}
fun ideaModelDependencies(module: Module, productionOnly: Boolean): List<IdeaModuleInfo> {
private fun ideaModelDependencies(module: Module, productionOnly: Boolean): List<IdeaModuleInfo> {
//NOTE: lib dependencies can be processed several times during recursive traversal
val result = LinkedHashSet<IdeaModuleInfo>()
val dependencyEnumerator = ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly()
@@ -102,8 +133,6 @@ data class ModuleProductionSourceInfo(override val module: Module) : ModuleSourc
ideaModelDependencies(module, productionOnly = true),
ProjectRootModificationTracker.getInstance(module.project))
})
override fun friends() = listOf(module.testSourceInfo())
}
//TODO: (module refactoring) do not create ModuleTestSourceInfo when there are no test roots for module
@@ -117,6 +146,16 @@ data class ModuleTestSourceInfo(override val module: Module) : ModuleSourceInfo
ideaModelDependencies(module, productionOnly = false),
ProjectRootModificationTracker.getInstance(module.project))
})
override fun modulesWhichInternalsAreVisible() = module.cached(CachedValueProvider {
val list = SmartList<ModuleInfo>(module.productionSourceInfo())
getRelatedProductionModule(module)?.let {
list.add(it.productionSourceInfo())
}
CachedValueProvider.Result(list, ProjectRootModificationTracker.getInstance(module.project))
})
}
internal fun ModuleSourceInfo.isTests() = this is ModuleTestSourceInfo
@@ -249,4 +288,4 @@ enum class ModuleOrigin {
MODULE,
LIBRARY,
OTHER
}
}