Report correct source to output mapping for kjsm files

Now IC can correctly remove kjsm files when source files are changed
This commit is contained in:
Alexey Tsvetkov
2018-03-19 01:06:15 +03:00
parent ea09f4caf6
commit 2584143e92
4 changed files with 35 additions and 31 deletions
@@ -27,8 +27,6 @@ import com.intellij.util.SmartList;
import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashMap;
import kotlin.collections.ArraysKt; import kotlin.collections.ArraysKt;
import kotlin.collections.CollectionsKt; import kotlin.collections.CollectionsKt;
import kotlin.io.FilesKt;
import kotlin.sequences.SequencesKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.analyzer.AnalysisResult;
@@ -66,7 +64,6 @@ import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver; import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus; import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil;
import org.jetbrains.kotlin.serialization.js.ModuleKind; import org.jetbrains.kotlin.serialization.js.ModuleKind;
import org.jetbrains.kotlin.utils.*; import org.jetbrains.kotlin.utils.*;
@@ -297,23 +294,12 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
if (config.getConfiguration().getBoolean(JSConfigurationKeys.META_INFO)) {
removeKjsmFilesFromOutput(outputDir);
}
OutputUtilsKt.writeAll(outputFiles, outputDir, messageCollector, OutputUtilsKt.writeAll(outputFiles, outputDir, messageCollector,
configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)); configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES));
return OK; return OK;
} }
private static void removeKjsmFilesFromOutput(File outputDir) {
for (File file : SequencesKt.toList(FilesKt.walkTopDown(outputDir))) {
if (file.isFile() && file.getPath().endsWith(KotlinJavascriptSerializationUtil.INSTANCE.getCLASS_METADATA_FILE_EXTENSION())) {
file.delete();
}
}
}
private static void checkDuplicateSourceFileNames( private static void checkDuplicateSourceFileNames(
@NotNull MessageCollector log, @NotNull MessageCollector log,
@NotNull List<KtFile> sourceFiles, @NotNull List<KtFile> sourceFiles,
@@ -94,16 +94,6 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
private val PATH_TO_KOTLIN_JS_LIBRARY = AbstractKotlinJpsBuildTestCase.TEST_DATA_PATH + "general/KotlinJavaScriptProjectWithDirectoryAsLibrary/" + KOTLIN_JS_LIBRARY private val PATH_TO_KOTLIN_JS_LIBRARY = AbstractKotlinJpsBuildTestCase.TEST_DATA_PATH + "general/KotlinJavaScriptProjectWithDirectoryAsLibrary/" + KOTLIN_JS_LIBRARY
private val KOTLIN_JS_LIBRARY_JAR = "$KOTLIN_JS_LIBRARY.jar" private val KOTLIN_JS_LIBRARY_JAR = "$KOTLIN_JS_LIBRARY.jar"
private fun k2jsOutput(vararg moduleNames: String): Array<String> {
val list = arrayListOf<String>()
for (moduleName in moduleNames) {
val outputDir = File("out/production/$moduleName")
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputFile(outputDir, moduleName, false).path))
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputMetaFile(outputDir, moduleName, false).path))
}
return list.toTypedArray()
}
private fun getMethodsOfClass(classFile: File): Set<String> { private fun getMethodsOfClass(classFile: File): Set<String> {
val result = TreeSet<String>() val result = TreeSet<String>()
ClassReader(FileUtil.loadFileBytes(classFile)).accept(object : ClassVisitor(Opcodes.ASM5) { ClassReader(FileUtil.loadFileBytes(classFile)).accept(object : ClassVisitor(Opcodes.ASM5) {
@@ -257,6 +247,21 @@ open class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
checkWhen(touch("src/test1.kt"), null, k2jsOutput(PROJECT_NAME)) checkWhen(touch("src/test1.kt"), null, k2jsOutput(PROJECT_NAME))
} }
private fun k2jsOutput(vararg moduleNames: String): Array<String> {
val list = arrayListOf<String>()
for (moduleName in moduleNames) {
val outputDir = File("out/production/$moduleName")
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputFile(outputDir, moduleName, false).path))
list.add(toSystemIndependentName(JpsJsModuleUtils.getOutputMetaFile(outputDir, moduleName, false).path))
val kjsmFiles = File(workDir, outputDir.path).walk()
.filter { it.isFile && it.extension.equals("kjsm", ignoreCase = true) }
list.addAll(kjsmFiles.map { toSystemIndependentName(it.relativeTo(workDir).path) })
}
return list.toTypedArray()
}
fun testKotlinJavaScriptProjectWithSourceMap() { fun testKotlinJavaScriptProjectWithSourceMap() {
initProject(JS_STDLIB) initProject(JS_STDLIB)
buildAllModules().assertSuccessful() buildAllModules().assertSuccessful()
@@ -115,8 +115,10 @@ object KotlinJavascriptSerializationUtil {
private val jsDescriptor: JsModuleDescriptor<ModuleDescriptor>, private val jsDescriptor: JsModuleDescriptor<ModuleDescriptor>,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings
) { ) {
fun asContentMap(): Map<String, ByteArray> { class SerializedPackage(val fqName: FqName, val bytes: ByteArray)
val contentMap = mutableMapOf<String, ByteArray>()
fun serializedPackages(): List<SerializedPackage> {
val packages = arrayListOf<SerializedPackage>()
for ((fqName, part) in serializedFragments) { for ((fqName, part) in serializedFragments) {
val stream = ByteArrayOutputStream() val stream = ByteArrayOutputStream()
@@ -129,10 +131,10 @@ object KotlinJavascriptSerializationUtil {
serializeHeader(jsDescriptor.data, fqName, languageVersionSettings).writeDelimitedTo(stream) serializeHeader(jsDescriptor.data, fqName, languageVersionSettings).writeDelimitedTo(stream)
part.writeTo(stream) part.writeTo(stream)
contentMap[JsSerializerProtocol.getKjsmFilePath(fqName)] = stream.toByteArray() packages.add(SerializedPackage(fqName, stream.toByteArray()))
} }
return contentMap return packages
} }
fun asString(): String = fun asString(): String =
@@ -32,10 +32,12 @@ import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
import org.jetbrains.kotlin.js.util.TextOutput import org.jetbrains.kotlin.js.util.TextOutput
import org.jetbrains.kotlin.js.util.TextOutputImpl import org.jetbrains.kotlin.js.util.TextOutputImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.File import java.io.File
@@ -114,9 +116,9 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
val jsMetaFile = SimpleOutputFile(sourceFilesForMetaFile, metaFileName, metaFileContent) val jsMetaFile = SimpleOutputFile(sourceFilesForMetaFile, metaFileName, metaFileContent)
outputFiles.add(jsMetaFile) outputFiles.add(jsMetaFile)
serializedMetadata.asContentMap().forEach { for (serializedPackage in serializedMetadata.serializedPackages()) {
// TODO Add correct source files val outputBinaryFile = kjsmFileForPackage(serializedPackage.fqName, serializedPackage.bytes)
outputFiles.add(SimpleOutputBinaryFile(emptyList(), config.moduleId + VfsUtilCore.VFS_SEPARATOR_CHAR + it.key, it.value)) outputFiles.add(outputBinaryFile)
} }
} }
@@ -130,6 +132,15 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
return SimpleOutputFileCollection(outputFiles) return SimpleOutputFileCollection(outputFiles)
} }
private fun kjsmFileForPackage(packageFqName: FqName, bytes: ByteArray): SimpleOutputBinaryFile {
val ktFiles = (bindingContext.get(BindingContext.PACKAGE_TO_FILES, packageFqName) ?: emptyList())
val sourceFiles = ktFiles.map { VfsUtilCore.virtualToIoFile(it.virtualFile) }
val relativePath = config.moduleId +
VfsUtilCore.VFS_SEPARATOR_CHAR +
JsSerializerProtocol.getKjsmFilePath(packageFqName)
return SimpleOutputBinaryFile(sourceFiles, relativePath, bytes)
}
private fun getCode(output: TextOutput, sourceLocationConsumer: SourceLocationConsumer?) { private fun getCode(output: TextOutput, sourceLocationConsumer: SourceLocationConsumer?) {
program.accept(JsToStringGenerationVisitor(output, sourceLocationConsumer ?: NoOpSourceLocationConsumer)) program.accept(JsToStringGenerationVisitor(output, sourceLocationConsumer ?: NoOpSourceLocationConsumer))
} }