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 { 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 get() = false
val name: Name val name: Name
fun dependencies(): List<ModuleInfo> fun dependencies(): List<ModuleInfo>
fun friends(): Collection<ModuleInfo> = listOf() fun modulesWhichInternalsAreVisible(): Collection<ModuleInfo> = listOf()
fun dependencyOnBuiltins(): DependencyOnBuiltins = DependenciesOnBuiltins.LAST fun dependencyOnBuiltins(): DependencyOnBuiltins = DependenciesOnBuiltins.LAST
val capabilities: Map<ModuleDescriptor.Capability<*>, Any?> val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
get() = emptyMap() get() = emptyMap()
@@ -193,8 +193,8 @@ abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
modules.forEach { modules.forEach {
module -> module ->
val descriptor = resolverForProject.descriptorForModule(module) val descriptor = resolverForProject.descriptorForModule(module)
module.friends().forEach { module.modulesWhichInternalsAreVisible().forEach {
descriptor.addFriend(resolverForProject.descriptorForModule(it as M)) resolverForProject.descriptorForModule(it as M).addFriend(descriptor)
} }
} }
} }
@@ -249,4 +249,4 @@ private class DelegatingPackageFragmentProvider(
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> { override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> {
return delegate().getSubPackagesOf(fqName, nameFilter) return delegate().getSubPackagesOf(fqName, nameFilter)
} }
} }
@@ -25,6 +25,10 @@ private val ALWAYS_TRUE: (Any?) -> Boolean = { true }
fun <T> alwaysTrue(): (T) -> Boolean = ALWAYS_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 = { } 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.search.GlobalSearchScope
import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.CachedValuesManager
import com.intellij.util.SmartList
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.alwaysNull
import org.jetbrains.kotlin.utils.emptyOrSingletonList import org.jetbrains.kotlin.utils.emptyOrSingletonList
import java.lang.reflect.Method
import java.util.* 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 { interface IdeaModuleInfo : ModuleInfo {
fun contentScope(): GlobalSearchScope fun contentScope(): GlobalSearchScope
@@ -71,7 +102,7 @@ private fun <T> Module.cached(provider: CachedValueProvider<T>): T {
return CachedValuesManager.getManager(project).getCachedValue(this, provider) 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 //NOTE: lib dependencies can be processed several times during recursive traversal
val result = LinkedHashSet<IdeaModuleInfo>() val result = LinkedHashSet<IdeaModuleInfo>()
val dependencyEnumerator = ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly() 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), ideaModelDependencies(module, productionOnly = true),
ProjectRootModificationTracker.getInstance(module.project)) 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 //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), ideaModelDependencies(module, productionOnly = false),
ProjectRootModificationTracker.getInstance(module.project)) 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 internal fun ModuleSourceInfo.isTests() = this is ModuleTestSourceInfo
@@ -249,4 +288,4 @@ enum class ModuleOrigin {
MODULE, MODULE,
LIBRARY, LIBRARY,
OTHER OTHER
} }