org.jetbrains.kotlin.cli.common.arguments.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2024 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.cli.common
import com.intellij.ide.highlighter.JavaFileType
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.ManualLanguageFeatureSetting
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.KotlinPaths
import org.jetbrains.kotlin.utils.KotlinPathsFromHomeDir
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
fun CompilerConfiguration.setupCommonArguments(
arguments: CommonCompilerArguments,
createMetadataVersion: ((IntArray) -> BinaryVersion)? = null
) {
val messageCollector = getNotNull(CommonConfigurationKeys.MESSAGE_COLLECTOR_KEY)
put(CommonConfigurationKeys.DISABLE_INLINE, arguments.noInline)
put(CommonConfigurationKeys.USE_FIR_EXTENDED_CHECKERS, arguments.useFirExtendedCheckers)
put(CommonConfigurationKeys.METADATA_KLIB, arguments.metadataKlib)
putIfNotNull(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT, arguments.intellijPluginRoot)
put(CommonConfigurationKeys.REPORT_OUTPUT_FILES, arguments.reportOutputFiles)
put(CommonConfigurationKeys.INCREMENTAL_COMPILATION, incrementalCompilationIsEnabled(arguments))
put(CommonConfigurationKeys.ALLOW_ANY_SCRIPTS_IN_SOURCE_ROOTS, arguments.allowAnyScriptsInSourceRoots)
put(CommonConfigurationKeys.IGNORE_CONST_OPTIMIZATION_ERRORS, arguments.ignoreConstOptimizationErrors)
val irVerificationMode = arguments.verifyIr?.let { verifyIrString ->
IrVerificationMode.resolveMode(verifyIrString).also {
if (it == null) {
messageCollector.report(CompilerMessageSeverity.ERROR, "Unsupported IR verification mode $verifyIrString")
}
}
} ?: IrVerificationMode.NONE
put(CommonConfigurationKeys.VERIFY_IR, irVerificationMode)
if (arguments.verifyIrVisibility) {
put(CommonConfigurationKeys.ENABLE_IR_VISIBILITY_CHECKS, true)
if (irVerificationMode == IrVerificationMode.NONE) {
messageCollector.report(
CompilerMessageSeverity.WARNING,
"'-Xverify-ir-visibility' has no effect unless '-Xverify-ir=warning' or '-Xverify-ir=error' is specified"
)
}
}
if (arguments.verifyIrVisibilityAfterInlining) {
put(CommonConfigurationKeys.ENABLE_IR_VISIBILITY_CHECKS_AFTER_INLINING, true)
if (irVerificationMode == IrVerificationMode.NONE) {
messageCollector.report(
CompilerMessageSeverity.WARNING,
"'-Xverify-ir-visibility-after-inlining' has no effect unless '-Xverify-ir=warning' or '-Xverify-ir=error' is specified"
)
}
}
val metadataVersionString = arguments.metadataVersion
if (metadataVersionString != null) {
val versionArray = BinaryVersion.parseVersionArray(metadataVersionString)
when {
versionArray == null -> messageCollector.report(
CompilerMessageSeverity.ERROR, "Invalid metadata version: $metadataVersionString", null
)
createMetadataVersion == null -> throw IllegalStateException("Unable to create metadata version: missing argument")
else -> put(CommonConfigurationKeys.METADATA_VERSION, createMetadataVersion(versionArray))
}
}
switchToFallbackModeIfNecessary(arguments, messageCollector)
setupLanguageVersionSettings(arguments)
val usesK2 = arguments.useK2 || languageVersionSettings.languageVersion.usesK2
put(CommonConfigurationKeys.USE_FIR, usesK2)
put(CommonConfigurationKeys.USE_LIGHT_TREE, arguments.useFirLT)
buildHmppModuleStructure(arguments)?.let { put(CommonConfigurationKeys.HMPP_MODULE_STRUCTURE, it) }
}
private fun switchToFallbackModeIfNecessary(arguments: CommonCompilerArguments, messageCollector: MessageCollector) {
fun warn(message: String) {
if (!arguments.suppressVersionWarnings) messageCollector.report(CompilerMessageSeverity.STRONG_WARNING, message)
}
if (arguments !is K2JVMCompilerArguments) return
//coordinated with org.jetbrains.kotlin.incremental.CompilerRunnerUtils.isK1ForcedByKapt
val isK2 =
arguments.useK2 || (arguments.languageVersion?.startsWith('2') ?: (LanguageVersion.LATEST_STABLE >= LanguageVersion.KOTLIN_2_0))
val isKaptUsed = arguments.pluginOptions?.any { it.startsWith("plugin:org.jetbrains.kotlin.kapt3") } == true
when {
isK2 && isKaptUsed && !arguments.useKapt4 -> {
warn("Kapt currently doesn't support language version 2.0+. Falling back to 1.9.")
arguments.languageVersion = LanguageVersion.KOTLIN_1_9.versionString
if (arguments.apiVersion?.startsWith("2") == true) {
arguments.apiVersion = ApiVersion.KOTLIN_1_9.versionString
}
arguments.useK2 = false
arguments.skipMetadataVersionCheck = true
arguments.skipPrereleaseCheck = true
arguments.allowUnstableDependencies = true
}
arguments.useKapt4 -> warn(
if (isK2) "K2 kapt is an experimental feature. Use with caution."
else "-Xuse-kapt4 flag can be only used with language version 2.0+."
)
}
}
fun CompilerConfiguration.setupLanguageVersionSettings(arguments: CommonCompilerArguments) {
languageVersionSettings = arguments.toLanguageVersionSettings(getNotNull(CommonConfigurationKeys.MESSAGE_COLLECTOR_KEY))
}
const val KOTLIN_HOME_PROPERTY = "kotlin.home"
fun computeKotlinPaths(messageCollector: MessageCollector, arguments: CommonCompilerArguments): KotlinPaths? {
val kotlinHomeProperty = System.getProperty(KOTLIN_HOME_PROPERTY)
val kotlinHome = when {
arguments.kotlinHome != null -> File(arguments.kotlinHome!!)
kotlinHomeProperty != null -> File(kotlinHomeProperty)
else -> null
}
return when {
kotlinHome == null -> PathUtil.kotlinPathsForCompiler
kotlinHome.isDirectory -> KotlinPathsFromHomeDir(kotlinHome)
else -> {
messageCollector.report(CompilerMessageSeverity.ERROR, "Kotlin home does not exist or is not a directory: $kotlinHome", null)
null
}
}?.also {
messageCollector.report(CompilerMessageSeverity.LOGGING, "Using Kotlin home directory " + it.homePath, null)
}
}
fun MessageCollector.reportArgumentParseProblems(arguments: CommonToolArguments) {
val errors = arguments.errors ?: return
for (flag in errors.unknownExtraFlags) {
report(CompilerMessageSeverity.STRONG_WARNING, "Flag is not supported by this version of the compiler: $flag")
}
for (argument in errors.extraArgumentsPassedInObsoleteForm) {
report(
CompilerMessageSeverity.STRONG_WARNING,
"Advanced option value is passed in an obsolete form. Please use the '=' character to specify the value: $argument=..."
)
}
for ((key, value) in errors.duplicateArguments) {
report(CompilerMessageSeverity.STRONG_WARNING, "Argument $key is passed multiple times. Only the last value will be used: $value")
}
for ((deprecatedName, newName) in errors.deprecatedArguments) {
report(CompilerMessageSeverity.STRONG_WARNING, "Argument $deprecatedName is deprecated. Please use $newName instead")
}
for (argfileError in errors.argfileErrors) {
report(CompilerMessageSeverity.STRONG_WARNING, argfileError)
}
reportUnsafeInternalArgumentsIfAny(arguments)
for (internalArgumentsError in errors.internalArgumentsParsingProblems) {
report(CompilerMessageSeverity.STRONG_WARNING, internalArgumentsError)
}
}
private fun MessageCollector.reportUnsafeInternalArgumentsIfAny(arguments: CommonToolArguments) {
val unsafeArguments = arguments.internalArguments.filterNot {
// -XXLanguage which turns on BUG_FIX considered safe
it is ManualLanguageFeatureSetting && it.languageFeature.kind == LanguageFeature.Kind.BUG_FIX && it.state == LanguageFeature.State.ENABLED
}
if (unsafeArguments.isNotEmpty()) {
val unsafeArgumentsString = unsafeArguments.joinToString(prefix = "\n", postfix = "\n\n", separator = "\n") {
it.stringRepresentation
}
report(
CompilerMessageSeverity.STRONG_WARNING,
"ATTENTION!\n" +
"This build uses unsafe internal compiler arguments:\n" +
unsafeArgumentsString +
"This mode is not recommended for production use,\n" +
"as no stability/compatibility guarantees are given on\n" +
"compiler or generated code. Use it at your own risk!\n"
)
}
}
private fun CompilerConfiguration.buildHmppModuleStructure(arguments: CommonCompilerArguments): HmppCliModuleStructure? {
val rawFragments = arguments.fragments
val rawFragmentSources = arguments.fragmentSources
val rawFragmentRefines = arguments.fragmentRefines
val messageCollector = getNotNull(CommonConfigurationKeys.MESSAGE_COLLECTOR_KEY)
fun reportError(message: String) {
messageCollector.report(CompilerMessageSeverity.ERROR, message)
}
fun reportWarning(message: String) {
messageCollector.report(CompilerMessageSeverity.WARNING, message)
}
if (rawFragments == null) {
if (rawFragmentRefines != null) {
reportError("-Xfragment-refines flag can not be used without -Xfragments")
}
return null
}
if (!languageVersionSettings.languageVersion.usesK2) {
reportWarning("-Xfragments flag is not supported for language version < 2.0")
return null
}
val sourcesByFragmentName: Map> = rawFragments.associateWith { mutableSetOf() }.apply {
rawFragmentSources.orEmpty().forEach { rawFragmentSourceArg ->
val split = rawFragmentSourceArg.split(":", limit = 2)
if (split.size < 2) {
reportError(
"Incorrect syntax for -Xfragment-sources argument. " +
"`: