Introduce experimental -Xuse-javac compilation mode

In this mode, javac AST and Symbol files are used during
Kotlin compilation instead of PSI / binary stuff.
Later, they are reused for Java file compilation.
javac in this mode is integrated into kotlinc.
This commit is contained in:
baratynskiy
2017-04-05 13:11:26 +03:00
committed by Mikhail Glukhikh
parent c9a04fe1e2
commit 5eea3b6569
217 changed files with 6537 additions and 565 deletions
@@ -137,6 +137,16 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
)
public String[] scriptResolverEnvironment;
// Javac options
@Argument(value = "-Xuse-javac", description = "Use javac for Java source and class files analysis")
public boolean useJavac;
@Argument(
value = "-Xjavac-arguments",
valueDescription = "<option[,]>",
description = "Java compiler arguments")
public String[] javacArguments;
// Paths to output directories for friend modules.
public String[] friendPaths;
+1
View File
@@ -23,5 +23,6 @@
<orderEntry type="module" module-name="annotation-collector" />
<orderEntry type="module" module-name="builtins-serializer" />
<orderEntry type="module" module-name="frontend.script" />
<orderEntry type="module" module-name="javac-wrapper" />
</component>
</module>
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
import org.jetbrains.kotlin.compiler.plugin.PluginCliOptionProcessingException
import org.jetbrains.kotlin.compiler.plugin.cliPluginUsageString
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
@@ -158,6 +159,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
val environment = createEnvironmentWithScriptingSupport(rootDisposable, configuration, arguments, messageCollector)
?: return COMPILATION_ERROR
registerJavacIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR
}
KotlinToJVMBytecodeCompiler.compileModules(environment, directory)
}
else if (arguments.script) {
@@ -183,6 +188,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
val environment = createEnvironmentWithScriptingSupport(rootDisposable, configuration, arguments, messageCollector)
?: return COMPILATION_ERROR
registerJavacIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR
}
if (environment.getSourceFiles().isEmpty()) {
if (arguments.version) {
return OK
@@ -192,6 +201,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)
compileJavaFilesIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR
}
}
if (arguments.reportPerf) {
@@ -211,6 +224,23 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
}
private fun registerJavacIfNeeded(environment: KotlinCoreEnvironment,
arguments: K2JVMCompilerArguments): Boolean {
if (arguments.useJavac) {
environment.configuration.put(JVMConfigurationKeys.USE_JAVAC, true)
return environment.registerJavac(arguments = arguments.javacArguments)
}
return true
}
private fun compileJavaFilesIfNeeded(environment: KotlinCoreEnvironment,
arguments: K2JVMCompilerArguments): Boolean {
if (arguments.useJavac) {
return JavacWrapper.getInstance(environment.project).use { it.compile() }
}
return true
}
private fun createEnvironmentWithScriptingSupport(rootDisposable: Disposable,
configuration: CompilerConfiguration,
@@ -25,6 +25,7 @@ import com.intellij.core.CoreApplicationEnvironment
import com.intellij.core.CoreJavaFileManager
import com.intellij.core.JavaCoreApplicationEnvironment
import com.intellij.core.JavaCoreProjectEnvironment
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.lang.MetaLanguage
import com.intellij.lang.java.JavaParserDefinition
@@ -70,10 +71,7 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
import org.jetbrains.kotlin.cli.common.toBooleanLenient
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesDynamicCompoundIndex
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
@@ -89,6 +87,7 @@ import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
import org.jetbrains.kotlin.extensions.PreprocessedVirtualFileFactoryExtension
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.javac.JavacWrapperRegistrar
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
@@ -219,6 +218,28 @@ class KotlinCoreEnvironment private constructor(
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
}
private val VirtualFile.javaFiles: List<VirtualFile>
get() = mutableListOf<VirtualFile>().apply {
VfsUtilCore.processFilesRecursively(this@javaFiles) { file ->
if (file.fileType == JavaFileType.INSTANCE) {
add(file)
}
true
}
}
private val allJavaFiles: List<File>
get() = configuration.javaSourceRoots
.mapNotNull(this::findLocalDirectory)
.flatMap { it.javaFiles }
.map { File(it.canonicalPath) }
fun registerJavac(javaFiles: List<File> = allJavaFiles,
kotlinFiles: List<KtFile> = sourceFiles,
arguments: Array<String>? = null): Boolean {
return JavacWrapperRegistrar.registerJavac(this, javaFiles, kotlinFiles, arguments)
}
private val applicationEnvironment: CoreApplicationEnvironment
get() = projectEnvironment.environment
@@ -327,6 +348,10 @@ class KotlinCoreEnvironment private constructor(
}
}
fun findLocalFile(path: String) = applicationEnvironment.localFileSystem.findFileByPath(path)
fun findJarFile(path: String) = applicationEnvironment.jarFileSystem.findFileByPath(path)
private fun findLocalDirectory(root: JvmContentRoot): VirtualFile? {
val path = root.file
val localFile = findLocalDirectory(path.absolutePath)
@@ -33,8 +33,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
@@ -52,6 +51,7 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.addKotlinSourceRoots
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.modules.TargetId
@@ -164,6 +164,22 @@ object KotlinToJVMBytecodeCompiler {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
writeOutput(state.configuration, state.factory, null)
}
if (projectConfiguration.getBoolean(JVMConfigurationKeys.USE_JAVAC)) {
val singleModule = chunk.singleOrNull()
if (singleModule != null) {
return JavacWrapper.getInstance(environment.project).use {
it.compile(File(singleModule.getOutputDirectory()))
}
}
else {
projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).let {
it.report(WARNING, "A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). -Xuse-javac option couldn't be used to compile java files")
}
JavacWrapper.getInstance(environment.project).close()
}
}
return true
}
finally {
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.jvm.config
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.ContentRoot
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.KotlinSourceRoot
import java.io.File
data class JvmClasspathRoot(override val file: File): JvmContentRoot
@@ -46,3 +47,10 @@ val CompilerConfiguration.jvmClasspathRoots: List<File>
@JvmOverloads fun CompilerConfiguration.addJavaSourceRoots(files: List<File>, packagePrefix: String? = null): Unit =
files.forEach { addJavaSourceRoot(it, packagePrefix) }
val CompilerConfiguration.javaSourceRoots: Set<String>
get() = get(JVMConfigurationKeys.CONTENT_ROOTS)
?.mapNotNullTo(hashSetOf<String>()) {
(it as? KotlinSourceRoot)?.path ?: (it as? JavaSourceRoot)?.file?.path
}
.orEmpty()