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");
|
||||
|
||||
Reference in New Issue
Block a user