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.
This commit is contained in:
+12
-1
@@ -79,9 +79,20 @@ public class K2JSCompilerArguments extends CommonCompilerArguments {
|
||||
// Advanced options
|
||||
|
||||
@GradleOption(DefaultValues.BooleanFalseDefault.class)
|
||||
@Argument(value = "-Xtypedarrays", description = "Translate primitive arrays to JS typed arrays")
|
||||
@Argument(value = "-Xtyped-arrays", description = "Translate primitive arrays to JS typed arrays")
|
||||
public boolean typedArrays;
|
||||
|
||||
@GradleOption(DefaultValues.BooleanFalseDefault.class)
|
||||
@Argument(value = "-Xfriend-modules-disabled", description = "Disable internal declaration export")
|
||||
public boolean friendModulesDisabled;
|
||||
|
||||
@Argument(
|
||||
value = "-Xfriend-modules",
|
||||
valueDescription = "<path>",
|
||||
description = "Paths to friend modules"
|
||||
)
|
||||
public String friendModules;
|
||||
|
||||
@NotNull
|
||||
public static K2JSCompilerArguments createDefaultInstance() {
|
||||
K2JSCompilerArguments arguments = new K2JSCompilerArguments();
|
||||
|
||||
@@ -274,11 +274,19 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
|
||||
ContainerUtil.addAll(libraries, ArraysKt.filterNot(arguments.libraries.split(File.pathSeparator), String::isEmpty));
|
||||
}
|
||||
|
||||
configuration.put(JSConfigurationKeys.LIBRARIES, libraries);
|
||||
|
||||
|
||||
if (arguments.typedArrays) {
|
||||
configuration.put(JSConfigurationKeys.TYPED_ARRAYS_ENABLED, true);
|
||||
}
|
||||
|
||||
configuration.put(JSConfigurationKeys.LIBRARIES, libraries);
|
||||
configuration.put(JSConfigurationKeys.FRIEND_PATHS_DISABLED, arguments.friendModulesDisabled);
|
||||
|
||||
if (!arguments.friendModulesDisabled && arguments.friendModules != null) {
|
||||
List<String> friendPaths = ArraysKt.filterNot(arguments.friendModules.split(File.pathSeparator), String::isEmpty);
|
||||
configuration.put(JSConfigurationKeys.FRIEND_PATHS, friendPaths);
|
||||
}
|
||||
|
||||
String moduleKindName = arguments.moduleKind;
|
||||
ModuleKind moduleKind = moduleKindName != null ? moduleKindMap.get(moduleKindName) : ModuleKind.PLAIN;
|
||||
|
||||
+4
-2
@@ -1,6 +1,8 @@
|
||||
Usage: kotlinc-js <options> <source files>
|
||||
where advanced options include:
|
||||
-Xtypedarrays Translate primitive arrays to JS typed arrays
|
||||
-Xtyped-arrays Translate primitive arrays to JS typed arrays
|
||||
-Xfriend-modules-disabled Disable internal declaration export
|
||||
-Xfriend-modules=<path> Paths to friend modules
|
||||
-Xno-inline Disable method inlining
|
||||
-Xrepeat=<count> Repeat compilation (for performance analysis)
|
||||
-Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes)
|
||||
@@ -14,4 +16,4 @@ where advanced options include:
|
||||
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
|
||||
|
||||
Advanced options are non-standard and may be changed or removed without any notice.
|
||||
OK
|
||||
OK
|
||||
@@ -0,0 +1,37 @@
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
|
||||
package lib
|
||||
|
||||
internal fun foo() = 1
|
||||
|
||||
internal val bar = 2
|
||||
|
||||
internal class A {
|
||||
internal fun baz(a: Int): Int {
|
||||
return a * 10
|
||||
}
|
||||
|
||||
internal val foo = 3
|
||||
|
||||
internal inner class B {
|
||||
internal fun foo() = 4
|
||||
}
|
||||
}
|
||||
|
||||
// MODULE: main(lib)(lib)
|
||||
// FILE: main.kt
|
||||
|
||||
package main
|
||||
|
||||
import lib.*
|
||||
|
||||
fun box(): String {
|
||||
if (foo() != 1) return "fail 1: ${foo()}"
|
||||
if (bar != 2) return "fail 2: ${bar}"
|
||||
val a = A()
|
||||
if (a.baz(10) != 100) return "fail 3: ${a.baz(10)}"
|
||||
if (a.foo != 3) return "fail 4: ${a.foo}"
|
||||
if (a.B().foo() != 4) return "fail 5: ${a.B().foo()}"
|
||||
return "OK"
|
||||
}
|
||||
+5
-3
@@ -46,10 +46,12 @@ public abstract class KotlinMultiFileTestWithJava<M, F> extends KotlinTestWithEn
|
||||
public class ModuleAndDependencies {
|
||||
final M module;
|
||||
final List<String> dependencies;
|
||||
final List<String> friends;
|
||||
|
||||
ModuleAndDependencies(M module, List<String> dependencies) {
|
||||
ModuleAndDependencies(M module, List<String> dependencies, List<String> friends) {
|
||||
this.module = module;
|
||||
this.dependencies = dependencies;
|
||||
this.friends = friends;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +131,9 @@ public abstract class KotlinMultiFileTestWithJava<M, F> extends KotlinTestWithEn
|
||||
}
|
||||
|
||||
@Override
|
||||
public M createModule(@NotNull String name, @NotNull List<String> dependencies) {
|
||||
public M createModule(@NotNull String name, @NotNull List<String> dependencies, @NotNull List<String> friends) {
|
||||
M module = createTestModule(name);
|
||||
ModuleAndDependencies oldValue = modules.put(name, new ModuleAndDependencies(module, dependencies));
|
||||
ModuleAndDependencies oldValue = modules.put(name, new ModuleAndDependencies(module, dependencies, friends));
|
||||
assert oldValue == null : "Module " + name + " declared more than once";
|
||||
|
||||
return module;
|
||||
|
||||
@@ -118,7 +118,7 @@ public class KotlinTestUtils {
|
||||
private static final String MODULE_DELIMITER = ",\\s*";
|
||||
|
||||
private static final Pattern FILE_OR_MODULE_PATTERN = Pattern.compile(
|
||||
"(?://\\s*MODULE:\\s*([^()\\n]+)(?:\\(([^()]+(?:" + MODULE_DELIMITER + "[^()]+)*)\\))?\\s*)?" +
|
||||
"(?://\\s*MODULE:\\s*([^()\\n]+)(?:\\(([^()]+(?:" + MODULE_DELIMITER + "[^()]+)*)\\))?\\s*(?:\\(([^()]+(?:" + MODULE_DELIMITER + "[^()]+)*)\\))?\\s*)?" +
|
||||
"//\\s*FILE:\\s*(.*)$", Pattern.MULTILINE);
|
||||
private static final Pattern DIRECTIVE_PATTERN = Pattern.compile("^//\\s*!([\\w_]+)(:\\s*(.*)$)?", Pattern.MULTILINE);
|
||||
|
||||
@@ -610,7 +610,7 @@ public class KotlinTestUtils {
|
||||
|
||||
public interface TestFileFactory<M, F> {
|
||||
F createFile(@Nullable M module, @NotNull String fileName, @NotNull String text, @NotNull Map<String, String> directives);
|
||||
M createModule(@NotNull String name, @NotNull List<String> dependencies);
|
||||
M createModule(@NotNull String name, @NotNull List<String> dependencies, @NotNull List<String> friends);
|
||||
}
|
||||
|
||||
public static abstract class TestFileFactoryNoModules<F> implements TestFileFactory<Void, F> {
|
||||
@@ -628,7 +628,7 @@ public class KotlinTestUtils {
|
||||
public abstract F create(@NotNull String fileName, @NotNull String text, @NotNull Map<String, String> directives);
|
||||
|
||||
@Override
|
||||
public Void createModule(@NotNull String name, @NotNull List<String> dependencies) {
|
||||
public Void createModule(@NotNull String name, @NotNull List<String> dependencies, @NotNull List<String> friends) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -651,12 +651,13 @@ public class KotlinTestUtils {
|
||||
while (true) {
|
||||
String moduleName = matcher.group(1);
|
||||
String moduleDependencies = matcher.group(2);
|
||||
String moduleFriends = matcher.group(3);
|
||||
if (moduleName != null) {
|
||||
hasModules = true;
|
||||
module = factory.createModule(moduleName, parseDependencies(moduleDependencies));
|
||||
module = factory.createModule(moduleName, parseModuleList(moduleDependencies), parseModuleList(moduleFriends));
|
||||
}
|
||||
|
||||
String fileName = matcher.group(3);
|
||||
String fileName = matcher.group(4);
|
||||
int start = processedChars;
|
||||
|
||||
boolean nextFileExists = matcher.find();
|
||||
@@ -681,7 +682,7 @@ public class KotlinTestUtils {
|
||||
}
|
||||
|
||||
if (isDirectiveDefined(expectedText, "WITH_COROUTINES")) {
|
||||
M supportModule = hasModules ? factory.createModule("support", Collections.emptyList()) : null;
|
||||
M supportModule = hasModules ? factory.createModule("support", Collections.emptyList(), Collections.emptyList()) : null;
|
||||
testFiles.add(factory.createFile(supportModule,
|
||||
"CoroutineUtil.kt",
|
||||
"import kotlin.coroutines.experimental.*\n" +
|
||||
@@ -715,7 +716,7 @@ public class KotlinTestUtils {
|
||||
return testFiles;
|
||||
}
|
||||
|
||||
private static List<String> parseDependencies(@Nullable String dependencies) {
|
||||
private static List<String> parseModuleList(@Nullable String dependencies) {
|
||||
if (dependencies == null) return Collections.emptyList();
|
||||
return StringsKt.split(dependencies, Pattern.compile(MODULE_DELIMITER), 0);
|
||||
}
|
||||
|
||||
+6
@@ -10535,6 +10535,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("internal.kt")
|
||||
public void testInternal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internal.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("internalOverride.kt")
|
||||
public void testInternalOverride() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internalOverride.kt");
|
||||
|
||||
@@ -10535,6 +10535,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("internal.kt")
|
||||
public void testInternal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internal.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("internalOverride.kt")
|
||||
public void testInternalOverride() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internalOverride.kt");
|
||||
|
||||
@@ -10535,6 +10535,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("internal.kt")
|
||||
public void testInternal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internal.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("internalOverride.kt")
|
||||
public void testInternalOverride() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internalOverride.kt");
|
||||
|
||||
@@ -97,6 +97,10 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
setDependencies(ModuleDependenciesImpl(descriptors, emptySet()))
|
||||
}
|
||||
|
||||
fun setDependencies(descriptors: List<ModuleDescriptorImpl>, friends: Set<ModuleDescriptorImpl>) {
|
||||
setDependencies(ModuleDependenciesImpl(descriptors, friends))
|
||||
}
|
||||
|
||||
override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean {
|
||||
return this == targetModule || targetModule in dependencies!!.modulesWhoseInternalsAreVisible
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Vendored
+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>
|
||||
|
||||
Vendored
+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>
|
||||
|
||||
Vendored
+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() {}
|
||||
|
||||
Vendored
+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>
|
||||
|
||||
Vendored
+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
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
fun testMain() {
|
||||
main()
|
||||
}
|
||||
internalFun()
|
||||
var a = internalVal
|
||||
}
|
||||
|
||||
@@ -39,10 +39,11 @@ object TopDownAnalyzerFacadeForJS {
|
||||
val context = ContextForNewModule(
|
||||
ProjectContext(config.project), Name.special("<${config.moduleId}>"), JsPlatform.builtIns, null
|
||||
)
|
||||
context.setDependencies(
|
||||
context.module.setDependencies(
|
||||
listOf(context.module) +
|
||||
config.moduleDescriptors.map { it.data } +
|
||||
listOf(JsPlatform.builtIns.builtInsModule)
|
||||
listOf(JsPlatform.builtIns.builtInsModule),
|
||||
config.friendModuleDescriptors.map { it.data }.toSet()
|
||||
)
|
||||
val trace = BindingTraceContext()
|
||||
trace.record(MODULE_KIND, context.module, config.moduleKind)
|
||||
|
||||
@@ -45,4 +45,10 @@ public class JSConfigurationKeys {
|
||||
CompilerConfigurationKey.create("fallback metadata");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> SERIALIZE_FRAGMENTS = CompilerConfigurationKey.create("serialize fragments");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> FRIEND_PATHS_DISABLED =
|
||||
CompilerConfigurationKey.create("disable support for friend paths");
|
||||
|
||||
public static final CompilerConfigurationKey<List<String>> FRIEND_PATHS =
|
||||
CompilerConfigurationKey.create("friend module paths");
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.intellij.util.SmartList;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import kotlin.Unit;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.config.*;
|
||||
@@ -63,10 +63,14 @@ public class JsConfig {
|
||||
private final LockBasedStorageManager storageManager = new LockBasedStorageManager();
|
||||
|
||||
private final List<KotlinJavascriptMetadata> metadata = new SmartList<>();
|
||||
private final List<KotlinJavascriptMetadata> friends = new SmartList<>();
|
||||
|
||||
@Nullable
|
||||
private List<JsModuleDescriptor<ModuleDescriptorImpl>> moduleDescriptors = null;
|
||||
|
||||
@Nullable
|
||||
private List<JsModuleDescriptor<ModuleDescriptorImpl>> friendModuleDescriptors = null;
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
public JsConfig(@NotNull Project project, @NotNull CompilerConfiguration configuration) {
|
||||
@@ -99,6 +103,13 @@ public class JsConfig {
|
||||
return getConfiguration().getList(JSConfigurationKeys.LIBRARIES);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getFriends() {
|
||||
if (getConfiguration().getBoolean(JSConfigurationKeys.FRIEND_PATHS_DISABLED)) return Collections.emptyList();
|
||||
return getConfiguration().getList(JSConfigurationKeys.FRIEND_PATHS);
|
||||
}
|
||||
|
||||
|
||||
public static abstract class Reporter {
|
||||
public void error(@NotNull String message) { /*Do nothing*/ }
|
||||
|
||||
@@ -109,8 +120,15 @@ public class JsConfig {
|
||||
return checkLibFilesAndReportErrors(report, null);
|
||||
}
|
||||
|
||||
private boolean checkLibFilesAndReportErrors(@NotNull JsConfig.Reporter report, @Nullable Function1<VirtualFile, Unit> action) {
|
||||
List<String> libraries = getLibraries();
|
||||
private boolean checkLibFilesAndReportErrors(@NotNull JsConfig.Reporter report, @Nullable Function2<VirtualFile, String, Unit> action) {
|
||||
return checkLibFilesAndReportErrors(getLibraries(), report, action);
|
||||
}
|
||||
|
||||
private boolean checkLibFilesAndReportErrors(
|
||||
@NotNull Collection<String> libraries,
|
||||
@NotNull JsConfig.Reporter report,
|
||||
@Nullable Function2<VirtualFile, String, Unit> action
|
||||
) {
|
||||
if (libraries.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -163,7 +181,7 @@ public class JsConfig {
|
||||
}
|
||||
|
||||
if (action != null) {
|
||||
action.invoke(file);
|
||||
action.invoke(file, path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,49 +211,85 @@ public class JsConfig {
|
||||
return moduleDescriptors;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JsModuleDescriptor<ModuleDescriptorImpl>> getFriendModuleDescriptors() {
|
||||
init();
|
||||
if (friendModuleDescriptors != null) return friendModuleDescriptors;
|
||||
|
||||
friendModuleDescriptors = new SmartList<>();
|
||||
for (KotlinJavascriptMetadata metadataEntry : friends) {
|
||||
JsModuleDescriptor<ModuleDescriptorImpl> descriptor = createModuleDescriptor(metadataEntry);
|
||||
friendModuleDescriptors.add(descriptor);
|
||||
}
|
||||
|
||||
friendModuleDescriptors = Collections.unmodifiableList(friendModuleDescriptors);
|
||||
|
||||
return friendModuleDescriptors;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (initialized) return;
|
||||
|
||||
if (!getLibraries().isEmpty()) {
|
||||
Function1<VirtualFile, Unit> action = file -> {
|
||||
String libraryPath = PathUtil.getLocalPath(file);
|
||||
assert libraryPath != null : "libraryPath for " + file + " should not be null";
|
||||
metadata.addAll(KotlinJavascriptMetadataUtils.loadMetadata(libraryPath));
|
||||
|
||||
return Unit.INSTANCE;
|
||||
};
|
||||
|
||||
boolean hasErrors = checkLibFilesAndReportErrors(new Reporter() {
|
||||
JsConfig.Reporter reporter = new Reporter() {
|
||||
@Override
|
||||
public void error(@NotNull String message) {
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
}, action);
|
||||
};
|
||||
|
||||
boolean hasErrors = checkLibFilesAndReportErrors(getFriends(), reporter, (file, path) -> {
|
||||
List<KotlinJavascriptMetadata> metaList = loadMetadata(file, "friendPath");
|
||||
metadata.addAll(metaList);
|
||||
friends.addAll(metaList);
|
||||
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
|
||||
hasErrors |= checkLibFilesAndReportErrors(CollectionsKt.subtract(getLibraries(), getFriends()), reporter, (file, path) -> {
|
||||
metadata.addAll(loadMetadata(file, "libraryPath"));
|
||||
|
||||
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
assert !hasErrors : "hasErrors should be false";
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<KotlinJavascriptMetadata> loadMetadata(@NotNull VirtualFile file, @NotNull String name) {
|
||||
String libraryPath = PathUtil.getLocalPath(file);
|
||||
assert libraryPath != null : name + " for " + file + " should not be null";
|
||||
return KotlinJavascriptMetadataUtils.loadMetadata(libraryPath);
|
||||
}
|
||||
|
||||
private final IdentityHashMap<KotlinJavascriptMetadata, JsModuleDescriptor<ModuleDescriptorImpl>> factoryMap = new IdentityHashMap<>();
|
||||
|
||||
private JsModuleDescriptor<ModuleDescriptorImpl> createModuleDescriptor(KotlinJavascriptMetadata metadata) {
|
||||
LanguageVersionSettings languageVersionSettings = CommonConfigurationKeysKt.getLanguageVersionSettings(configuration);
|
||||
assert metadata.getVersion().isCompatible() ||
|
||||
languageVersionSettings.isFlagEnabled(AnalysisFlags.getSkipMetadataVersionCheck()) :
|
||||
"Expected JS metadata version " + JsMetadataVersion.INSTANCE + ", but actual metadata version is " + metadata.getVersion();
|
||||
return factoryMap.computeIfAbsent(metadata, m -> {
|
||||
LanguageVersionSettings languageVersionSettings = CommonConfigurationKeysKt.getLanguageVersionSettings(configuration);
|
||||
assert m.getVersion().isCompatible() ||
|
||||
languageVersionSettings.isFlagEnabled(AnalysisFlags.getSkipMetadataVersionCheck()) :
|
||||
"Expected JS metadata version " + JsMetadataVersion.INSTANCE + ", but actual metadata version is " + m.getVersion();
|
||||
|
||||
ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(
|
||||
Name.special("<" + metadata.getModuleName() + ">"), storageManager, JsPlatform.INSTANCE.getBuiltIns()
|
||||
);
|
||||
ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(
|
||||
Name.special("<" + m.getModuleName() + ">"), storageManager, JsPlatform.INSTANCE.getBuiltIns()
|
||||
);
|
||||
|
||||
JsModuleDescriptor<PackageFragmentProvider> rawDescriptor = KotlinJavascriptSerializationUtil.readModule(
|
||||
metadata.getBody(), storageManager, moduleDescriptor,
|
||||
new CompilerDeserializationConfiguration(languageVersionSettings)
|
||||
);
|
||||
JsModuleDescriptor<PackageFragmentProvider> rawDescriptor = KotlinJavascriptSerializationUtil.readModule(
|
||||
m.getBody(), storageManager, moduleDescriptor,
|
||||
new CompilerDeserializationConfiguration(languageVersionSettings)
|
||||
);
|
||||
|
||||
PackageFragmentProvider provider = rawDescriptor.getData();
|
||||
moduleDescriptor.initialize(provider != null ? provider : PackageFragmentProvider.Empty.INSTANCE);
|
||||
PackageFragmentProvider provider = rawDescriptor.getData();
|
||||
moduleDescriptor.initialize(provider != null ? provider : PackageFragmentProvider.Empty.INSTANCE);
|
||||
|
||||
return rawDescriptor.copy(moduleDescriptor);
|
||||
return rawDescriptor.copy(moduleDescriptor);
|
||||
});
|
||||
}
|
||||
|
||||
private static void setDependencies(ModuleDescriptorImpl module, List<ModuleDescriptorImpl> modules) {
|
||||
|
||||
@@ -273,38 +273,40 @@ class NameSuggestion {
|
||||
}
|
||||
|
||||
fun mangledAndStable() = NameAndStability(getStableMangledName(baseName, encodeSignature(descriptor)), true)
|
||||
fun mangledInternal() = NameAndStability(getInternalMangledName(baseName, encodeSignature(descriptor)), true)
|
||||
fun mangledPrivate() = NameAndStability(getPrivateMangledName(baseName, descriptor), false)
|
||||
|
||||
val effectiveVisibility = descriptor.ownEffectiveVisibility
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
return when (containingDeclaration) {
|
||||
is PackageFragmentDescriptor -> if (effectiveVisibility.isPublicAPI) mangledAndStable() else regularAndUnstable()
|
||||
is ClassDescriptor -> {
|
||||
is PackageFragmentDescriptor -> when {
|
||||
effectiveVisibility.isPublicAPI -> mangledAndStable()
|
||||
|
||||
effectiveVisibility == Visibilities.INTERNAL -> mangledInternal()
|
||||
|
||||
else -> regularAndUnstable()
|
||||
}
|
||||
is ClassDescriptor -> when {
|
||||
// valueOf() is created in the library with a mangled name for every enum class
|
||||
if (descriptor is FunctionDescriptor && descriptor.isEnumValueOfMethod()) return mangledAndStable()
|
||||
descriptor is FunctionDescriptor && descriptor.isEnumValueOfMethod() -> mangledAndStable()
|
||||
|
||||
// Make all public declarations stable
|
||||
if (effectiveVisibility == Visibilities.PUBLIC) {
|
||||
return mangledAndStable()
|
||||
}
|
||||
effectiveVisibility == Visibilities.PUBLIC -> mangledAndStable()
|
||||
|
||||
if (descriptor is CallableMemberDescriptor && descriptor.isOverridableOrOverrides) return mangledAndStable()
|
||||
descriptor is CallableMemberDescriptor && descriptor.isOverridableOrOverrides -> mangledAndStable()
|
||||
|
||||
// Make all protected declarations of non-final public classes stable
|
||||
if (effectiveVisibility == Visibilities.PROTECTED &&
|
||||
effectiveVisibility == Visibilities.PROTECTED &&
|
||||
!containingDeclaration.isFinalClass &&
|
||||
containingDeclaration.visibility.isPublicAPI
|
||||
) {
|
||||
return mangledAndStable()
|
||||
}
|
||||
containingDeclaration.visibility.isPublicAPI -> mangledAndStable()
|
||||
|
||||
effectiveVisibility == Visibilities.INTERNAL -> mangledInternal()
|
||||
|
||||
// Mangle (but make unstable) all non-public API of public classes
|
||||
if (containingDeclaration.visibility.isPublicAPI && !containingDeclaration.isFinalClass) {
|
||||
return mangledPrivate()
|
||||
}
|
||||
containingDeclaration.visibility.isPublicAPI && !containingDeclaration.isFinalClass -> mangledPrivate()
|
||||
|
||||
regularAndUnstable()
|
||||
else -> regularAndUnstable()
|
||||
}
|
||||
else -> {
|
||||
assert(containingDeclaration is CallableMemberDescriptor) {
|
||||
@@ -323,6 +325,11 @@ class NameSuggestion {
|
||||
return getStableMangledName(baseName, ownerName + ":" + encodeSignature(descriptor))
|
||||
}
|
||||
|
||||
fun getInternalMangledName(suggestedName: String, forCalculateId: String): String {
|
||||
val suffix = "_${mangledId("internal:" + forCalculateId)}\$"
|
||||
return suggestedName + suffix
|
||||
}
|
||||
|
||||
@JvmStatic fun getStableMangledName(suggestedName: String, forCalculateId: String): String {
|
||||
val suffix = if (forCalculateId.isEmpty()) "" else "_${mangledId(forCalculateId)}\$"
|
||||
return suggestedName + suffix
|
||||
|
||||
@@ -96,9 +96,10 @@ abstract class BasicBoxTest(
|
||||
|
||||
val generatedJsFiles = orderedModules.asReversed().mapNotNull { module ->
|
||||
val dependencies = module.dependencies.mapNotNull { modules[it]?.outputFileName(outputDir) + ".meta.js" }
|
||||
val friends = module.friends.mapNotNull { modules[it]?.outputFileName(outputDir) + ".meta.js" }
|
||||
|
||||
val outputFileName = module.outputFileName(outputDir) + ".js"
|
||||
generateJavaScriptFile(file.parent, module, outputFileName, dependencies, modules.size > 1,
|
||||
generateJavaScriptFile(file.parent, module, outputFileName, dependencies, friends, modules.size > 1,
|
||||
outputPrefixFile, outputPostfixFile, mainCallParameters)
|
||||
|
||||
if (!module.name.endsWith(OLD_MODULE_SUFFIX)) outputFileName else null
|
||||
@@ -222,6 +223,7 @@ abstract class BasicBoxTest(
|
||||
module: TestModule,
|
||||
outputFileName: String,
|
||||
dependencies: List<String>,
|
||||
friends: List<String>,
|
||||
multiModule: Boolean,
|
||||
outputPrefixFile: File?,
|
||||
outputPostfixFile: File?,
|
||||
@@ -239,7 +241,7 @@ abstract class BasicBoxTest(
|
||||
val additionalFiles = globalCommonFiles + localCommonFiles + additionalCommonFiles
|
||||
val psiFiles = createPsiFiles(testFiles + additionalFiles)
|
||||
|
||||
val config = createConfig(module, dependencies, multiModule, additionalMetadata = null)
|
||||
val config = createConfig(module, dependencies, friends, multiModule, additionalMetadata = null)
|
||||
val outputFile = File(outputFileName)
|
||||
|
||||
translateFiles(psiFiles.map(TranslationUnit::SourceFile), outputFile, config, outputPrefixFile, outputPostfixFile, mainCallParameters)
|
||||
@@ -263,7 +265,7 @@ abstract class BasicBoxTest(
|
||||
}
|
||||
|
||||
val headerFile = File(incrementalDir, HEADER_FILE)
|
||||
val recompiledConfig = createConfig(module, dependencies, multiModule, Pair(headerFile,serializedMetadata))
|
||||
val recompiledConfig = createConfig(module, dependencies, friends, multiModule, Pair(headerFile,serializedMetadata))
|
||||
val recompiledOutputFile = File(outputFile.parentFile, outputFile.nameWithoutExtension + "-recompiled.js")
|
||||
|
||||
translateFiles(allTranslationUnits, recompiledOutputFile, recompiledConfig, outputPrefixFile, outputPostfixFile,
|
||||
@@ -357,7 +359,7 @@ abstract class BasicBoxTest(
|
||||
private fun createPsiFiles(fileNames: List<String>): List<KtFile> = fileNames.map(this::createPsiFile)
|
||||
|
||||
private fun createConfig(
|
||||
module: TestModule, dependencies: List<String>, multiModule: Boolean, additionalMetadata: Pair<File, List<File>>?
|
||||
module: TestModule, dependencies: List<String>, friends: List<String>, multiModule: Boolean, additionalMetadata: Pair<File, List<File>>?
|
||||
): JsConfig {
|
||||
val configuration = environment.configuration.copy()
|
||||
|
||||
@@ -368,6 +370,7 @@ abstract class BasicBoxTest(
|
||||
}
|
||||
|
||||
configuration.put(JSConfigurationKeys.LIBRARIES, JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST + dependencies)
|
||||
configuration.put(JSConfigurationKeys.FRIEND_PATHS, friends)
|
||||
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, module.name.removeSuffix(OLD_MODULE_SUFFIX))
|
||||
configuration.put(JSConfigurationKeys.MODULE_KIND, module.moduleKind)
|
||||
@@ -397,7 +400,7 @@ abstract class BasicBoxTest(
|
||||
private inner class TestFileFactoryImpl : TestFileFactory<TestModule, TestFile>, Closeable {
|
||||
var testPackage: String? = null
|
||||
val tmpDir = KotlinTestUtils.tmpDir("js-tests")
|
||||
val defaultModule = TestModule(TEST_MODULE, emptyList())
|
||||
val defaultModule = TestModule(TEST_MODULE, emptyList(), emptyList())
|
||||
|
||||
override fun createFile(module: TestModule?, fileName: String, text: String, directives: Map<String, String>): TestFile? {
|
||||
val currentModule = module ?: defaultModule
|
||||
@@ -433,8 +436,8 @@ abstract class BasicBoxTest(
|
||||
return TestFile(temporaryFile.absolutePath, currentModule, recompile = RECOMPILE_PATTERN.matcher(text).find())
|
||||
}
|
||||
|
||||
override fun createModule(name: String, dependencies: List<String>): TestModule? {
|
||||
return TestModule(name, dependencies)
|
||||
override fun createModule(name: String, dependencies: List<String>, friends: List<String>): TestModule? {
|
||||
return TestModule(name, dependencies, friends)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
@@ -450,9 +453,11 @@ abstract class BasicBoxTest(
|
||||
|
||||
private class TestModule(
|
||||
val name: String,
|
||||
dependencies: List<String>
|
||||
dependencies: List<String>,
|
||||
friends: List<String>
|
||||
) {
|
||||
val dependencies = dependencies.toMutableList()
|
||||
val friends = friends.toMutableList()
|
||||
var moduleKind = ModuleKind.PLAIN
|
||||
var inliningDisabled = false
|
||||
val files = mutableListOf<TestFile>()
|
||||
|
||||
@@ -12072,6 +12072,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("internal.kt")
|
||||
public void testInternal() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internal.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("internalOverride.kt")
|
||||
public void testInternalOverride() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/mangling/internalOverride.kt");
|
||||
|
||||
+10
-2
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedPackage
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.exportedTag
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||
@@ -151,7 +152,14 @@ internal class DeclarationExporter(val context: StaticContext) {
|
||||
private fun JsExpression.exportStatement(declaration: DeclarationDescriptor) = JsExpressionStatement(this).also {
|
||||
it.exportedTag = context.getTag(declaration)
|
||||
}
|
||||
|
||||
private fun EffectiveVisibility.publicOrInternal(): Boolean {
|
||||
if (publicApi) return true
|
||||
if (context.config.configuration.getBoolean(JSConfigurationKeys.FRIEND_PATHS_DISABLED)) return false
|
||||
return toVisibility() == Visibilities.INTERNAL
|
||||
}
|
||||
|
||||
private fun MemberDescriptor.shouldBeExported(force: Boolean) =
|
||||
force || effectiveVisibility(checkPublishedApi = true).publicOrInternal() || AnnotationsUtils.getJsNameAnnotation(this) != null
|
||||
}
|
||||
|
||||
private fun MemberDescriptor.shouldBeExported(force: Boolean) =
|
||||
force || effectiveVisibility(checkPublishedApi = true).publicApi || AnnotationsUtils.getJsNameAnnotation(this) != null
|
||||
|
||||
@@ -214,6 +214,7 @@ val SIMPLE = "baz"
|
||||
val SIMPLE0 = "${SIMPLE}_0"
|
||||
val NATIVE = SIMPLE
|
||||
val STABLE = "baz_za3lpa$"
|
||||
val INTERNAL = "baz_kcn2v3$"
|
||||
|
||||
fun box(): String {
|
||||
testGroup = "Top Level"
|
||||
@@ -225,7 +226,7 @@ fun box(): String {
|
||||
testGroup = "Public Class"
|
||||
test(STABLE) { PublicClass().public_baz(0) }
|
||||
test(NATIVE) { PublicClass().public_baz("native") }
|
||||
test(SIMPLE0) { PublicClass().internal_baz(0) }
|
||||
test(INTERNAL) { PublicClass().internal_baz(0) }
|
||||
test(NATIVE) { PublicClass().internal_baz("native") }
|
||||
test(SIMPLE0, PublicClass().call_private_baz)
|
||||
test(NATIVE, PublicClass().call_private_native_baz)
|
||||
@@ -233,7 +234,7 @@ fun box(): String {
|
||||
testGroup = "Internal Class"
|
||||
test(STABLE) { InternalClass().public_baz(0) }
|
||||
test(NATIVE) { InternalClass().public_baz("native") }
|
||||
test(SIMPLE0) { InternalClass().internal_baz(0) }
|
||||
test(INTERNAL) { InternalClass().internal_baz(0) }
|
||||
test(NATIVE) { InternalClass().internal_baz("native") }
|
||||
test(SIMPLE0, InternalClass().call_private_baz)
|
||||
test(NATIVE, InternalClass().call_private_native_baz)
|
||||
@@ -241,7 +242,7 @@ fun box(): String {
|
||||
testGroup = "Private Class"
|
||||
test(STABLE) { PrivateClass().public_baz(0) }
|
||||
test(NATIVE) { PrivateClass().public_baz("native") }
|
||||
test(SIMPLE0) { PrivateClass().internal_baz(0) }
|
||||
test(INTERNAL) { PrivateClass().internal_baz(0) }
|
||||
test(NATIVE) { PrivateClass().internal_baz("native") }
|
||||
test(SIMPLE0, PrivateClass().call_private_baz)
|
||||
test(NATIVE, PrivateClass().call_private_native_baz)
|
||||
@@ -249,7 +250,7 @@ fun box(): String {
|
||||
testGroup = "Open Public Class"
|
||||
test(STABLE) { OpenPublicClass().public_baz(0) }
|
||||
test(NATIVE) { OpenPublicClass().public_baz("native") }
|
||||
testMangledPrivate { OpenPublicClass().internal_baz(0) }
|
||||
test(INTERNAL) { OpenPublicClass().internal_baz(0) }
|
||||
test(NATIVE) { OpenPublicClass().internal_baz("native") }
|
||||
testMangledPrivate(OpenPublicClass().call_private_baz)
|
||||
test(NATIVE, OpenPublicClass().call_private_native_baz)
|
||||
@@ -257,7 +258,7 @@ fun box(): String {
|
||||
testGroup = "Open Internal Class"
|
||||
test(STABLE) { OpenInternalClass().public_baz(0) }
|
||||
test(NATIVE) { OpenInternalClass().public_baz("native") }
|
||||
test(SIMPLE0) { OpenInternalClass().internal_baz(0) }
|
||||
test(INTERNAL) { OpenInternalClass().internal_baz(0) }
|
||||
test(NATIVE) { OpenInternalClass().internal_baz("native") }
|
||||
test(SIMPLE0, OpenInternalClass().call_private_baz)
|
||||
test(NATIVE, OpenInternalClass().call_private_native_baz)
|
||||
@@ -265,7 +266,7 @@ fun box(): String {
|
||||
testGroup = "Open Private Class"
|
||||
test(STABLE) { OpenPrivateClass().public_baz(0) }
|
||||
test(NATIVE) { OpenPrivateClass().public_baz("native") }
|
||||
test(SIMPLE0) { OpenPrivateClass().internal_baz(0) }
|
||||
test(INTERNAL) { OpenPrivateClass().internal_baz(0) }
|
||||
test(NATIVE) { OpenPrivateClass().internal_baz("native") }
|
||||
test(SIMPLE0, OpenPrivateClass().call_private_baz)
|
||||
test(NATIVE, OpenPrivateClass().call_private_native_baz)
|
||||
|
||||
@@ -14,9 +14,11 @@ fun test2(`p 1`: Int, `.p 2`: Int) = `+`(`p 1`, `.p 2`)
|
||||
fun test3(): String {
|
||||
val `#` = "K"
|
||||
class ` `(private val `::`: String) {
|
||||
internal fun `@`() = `::` + `#`
|
||||
private fun `@`() = `::` + `#`
|
||||
|
||||
operator fun invoke() = `@`()
|
||||
}
|
||||
return ` `("O").`@`()
|
||||
return ` `("O")()
|
||||
}
|
||||
|
||||
fun test4(): String {
|
||||
|
||||
+9
@@ -124,6 +124,15 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCompilerTestAccessInternalProduction() {
|
||||
val project = Project("kotlin2JsInternalTest", "2.10")
|
||||
|
||||
project.build("runRhino") {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testJsCustomSourceSet() {
|
||||
val project = Project("kotlin2JsProjectWithCustomSourceset", "2.10")
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin2js'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
|
||||
compile "org.mozilla:rhino:1.7.7.1"
|
||||
}
|
||||
|
||||
task runRhino(type: JavaExec) {
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
workingDir = "${buildDir}/classes/"
|
||||
main = 'org.mozilla.javascript.tools.shell.Main'
|
||||
args = ["-opt", "-1", "-f", "kotlin.js", "-f", "main/kotlin2JsInternalTest_main.js", "-f", "test/kotlin2JsInternalTest_test.js", "-f", "check.js"]
|
||||
}
|
||||
|
||||
build.doLast {
|
||||
configurations.compile.each { File file ->
|
||||
copy {
|
||||
includeEmptyDirs = false
|
||||
|
||||
from zipTree(file.absolutePath)
|
||||
into "${buildDir}/classes/"
|
||||
include { fileTreeElement ->
|
||||
def path = fileTreeElement.path
|
||||
path.endsWith(".js") && (path.startsWith("META-INF/resources/") || !path.startsWith("META-INF/"))
|
||||
}
|
||||
}
|
||||
}
|
||||
copy {
|
||||
from "."
|
||||
include "check.js"
|
||||
into "${buildDir}/classes/"
|
||||
}
|
||||
}
|
||||
|
||||
runRhino.dependsOn build
|
||||
+1
@@ -0,0 +1 @@
|
||||
kotlin2JsInternalTest_test.test();
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
*/
|
||||
|
||||
internal val CONST = "CONST"
|
||||
|
||||
open class PublicClass {
|
||||
internal fun foo(): String = "foo"
|
||||
internal val bar: String = "bar"
|
||||
open internal fun baz(): String = "PublicClass.baz()"
|
||||
}
|
||||
|
||||
internal data class InternalDataClass(val x: Int, val y: Int)
|
||||
|
||||
internal fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
*/
|
||||
|
||||
class PublicClassHeir : PublicClass() {
|
||||
override internal fun baz(): String = "PublicClassHeir.baz()"
|
||||
}
|
||||
|
||||
fun <T> assertEquals(e: T, a: T) {
|
||||
if (e != a) throw Exception("Expected: $e, actual: $a")
|
||||
}
|
||||
|
||||
fun test() {
|
||||
assertEquals("CONST", CONST)
|
||||
|
||||
assertEquals("foo", PublicClass().foo())
|
||||
assertEquals("bar", PublicClass().bar)
|
||||
assertEquals("PublicClass.baz()", PublicClass().baz())
|
||||
|
||||
assertEquals("foo", PublicClassHeir().foo())
|
||||
assertEquals("bar", PublicClassHeir().bar)
|
||||
assertEquals("PublicClassHeir.baz()", PublicClassHeir().baz())
|
||||
|
||||
val data = InternalDataClass(10, 20)
|
||||
assertEquals(10, data.x)
|
||||
assertEquals(20, data.y)
|
||||
|
||||
assertEquals("OK", box())
|
||||
}
|
||||
+6
@@ -4,6 +4,12 @@ package org.jetbrains.kotlin.gradle.dsl
|
||||
|
||||
interface KotlinJsOptions : org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions {
|
||||
|
||||
/**
|
||||
* Disable internal declaration export
|
||||
* Default value: false
|
||||
*/
|
||||
var friendModulesDisabled: kotlin.Boolean
|
||||
|
||||
/**
|
||||
* Whether a main function should be called
|
||||
* Possible values: "call", "noCall"
|
||||
|
||||
+7
@@ -24,6 +24,11 @@ internal abstract class KotlinJsOptionsBase : org.jetbrains.kotlin.gradle.dsl.Ko
|
||||
get() = verboseField ?: false
|
||||
set(value) { verboseField = value }
|
||||
|
||||
private var friendModulesDisabledField: kotlin.Boolean? = null
|
||||
override var friendModulesDisabled: kotlin.Boolean
|
||||
get() = friendModulesDisabledField ?: false
|
||||
set(value) { friendModulesDisabledField = value }
|
||||
|
||||
private var mainField: kotlin.String? = null
|
||||
override var main: kotlin.String
|
||||
get() = mainField ?: "call"
|
||||
@@ -69,6 +74,7 @@ internal abstract class KotlinJsOptionsBase : org.jetbrains.kotlin.gradle.dsl.Ko
|
||||
languageVersionField?.let { args.languageVersion = it }
|
||||
suppressWarningsField?.let { args.suppressWarnings = it }
|
||||
verboseField?.let { args.verbose = it }
|
||||
friendModulesDisabledField?.let { args.friendModulesDisabled = it }
|
||||
mainField?.let { args.main = it }
|
||||
metaInfoField?.let { args.metaInfo = it }
|
||||
moduleKindField?.let { args.moduleKind = it }
|
||||
@@ -85,6 +91,7 @@ internal fun org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments.fil
|
||||
languageVersion = "1.1"
|
||||
suppressWarnings = false
|
||||
verbose = false
|
||||
friendModulesDisabled = false
|
||||
main = "call"
|
||||
metaInfo = true
|
||||
moduleKind = "plain"
|
||||
|
||||
+2
@@ -372,6 +372,8 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile<K2JSCompilerArguments>(),
|
||||
null
|
||||
}
|
||||
|
||||
args.friendModules = friendDependency
|
||||
|
||||
logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}")
|
||||
|
||||
val messageCollector = GradleMessageCollector(logger)
|
||||
|
||||
@@ -106,13 +106,6 @@
|
||||
<plugin>
|
||||
<artifactId>maven-invoker-plugin</artifactId>
|
||||
<version>1.9</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.mozilla</groupId>
|
||||
<artifactId>rhino</artifactId>
|
||||
<version>1.7.7.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<projectsDirectory>src/it</projectsDirectory>
|
||||
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
this['test-js-accessToInternal-tests'].org.jetbrains.test();
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>test-js-accessToInternal</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-js</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<goals>
|
||||
<goal>js</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<output>${project.basedir}/customOutput/</output>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<goals>
|
||||
<goal>test-js</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.10</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-js</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>false</overWrite>
|
||||
<outputDirectory>${project.build.directory}/js/</outputDirectory>
|
||||
<includes>**/*.js</includes>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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
|
||||
|
||||
internal val CONST = "CONST"
|
||||
|
||||
open class PublicClass {
|
||||
internal fun foo(): String = "foo"
|
||||
internal val bar: String = "bar"
|
||||
open internal fun baz(): String = "PublicClass.baz()"
|
||||
}
|
||||
|
||||
internal data class InternalDataClass(val x: Int, val y: Int)
|
||||
|
||||
internal fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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
|
||||
|
||||
class PublicClassHeir : PublicClass() {
|
||||
override internal fun baz(): String = "PublicClassHeir.baz()"
|
||||
}
|
||||
|
||||
fun <T> assertEquals(e: T, a: T) {
|
||||
if (e != a) throw Exception("Expected: $e, actual: $a")
|
||||
}
|
||||
|
||||
fun test() {
|
||||
assertEquals("CONST", CONST)
|
||||
|
||||
assertEquals("foo", PublicClass().foo())
|
||||
assertEquals("bar", PublicClass().bar)
|
||||
assertEquals("PublicClass.baz()", PublicClass().baz())
|
||||
|
||||
assertEquals("foo", PublicClassHeir().foo())
|
||||
assertEquals("bar", PublicClassHeir().bar)
|
||||
assertEquals("PublicClassHeir.baz()", PublicClassHeir().baz())
|
||||
|
||||
val data = InternalDataClass(10, 20)
|
||||
assertEquals(10, data.x)
|
||||
assertEquals(20, data.y)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import java.io.*;
|
||||
import javax.script.*;
|
||||
|
||||
File file = new File(basedir, "target/js/test-js-accessToInternal.js");
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
throw new FileNotFoundException("Could not find generated JS : " + file);
|
||||
}
|
||||
|
||||
File testFile = new File(basedir, "target/test-js/test-js-accessToInternal-tests.js");
|
||||
if (!testFile.exists() || !testFile.isFile()) {
|
||||
throw new FileNotFoundException("Could not find generated JS : " + testFile);
|
||||
}
|
||||
|
||||
String basePath = basedir.getPath();
|
||||
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
|
||||
engine.eval(new FileReader(basePath + "/target/js/kotlin.js"));
|
||||
engine.eval(new FileReader(basePath + "/target/js/test-js-accessToInternal.js"));
|
||||
engine.eval(new FileReader(basePath + "/target/test-js/test-js-accessToInternal-tests.js"));
|
||||
engine.eval(new FileReader(basePath + "/check.js"));
|
||||
@@ -1,5 +1,5 @@
|
||||
import java.io.*;
|
||||
import org.mozilla.javascript.tools.shell.Main;
|
||||
import javax.script.*;
|
||||
|
||||
File file = new File(basedir, "target/js/test-js-moduleKind.js");
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
@@ -7,9 +7,9 @@ if (!file.exists() || !file.isFile()) {
|
||||
}
|
||||
|
||||
String basePath = basedir.getPath();
|
||||
Main.main(new String[] {
|
||||
"-O", "-1",
|
||||
"-f", basePath + "/amd.js",
|
||||
"-f", basePath + "/target/js/kotlin.js",
|
||||
"-f", basePath + "/target/js/test-js-moduleKind.js",
|
||||
"-f", basePath + "/check.js"})
|
||||
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
|
||||
engine.eval(new FileReader(basePath + "/amd.js"));
|
||||
engine.eval(new FileReader(basePath + "/target/js/kotlin.js"));
|
||||
engine.eval(new FileReader(basePath + "/target/js/test-js-moduleKind.js"));
|
||||
engine.eval(new FileReader(basePath + "/check.js"));
|
||||
+20
-20
@@ -34,9 +34,11 @@ import org.jetbrains.kotlin.js.JavaScript;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -109,15 +111,11 @@ public class K2JSCompilerMojo extends KotlinCompileMojoBase<K2JSCompilerArgument
|
||||
|
||||
arguments.sourceMap = sourceMap;
|
||||
|
||||
Set<String> collector = getOutputDirectoriesCollector();
|
||||
|
||||
if (outputFile != null) {
|
||||
collector.add(new File(outputFile).getParent());
|
||||
}
|
||||
if (metaInfo) {
|
||||
String output = com.google.common.base.Objects.firstNonNull(outputFile, ""); // fqname here because of J8 compatibility issues
|
||||
String metaFile = StringsKt.substringBeforeLast(output, JavaScript.DOT_EXTENSION, output) + KotlinJavascriptMetadataUtils.META_JS_SUFFIX;
|
||||
collector.add(new File(metaFile).getParent());
|
||||
ConcurrentMap<String, List<String>> collector = getOutputDirectoriesCollector();
|
||||
String key = project.getArtifactId();
|
||||
List<String> paths = collector.computeIfAbsent(key, k -> Collections.synchronizedList(new ArrayList<String>()));
|
||||
paths.add(new File(outputFile).getParent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,14 +143,16 @@ public class K2JSCompilerMojo extends KotlinCompileMojoBase<K2JSCompilerArgument
|
||||
}
|
||||
}
|
||||
|
||||
for (String path : getOutputDirectoriesCollector()) {
|
||||
File file = new File(path);
|
||||
for (List<String> paths : getOutputDirectoriesCollector().values()) {
|
||||
for (String path : paths) {
|
||||
File file = new File(path);
|
||||
|
||||
if (file.exists() && LibraryUtils.isKotlinJavascriptLibrary(file)) {
|
||||
libraries.add(file.getAbsolutePath());
|
||||
}
|
||||
else {
|
||||
getLog().debug("JS output directory missing: " + file);
|
||||
if (file.exists() && LibraryUtils.isKotlinJavascriptLibrary(file)) {
|
||||
libraries.add(file.getAbsolutePath());
|
||||
}
|
||||
else {
|
||||
getLog().debug("JS output directory missing: " + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,12 +177,12 @@ public class K2JSCompilerMojo extends KotlinCompileMojoBase<K2JSCompilerArgument
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Set<String> getOutputDirectoriesCollector() {
|
||||
protected ConcurrentMap<String, List<String>> getOutputDirectoriesCollector() {
|
||||
lock.lock();
|
||||
try {
|
||||
Set<String> collector = (Set<String>) getPluginContext().get(OUTPUT_DIRECTORIES_COLLECTOR_PROPERTY_NAME);
|
||||
ConcurrentMap<String, List<String>> collector = (ConcurrentMap<String, List<String>>) getPluginContext().get(OUTPUT_DIRECTORIES_COLLECTOR_PROPERTY_NAME);
|
||||
if (collector == null) {
|
||||
collector = new ConcurrentSkipListSet<String>();
|
||||
collector = new ConcurrentSkipListMap<String, List<String>>();
|
||||
getPluginContext().put(OUTPUT_DIRECTORIES_COLLECTOR_PROPERTY_NAME, collector);
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.maven;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.apache.maven.artifact.DependencyResolutionRequiredException;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
@@ -27,8 +28,9 @@ import org.apache.maven.project.MavenProject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Collections;
|
||||
/**
|
||||
* Converts Kotlin to JavaScript code
|
||||
*
|
||||
@@ -79,6 +81,8 @@ public class KotlinTestJSCompilerMojo extends K2JSCompilerMojo {
|
||||
|
||||
@Override
|
||||
protected void configureSpecificCompilerArguments(@NotNull K2JSCompilerArguments arguments) throws MojoExecutionException {
|
||||
List<String> friends = getOutputDirectoriesCollector().getOrDefault(project.getArtifactId(), Collections.emptyList());
|
||||
arguments.friendModules = StringUtil.join(friends, File.pathSeparator);
|
||||
output = testOutput;
|
||||
|
||||
super.configureSpecificCompilerArguments(arguments);
|
||||
|
||||
Reference in New Issue
Block a user