[FIR] Support .jar output with -Xuse-fir flag

To proper support we need to fully implement main function detector,
  see KT-44557

^KT-42868 Fixed
This commit is contained in:
Dmitriy Novozhilov
2021-09-20 12:59:23 +03:00
committed by teamcityserver
parent 9a5a3bfdfb
commit 8286927e8c
@@ -22,16 +22,15 @@ import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.CodegenFactory import org.jetbrains.kotlin.codegen.CodegenFactory
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.fir.DependencyListForCliModule import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.backend.Fir2IrResult import org.jetbrains.kotlin.fir.backend.Fir2IrResult
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.pipeline.buildFirFromKtFiles import org.jetbrains.kotlin.fir.pipeline.buildFirFromKtFiles
import org.jetbrains.kotlin.fir.pipeline.convertToIr import org.jetbrains.kotlin.fir.pipeline.convertToIr
import org.jetbrains.kotlin.fir.pipeline.runCheckers import org.jetbrains.kotlin.fir.pipeline.runCheckers
@@ -41,6 +40,11 @@ import org.jetbrains.kotlin.fir.session.FirSessionFactory
import org.jetbrains.kotlin.fir.session.FirSessionFactory.createSessionWithDependencies import org.jetbrains.kotlin.fir.session.FirSessionFactory.createSessionWithDependencies
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
import org.jetbrains.kotlin.fir.types.arrayElementType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isArrayType
import org.jetbrains.kotlin.fir.types.isString
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackagePartProvider import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackagePartProvider
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.Module import org.jetbrains.kotlin.modules.Module
@@ -78,7 +82,7 @@ object FirKotlinToJvmBytecodeCompiler {
"ATTENTION!\n This build uses in-dev FIR: \n -Xuse-fir" "ATTENTION!\n This build uses in-dev FIR: \n -Xuse-fir"
) )
val outputs = newLinkedHashMapWithExpectedSize<Module, GenerationState>(chunk.size) val outputs = newLinkedHashMapWithExpectedSize<Module, Pair<FirResult, GenerationState>>(chunk.size)
val targetIds = projectConfiguration.get(JVMConfigurationKeys.MODULES)?.map(::TargetId) val targetIds = projectConfiguration.get(JVMConfigurationKeys.MODULES)?.map(::TargetId)
val incrementalComponents = projectConfiguration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS) val incrementalComponents = projectConfiguration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
val isMultiModuleChunk = chunk.size > 1 val isMultiModuleChunk = chunk.size > 1
@@ -102,17 +106,21 @@ object FirKotlinToJvmBytecodeCompiler {
outputs[module] = generationState outputs[module] = generationState
} }
val mainClassFqName: FqName? = val mainClassFqName: FqName? = runIf(chunk.size == 1 && projectConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
if (chunk.size == 1 && projectConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) val firResult = outputs.values.single().first
TODO(".jar output is not yet supported for -Xuse-fir: KT-42868") findMainClass(firResult)
else null }
return writeOutputs( return writeOutputs(
(projectEnvironment as? PsiBasedProjectEnvironment)?.project, projectConfiguration, chunk, outputs, mainClassFqName (projectEnvironment as? PsiBasedProjectEnvironment)?.project,
projectConfiguration,
chunk,
outputs.mapValues { (_, value) -> value.second },
mainClassFqName
) )
} }
private fun CompilationContext.compileModule(): GenerationState? { private fun CompilationContext.compileModule(): Pair<FirResult, GenerationState>? {
performanceManager?.notifyAnalysisStarted() performanceManager?.notifyAnalysisStarted()
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
@@ -141,7 +149,7 @@ object FirKotlinToJvmBytecodeCompiler {
performanceManager?.notifyGenerationFinished() performanceManager?.notifyGenerationFinished()
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
return generationState return firResult to generationState
} }
private class FirResult( private class FirResult(
@@ -335,4 +343,38 @@ object FirKotlinToJvmBytecodeCompiler {
val incrementalComponents: IncrementalCompilationComponents?, val incrementalComponents: IncrementalCompilationComponents?,
val extendedAnalysisMode: Boolean val extendedAnalysisMode: Boolean
) )
private fun findMainClass(firResult: FirResult): FqName? {
// TODO: replace with proper main function detector, KT-44557
val compatibleClasses = mutableListOf<FqName>()
val visitor = object : FirVisitorVoid() {
lateinit var file: FirFile
override fun visitElement(element: FirElement) {}
override fun visitFile(file: FirFile) {
this.file = file
file.acceptChildren(this)
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
if (simpleFunction.name.asString() != "main") return
if (simpleFunction.typeParameters.isNotEmpty()) return
when (simpleFunction.valueParameters.size) {
0 -> {}
1 -> {
val parameterType = simpleFunction.valueParameters.single().returnTypeRef.coneType
if (!parameterType.isArrayType || parameterType.arrayElementType()?.isString != true) return
}
else -> return
}
compatibleClasses += FqName.fromSegments(
file.packageFqName.pathSegments().map { it.asString() } + "${file.name.removeSuffix(".kt").capitalize()}Kt"
)
}
}
firResult.fir.forEach { it.accept(visitor) }
return compatibleClasses.singleOrNull()
}
} }