Replace reflection-based compiler arguments copying with generated code

Using of Kotlin reflection for simple operations like bean management is very slow

First time initialization time: 261 ms for `copyBean(K2JVMCompilerArguments())`
Subsequent calls of `copyBean(K2JVMCompilerArguments())` take 1.7 ms per call

Unfortunately compiler argument handling is also used in Kotlin IntelliJ plugin
to parse facet settings. Big projects may have thousands of Kotlin facets

The same `ArgumentUtilsKt.copyProperties` frame is seen across various freezes:
IDEA-252440 2-3 minutes freeze on Kotlin project reimporting in last 203 eap
IDEA-253107 A lot of short freezes (1-3 sec) during Kotlin project development
KTIJ-23501 Make main run configuration detection lighter
KTIJ-22435 Unresponsive UI with 100% cpu

Reflection issue:
KT-56358 KClasses.getMemberProperties takes too much time

This commit replaces all reflection stuff with a simple code generation
Now `K2JVMCompilerArguments().clone()` goes to hard-to-measure time
This commit is contained in:
Leonid Shalupov
2023-03-08 18:20:51 +01:00
parent 56557fb8ff
commit 7480befe32
34 changed files with 744 additions and 75 deletions
@@ -0,0 +1,24 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Generate Compiler Arguments Copy" type="GradleRunConfiguration" factoryName="Gradle" folderName="Generators">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$/generators" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="generateCompilerArgumentsCopy" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<ForceTestExec>false</ForceTestExec>
<method v="2" />
</configuration>
</component>
+4 -1
View File
@@ -20,7 +20,10 @@ dependencies {
}
sourceSets {
"main" { projectDefault() }
"main" {
projectDefault()
generatedDir()
}
"test" {}
}
@@ -0,0 +1,88 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.cli.common.arguments
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyCommonCompilerArguments(from: CommonCompilerArguments, to: CommonCompilerArguments): CommonCompilerArguments {
copyCommonToolArguments(from, to)
to.allowAnyScriptsInSourceRoots = from.allowAnyScriptsInSourceRoots
to.allowKotlinPackage = from.allowKotlinPackage
to.allowResultReturnType = from.allowResultReturnType
to.apiVersion = from.apiVersion
to.autoAdvanceApiVersion = from.autoAdvanceApiVersion
to.autoAdvanceLanguageVersion = from.autoAdvanceLanguageVersion
to.builtInsFromSources = from.builtInsFromSources
to.checkPhaseConditions = from.checkPhaseConditions
to.checkStickyPhaseConditions = from.checkStickyPhaseConditions
to.commonSources = from.commonSources?.copyOf()
to.contextReceivers = from.contextReceivers
to.disableDefaultScriptingPlugin = from.disableDefaultScriptingPlugin
to.disablePhases = from.disablePhases?.copyOf()
to.disableUltraLightClasses = from.disableUltraLightClasses
to.dumpDirectory = from.dumpDirectory
to.dumpOnlyFqName = from.dumpOnlyFqName
to.dumpPerf = from.dumpPerf
to.effectSystem = from.effectSystem
to.enableBuilderInference = from.enableBuilderInference
to.enableSignatureClashChecks = from.enableSignatureClashChecks
to.expectActualLinker = from.expectActualLinker
to.experimental = from.experimental?.copyOf()
to.explicitApi = from.explicitApi
to.extendedCompilerChecks = from.extendedCompilerChecks
to.fragmentRefines = from.fragmentRefines?.copyOf()
to.fragmentSources = from.fragmentSources?.copyOf()
to.fragments = from.fragments?.copyOf()
to.ignoreConstOptimizationErrors = from.ignoreConstOptimizationErrors
to.incrementalCompilation = from.incrementalCompilation
to.inferenceCompatibility = from.inferenceCompatibility
to.inlineClasses = from.inlineClasses
to.intellijPluginRoot = from.intellijPluginRoot
to.kotlinHome = from.kotlinHome
to.languageVersion = from.languageVersion
to.legacySmartCastAfterTry = from.legacySmartCastAfterTry
to.listPhases = from.listPhases
to.metadataVersion = from.metadataVersion
to.multiPlatform = from.multiPlatform
to.newInference = from.newInference
to.noCheckActual = from.noCheckActual
to.noInline = from.noInline
to.normalizeAbsolutePath = from.normalizeAbsolutePath
to.optIn = from.optIn?.copyOf()
to.phasesToDump = from.phasesToDump?.copyOf()
to.phasesToDumpAfter = from.phasesToDumpAfter?.copyOf()
to.phasesToDumpBefore = from.phasesToDumpBefore?.copyOf()
to.phasesToValidate = from.phasesToValidate?.copyOf()
to.phasesToValidateAfter = from.phasesToValidateAfter?.copyOf()
to.phasesToValidateBefore = from.phasesToValidateBefore?.copyOf()
to.pluginClasspaths = from.pluginClasspaths?.copyOf()
to.pluginConfigurations = from.pluginConfigurations?.copyOf()
to.pluginOptions = from.pluginOptions?.copyOf()
to.profilePhases = from.profilePhases
to.progressiveMode = from.progressiveMode
to.properIeee754Comparisons = from.properIeee754Comparisons
to.readDeserializedContracts = from.readDeserializedContracts
to.relativePathBases = from.relativePathBases?.copyOf()
to.renderInternalDiagnosticNames = from.renderInternalDiagnosticNames
to.reportOutputFiles = from.reportOutputFiles
to.reportPerf = from.reportPerf
to.script = from.script
to.selfUpperBoundInference = from.selfUpperBoundInference
to.skipMetadataVersionCheck = from.skipMetadataVersionCheck
to.skipPrereleaseCheck = from.skipPrereleaseCheck
to.suppressVersionWarnings = from.suppressVersionWarnings
to.unrestrictedBuilderInference = from.unrestrictedBuilderInference
to.useExperimental = from.useExperimental?.copyOf()
to.useFirExtendedCheckers = from.useFirExtendedCheckers
to.useFirIC = from.useFirIC
to.useFirLT = from.useFirLT
to.useK2 = from.useK2
to.useMixedNamedArguments = from.useMixedNamedArguments
to.verbosePhases = from.verbosePhases?.copyOf()
return to
}
@@ -0,0 +1,21 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.cli.common.arguments
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyCommonToolArguments(from: CommonToolArguments, to: CommonToolArguments): CommonToolArguments {
to.allWarningsAsErrors = from.allWarningsAsErrors
to.extraHelp = from.extraHelp
to.freeArgs = from.freeArgs
to.help = from.help
to.internalArguments = from.internalArguments
to.suppressWarnings = from.suppressWarnings
to.verbose = from.verbose
to.version = from.version
return to
}
@@ -0,0 +1,74 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.cli.common.arguments
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyK2JSCompilerArguments(from: K2JSCompilerArguments, to: K2JSCompilerArguments): K2JSCompilerArguments {
copyCommonCompilerArguments(from, to)
to.cacheDirectory = from.cacheDirectory
to.enableJsScripting = from.enableJsScripting
to.errorTolerancePolicy = from.errorTolerancePolicy
to.extensionFunctionsInExternals = from.extensionFunctionsInExternals
to.fakeOverrideValidator = from.fakeOverrideValidator
to.forceDeprecatedLegacyCompilerUsage = from.forceDeprecatedLegacyCompilerUsage
to.friendModules = from.friendModules
to.friendModulesDisabled = from.friendModulesDisabled
to.generateDts = from.generateDts
to.generatePolyfills = from.generatePolyfills
to.includes = from.includes
to.irBaseClassInMetadata = from.irBaseClassInMetadata
to.irBuildCache = from.irBuildCache
to.irDce = from.irDce
to.irDcePrintReachabilityInfo = from.irDcePrintReachabilityInfo
to.irDceRuntimeDiagnostic = from.irDceRuntimeDiagnostic
to.irGenerateInlineAnonymousFunctions = from.irGenerateInlineAnonymousFunctions
to.irKeep = from.irKeep
to.irMinimizedMemberNames = from.irMinimizedMemberNames
to.irModuleName = from.irModuleName
to.irNewIr2Js = from.irNewIr2Js
to.irOnly = from.irOnly
to.irPerFile = from.irPerFile
to.irPerModule = from.irPerModule
to.irPerModuleOutputName = from.irPerModuleOutputName
to.irProduceJs = from.irProduceJs
to.irProduceKlibDir = from.irProduceKlibDir
to.irProduceKlibFile = from.irProduceKlibFile
to.irPropertyLazyInitialization = from.irPropertyLazyInitialization
to.irSafeExternalBoolean = from.irSafeExternalBoolean
to.irSafeExternalBooleanDiagnostic = from.irSafeExternalBooleanDiagnostic
to.libraries = from.libraries
to.main = from.main
to.metaInfo = from.metaInfo
to.metadataOnly = from.metadataOnly
to.moduleKind = from.moduleKind
to.moduleName = from.moduleName
to.noStdlib = from.noStdlib
to.outputDir = from.outputDir
to.outputFile = from.outputFile
to.outputPostfix = from.outputPostfix
to.outputPrefix = from.outputPrefix
to.partialLinkageLogLevel = from.partialLinkageLogLevel
to.partialLinkageMode = from.partialLinkageMode
to.sourceMap = from.sourceMap
to.sourceMapBaseDirs = from.sourceMapBaseDirs
to.sourceMapEmbedSources = from.sourceMapEmbedSources
to.sourceMapNamesPolicy = from.sourceMapNamesPolicy
to.sourceMapPrefix = from.sourceMapPrefix
to.strictImplicitExportType = from.strictImplicitExportType
to.target = from.target
to.typedArrays = from.typedArrays
to.useEsClasses = from.useEsClasses
to.wasm = from.wasm
to.wasmDebug = from.wasmDebug
to.wasmEnableArrayRangeChecks = from.wasmEnableArrayRangeChecks
to.wasmEnableAsserts = from.wasmEnableAsserts
to.wasmGenerateWat = from.wasmGenerateWat
to.wasmKClassFqn = from.wasmKClassFqn
return to
}
@@ -0,0 +1,20 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.cli.common.arguments
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyK2JSDceArguments(from: K2JSDceArguments, to: K2JSDceArguments): K2JSDceArguments {
copyCommonToolArguments(from, to)
to.declarationsToKeep = from.declarationsToKeep?.copyOf()
to.devMode = from.devMode
to.devModeOverwritingStrategy = from.devModeOverwritingStrategy
to.outputDirectory = from.outputDirectory
to.printReachabilityInfo = from.printReachabilityInfo
return to
}
@@ -0,0 +1,91 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.cli.common.arguments
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyK2JVMCompilerArguments(from: K2JVMCompilerArguments, to: K2JVMCompilerArguments): K2JVMCompilerArguments {
copyCommonCompilerArguments(from, to)
to.abiStability = from.abiStability
to.additionalJavaModules = from.additionalJavaModules?.copyOf()
to.allowNoSourceFiles = from.allowNoSourceFiles
to.allowUnstableDependencies = from.allowUnstableDependencies
to.assertionsMode = from.assertionsMode
to.backendThreads = from.backendThreads
to.buildFile = from.buildFile
to.classpath = from.classpath
to.compileJava = from.compileJava
to.declarationsOutputPath = from.declarationsOutputPath
to.defaultScriptExtension = from.defaultScriptExtension
to.destination = from.destination
to.disableStandardScript = from.disableStandardScript
to.doNotClearBindingContext = from.doNotClearBindingContext
to.emitJvmTypeAnnotations = from.emitJvmTypeAnnotations
to.enableDebugMode = from.enableDebugMode
to.enableIrInliner = from.enableIrInliner
to.enableJvmPreview = from.enableJvmPreview
to.enhanceTypeParameterTypesToDefNotNull = from.enhanceTypeParameterTypesToDefNotNull
to.expression = from.expression
to.friendPaths = from.friendPaths?.copyOf()
to.includeRuntime = from.includeRuntime
to.inheritMultifileParts = from.inheritMultifileParts
to.javaModulePath = from.javaModulePath
to.javaPackagePrefix = from.javaPackagePrefix
to.javaParameters = from.javaParameters
to.javaSourceRoots = from.javaSourceRoots?.copyOf()
to.javacArguments = from.javacArguments?.copyOf()
to.jdkHome = from.jdkHome
to.jdkRelease = from.jdkRelease
to.jspecifyAnnotations = from.jspecifyAnnotations
to.jsr305 = from.jsr305?.copyOf()
to.jvmDefault = from.jvmDefault
to.jvmTarget = from.jvmTarget
to.klibLibraries = from.klibLibraries
to.lambdas = from.lambdas
to.linkViaSignatures = from.linkViaSignatures
to.moduleName = from.moduleName
to.noCallAssertions = from.noCallAssertions
to.noJdk = from.noJdk
to.noKotlinNothingValueException = from.noKotlinNothingValueException
to.noNewJavaAnnotationTargets = from.noNewJavaAnnotationTargets
to.noOptimize = from.noOptimize
to.noOptimizedCallableReferences = from.noOptimizedCallableReferences
to.noParamAssertions = from.noParamAssertions
to.noReceiverAssertions = from.noReceiverAssertions
to.noReflect = from.noReflect
to.noResetJarTimestamps = from.noResetJarTimestamps
to.noSourceDebugExtension = from.noSourceDebugExtension
to.noStdlib = from.noStdlib
to.noUnifiedNullChecks = from.noUnifiedNullChecks
to.nullabilityAnnotations = from.nullabilityAnnotations?.copyOf()
to.oldInnerClassesLogic = from.oldInnerClassesLogic
to.profileCompilerCommand = from.profileCompilerCommand
to.repeatCompileModules = from.repeatCompileModules
to.samConversions = from.samConversions
to.sanitizeParentheses = from.sanitizeParentheses
to.scriptResolverEnvironment = from.scriptResolverEnvironment?.copyOf()
to.scriptTemplates = from.scriptTemplates?.copyOf()
to.serializeIr = from.serializeIr
to.strictMetadataVersionSemantics = from.strictMetadataVersionSemantics
to.stringConcat = from.stringConcat
to.supportCompatqualCheckerFrameworkAnnotations = from.supportCompatqualCheckerFrameworkAnnotations
to.suppressDeprecatedJvmTargetWarning = from.suppressDeprecatedJvmTargetWarning
to.suppressMissingBuiltinsError = from.suppressMissingBuiltinsError
to.typeEnhancementImprovementsInStrictMode = from.typeEnhancementImprovementsInStrictMode
to.useFastJarFileSystem = from.useFastJarFileSystem
to.useIR = from.useIR
to.useJavac = from.useJavac
to.useOldBackend = from.useOldBackend
to.useOldClassFilesReading = from.useOldClassFilesReading
to.useOldInlineClassesManglingScheme = from.useOldInlineClassesManglingScheme
to.useTypeTable = from.useTypeTable
to.validateBytecode = from.validateBytecode
to.validateIr = from.validateIr
to.valueClasses = from.valueClasses
return to
}
@@ -0,0 +1,21 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.cli.common.arguments
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyK2MetadataCompilerArguments(from: K2MetadataCompilerArguments, to: K2MetadataCompilerArguments): K2MetadataCompilerArguments {
copyCommonCompilerArguments(from, to)
to.classpath = from.classpath
to.destination = from.destination
to.enabledInJps = from.enabledInJps
to.friendPaths = from.friendPaths?.copyOf()
to.moduleName = from.moduleName
to.refinesPaths = from.refinesPaths?.copyOf()
return to
}
@@ -0,0 +1,105 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.cli.common.arguments
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyK2NativeCompilerArguments(from: K2NativeCompilerArguments, to: K2NativeCompilerArguments): K2NativeCompilerArguments {
copyCommonCompilerArguments(from, to)
to.allocator = from.allocator
to.autoCacheDir = from.autoCacheDir
to.autoCacheableFrom = from.autoCacheableFrom?.copyOf()
to.backendThreads = from.backendThreads
to.binaryOptions = from.binaryOptions?.copyOf()
to.bundleId = from.bundleId
to.cacheDirectories = from.cacheDirectories?.copyOf()
to.cachedLibraries = from.cachedLibraries?.copyOf()
to.checkDependencies = from.checkDependencies
to.checkExternalCalls = from.checkExternalCalls
to.clangOptions = from.clangOptions?.copyOf()
to.compileFromBitcode = from.compileFromBitcode
to.coverage = from.coverage
to.coverageFile = from.coverageFile
to.coveredLibraries = from.coveredLibraries?.copyOf()
to.debug = from.debug
to.debugInfoFormatVersion = from.debugInfoFormatVersion
to.debugPrefixMap = from.debugPrefixMap?.copyOf()
to.destroyRuntimeMode = from.destroyRuntimeMode
to.embedBitcode = from.embedBitcode
to.embedBitcodeMarker = from.embedBitcodeMarker
to.emitLazyObjCHeader = from.emitLazyObjCHeader
to.enableAssertions = from.enableAssertions
to.exportKDoc = from.exportKDoc
to.exportedLibraries = from.exportedLibraries?.copyOf()
to.externalDependencies = from.externalDependencies
to.fakeOverrideValidator = from.fakeOverrideValidator
to.filesToCache = from.filesToCache?.copyOf()
to.frameworkImportHeaders = from.frameworkImportHeaders?.copyOf()
to.friendModules = from.friendModules
to.gc = from.gc
to.generateDebugTrampolineString = from.generateDebugTrampolineString
to.generateNoExitTestRunner = from.generateNoExitTestRunner
to.generateTestRunner = from.generateTestRunner
to.generateWorkerTestRunner = from.generateWorkerTestRunner
to.includeBinaries = from.includeBinaries?.copyOf()
to.includes = from.includes?.copyOf()
to.lazyIrForCaches = from.lazyIrForCaches
to.libraries = from.libraries?.copyOf()
to.libraryToAddToCache = from.libraryToAddToCache
to.libraryVersion = from.libraryVersion
to.lightDebugDeprecated = from.lightDebugDeprecated
to.lightDebugString = from.lightDebugString
to.linkerArguments = from.linkerArguments?.copyOf()
to.listTargets = from.listTargets
to.llvmVariant = from.llvmVariant
to.mainPackage = from.mainPackage
to.makePerFileCache = from.makePerFileCache
to.manifestFile = from.manifestFile
to.memoryModel = from.memoryModel
to.metadataKlib = from.metadataKlib
to.moduleName = from.moduleName
to.nativeLibraries = from.nativeLibraries?.copyOf()
to.noObjcGenerics = from.noObjcGenerics
to.nodefaultlibs = from.nodefaultlibs
to.noendorsedlibs = from.noendorsedlibs
to.nomain = from.nomain
to.nopack = from.nopack
to.nostdlib = from.nostdlib
to.omitFrameworkBinary = from.omitFrameworkBinary
to.optimization = from.optimization
to.outputName = from.outputName
to.overrideKonanProperties = from.overrideKonanProperties?.copyOf()
to.partialLinkageLogLevel = from.partialLinkageLogLevel
to.partialLinkageMode = from.partialLinkageMode
to.preLinkCaches = from.preLinkCaches
to.printBitCode = from.printBitCode
to.printFiles = from.printFiles
to.printIr = from.printIr
to.produce = from.produce
to.propertyLazyInitialization = from.propertyLazyInitialization
to.purgeUserLibs = from.purgeUserLibs
to.refinesPaths = from.refinesPaths?.copyOf()
to.repositories = from.repositories?.copyOf()
to.runtimeFile = from.runtimeFile
to.runtimeLogs = from.runtimeLogs
to.saveDependenciesPath = from.saveDependenciesPath
to.saveLlvmIrAfter = from.saveLlvmIrAfter.copyOf()
to.saveLlvmIrDirectory = from.saveLlvmIrDirectory
to.serializedDependencies = from.serializedDependencies
to.shortModuleName = from.shortModuleName
to.singleLinkerArguments = from.singleLinkerArguments?.copyOf()
to.staticFramework = from.staticFramework
to.target = from.target
to.temporaryFilesDir = from.temporaryFilesDir
to.testDumpOutputPath = from.testDumpOutputPath
to.verifyBitCode = from.verifyBitCode
to.verifyCompiler = from.verifyCompiler
to.verifyIr = from.verifyIr
to.workerExceptionHandling = from.workerExceptionHandling
return to
}
@@ -1069,5 +1069,7 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
}
// Used only for serialize and deserialize settings. Don't use in other places!
class DummyImpl : CommonCompilerArguments()
class DummyImpl : CommonCompilerArguments() {
override fun copyOf(): Freezable = copyCommonCompilerArguments(this, DummyImpl())
}
}
@@ -23,7 +23,10 @@ abstract class Freezable {
private var frozen: Boolean = false
internal fun getInstanceWithFreezeStatus(value: Boolean) = if (value == frozen) this else copyBean(this).apply { frozen = value }
protected open fun copyOf(): Freezable = copyBean(this)
internal fun copyOfInternal(): Freezable = copyOf()
internal fun getInstanceWithFreezeStatus(value: Boolean) = if (value == frozen) this else copyOf().apply { frozen = value }
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Please use type safe extension functions")
fun frozen() = getInstanceWithFreezeStatus(true)
@@ -32,6 +35,9 @@ abstract class Freezable {
fun unfrozen() = getInstanceWithFreezeStatus(false)
}
@Suppress("UNCHECKED_CAST")
fun <T : Freezable> T.copyOf(): T = copyOfInternal() as T
@Suppress(
"UNCHECKED_CAST",
"EXTENSION_SHADOWED_BY_MEMBER", // It's false positive shadowed warning KT-21598
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.cli.common.arguments
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties
import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.*
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
@@ -654,6 +653,8 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
}
}
}
override fun copyOf(): Freezable = copyK2JSCompilerArguments(this, K2JSCompilerArguments())
}
fun K2JSCompilerArguments.isPreIrBackendDisabled(): Boolean =
@@ -80,6 +80,8 @@ class K2JSDceArguments : CommonToolArguments() {
checkFrozen()
field = if (value.isNullOrEmpty()) null else value
}
override fun copyOf(): Freezable = copyK2JSDceArguments(this, K2JSDceArguments())
}
object DevModeOverwritingStrategies {
@@ -923,4 +923,6 @@ Also sets `-jvm-target` value equal to the selected JDK version"""
)
}
}
override fun copyOf(): Freezable = copyK2JVMCompilerArguments(this, K2JVMCompilerArguments())
}
@@ -78,4 +78,6 @@ class K2MetadataCompilerArguments : CommonCompilerArguments() {
checkFrozen()
field = value
}
override fun copyOf(): Freezable = copyK2MetadataCompilerArguments(this, K2MetadataCompilerArguments())
}
@@ -476,6 +476,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
}
}
override fun copyOf(): Freezable = copyK2NativeCompilerArguments(this, K2NativeCompilerArguments())
companion object {
const val EMBED_BITCODE_FLAG = "-Xembed-bitcode"
const val EMBED_BITCODE_MARKER_FLAG = "-Xembed-bitcode-marker"
@@ -26,8 +26,7 @@ import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField
@Suppress("UNCHECKED_CAST")
fun <T : Any> copyBean(bean: T) = copyBeanTo(bean, bean::class.java.newInstance()!!)
fun <T : Any> copyBean(bean: T): T = copyBeanTo(bean, bean::class.java.newInstance())
@Suppress("UNCHECKED_CAST")
fun <T : Any> copyBeanTo(from: T, to: T, filter: ((KProperty1<T, Any?>, Any?) -> Boolean)? = null) =
+3
View File
@@ -78,6 +78,7 @@ dependencies {
testImplementation(projectTests(":compiler:tests-common-new"))
testImplementation(projectTests(":js:js.tests"))
testImplementation(project(":kotlin-gradle-compiler-types"))
testImplementation(project(":jps:jps-common"))
testApiJUnit5()
if (Ide.IJ()) {
@@ -91,6 +92,8 @@ projectTest(parallel = true) {
workingDir = rootDir
}
val generateCompilerArgumentsCopy by generator("org.jetbrains.kotlin.generators.arguments.GenerateCompilerArgumentsCopyKt")
val generateTests by generator("org.jetbrains.kotlin.generators.tests.GenerateTestsKt") {
dependsOn(":generators:analysis-api-generator:generateFrontendApiTests")
}
@@ -0,0 +1,129 @@
/*
* Copyright 2010-2023 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.generators.arguments
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.config.CompilerSettings
import org.jetbrains.kotlin.config.JpsPluginSettings
import org.jetbrains.kotlin.utils.Printer
import java.io.File
import kotlin.reflect.KClass
import kotlin.reflect.KClassifier
import kotlin.reflect.KType
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.superclasses
private val CLASSES_TO_PROCESS: List<KClass<*>> = listOf(
JpsPluginSettings::class,
CompilerSettings::class,
K2MetadataCompilerArguments::class,
K2NativeCompilerArguments::class,
K2JSDceArguments::class,
K2JSCompilerArguments::class,
K2JVMCompilerArguments::class,
)
private val PACKAGE_TO_DIR_MAPPING: Map<Package, File> = mapOf(
K2JVMCompilerArguments::class.java.`package` to File("compiler/cli/cli-common/gen"),
JpsPluginSettings::class.java.`package` to File("jps/jps-common/gen"),
)
fun generateCompilerArgumentsCopy(withPrinterToFile: (targetFile: File, Printer.() -> Unit) -> Unit) {
val processed = mutableSetOf<KClass<*>>()
for (klass in CLASSES_TO_PROCESS) {
generateRec(klass, withPrinterToFile, processed)
}
}
private fun generateRec(
klass: KClass<*>,
withPrinterToFile: (targetFile: File, Printer.() -> Unit) -> Unit,
processed: MutableSet<KClass<*>>,
) {
if (!processed.add(klass)) return
val klassName = klass.simpleName!!
val fqn = klass.qualifiedName!!
val `package` = klass.java.`package`
val destDir = PACKAGE_TO_DIR_MAPPING[`package`]!!.resolve(`package`.name.replace('.', '/'))
withPrinterToFile(destDir.resolve(klassName + "CopyGenerated.kt")) {
println(
"""
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package ${`package`.name}
""".trimIndent()
)
fun isSupportedImmutable(type: KType): Boolean {
val classifier: KClassifier = type.classifier!!
return when {
classifier is KClass<*> && classifier == List::class -> isSupportedImmutable(type.arguments.single().type!!)
classifier == InternalArgument::class -> true
classifier == Boolean::class -> true
classifier == Int::class -> true
classifier == String::class -> true
else -> false
}
}
println("@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)")
println("fun copy$klassName(from: $klassName, to: $klassName): $klassName {")
withIndent {
val superClasses: List<KClass<*>> = klass.superclasses.filterNot { it.java.isInterface }
check(superClasses.size < 2) {
"too many super classes in $klass: ${superClasses.joinToString()}"
}
val superKlass = superClasses.singleOrNull()
if (superKlass != null && superKlass != Freezable::class) {
generateRec(superKlass, withPrinterToFile, processed)
if (superKlass.java.`package` != `package`) {
print("${superKlass.java.`package`.name}.")
}
println("copy${superKlass.simpleName}(from, to)")
println()
}
val properties = collectProperties(klass, false)
for (property in properties.filter { klass.declaredMemberProperties.contains(it) }) {
val type = property.returnType
val classifier: KClassifier = type.classifier!!
when {
// Please add cases on the go
// Please add a test to GenerateCompilerArgumentsCopyTest if the change is not trivial
classifier is KClass<*> && classifier.java.isArray -> {
val arrayElementType = type.arguments.single().type!!
val nullableMarker = if (type.isMarkedNullable) "?" else ""
when (arrayElementType.classifier) {
String::class -> println("to.${property.name} = from.${property.name}${nullableMarker}.copyOf()")
else -> error("Unsupported array element type $arrayElementType (member '${property.name}' of $fqn)")
}
}
isSupportedImmutable(type) -> println("to.${property.name} = from.${property.name}")
else -> error("Unsupported type to copy: $type (member '${property.name}' of $fqn)")
}
}
println()
println("return to")
}
println("}")
}
}
fun main() {
generateCompilerArgumentsCopy(::getPrinterToFile)
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2023 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.generators.arguments
import junit.framework.TestCase
import org.jetbrains.kotlin.cli.common.arguments.*
import java.lang.reflect.Modifier
import kotlin.reflect.jvm.javaField
import kotlin.test.assertContentEquals
class GenerateCompilerArgumentsCopyTest : TestCase() {
fun testCompilerArgumentsCopyFunctionsAreUpToDate() {
generateCompilerArgumentsCopy(::getPrinterForTests)
}
fun testCopyDoesNotCopyTransientFields() {
val a = K2JVMCompilerArguments()
a.errors = ArgumentParseErrors()
a.moduleName = "my module name"
val b = K2JVMCompilerArguments()
assertNull(b.errors)
assertNull(b.moduleName)
copyK2JVMCompilerArguments(a, b)
assertNull(b.errors)
assertEquals("my module name", b.moduleName)
}
fun testCopyDuplicatesArray() {
val a = K2JVMCompilerArguments()
a.additionalJavaModules = arrayOf("xxx")
val b = K2JVMCompilerArguments()
copyK2JVMCompilerArguments(a, b)
assertContentEquals(a.additionalJavaModules, b.additionalJavaModules)
assertNotSame(a.additionalJavaModules, b.additionalJavaModules)
b.additionalJavaModules!![0] = "yyy"
assertEquals("xxx", a.additionalJavaModules!![0])
}
fun testCollectPropertiesDoesNotReturnTransient() {
val errorProperty = CommonToolArguments::errors
assertTrue(Modifier.isTransient(errorProperty.javaField!!.modifiers))
val properties = collectProperties(CommonToolArguments::class, false)
assertFalse(properties.any { it.name == errorProperty.name })
}
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.generators.arguments
import org.jetbrains.kotlin.utils.Printer
import java.io.File
import java.io.PrintStream
fun generateGradleCompilerTypes(withPrinterToFile: (targetFile: File, Printer.() -> Unit) -> Unit) {
val destDir = File("libraries/tools/kotlin-gradle-compiler-types/src/generated/kotlin")
@@ -27,16 +26,5 @@ fun generateGradleCompilerTypes(withPrinterToFile: (targetFile: File, Printer.()
}
fun main() {
fun getPrinter(file: File, fn: Printer.() -> Unit) {
if (!file.exists()) {
file.parentFile.mkdirs()
file.createNewFile()
}
PrintStream(file.outputStream().buffered()).use {
val printer = Printer(it)
printer.fn()
}
}
generateGradleCompilerTypes(::getPrinter)
generateGradleCompilerTypes(::getPrinterToFile)
}
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.File
import java.io.PrintStream
import kotlin.reflect.KAnnotatedElement
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
@@ -145,18 +144,7 @@ fun generateKotlinGradleOptions(withPrinterToFile: (targetFile: File, Printer.()
}
fun main() {
fun getPrinter(file: File, fn: Printer.() -> Unit) {
if (!file.exists()) {
file.parentFile.mkdirs()
file.createNewFile()
}
PrintStream(file.outputStream()).use {
val printer = Printer(it)
printer.fn()
}
}
generateKotlinGradleOptions(::getPrinter)
generateKotlinGradleOptions(::getPrinterToFile)
}
private fun generateKotlinCommonToolOptions(
@@ -9,42 +9,14 @@ package org.jetbrains.kotlin.generators.arguments.test
import junit.framework.TestCase
import org.jetbrains.kotlin.generators.arguments.generateGradleCompilerTypes
import org.jetbrains.kotlin.generators.arguments.generateKotlinGradleOptions
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.utils.Printer
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import org.jetbrains.kotlin.generators.arguments.getPrinterForTests
class GenerateKotlinGradleOptionsTest : TestCase() {
fun testKotlinGradleOptionsAreUpToDate() {
fun getPrinter(file: File, fn: Printer.() -> Unit) {
val bytesOut = ByteArrayOutputStream()
PrintStream(bytesOut).use {
val printer = Printer(it)
printer.fn()
}
val upToDateContent = bytesOut.toString()
KtUsefulTestCase.assertSameLinesWithFile(file.absolutePath, upToDateContent)
}
generateKotlinGradleOptions(::getPrinter)
generateKotlinGradleOptions(::getPrinterForTests)
}
fun testKotlinGradleTypesAreUpToDate() {
fun getPrinter(file: File, fn: Printer.() -> Unit) {
val bytesOut = ByteArrayOutputStream()
PrintStream(bytesOut).use {
val printer = Printer(it)
printer.fn()
}
val upToDateContent = bytesOut.toString()
KtUsefulTestCase.assertSameLinesWithFile(file.absolutePath, upToDateContent)
}
generateGradleCompilerTypes(::getPrinter)
generateGradleCompilerTypes(::getPrinterForTests)
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2023 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.generators.arguments
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.utils.Printer
import java.io.File
import java.nio.file.Files
private fun printToString(fn: Printer.() -> Unit): String {
val builder = StringBuilder()
Printer(builder).fn()
return builder.toString()
}
fun getPrinterForTests(file: File, fn: Printer.() -> Unit) {
KtUsefulTestCase.assertSameLinesWithFile(file.absolutePath, printToString(fn))
}
fun getPrinterToFile(file: File, fn: Printer.() -> Unit) {
Files.createDirectories(file.toPath().parent)
file.writeText(printToString(fn))
}
+4 -1
View File
@@ -36,7 +36,10 @@ dependencies {
}
sourceSets {
"main" { projectDefault() }
"main" {
projectDefault()
generatedDir()
}
"test" { projectDefault() }
}
@@ -0,0 +1,18 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.config
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyCompilerSettings(from: CompilerSettings, to: CompilerSettings): CompilerSettings {
to.additionalArguments = from.additionalArguments
to.copyJsLibraryFiles = from.copyJsLibraryFiles
to.outputDirectoryForJsLibraryFiles = from.outputDirectoryForJsLibraryFiles
to.scriptTemplates = from.scriptTemplates
to.scriptTemplatesClasspath = from.scriptTemplatesClasspath
return to
}
@@ -0,0 +1,14 @@
@file:Suppress("unused", "DuplicatedCode")
// DO NOT EDIT MANUALLY!
// Generated by generators/tests/org/jetbrains/kotlin/generators/arguments/GenerateCompilerArgumentsCopy.kt
// To regenerate run 'generateCompilerArgumentsCopy' task
package org.jetbrains.kotlin.config
@OptIn(org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI::class)
fun copyJpsPluginSettings(from: JpsPluginSettings, to: JpsPluginSettings): JpsPluginSettings {
to.version = from.version
return to
}
@@ -50,6 +50,8 @@ class CompilerSettings : Freezable() {
val DEFAULT_ADDITIONAL_ARGUMENTS = ""
private val DEFAULT_OUTPUT_DIRECTORY = "lib"
}
override fun copyOf(): Freezable = copyCompilerSettings(this, CompilerSettings())
}
val CompilerSettings.additionalArgumentsAsList: List<String>
@@ -14,4 +14,6 @@ class JpsPluginSettings : Freezable() {
checkFrozen()
field = value
}
override fun copyOf(): Freezable = copyJpsPluginSettings(this, JpsPluginSettings())
}
@@ -177,7 +177,7 @@ class KotlinFacetSettings {
val compilerSettings = compilerSettings
mergedCompilerArguments = if (compilerArguments != null) {
copyBean(compilerArguments).apply {
compilerArguments.copyOf().apply {
if (compilerSettings != null) {
parseCommandLineArguments(compilerSettings.additionalArgumentsAsList, this)
}
@@ -364,14 +364,14 @@ private fun KotlinFacetSettings.writeConfig(element: Element) {
element.addContent(Element("testOutputPath").apply { addContent(FileUtilRt.toSystemIndependentName(it)) })
}
}
compilerSettings?.let { copyBean(it) }?.let {
compilerSettings?.copyOf()?.let {
it.convertPathsToSystemIndependent()
buildChildElement(element, "compilerSettings", it, filter)
}
}
private fun KotlinFacetSettings.writeV2toV4Config(element: Element) = writeConfig(element).apply {
compilerArguments?.let { copyBean(it) }?.let {
compilerArguments?.copyOf()?.let {
it.convertPathsToSystemIndependent()
val compilerArgumentsXml = buildChildElement(element, "compilerArguments", it, SkipDefaultsSerializationFilter())
compilerArgumentsXml.dropVersionsIfNecessary(it)
@@ -379,7 +379,7 @@ private fun KotlinFacetSettings.writeV2toV4Config(element: Element) = writeConfi
}
private fun KotlinFacetSettings.writeLatestConfig(element: Element) = writeConfig(element).apply {
compilerArguments?.let { copyBean(it) }?.let {
compilerArguments?.copyOf()?.let {
it.convertPathsToSystemIndependent()
val compilerArgumentsXml = CompilerArgumentsSerializerV5(it).serializeTo(element)
compilerArgumentsXml.dropVersionsIfNecessary(it)
@@ -9,6 +9,8 @@
package org.jetbrains.kotlin.platform.impl
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.Freezable
import org.jetbrains.kotlin.cli.common.arguments.copyCommonCompilerArguments
import org.jetbrains.kotlin.platform.IdePlatform
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatform
@@ -57,7 +59,9 @@ object NativeIdePlatformKind : IdePlatformKind() {
}
// These are fake compiler arguments for Kotlin/Native - only for usage within IDEA plugin:
class FakeK2NativeCompilerArguments : CommonCompilerArguments()
class FakeK2NativeCompilerArguments : CommonCompilerArguments() {
override fun copyOf(): Freezable = copyCommonCompilerArguments(this, FakeK2NativeCompilerArguments())
}
val IdePlatformKind?.isKotlinNative
get() = this is NativeIdePlatformKind
@@ -10,7 +10,9 @@ import org.jetbrains.jps.model.ex.JpsElementChildRoleBase
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.CompilerSettings
import org.jetbrains.kotlin.config.KotlinFacetSettings
import org.jetbrains.kotlin.config.KotlinModuleKind
import org.jetbrains.kotlin.platform.TargetPlatform
val JpsModule.kotlinFacet: JpsKotlinFacetModuleExtension?
@@ -70,7 +72,7 @@ val JpsModule.testOutputFilePath: String?
val JpsModule.kotlinCompilerSettings: CompilerSettings
get() {
val defaultSettings = copyBean(project.kotlinCompilerSettings)
val defaultSettings = project.kotlinCompilerSettings.copyOf()
val facetSettings = kotlinFacet?.settings ?: return defaultSettings
if (facetSettings.useProjectSettings) return defaultSettings
return facetSettings.compilerSettings ?: defaultSettings
@@ -90,7 +92,7 @@ val JpsModule.k2JvmCompilerArguments
private inline fun <reified T : CommonCompilerArguments> JpsModule.getCompilerArguments(): T {
val projectSettings = project.kotlinCompilerSettingsContainer[T::class.java]
val projectSettingsCopy = copyBean(projectSettings)
val projectSettingsCopy = projectSettings.copyOf()
val facetSettings = kotlinFacet?.settings ?: return projectSettingsCopy
if (facetSettings.useProjectSettings) return projectSettingsCopy
@@ -21,8 +21,7 @@ import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.*
import org.gradle.process.ExecOperations
import org.gradle.work.NormalizeLineEndings
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.compilerRunner.*
import org.jetbrains.kotlin.compilerRunner.KotlinNativeCInteropRunner.Companion.run
import org.jetbrains.kotlin.gradle.dsl.*
@@ -300,7 +299,9 @@ abstract class AbstractKotlinNativeCompile<
}
// Remove it once actual K2NativeCompilerArguments will be available without 'kotlin.native.enabled = true' flag
class StubK2NativeCompilerArguments : CommonCompilerArguments()
class StubK2NativeCompilerArguments : CommonCompilerArguments() {
override fun copyOf(): Freezable = copyCommonCompilerArguments(this, StubK2NativeCompilerArguments())
}
/**
* A task producing a klibrary from a compilation.