MT tests: rewrite model dump and reading to javax.xml
note that format of the argument part is changed
diff --git a/compiler/cli/build.gradle.kts b/compiler/cli/build.gradle.kts
index 13ce77d..6a499ea 100644
--- a/compiler/cli/build.gradle.kts
+++ b/compiler/cli/build.gradle.kts
@@ -30,6 +30,7 @@
api(project(":compiler:fir:fir-serialization"))
api(project(":compiler:ir.inline"))
api(project(":kotlin-util-io"))
+ implementation(project(":kotlin-build-common"))
compileOnly(toolsJarApi())
compileOnly(intellijCore())
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt
index ee752a1..f91ab58 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt
@@ -9,13 +9,6 @@
import com.intellij.openapi.Disposable
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.util.xmlb.SkipDefaultsSerializationFilter
-import com.intellij.util.xmlb.XmlSerializer
-import org.jdom.Attribute
-import org.jdom.Document
-import org.jdom.Element
-import org.jdom.output.Format
-import org.jdom.output.XMLOutputter
import org.jetbrains.kotlin.KtPsiSourceFile
import org.jetbrains.kotlin.KtSourceFile
import org.jetbrains.kotlin.cli.common.*
@@ -38,6 +31,7 @@
import org.jetbrains.kotlin.cli.pipeline.jvm.JvmFrontendPipelinePhase.createEnvironmentAndSources
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
+import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
import org.jetbrains.kotlin.fir.DependencyListForCliModule
@@ -55,6 +49,8 @@
import org.jetbrains.kotlin.util.PhaseType
import org.jetbrains.kotlin.utils.fileUtils.descendantRelativeTo
import java.io.File
+import javax.xml.stream.XMLOutputFactory
+import javax.xml.stream.XMLStreamWriter
object JvmFrontendPipelinePhase : PipelinePhase<ConfigurationPipelineArtifact, JvmFrontendPipelineArtifact>(
name = "JvmFrontendPipelinePhase",
@@ -66,63 +62,6 @@
configuration: CompilerConfiguration,
arguments: CommonCompilerArguments,
) {
- val modules = Element("modules").apply {
- // Just write out all compiler arguments as is
- addContent(
- Element("compilerArguments").apply {
- val skipDefaultsFilter = SkipDefaultsSerializationFilter()
- val element = XmlSerializer.serialize(arguments, skipDefaultsFilter)
- addContent(element)
- }
- )
- for (module in chunk) {
- addContent(Element("module").apply {
- attributes.add(
- Attribute("timestamp", System.currentTimeMillis().toString())
- )
-
- attributes.add(
- Attribute("name", module.getModuleName())
- )
- attributes.add(
- Attribute("type", module.getModuleType())
- )
- attributes.add(
- Attribute("outputDir", module.getOutputDirectory())
- )
-
- for (friendDir in module.getFriendPaths()) {
- addContent(Element("friendDir").setAttribute("path", friendDir))
- }
- for (source in module.getSourceFiles()) {
- addContent(Element("sources").setAttribute("path", source))
- }
- for (javaSourceRoots in module.getJavaSourceRoots()) {
- addContent(
- Element("javaSourceRoots").apply {
- setAttribute("path", javaSourceRoots.path)
- javaSourceRoots.packagePrefix?.let { setAttribute("packagePrefix", it) }
- }
- )
- }
- for (classpath in configuration.get(CONTENT_ROOTS).orEmpty()) {
- if (classpath is JvmClasspathRoot) {
- addContent(Element("classpath").setAttribute("path", classpath.file.absolutePath))
- } else if (classpath is JvmModulePathRoot) {
- addContent(Element("modulepath").setAttribute("path", classpath.file.absolutePath))
- }
- }
- for (commonSources in module.getCommonSourceFiles()) {
- addContent(Element("commonSources").setAttribute("path", commonSources))
- }
- module.modularJdkRoot?.let {
- addContent(Element("modularJdkRoot").setAttribute("path", module.modularJdkRoot))
- }
- })
- }
- }
- val document = Document(modules)
- val outputter = XMLOutputter(Format.getPrettyFormat())
val dirFile = File(dir)
if (!dirFile.exists()) {
dirFile.mkdirs()
@@ -139,10 +78,78 @@
outputFile = file()
counter++
} while (outputFile.exists())
- outputFile.bufferedWriter().use {
- outputter.output(document, it)
- }
+ // Write XML using StAX
+ outputFile.bufferedWriter().use { writer ->
+ val xmlFactory = XMLOutputFactory.newInstance()
+ with(xmlFactory.createXMLStreamWriter(writer)) {
+ writeStartDocument("UTF-8", "1.0")
+ val depth = PrettyPrintDepth(0)
+
+ // <modules>
+ start("modules", depth)
+
+ // compilerArguments
+ start("compilerArguments", depth)
+ for (arg in ArgumentUtils.convertArgumentsToStringList(arguments)) {
+ empty("arg", depth)
+ writeAttribute("value", arg)
+ }
+ end(depth) // compilerArguments
+
+ // modules
+ for (module in chunk) {
+ start("module", depth)
+ writeAttribute("timestamp", System.currentTimeMillis().toString())
+ writeAttribute("name", module.getModuleName())
+ writeAttribute("type", module.getModuleType())
+ writeAttribute("outputDir", module.getOutputDirectory())
+
+ for (friendDir in module.getFriendPaths()) {
+ empty("friendDir", depth)
+ writeAttribute("path", friendDir)
+ }
+ for (source in module.getSourceFiles()) {
+ empty("sources", depth)
+ writeAttribute("path", source)
+ }
+ for (javaSourceRoots in module.getJavaSourceRoots()) {
+ start("javaSourceRoots", depth)
+ writeAttribute("path", javaSourceRoots.path)
+ javaSourceRoots.packagePrefix?.let { writeAttribute("packagePrefix", it) }
+ end(depth)
+ }
+ for (classpath in configuration.get(CONTENT_ROOTS).orEmpty()) {
+ when (classpath) {
+ is JvmClasspathRoot -> {
+ empty("classpath", depth)
+ writeAttribute("path", classpath.file.absolutePath)
+ }
+ is JvmModulePathRoot -> {
+ empty("modulepath", depth)
+ writeAttribute("path", classpath.file.absolutePath)
+ }
+ }
+ }
+ for (commonSources in module.getCommonSourceFiles()) {
+ empty("commonSources", depth)
+ writeAttribute("path", commonSources)
+ }
+ module.modularJdkRoot?.let {
+ empty("modularJdkRoot", depth)
+ writeAttribute("path", it)
+ }
+
+ end(depth) // module
+ }
+
+ end(depth) // modules
+ writeCharacters("\n")
+ writeEndDocument()
+ flush()
+ close()
+ }
+ }
}
override fun executePhase(input: ConfigurationPipelineArtifact): JvmFrontendPipelineArtifact? {
@@ -473,3 +480,29 @@
)
}
}
+
+
+// Pretty-printing helpers for StAX writer
+private data class PrettyPrintDepth(var value: Int)
+
+private fun XMLStreamWriter.indent(depth: PrettyPrintDepth) {
+ writeCharacters("\n")
+ if (depth.value > 0) writeCharacters(" ".repeat(depth.value))
+}
+
+private fun XMLStreamWriter.start(name: String, depth: PrettyPrintDepth) {
+ indent(depth)
+ writeStartElement(name)
+ depth.value++
+}
+
+private fun XMLStreamWriter.end(depth: PrettyPrintDepth) {
+ depth.value--
+ indent(depth)
+ writeEndElement()
+}
+
+private fun XMLStreamWriter.empty(name: String, depth: PrettyPrintDepth) {
+ indent(depth)
+ writeEmptyElement(name)
+}
diff --git a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt
index 9d3ce45..8b135ec 100644
--- a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt
+++ b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt
@@ -5,11 +5,9 @@
package org.jetbrains.kotlin.fir
-import com.intellij.openapi.util.JDOMUtil
-import com.intellij.util.xmlb.XmlSerializer
-import org.jdom.Element
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
+import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.test.kotlinPathsForDistDirectoryForTests
@@ -20,6 +18,9 @@
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
+import javax.xml.stream.XMLInputFactory
+import javax.xml.stream.XMLStreamConstants
+import javax.xml.stream.XMLStreamReader
data class ModuleData(
val name: String,
@@ -180,73 +181,144 @@
}
internal fun loadModuleDumpFile(file: File): List<ModuleData> {
- val rootElement = JDOMUtil.load(file)
- val modules = rootElement.getChildren("module")
- val arguments = rootElement.getChild("compilerArguments")?.let { loadCompilerArguments(it) }
- return modules.map { node -> loadModule(node).also { it.arguments = arguments } }
+ val modules = mutableListOf<ModuleData>()
+ var arguments: CommonCompilerArguments? = null
+
+ val xmlFactory = XMLInputFactory.newInstance()
+ file.inputStream().use { input ->
+ val xr = xmlFactory.createXMLStreamReader(input)
+ while (xr.hasNext()) {
+ when (xr.next()) {
+ XMLStreamConstants.START_ELEMENT -> when (xr.localName) {
+ "compilerArguments" -> {
+ arguments = readCompilerArguments(xr)
+ // Assign to already parsed modules as well
+ modules.forEach { it.arguments = arguments }
+ }
+ "module" -> {
+ val m = readModule(xr)
+ m.arguments = arguments
+ modules += m
+ }
+ else -> {}
+ }
+ else -> {}
+ }
+ }
+ xr.close()
+ }
+ return modules
}
-private fun loadModule(moduleElement: Element): ModuleData {
- val outputDir = moduleElement.getAttribute("outputDir").value
- val moduleName = moduleElement.getAttribute("name").value
+private fun readModule(xr: XMLStreamReader): ModuleData {
+ // reader is positioned at START_ELEMENT <module>
+ val outputDir = xr.getAttributeValue(null, "outputDir") ?: ""
+ val moduleName = xr.getAttributeValue(null, "name") ?: ""
val moduleNameQualifier = outputDir.substringAfterLast("/")
+ val timestamp = xr.getAttributeValue(null, "timestamp")?.toLongOrNull() ?: 0L
+ val jdkHome = xr.getAttributeValue(null, "jdkHome")
+
val javaSourceRoots = mutableListOf<JavaSourceRootData<String>>()
val classpath = mutableListOf<String>()
val sources = mutableListOf<String>()
val friendDirs = mutableListOf<String>()
val optInAnnotations = mutableListOf<String>()
- val timestamp = moduleElement.getAttribute("timestamp")?.longValue ?: 0
- val jdkHome = moduleElement.getAttribute("jdkHome")?.value
var modularJdkRoot: String? = null
var isCommon = false
- for (item in moduleElement.children) {
- when (item.name) {
- "classpath" -> {
- val path = item.getAttribute("path").value
- if (path != outputDir) {
- classpath += path
+ while (xr.hasNext()) {
+ when (xr.next()) {
+ XMLStreamConstants.START_ELEMENT -> when (xr.localName) {
+ "classpath" -> {
+ val path = xr.getAttributeValue(null, "path")
+ if (path != null && path != outputDir) classpath += path
+ skipElement(xr)
+ }
+ "friendDir" -> {
+ xr.getAttributeValue(null, "path")?.let { friendDirs += it }
+ skipElement(xr)
+ }
+ "javaSourceRoots" -> {
+ val path = xr.getAttributeValue(null, "path")
+ val pkg = xr.getAttributeValue(null, "packagePrefix")
+ if (path != null) javaSourceRoots += JavaSourceRootData(path, pkg)
+ skipElement(xr)
+ }
+ "sources" -> {
+ xr.getAttributeValue(null, "path")?.let { sources += it }
+ skipElement(xr)
+ }
+ "commonSources" -> {
+ isCommon = true
+ skipElement(xr)
+ }
+ "modularJdkRoot" -> {
+ modularJdkRoot = xr.getAttributeValue(null, "path")
+ skipElement(xr)
+ }
+ "useOptIn" -> {
+ xr.getAttributeValue(null, "annotation")?.let { optInAnnotations += it }
+ skipElement(xr)
+ }
+ else -> {
+ // Skip any unknown children fully
+ skipElement(xr)
}
}
- "friendDir" -> {
- val path = item.getAttribute("path").value
- friendDirs += path
+ XMLStreamConstants.END_ELEMENT -> if (xr.localName == "module") {
+ return ModuleData(
+ moduleName,
+ timestamp,
+ outputDir,
+ moduleNameQualifier,
+ classpath,
+ sources,
+ javaSourceRoots,
+ friendDirs,
+ optInAnnotations,
+ modularJdkRoot,
+ jdkHome,
+ isCommon,
+ )
}
- "javaSourceRoots" -> {
- javaSourceRoots +=
- JavaSourceRootData(
- item.getAttribute("path").value,
- item.getAttribute("packagePrefix")?.value,
- )
- }
- "sources" -> sources += item.getAttribute("path").value
- "commonSources" -> isCommon = true
- "modularJdkRoot" -> modularJdkRoot = item.getAttribute("path").value
- "useOptIn" -> optInAnnotations += item.getAttribute("annotation").value
}
}
-
- return ModuleData(
- moduleName,
- timestamp,
- outputDir,
- moduleNameQualifier,
- classpath,
- sources,
- javaSourceRoots,
- friendDirs,
- optInAnnotations,
- modularJdkRoot,
- jdkHome,
- isCommon,
- )
+ error("Unexpected end of XML while reading <module>")
}
-private fun loadCompilerArguments(argumentsRoot: Element): CommonCompilerArguments? {
- val element = argumentsRoot.children.singleOrNull() ?: return null
- return when (element.name) {
- "K2JVMCompilerArguments" -> K2JVMCompilerArguments().also { XmlSerializer.deserializeInto(it, element) }
- else -> null
+private fun readCompilerArguments(xr: javax.xml.stream.XMLStreamReader): CommonCompilerArguments? {
+ // reader is positioned at START_ELEMENT <compilerArguments>
+ val args = mutableListOf<String>()
+ while (xr.hasNext()) {
+ when (xr.next()) {
+ XMLStreamConstants.START_ELEMENT -> {
+ when (xr.localName) {
+ "arg" -> {
+ xr.getAttributeValue(null, "value")?.let { args += it }
+ skipElement(xr)
+ }
+ else -> {
+ // Unknown format, skip it entirely
+ skipElement(xr)
+ }
+ }
+ }
+ XMLStreamConstants.END_ELEMENT -> if (xr.localName == "compilerArguments") {
+ return parseCommandLineArguments<K2JVMCompilerArguments>(args)
+ }
+ }
+ }
+ error("Unexpected end of XML while reading <compilerArguments>")
+}
+
+private fun skipElement(xr: javax.xml.stream.XMLStreamReader) {
+ // Assumes the reader is at START_ELEMENT; consumes until matching END_ELEMENT
+ var depth = 1
+ while (depth > 0 && xr.hasNext()) {
+ when (xr.next()) {
+ XMLStreamConstants.START_ELEMENT -> depth++
+ XMLStreamConstants.END_ELEMENT -> depth--
+ }
}
}