K2 Scripting: add proper CFG processing for scripts
#KT-59683 fixed #KT-63328 fixed
This commit is contained in:
committed by
Space Team
parent
a69eaa0ea3
commit
12da3d2b9f
+9
@@ -858,4 +858,13 @@ private abstract class FirLazyBodiesCalculatorTransformer : FirTransformer<Persi
|
||||
|
||||
return codeFragment
|
||||
}
|
||||
|
||||
override fun transformScript(script: FirScript, data: PersistentList<FirRegularClass>): FirScript {
|
||||
for (declaration in script.declarations) {
|
||||
if (declaration !is FirAnonymousInitializer) continue
|
||||
declaration.accept(this, data)
|
||||
}
|
||||
|
||||
return script
|
||||
}
|
||||
}
|
||||
|
||||
+1
-21
@@ -10,15 +10,13 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveT
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.LLFirReturnTypeCalculatorWithJump
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isElementWhichShouldBeResolvedAsPartOfScript
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirElementWithResolveState
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformerDispatcher
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
|
||||
internal abstract class LLFirAbstractBodyTargetResolver(
|
||||
@@ -81,22 +79,4 @@ internal abstract class LLFirAbstractBodyTargetResolver(
|
||||
target.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
}
|
||||
|
||||
protected fun resolveScript(script: FirScript) {
|
||||
transformer.declarationsTransformer?.withScript(script) {
|
||||
script.parameters.forEach { it.transformSingle(transformer, ResolutionMode.ContextIndependent) }
|
||||
script.transformDeclarations(
|
||||
transformer = object : FirTransformer<Any?>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Any?): E {
|
||||
if (element !is FirDeclaration || !element.isElementWhichShouldBeResolvedAsPartOfScript) return element
|
||||
|
||||
transformer.firResolveContextCollector?.addDeclarationContext(element, transformer.context)
|
||||
return element.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
}
|
||||
},
|
||||
data = null,
|
||||
)
|
||||
|
||||
script
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+75
-27
@@ -18,9 +18,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirMo
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.*
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDelegatedConstructorIsResolved
|
||||
import org.jetbrains.kotlin.fir.FirElementWithResolveState
|
||||
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
@@ -28,20 +26,17 @@ import org.jetbrains.kotlin.fir.expressions.builder.buildLazyDelegatedConstructo
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildMultiDelegatedConstructorCall
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirLazyDelegatedConstructorCall
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildExplicitThisReference
|
||||
import org.jetbrains.kotlin.fir.resolve.FirCodeFragmentContext
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.codeFragmentContext
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.RealVariable
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isUsedInControlFlowGraphBuilderForClass
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isUsedInControlFlowGraphBuilderForFile
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isUsedInControlFlowGraphBuilderForScript
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractsDslNames
|
||||
@@ -50,6 +45,8 @@ import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.isResolved
|
||||
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment
|
||||
@@ -105,6 +102,7 @@ private class LLFirBodyTargetResolver(
|
||||
firResolveContextCollector = firResolveContextCollector,
|
||||
) {
|
||||
override val preserveCFGForClasses: Boolean get() = false
|
||||
override val buildCfgForScripts: Boolean get() = false
|
||||
override val buildCfgForFiles: Boolean get() = false
|
||||
|
||||
/**
|
||||
@@ -153,6 +151,12 @@ private class LLFirBodyTargetResolver(
|
||||
|
||||
return true
|
||||
}
|
||||
is FirScript -> {
|
||||
if (target.resolvePhase >= resolverPhase) return true
|
||||
// resolve properties so they are available for CFG building in resolveScript
|
||||
resolveMembersForControlFlowGraph(target)
|
||||
return false
|
||||
}
|
||||
is FirCodeFragment -> {
|
||||
resolveCodeFragmentContext(target)
|
||||
performCustomResolveUnderLock(target) {
|
||||
@@ -224,6 +228,35 @@ private class LLFirBodyTargetResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateControlFlowGraph(target: FirScript) {
|
||||
checkWithAttachment(
|
||||
target.controlFlowGraphReference == null,
|
||||
{ "'controlFlowGraphReference' should be 'null' if the script phase < $resolverPhase)" },
|
||||
) {
|
||||
withFirEntry("firScript", target)
|
||||
}
|
||||
|
||||
val dataFlowAnalyzer = transformer.declarationsTransformer.dataFlowAnalyzer
|
||||
dataFlowAnalyzer.enterScript(target, buildGraph = true)
|
||||
val controlFlowGraph = dataFlowAnalyzer.exitScript()
|
||||
?: errorWithAttachment("CFG should not be 'null' as 'buildGraph' is specified") {
|
||||
withFirEntry("firScript", target)
|
||||
}
|
||||
|
||||
target.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(controlFlowGraph))
|
||||
}
|
||||
|
||||
private fun resolveMembersForControlFlowGraph(target: FirScript) {
|
||||
withScript(target) {
|
||||
for (member in target.declarations) {
|
||||
if (member is FirControlFlowGraphOwner && member.isUsedInControlFlowGraphBuilderForScript && member !is FirAnonymousInitializer) {
|
||||
member.lazyResolveToPhase(resolverPhase.previous)
|
||||
performResolve(member)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveCodeFragmentContext(firCodeFragment: FirCodeFragment) {
|
||||
val ktCodeFragment = firCodeFragment.psi as? KtCodeFragment
|
||||
?: errorWithAttachment("Code fragment source not found") {
|
||||
@@ -281,12 +314,35 @@ private class LLFirBodyTargetResolver(
|
||||
|
||||
override fun rawResolve(target: FirElementWithResolveState) {
|
||||
when (target) {
|
||||
is FirScript -> target.let(::resolveScript)
|
||||
is FirScript -> {
|
||||
resolveScript(target)
|
||||
calculateControlFlowGraph(target)
|
||||
}
|
||||
|
||||
else -> super.rawResolve(target)
|
||||
}
|
||||
|
||||
LLFirDeclarationModificationService.bodyResolved(target, resolverPhase)
|
||||
}
|
||||
|
||||
protected fun resolveScript(script: FirScript) {
|
||||
transformer.declarationsTransformer.withScript(script) {
|
||||
script.parameters.forEach { it.transformSingle(transformer, ResolutionMode.ContextIndependent) }
|
||||
script.transformDeclarations(
|
||||
transformer = object : FirTransformer<Any?>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Any?): E {
|
||||
if (element !is FirDeclaration || !element.isElementWhichShouldBeResolvedAsPartOfScript) return element
|
||||
|
||||
transformer.firResolveContextCollector?.addDeclarationContext(element, transformer.context)
|
||||
return element.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
}
|
||||
},
|
||||
data = null,
|
||||
)
|
||||
|
||||
script
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object BodyStateKeepers {
|
||||
@@ -294,27 +350,19 @@ internal object BodyStateKeepers {
|
||||
val oldDeclarations = script.declarations
|
||||
if (oldDeclarations.none { it.isElementWhichShouldBeResolvedAsPartOfScript }) return@stateKeeper
|
||||
|
||||
add(RESULT_PROPERTY, designation)
|
||||
add(FirScript::declarations, FirScript::replaceDeclarations) {
|
||||
val lastProperty = oldDeclarations.lastOrNull()
|
||||
if (lastProperty is FirProperty &&
|
||||
lastProperty.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty &&
|
||||
lastProperty.bodyResolveState != FirPropertyBodyResolveState.ALL_BODIES_RESOLVED
|
||||
) {
|
||||
add(RESULT_PROPERTY, designation)
|
||||
val recreatedDeclarations = FirLazyBodiesCalculator.createDeclarationsForScript(script)
|
||||
requireSameSize(oldDeclarations, recreatedDeclarations)
|
||||
|
||||
ArrayList<FirDeclaration>(oldDeclarations.size).apply {
|
||||
oldDeclarations.zip(recreatedDeclarations).mapTo(this) { (old, new) ->
|
||||
when {
|
||||
!old.isElementWhichShouldBeResolvedAsPartOfScript -> old
|
||||
old is FirProperty && old.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -> {
|
||||
if (old.bodyResolveState != FirPropertyBodyResolveState.ALL_BODIES_RESOLVED) {
|
||||
old.replaceInitializer((new as FirProperty).initializer)
|
||||
}
|
||||
old
|
||||
}
|
||||
|
||||
else -> new
|
||||
}
|
||||
}
|
||||
}
|
||||
lastProperty.replaceInitializer((recreatedDeclarations.last() as FirProperty).initializer)
|
||||
}
|
||||
|
||||
entityList(oldDeclarations.mapNotNull { it as? FirAnonymousInitializer }, ANONYMOUS_INITIALIZER, designation)
|
||||
add(FirScript::controlFlowGraphReference, FirScript::replaceControlFlowGraphReference)
|
||||
}
|
||||
|
||||
private val RESULT_PROPERTY: StateKeeper<FirScript, FirDesignationWithFile> = stateKeeper { script, _ ->
|
||||
|
||||
+14
-1
@@ -10,12 +10,14 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirEle
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.LLFirDeclarationModificationService
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReturnTypeRefIsResolved
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.forEachDependentDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isScriptDependentDeclaration
|
||||
import org.jetbrains.kotlin.fir.FirElementWithResolveState
|
||||
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitAwareBodyResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
|
||||
@@ -27,6 +29,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.util.setMultimapOf
|
||||
import org.jetbrains.kotlin.fir.utils.exceptions.withFirSymbolEntry
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
|
||||
internal object LLFirImplicitTypesLazyResolver : LLFirLazyResolver(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
|
||||
@@ -140,6 +143,7 @@ internal class LLFirImplicitBodyTargetResolver(
|
||||
returnTypeCalculator = createReturnTypeCalculator(firResolveContextCollector = firResolveContextCollector),
|
||||
) {
|
||||
override val preserveCFGForClasses: Boolean get() = false
|
||||
override val buildCfgForScripts: Boolean get() = false
|
||||
override val buildCfgForFiles: Boolean get() = false
|
||||
override fun transformForeignAnnotationCall(symbol: FirBasedSymbol<*>, annotationCall: FirAnnotationCall): FirAnnotationCall {
|
||||
llImplicitBodyResolveComputationSession.postponeForeignAnnotationResolution(symbol)
|
||||
@@ -202,7 +206,16 @@ internal class LLFirImplicitBodyTargetResolver(
|
||||
|
||||
override fun rawResolve(target: FirElementWithResolveState) {
|
||||
when {
|
||||
target is FirScript -> resolveScript(target)
|
||||
target is FirScript -> {
|
||||
transformer.declarationsTransformer.withScript(target) {
|
||||
target.forEachDependentDeclaration {
|
||||
it.transformSingle(transformer, ResolutionMode.ContextIndependent)
|
||||
}
|
||||
|
||||
target
|
||||
}
|
||||
}
|
||||
|
||||
target is FirCallableDeclaration && target.attributes.callableCopySubstitutionForTypeUpdater != null -> {
|
||||
transformer.returnTypeCalculator.callableCopyTypeCalculator.computeReturnType(target)
|
||||
Unit
|
||||
|
||||
Reference in New Issue
Block a user