JS: support internal visibility from friend modules
Friend modules should be provided using the -Xfriend-modules flag
in the same format as -libraries. No manual configuration required for
JPS, Gradle and Maven plugins.
Friend modules could be switched off using the -Xfriend-modules-disabled
flag. Doing that will
* prevent internal declarations from being exported,
* values provided by -Xfriend-modules ignored,
* raise a compilation error on attemps to use internal declarations from other modules
Fixes #KT-15135 and #KT-16568.
Original commit: 2e9a59819a
This commit is contained in:
@@ -373,6 +373,11 @@ class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
|
||||
makeAll().assertSuccessful()
|
||||
}
|
||||
|
||||
fun testKotlinJavaScriptInternalFromSpecialRelatedModule() {
|
||||
initProject(JS_STDLIB)
|
||||
makeAll().assertSuccessful()
|
||||
}
|
||||
|
||||
fun testKotlinJavaScriptProjectWithTests() {
|
||||
initProject(JS_STDLIB)
|
||||
makeAll().assertSuccessful()
|
||||
|
||||
@@ -82,6 +82,7 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
|
||||
environment: JpsCompilerEnvironment,
|
||||
sourceFiles: Collection<File>,
|
||||
libraries: List<String>,
|
||||
friendModules: List<String>,
|
||||
outputFile: File
|
||||
) {
|
||||
log.debug("K2JS: common arguments: " + ArgumentUtils.convertArgumentsToStringList(commonArguments))
|
||||
@@ -90,7 +91,7 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
|
||||
val arguments = mergeBeans(commonArguments, XmlSerializerUtil.createCopy(k2jsArguments))
|
||||
log.debug("K2JS: merged arguments: " + ArgumentUtils.convertArgumentsToStringList(arguments))
|
||||
|
||||
setupK2JsArguments(outputFile, sourceFiles, libraries, arguments)
|
||||
setupK2JsArguments(outputFile, sourceFiles, libraries, friendModules, arguments)
|
||||
log.debug("K2JS: arguments after setup" + ArgumentUtils.convertArgumentsToStringList(arguments))
|
||||
|
||||
withCompilerSettings(compilerSettings) {
|
||||
@@ -203,13 +204,14 @@ class JpsKotlinCompilerRunner : KotlinCompilerRunner<JpsCompilerEnvironment>() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupK2JsArguments(_outputFile: File, sourceFiles: Collection<File>, _libraries: List<String>, settings: K2JSCompilerArguments) {
|
||||
private fun setupK2JsArguments(_outputFile: File, sourceFiles: Collection<File>, _libraries: List<String>, _friendModules: List<String>, settings: K2JSCompilerArguments) {
|
||||
with(settings) {
|
||||
noStdlib = true
|
||||
freeArgs = sourceFiles.map { it.path }
|
||||
outputFile = _outputFile.path
|
||||
metaInfo = true
|
||||
libraries = _libraries.joinToString(File.pathSeparator)
|
||||
friendModules = _friendModules.joinToString(File.pathSeparator)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,18 +51,16 @@ object JpsJsModuleUtils {
|
||||
if (module.moduleType != JpsJavaModuleType.INSTANCE) return
|
||||
|
||||
if ((module != target.module || target.isTests) && module.sourceRoots.any { it.rootType == JavaSourceRootType.SOURCE}) {
|
||||
addTarget(module, JavaModuleBuildTargetType.PRODUCTION)
|
||||
addTarget(module, isTests = false)
|
||||
}
|
||||
|
||||
if (module != target.module && target.isTests && module.sourceRoots.any { it.rootType == JavaSourceRootType.TEST_SOURCE}) {
|
||||
addTarget(module, JavaModuleBuildTargetType.TEST)
|
||||
addTarget(module, isTests = true)
|
||||
}
|
||||
}
|
||||
|
||||
fun addTarget(module: JpsModule, targetType: JavaModuleBuildTargetType) {
|
||||
val moduleBuildTarget = ModuleBuildTarget(module, targetType)
|
||||
val outputDir = KotlinBuilderModuleScriptGenerator.getOutputDirSafe(moduleBuildTarget)
|
||||
val metaInfoFile = getOutputMetaFile(outputDir, module.name, targetType.isTests)
|
||||
fun addTarget(module: JpsModule, isTests: Boolean) {
|
||||
val metaInfoFile = getOutputMetaFile(module, isTests)
|
||||
if (metaInfoFile.exists()) {
|
||||
result.add(metaInfoFile.absolutePath)
|
||||
}
|
||||
@@ -70,6 +68,13 @@ object JpsJsModuleUtils {
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getOutputMetaFile(module: JpsModule, isTests: Boolean): File {
|
||||
val moduleBuildTarget = ModuleBuildTarget(module, if (isTests) JavaModuleBuildTargetType.TEST else JavaModuleBuildTargetType.PRODUCTION)
|
||||
val outputDir = KotlinBuilderModuleScriptGenerator.getOutputDirSafe(moduleBuildTarget)
|
||||
return getOutputMetaFile(outputDir, module.name, isTests)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getOutputFile(outputDir: File, moduleName: String, isTests: Boolean)
|
||||
= File(outputDir, moduleName + suffix(isTests) + KotlinJavascriptMetadataUtils.JS_EXT)
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.daemon.common.isDaemonEnabled
|
||||
import org.jetbrains.kotlin.incremental.*
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.jps.JpsKotlinCompilerSettings
|
||||
import org.jetbrains.kotlin.jps.build.JpsJsModuleUtils.getOutputMetaFile
|
||||
import org.jetbrains.kotlin.jps.incremental.*
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
@@ -661,8 +662,13 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
||||
val compilerSettings = JpsKotlinCompilerSettings.getCompilerSettings(representativeModule)
|
||||
val k2JsArguments = JpsKotlinCompilerSettings.getK2JsCompilerArguments(representativeModule)
|
||||
|
||||
val friendPaths = KotlinBuilderModuleScriptGenerator.getProductionModulesWhichInternalsAreVisible(representativeTarget).mapNotNull {
|
||||
val file = getOutputMetaFile(it, false)
|
||||
if (file.exists()) file.absolutePath.toString() else null
|
||||
}
|
||||
|
||||
val compilerRunner = JpsKotlinCompilerRunner()
|
||||
compilerRunner.runK2JsCompiler(commonArguments, k2JsArguments, compilerSettings, environment, sourceFiles, libraries, outputFile)
|
||||
compilerRunner.runK2JsCompiler(commonArguments, k2JsArguments, compilerSettings, environment, sourceFiles, libraries, friendPaths, outputFile)
|
||||
return environment.outputItemsCollector
|
||||
}
|
||||
|
||||
|
||||
+10
-9
@@ -132,20 +132,21 @@ object KotlinBuilderModuleScriptGenerator {
|
||||
fun getOutputDirSafe(target: ModuleBuildTarget): File =
|
||||
target.outputDir ?: throw ProjectBuildException("No output directory found for " + target)
|
||||
|
||||
private fun getAdditionalOutputDirsWhereInternalsAreVisible(target: ModuleBuildTarget): List<File> {
|
||||
if (!target.isTests) return emptyList()
|
||||
fun getProductionModulesWhichInternalsAreVisible(from: ModuleBuildTarget): List<JpsModule> {
|
||||
if (!from.isTests) return emptyList()
|
||||
|
||||
val result = SmartList<File>()
|
||||
|
||||
result.addIfNotNull(JpsJavaExtensionService.getInstance().getOutputDirectory(target.module, false))
|
||||
|
||||
getRelatedProductionModule(target.module)?.let {
|
||||
result.addIfNotNull(JpsJavaExtensionService.getInstance().getOutputDirectory(it, false))
|
||||
}
|
||||
val result = SmartList<JpsModule>(from.module)
|
||||
result.addIfNotNull(getRelatedProductionModule(from.module))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun getAdditionalOutputDirsWhereInternalsAreVisible(target: ModuleBuildTarget): List<File> {
|
||||
return getProductionModulesWhichInternalsAreVisible(target).mapNotNullTo(SmartList<File>()) {
|
||||
JpsJavaExtensionService.getInstance().getOutputDirectory(it, false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findClassPathRoots(target: ModuleBuildTarget): Collection<File> {
|
||||
return getAllDependencies(target).classes().roots.filter { file ->
|
||||
if (!file.exists()) {
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="DEFAULT_COMPILER" value="Javac" />
|
||||
<resourceExtensions />
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="CopyrightManager" default="">
|
||||
<module2copyright />
|
||||
</component>
|
||||
<component name="DependencyValidationManager">
|
||||
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||
</component>
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/module1/module1.iml" filepath="$PROJECT_DIR$/module1/module1.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/module2/module2.iml" filepath="$PROJECT_DIR$/module2/module2.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA_JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA_JDK" jdkType="JavaSDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinRuntime" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package test1
|
||||
|
||||
@Target(AnnotationTarget.FILE)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
internal annotation class InternalFileAnnotation1()
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
internal annotation class InternalClassAnnotation1()
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
internal annotation class InternalFunctionAnnotation1()
|
||||
|
||||
internal open class InternalClass1
|
||||
|
||||
abstract class ClassA1(internal val member: Int)
|
||||
|
||||
abstract class ClassB1 {
|
||||
internal abstract val member: Int
|
||||
internal fun func() = 1
|
||||
}
|
||||
|
||||
internal val internalProp = 1
|
||||
|
||||
internal fun internalFun() {}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA_JDK" jdkType="JavaSDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="module1" />
|
||||
<orderEntry type="library" name="KotlinRuntime" level="project" />
|
||||
</component>
|
||||
<component name="TestModuleProperties" production-module="module1" />
|
||||
</module>
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
@file:InternalFileAnnotation1
|
||||
|
||||
package test2
|
||||
|
||||
import test1.*
|
||||
|
||||
internal class FromInternalClass1: InternalClass1()
|
||||
|
||||
@InternalClassAnnotation1
|
||||
class FromClassA1 : ClassA1(10) {
|
||||
@InternalClassAnnotation1
|
||||
class Nested {
|
||||
@InternalFunctionAnnotation1
|
||||
fun foo() {}
|
||||
}
|
||||
}
|
||||
|
||||
class FromClassB1 : ClassB1() {
|
||||
internal override val member = 10
|
||||
}
|
||||
|
||||
@InternalFunctionAnnotation1
|
||||
fun foo() {}
|
||||
|
||||
fun box() {
|
||||
internalProp
|
||||
internalFun()
|
||||
|
||||
InternalClass1()
|
||||
FromClassA1().member
|
||||
FromClassB1().member
|
||||
FromClassB1().func()
|
||||
}
|
||||
@@ -1,2 +1,6 @@
|
||||
fun main() {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun internalFun() {}
|
||||
|
||||
internal val internalVal = 10
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
fun testMain() {
|
||||
main()
|
||||
}
|
||||
internalFun()
|
||||
var a = internalVal
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user