diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt index 7971a2ca13d..56ee093a169 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt @@ -79,6 +79,7 @@ fun main(args: Array) { alias("RegularClassChecker") alias("ConstructorChecker") alias("FileChecker") + alias("ScriptChecker") alias("FirTypeParameterChecker") alias("TypeAliasChecker") alias("AnonymousFunctionChecker") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt index ed5293a8380..77809167f48 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt @@ -35,6 +35,8 @@ class ComposedDeclarationCheckers : DeclarationCheckers() { get() = _constructorCheckers override val fileCheckers: Set get() = _fileCheckers + override val scriptCheckers: Set + get() = _scriptCheckers override val typeParameterCheckers: Set get() = _typeParameterCheckers override val typeAliasCheckers: Set @@ -68,6 +70,7 @@ class ComposedDeclarationCheckers : DeclarationCheckers() { private val _regularClassCheckers: MutableSet = mutableSetOf() private val _constructorCheckers: MutableSet = mutableSetOf() private val _fileCheckers: MutableSet = mutableSetOf() + private val _scriptCheckers: MutableSet = mutableSetOf() private val _typeParameterCheckers: MutableSet = mutableSetOf() private val _typeAliasCheckers: MutableSet = mutableSetOf() private val _anonymousFunctionCheckers: MutableSet = mutableSetOf() @@ -92,6 +95,7 @@ class ComposedDeclarationCheckers : DeclarationCheckers() { _regularClassCheckers += checkers.regularClassCheckers _constructorCheckers += checkers.constructorCheckers _fileCheckers += checkers.fileCheckers + _scriptCheckers += checkers.scriptCheckers _typeParameterCheckers += checkers.typeParameterCheckers _typeAliasCheckers += checkers.typeAliasCheckers _anonymousFunctionCheckers += checkers.anonymousFunctionCheckers diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt index faf463e3b73..5efcaccb8c7 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt @@ -29,6 +29,7 @@ abstract class DeclarationCheckers { open val regularClassCheckers: Set = emptySet() open val constructorCheckers: Set = emptySet() open val fileCheckers: Set = emptySet() + open val scriptCheckers: Set = emptySet() open val typeParameterCheckers: Set = emptySet() open val typeAliasCheckers: Set = emptySet() open val anonymousFunctionCheckers: Set = emptySet() @@ -52,6 +53,7 @@ abstract class DeclarationCheckers { @CheckersComponentInternal internal val allRegularClassCheckers: Set by lazy { regularClassCheckers + classCheckers + classLikeCheckers + basicDeclarationCheckers } @CheckersComponentInternal internal val allConstructorCheckers: Set by lazy { constructorCheckers + functionCheckers + callableDeclarationCheckers + basicDeclarationCheckers } @CheckersComponentInternal internal val allFileCheckers: Set by lazy { fileCheckers + basicDeclarationCheckers } + @CheckersComponentInternal internal val allScriptCheckers: Set by lazy { scriptCheckers + basicDeclarationCheckers } @CheckersComponentInternal internal val allTypeParameterCheckers: Set by lazy { typeParameterCheckers + basicDeclarationCheckers } @CheckersComponentInternal internal val allTypeAliasCheckers: Set by lazy { typeAliasCheckers + classLikeCheckers + basicDeclarationCheckers } @CheckersComponentInternal internal val allAnonymousFunctionCheckers: Set by lazy { anonymousFunctionCheckers + functionCheckers + callableDeclarationCheckers + basicDeclarationCheckers } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt index 655e012d1d5..cd18af26faf 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirScript import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.declarations.FirTypeParameter @@ -40,6 +41,7 @@ typealias FirClassChecker = FirDeclarationChecker typealias FirRegularClassChecker = FirDeclarationChecker typealias FirConstructorChecker = FirDeclarationChecker typealias FirFileChecker = FirDeclarationChecker +typealias FirScriptChecker = FirDeclarationChecker typealias FirTypeParameterChecker = FirDeclarationChecker typealias FirTypeAliasChecker = FirDeclarationChecker typealias FirAnonymousFunctionChecker = FirDeclarationChecker diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 7e760871bbb..00bf92e9c6a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -157,6 +157,11 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirTopLevelPropertiesChecker, ) + override val scriptCheckers: Set + get() = setOf( + FirScriptPropertiesChecker + ) + override val controlFlowAnalyserCheckers: Set get() = setOf( FirCallsEffectAnalyzer, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt index ad5067bb63c..68889c51074 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt @@ -34,44 +34,50 @@ import org.jetbrains.kotlin.lexer.KtTokens // See old FE's [DeclarationsChecker] object FirTopLevelPropertiesChecker : FirFileChecker() { override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) { - val topLevelProperties = declaration.effectiveTopLevelProperties - val info = declaration.collectionInitializationInfo(topLevelProperties, context, reporter) - for (topLevelProperty in topLevelProperties) { - val symbol = topLevelProperty.symbol - val isDefinitelyAssigned = info?.get(symbol)?.isDefinitelyVisited() == true - checkProperty(containingDeclaration = null, topLevelProperty, isDefinitelyAssigned, context, reporter, reachable = true) - } + val topLevelProperties = declaration.declarations.filterIsInstance() + checkFileLikeDeclaration(declaration, topLevelProperties, context, reporter) } +} - /** - * Scripts are nested as a single declaration under [FirFile]s and contain their own statements. To properly check all "top-level" - * properties, script statements need to be unwrapped. - */ - private val FirFile.effectiveTopLevelProperties: List - get() = when (val script = declarations.singleOrNull()) { - is FirScript -> script.statements.filterIsInstance() - else -> declarations.filterIsInstance() - } - - private fun FirFile.collectionInitializationInfo( - topLevelProperties: List, - context: CheckerContext, - reporter: DiagnosticReporter, - ): PropertyInitializationInfo? { - val graph = (this as? FirControlFlowGraphOwner)?.controlFlowGraphReference?.controlFlowGraph ?: return null - - val propertySymbols = topLevelProperties.mapNotNullTo(mutableSetOf()) { declaration -> - declaration.symbol.takeIf { it.requiresInitialization(isForInitialization = true) } - } - if (propertySymbols.isEmpty()) return null - - // TODO, KT-59803: merge with `FirPropertyInitializationAnalyzer` for fewer passes. - val data = PropertyInitializationInfoData(propertySymbols, receiver = null, graph) - data.checkPropertyAccesses(isForInitialization = true, context, reporter) - return data.getValue(graph.exitNode)[NormalPath] +object FirScriptPropertiesChecker : FirScriptChecker() { + override fun check(declaration: FirScript, context: CheckerContext, reporter: DiagnosticReporter) { + val topLevelProperties = declaration.statements.filterIsInstance() + checkFileLikeDeclaration(declaration, topLevelProperties, context, reporter) } } +private fun checkFileLikeDeclaration( + declaration: FirDeclaration, + topLevelProperties: List, + context: CheckerContext, + reporter: DiagnosticReporter, +) { + val info = declaration.collectionInitializationInfo(topLevelProperties, context, reporter) + for (topLevelProperty in topLevelProperties) { + val symbol = topLevelProperty.symbol + val isDefinitelyAssigned = info?.get(symbol)?.isDefinitelyVisited() == true + checkProperty(containingDeclaration = null, topLevelProperty, isDefinitelyAssigned, context, reporter, reachable = true) + } +} + +private fun FirDeclaration.collectionInitializationInfo( + topLevelProperties: List, + context: CheckerContext, + reporter: DiagnosticReporter, +): PropertyInitializationInfo? { + val graph = (this as? FirControlFlowGraphOwner)?.controlFlowGraphReference?.controlFlowGraph ?: return null + + val propertySymbols = topLevelProperties.mapNotNullTo(mutableSetOf()) { declaration -> + declaration.symbol.takeIf { it.requiresInitialization(isForInitialization = true) } + } + if (propertySymbols.isEmpty()) return null + + // TODO, KT-59803: merge with `FirPropertyInitializationAnalyzer` for fewer passes. + val data = PropertyInitializationInfoData(propertySymbols, receiver = null, graph) + data.checkPropertyAccesses(isForInitialization = true, context, reporter) + return data.getValue(graph.exitNode)[NormalPath] +} + // Matched FE 1.0's [DeclarationsChecker#checkPropertyInitializer]. internal fun checkPropertyInitializer( containingClass: FirClass?, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ControlFlowAnalysisDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ControlFlowAnalysisDiagnosticComponent.kt index e01c7b48bbd..399f676194e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ControlFlowAnalysisDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ControlFlowAnalysisDiagnosticComponent.kt @@ -44,6 +44,12 @@ class ControlFlowAnalysisDiagnosticComponent( analyze(file, data) } + // ------------------------------- File ------------------------------- + + override fun visitScript(script: FirScript, data: CheckerContext) { + analyze(script, data) + } + // ------------------------------- Class initializer ------------------------------- override fun visitRegularClass(regularClass: FirRegularClass, data: CheckerContext) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt index 7c52bc17323..a5c2318cb2b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt @@ -108,7 +108,7 @@ class DeclarationCheckersDiagnosticComponent( } override fun visitScript(script: FirScript, data: CheckerContext) { - checkers.allBasicDeclarationCheckers.check(script, data) + checkers.allScriptCheckers.check(script, data) } override fun visitCodeFragment(codeFragment: FirCodeFragment, data: CheckerContext) {