diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java index ddd74527974..9ae4f1e90d8 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -53,6 +53,7 @@ import org.jetbrains.kotlin.js.config.JsConfig; import org.jetbrains.kotlin.js.facade.K2JSTranslator; import org.jetbrains.kotlin.js.facade.MainCallParameters; import org.jetbrains.kotlin.js.facade.TranslationResult; +import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver; import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus; import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.serialization.js.ModuleKind; @@ -63,6 +64,7 @@ import org.jetbrains.kotlin.utils.StringsKt; import java.io.File; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; import static org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR; import static org.jetbrains.kotlin.cli.common.ExitCode.OK; @@ -182,6 +184,10 @@ public class K2JSCompiler extends CLICompiler { } } + if (config.getConfiguration().getBoolean(JSConfigurationKeys.SOURCE_MAP)) { + checkDuplicateSourceFileNames(messageCollector, sourcesFiles, config.getSourceMapRoots()); + } + MainCallParameters mainCallParameters = createMainCallParameters(arguments.main); TranslationResult translationResult; @@ -221,6 +227,41 @@ public class K2JSCompiler extends CLICompiler { return OK; } + private static void checkDuplicateSourceFileNames( + @NotNull MessageCollector log, + @NotNull List sourceFiles, + @NotNull List sourceRoots + ) { + if (sourceRoots.isEmpty()) return; + + List sourceRootFiles = sourceRoots.stream().map(File::new).collect(Collectors.toList()); + SourceFilePathResolver pathResolver = new SourceFilePathResolver(sourceRootFiles); + Map pathMap = new HashMap<>(); + Set duplicatePaths = new HashSet<>(); + + try { + for (KtFile sourceFile : sourceFiles) { + String path = sourceFile.getVirtualFile().getPath(); + String relativePath = pathResolver.getPathRelativeToSourceRoots(new File(sourceFile.getVirtualFile().getPath())); + + String existingPath = pathMap.get(relativePath); + if (existingPath != null) { + if (duplicatePaths.add(relativePath)) { + log.report(WARNING, "There are files with same path '" + relativePath + "', relative to source roots: " + + "'" + path + "' and '" + existingPath + "'. " + + "This will likely cause problems with debugger", null); + } + } + else { + pathMap.put(relativePath, path); + } + } + } + catch (IOException e) { + log.report(ERROR, "IO error occurred validating source path:\n" + ExceptionUtil.getThrowableText(e), null); + } + } + private static void reportCompiledSourcesList(@NotNull MessageCollector messageCollector, @NotNull List sourceFiles) { Iterable fileNames = CollectionsKt.map(sourceFiles, file -> { VirtualFile virtualFile = file.getVirtualFile(); diff --git a/compiler/testData/cli/js/sourceMapDuplicatePath/bar/lib.kt b/compiler/testData/cli/js/sourceMapDuplicatePath/bar/lib.kt new file mode 100644 index 00000000000..e8dbd3f5895 --- /dev/null +++ b/compiler/testData/cli/js/sourceMapDuplicatePath/bar/lib.kt @@ -0,0 +1 @@ +fun bar() = foo() + "bar" \ No newline at end of file diff --git a/compiler/testData/cli/js/sourceMapDuplicatePath/foo/lib.kt b/compiler/testData/cli/js/sourceMapDuplicatePath/foo/lib.kt new file mode 100644 index 00000000000..19c24b381ed --- /dev/null +++ b/compiler/testData/cli/js/sourceMapDuplicatePath/foo/lib.kt @@ -0,0 +1 @@ +fun foo() = "foo" \ No newline at end of file diff --git a/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.args b/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.args new file mode 100644 index 00000000000..e99539d99f3 --- /dev/null +++ b/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.args @@ -0,0 +1,7 @@ +$TESTDATA_DIR$/sourceMapDuplicatePath/ +-no-stdlib +-source-map +-source-map-source-roots +$TESTDATA_DIR$/sourceMapDuplicatePath/foo:$TESTDATA_DIR$/sourceMapDuplicatePath/bar +-output +$TEMP_DIR$/out.js diff --git a/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.out b/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.out new file mode 100644 index 00000000000..a7d9bd4940f --- /dev/null +++ b/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.out @@ -0,0 +1,2 @@ +warning: there are files with same path 'lib.kt', relative to source roots: '$TESTDATA_DIR$/sourceMapDuplicatePath/foo/lib.kt' and '$TESTDATA_DIR$/sourceMapDuplicatePath/bar/lib.kt'. This will likely cause problems with debugger +OK diff --git a/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.test b/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.test new file mode 100644 index 00000000000..b8a8b92d60d --- /dev/null +++ b/compiler/testData/cli/js/sourceMapDuplicateRelativePaths.test @@ -0,0 +1,2 @@ +// EXISTS: out.js +// EXISTS: out.js.map diff --git a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java index a0cd68f27db..46de7c0904f 100644 --- a/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cli/CliTestGenerated.java @@ -521,6 +521,12 @@ public class CliTestGenerated extends AbstractCliTest { doJsTest(fileName); } + @TestMetadata("sourceMapDuplicateRelativePaths.args") + public void testSourceMapDuplicateRelativePaths() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/js/sourceMapDuplicateRelativePaths.args"); + doJsTest(fileName); + } + @TestMetadata("sourceMapPrefix.args") public void testSourceMapPrefix() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/js/sourceMapPrefix.args");