Support repeated analysis and frontend-only-mode in K2JsIrCompiler
This commit is contained in:
committed by
TeamCityServer
parent
e75ca75e3e
commit
06d3c6f233
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.ir.backend.js.ic.buildCache
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.ic.checkCaches
|
import org.jetbrains.kotlin.ir.backend.js.ic.checkCaches
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||||
|
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||||
import org.jetbrains.kotlin.js.config.*
|
import org.jetbrains.kotlin.js.config.*
|
||||||
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
|
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||||
@@ -221,17 +222,25 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
// Run analysis if main module is sources
|
// Run analysis if main module is sources
|
||||||
lateinit var sourceModule: ModulesStructure
|
lateinit var sourceModule: ModulesStructure
|
||||||
if (arguments.includes == null) {
|
if (arguments.includes == null) {
|
||||||
sourceModule = prepareAnalyzedSourceModule(
|
do {
|
||||||
projectJs,
|
sourceModule = prepareAnalyzedSourceModule(
|
||||||
environmentForJS.getSourceFiles(),
|
projectJs,
|
||||||
configurationJs,
|
environmentForJS.getSourceFiles(),
|
||||||
libraries,
|
configurationJs,
|
||||||
friendLibraries,
|
libraries,
|
||||||
AnalyzerWithCompilerReport(config.configuration),
|
friendLibraries,
|
||||||
icUseGlobalSignatures = icCaches.isNotEmpty(),
|
AnalyzerWithCompilerReport(config.configuration),
|
||||||
icUseStdlibCache = icCaches.isNotEmpty(),
|
icUseGlobalSignatures = icCaches.isNotEmpty(),
|
||||||
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = arguments.includes).data else emptyMap()
|
icUseStdlibCache = icCaches.isNotEmpty(),
|
||||||
)
|
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = arguments.includes).data else emptyMap()
|
||||||
|
)
|
||||||
|
val result = sourceModule.jsFrontEndResult.jsAnalysisResult
|
||||||
|
if (result is JsAnalysisResult.RetryWithAdditionalRoots) {
|
||||||
|
environmentForJS.addKotlinSourceRoots(result.additionalKotlinRoots)
|
||||||
|
}
|
||||||
|
} while (result is JsAnalysisResult.RetryWithAdditionalRoots)
|
||||||
|
if (!sourceModule.jsFrontEndResult.jsAnalysisResult.shouldGenerateCode)
|
||||||
|
return OK
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
|
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
|
||||||
|
|||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.integration
|
||||||
|
|
||||||
|
import com.intellij.mock.MockProject
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
|
import org.jetbrains.kotlin.cli.common.CLITool
|
||||||
|
import org.jetbrains.kotlin.cli.js.K2JSCompiler
|
||||||
|
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.container.ComponentProvider
|
||||||
|
import org.jetbrains.kotlin.context.ProjectContext
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
|
import org.jetbrains.kotlin.resolve.extensions.AnalysisHandlerExtension
|
||||||
|
import org.jetbrains.kotlin.test.CompilerTestUtil
|
||||||
|
import org.jetbrains.kotlin.test.TestCaseWithTmpdir
|
||||||
|
import java.io.File
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
|
private data class TestKtFile(
|
||||||
|
val name: String,
|
||||||
|
val content: String
|
||||||
|
)
|
||||||
|
|
||||||
|
private val classNotFound = TestKtFile("C.kt", "class C : ClassNotFound")
|
||||||
|
private val repeatedAnalysis = TestKtFile("D.kt", "class D : Generated")
|
||||||
|
|
||||||
|
class JsIrAnalysisHandlerExtensionTest : TestCaseWithTmpdir() {
|
||||||
|
|
||||||
|
// Writes the service file only; CustomComponentRegistrar is already in classpath.
|
||||||
|
private fun writePlugin(): String {
|
||||||
|
val jarFile = tmpdir.resolve("plugin.jar")
|
||||||
|
ZipOutputStream(jarFile.outputStream()).use {
|
||||||
|
val entry = ZipEntry("META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar")
|
||||||
|
it.putNextEntry(entry)
|
||||||
|
it.write(CustomComponentRegistrar::class.java.name.toByteArray())
|
||||||
|
}
|
||||||
|
return jarFile.absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
private val jsirStdlib: String?
|
||||||
|
get() = System.getProperty("kotlin.js.full.stdlib.path")
|
||||||
|
|
||||||
|
private val wasmStdlib: String?
|
||||||
|
get() = System.getProperty("kotlin.wasm.stdlib.path")
|
||||||
|
|
||||||
|
private val outjs: String
|
||||||
|
get() = tmpdir.resolve("out.js").absolutePath
|
||||||
|
|
||||||
|
private val outklib: String
|
||||||
|
get() = tmpdir.resolve("out.klib").absolutePath
|
||||||
|
|
||||||
|
private fun runTest(compiler: CLITool<*>, src: TestKtFile, libs: String, outFile: String, extras: List<String> = emptyList()) {
|
||||||
|
val mainKt = tmpdir.resolve(src.name).apply {
|
||||||
|
writeText(src.content)
|
||||||
|
}
|
||||||
|
val plugin = writePlugin()
|
||||||
|
val args = listOf(
|
||||||
|
"-Xplugin=$plugin",
|
||||||
|
"-libraries", libs,
|
||||||
|
"-output", outFile,
|
||||||
|
mainKt.absolutePath)
|
||||||
|
CompilerTestUtil.executeCompilerAssertSuccessful(compiler, args + extras)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testShouldNotGenerateCodeJs() {
|
||||||
|
if (jsirStdlib != null)
|
||||||
|
runTest(K2JSCompiler(), classNotFound, jsirStdlib!!, outjs, listOf("-Xir-produce-js"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testShouldNotGenerateCodeKlib() {
|
||||||
|
if (jsirStdlib != null)
|
||||||
|
runTest(K2JSCompiler(), classNotFound, jsirStdlib!!, outklib, listOf("-Xir-produce-klib-file"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testShouldNotGenerateCodeWasm() {
|
||||||
|
if (jsirStdlib != null && wasmStdlib != null)
|
||||||
|
runTest(K2JSCompiler(), classNotFound, "$jsirStdlib,$wasmStdlib", outjs, listOf("-Xir-produce-js", "-Xwasm"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testRepeatedAnalysisJs() {
|
||||||
|
if (jsirStdlib != null)
|
||||||
|
runTest(K2JSCompiler(), repeatedAnalysis, jsirStdlib!!, outjs, listOf("-Xir-produce-js"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testRepeatedAnalysisKlib() {
|
||||||
|
if (jsirStdlib != null)
|
||||||
|
runTest(K2JSCompiler(), repeatedAnalysis, jsirStdlib!!, outklib, listOf("-Xir-produce-klib-file"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testRepeatedAnalysisWasm() {
|
||||||
|
if (jsirStdlib != null && wasmStdlib != null)
|
||||||
|
runTest(K2JSCompiler(), repeatedAnalysis, "$jsirStdlib,$wasmStdlib", outjs, listOf("-Xir-produce-js", "-Xwasm"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomComponentRegistrar : ComponentRegistrar {
|
||||||
|
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||||
|
AnalysisHandlerExtension.registerExtension(project, CustomAnalysisHandler())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume that the directory of input files is writeable!
|
||||||
|
private class CustomAnalysisHandler : AnalysisHandlerExtension {
|
||||||
|
override fun doAnalysis(
|
||||||
|
project: Project,
|
||||||
|
module: ModuleDescriptor,
|
||||||
|
projectContext: ProjectContext,
|
||||||
|
files: Collection<KtFile>,
|
||||||
|
bindingTrace: BindingTrace,
|
||||||
|
componentProvider: ComponentProvider
|
||||||
|
): AnalysisResult? {
|
||||||
|
val filenames = files.map { it.name }
|
||||||
|
if (repeatedAnalysis.name in filenames) {
|
||||||
|
if ("Generated.kt" in filenames) {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
val outDir = File(files.single { it.name == repeatedAnalysis.name }.virtualFilePath).parentFile
|
||||||
|
outDir.resolve("Generated.kt").apply {
|
||||||
|
writeText("interface Generated")
|
||||||
|
}
|
||||||
|
return AnalysisResult.RetryWithAdditionalRoots(BindingContext.EMPTY, module, emptyList(), listOf(outDir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AnalysisResult.success(BindingContext.EMPTY, module, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user