fix access from tests to internal elements in production code in case of circular dependency

This commit is contained in:
Michael Nedzelsky
2015-11-09 15:42:16 +03:00
parent a8b11ff07b
commit 5b59fc74bc
28 changed files with 292 additions and 30 deletions
@@ -28,6 +28,7 @@ public class ModuleBuilder(
private val sourceFiles = ArrayList<String>()
private val classpathRoots = ArrayList<String>()
private val javaSourceRoots = ArrayList<JavaRootPath>()
private val friendDirs = ArrayList<String>()
public fun addSourceFiles(pattern: String) {
sourceFiles.add(pattern)
@@ -41,7 +42,12 @@ public class ModuleBuilder(
javaSourceRoots.add(rootPath)
}
public fun addFriendDir(friendDir: String) {
friendDirs.add(friendDir)
}
override fun getOutputDirectory(): String = outputDir
override fun getFriendPaths(): List<String> = friendDirs
override fun getJavaSourceRoots(): List<JavaRootPath> = javaSourceRoots
override fun getSourceFiles(): List<String> = sourceFiles
override fun getClasspathRoots(): List<String> = classpathRoots
@@ -47,6 +47,7 @@ public class ModuleXmlParser {
public static final String TYPE_PRODUCTION = "java-production";
public static final String TYPE_TEST = "java-test";
public static final String OUTPUT_DIR = "outputDir";
public static final String FRIEND_DIR = "friendDir";
public static final String SOURCES = "sources";
public static final String JAVA_SOURCE_ROOTS = "javaSourceRoots";
public static final String JAVA_SOURCE_PACKAGE_PREFIX = "packagePrefix";
@@ -162,6 +163,10 @@ public class ModuleXmlParser {
String path = getAttribute(attributes, PATH, qName);
moduleBuilder.addSourceFiles(path);
}
else if (FRIEND_DIR.equalsIgnoreCase(qName)) {
String path = getAttribute(attributes, PATH, qName);
moduleBuilder.addFriendDir(path);
}
else if (CLASSPATH.equalsIgnoreCase(qName)) {
String path = getAttribute(attributes, PATH, qName);
moduleBuilder.addClasspathEntry(path);
@@ -18,13 +18,11 @@ package org.jetbrains.kotlin.cli.common
import com.intellij.openapi.Disposable
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.load.kotlin.getSourceElement
import org.jetbrains.kotlin.load.kotlin.isContainedByCompiledPartOfOurModule
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.util.ModuleVisibilityHelper
@@ -44,37 +42,37 @@ class ModuleVisibilityHelperImpl : ModuleVisibilityHelper {
}
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(project)
fun findModule(kotlinFile: KtFile): Module? = moduleVisibilityManager.chunk.firstOrNull { it.getSourceFiles().containsRaw(kotlinFile.virtualFile.path) }
val whatSource = getSourceElement(what)
if (whatSource is KotlinSourceElement) {
if (moduleVisibilityManager.chunk.size > 1 && fromSource is KotlinSourceElement) {
val fromSourceKotlinFile = fromSource.psi.getContainingKtFile()
val whatSourceKotlinFile = whatSource.psi.getContainingKtFile()
return findModule(whatSourceKotlinFile) === findModule(fromSourceKotlinFile)
}
return true
}
moduleVisibilityManager.friendPaths.forEach {
if (isContainedByCompiledPartOfOurModule(what, File(it))) return true
}
val modules = moduleVisibilityManager.chunk
val outputDirectories = modules.map { File(it.getOutputDirectory()) }
if (outputDirectories.isEmpty()) return isContainedByCompiledPartOfOurModule(what, null)
val whatSource = getSourceElement(what)
if (whatSource is KotlinSourceElement) {
if (modules.size > 1 && fromSource is KotlinSourceElement) {
return findModule(what, modules) === findModule(from, modules)
}
outputDirectories.forEach {
if (isContainedByCompiledPartOfOurModule(what, it)) return true
return true
}
// Hack in order to allow access to internal elements in production code from tests
if (modules.singleOrNull()?.getModuleType() == ModuleXmlParser.TYPE_TEST) return true
if (modules.isEmpty()) return false
return false
return findModule(from, modules) === findModule(what, modules)
}
private fun findModule(descriptor: DeclarationDescriptor, modules: Collection<Module>): Module? {
val sourceElement = getSourceElement(descriptor)
if (sourceElement is KotlinSourceElement) {
return modules.singleOrNull() ?: modules.firstOrNull { sourceElement.psi.getContainingKtFile().virtualFile.path in it.getSourceFiles() }
}
else {
return modules.firstOrNull { module ->
isContainedByCompiledPartOfOurModule(descriptor, File(module.getOutputDirectory())) ||
module.getFriendPaths().any { isContainedByCompiledPartOfOurModule(descriptor, File(it))}
}
}
}
}