[JS IR] initial support for KLIB incremental compilation with K2
diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt
index f4fd406..31c0d53 100644
--- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt
+++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt
@@ -63,6 +63,7 @@
 import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
 import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
 import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.progress.IncrementalNextRoundException
 import org.jetbrains.kotlin.psi.KtFile
 import org.jetbrains.kotlin.serialization.js.ModuleKind
 import org.jetbrains.kotlin.utils.KotlinPaths
@@ -483,18 +484,28 @@
         val mainModule = MainModule.SourceFiles(environmentForJS.getSourceFiles())
         val moduleStructure = ModulesStructure(environmentForJS.project, mainModule, configuration, libraries, friendLibraries)
 
+        val lookupTracker = configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: LookupTracker.DO_NOTHING
+
         val outputs = compileModuleToAnalyzedFir(
             moduleStructure = moduleStructure,
             ktFiles = environmentForJS.getSourceFiles(),
             libraries = libraries,
             friendLibraries = friendLibraries,
             messageCollector = messageCollector,
-            diagnosticsReporter = diagnosticsReporter
+            diagnosticsReporter = diagnosticsReporter,
+            incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER],
+            lookupTracker = lookupTracker,
         ) ?: return null
 
         // FIR2IR
         val fir2IrActualizedResult = transformFirToIr(moduleStructure, outputs, diagnosticsReporter)
 
+        if (configuration.getBoolean(CommonConfigurationKeys.INCREMENTAL_COMPILATION)) {
+            if (shouldGoToNextIcRound(moduleStructure, outputs, fir2IrActualizedResult, configuration)) {
+                throw IncrementalNextRoundException()
+            }
+        }
+
         // Serialize klib
         if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
             serializeFirKlib(
diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt
index 9441ed9..c950939 100644
--- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt
+++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt
@@ -17,6 +17,7 @@
 import org.jetbrains.kotlin.cli.common.messages.MessageCollector
 import org.jetbrains.kotlin.cli.common.prepareJsSessions
 import org.jetbrains.kotlin.config.CommonConfigurationKeys
+import org.jetbrains.kotlin.config.CompilerConfiguration
 import org.jetbrains.kotlin.config.languageVersionSettings
 import org.jetbrains.kotlin.constant.EvaluatedConstTracker
 import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
@@ -38,10 +39,13 @@
 import org.jetbrains.kotlin.fir.resolve.ScopeSession
 import org.jetbrains.kotlin.fir.serialization.FirKLibSerializerExtension
 import org.jetbrains.kotlin.fir.serialization.serializeSingleFirFile
+import org.jetbrains.kotlin.fir.session.KlibIcData
 import org.jetbrains.kotlin.incremental.components.LookupTracker
+import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
 import org.jetbrains.kotlin.ir.backend.js.*
 import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
 import org.jetbrains.kotlin.ir.util.IrMessageLogger
+import org.jetbrains.kotlin.js.config.JSConfigurationKeys
 import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
 import org.jetbrains.kotlin.library.KotlinAbiVersion
 import org.jetbrains.kotlin.library.unresolvedDependencies
@@ -50,6 +54,7 @@
 import org.jetbrains.kotlin.psi.KtFile
 import org.jetbrains.kotlin.storage.LockBasedStorageManager
 import org.jetbrains.kotlin.utils.metadataVersion
+import java.io.File
 import java.nio.file.Paths
 
 fun compileModuleToAnalyzedFir(
@@ -58,7 +63,9 @@
     libraries: List<String>,
     friendLibraries: List<String>,
     messageCollector: MessageCollector,
-    diagnosticsReporter: BaseDiagnosticsCollector
+    diagnosticsReporter: BaseDiagnosticsCollector,
+    incrementalDataProvider: IncrementalDataProvider?,
+    lookupTracker: LookupTracker?,
 ): List<ModuleCompilerAnalyzedOutput>? {
     val renderDiagnosticNames = moduleStructure.compilerConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
 
@@ -83,7 +90,8 @@
 
     val sessionsWithSources = prepareJsSessions(
         ktFiles, moduleStructure.compilerConfiguration, escapedMainModuleName,
-        resolvedLibraries, dependencyList, extensionRegistrars, isCommonSourceForPsi, fileBelongsToModuleForPsi
+        resolvedLibraries, dependencyList, extensionRegistrars, isCommonSourceForPsi, fileBelongsToModuleForPsi,
+        lookupTracker, icData = incrementalDataProvider?.let { KlibIcData(it) }
     )
 
     val outputs = sessionsWithSources.map {
@@ -207,3 +215,51 @@
         )
     }
 }
+
+fun shouldGoToNextIcRound(
+    moduleStructure: ModulesStructure,
+    firOutputs: List<ModuleCompilerAnalyzedOutput>,
+    fir2IrActualizedResult: Fir2IrActualizedResult,
+    config: CompilerConfiguration,
+): Boolean {
+    val sourceFiles = mutableListOf<KtSourceFile>()
+    val firFilesAndSessionsBySourceFile = mutableMapOf<KtSourceFile, Triple<FirFile, FirSession, ScopeSession>>()
+
+    for (output in firOutputs) {
+        output.fir.forEach {
+            sourceFiles.add(it.sourceFile!!)
+            firFilesAndSessionsBySourceFile[it.sourceFile!!] = Triple(it, output.session, output.scopeSession)
+        }
+    }
+
+    val metadataVersion = moduleStructure.compilerConfiguration.metadataVersion()
+
+    val actualizedExpectDeclarations = fir2IrActualizedResult.irActualizedResult.extractFirDeclarations()
+
+    val nextRoundChecker = config.get(JSConfigurationKeys.INCREMENTAL_NEXT_ROUND_CHECKER) ?: return false
+
+    for (ktFile in sourceFiles) {
+
+        val (firFile, session, scopeSession) = firFilesAndSessionsBySourceFile[ktFile]
+            ?: error("cannot find FIR file by source file ${ktFile.name} (${ktFile.path})")
+
+        val packageFragment = serializeSingleFirFile(
+            firFile,
+            session,
+            scopeSession,
+            actualizedExpectDeclarations,
+            FirKLibSerializerExtension(
+                session, metadataVersion,
+                ConstValueProviderImpl(fir2IrActualizedResult.components),
+                allowErrorTypes = false, exportKDoc = false
+            ),
+            moduleStructure.compilerConfiguration.languageVersionSettings,
+        )
+
+        // to minimize a number of IC rounds, we should inspect all proto for changes first,
+        // then go to a next round if needed, with all new dirty files
+        nextRoundChecker.checkProtoChanges(File(ktFile.path!!), packageFragment.toByteArray())
+    }
+
+    return nextRoundChecker.shouldGoToNextRound()
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt
index 46faee1..a8dd22a 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt
@@ -16,6 +16,7 @@
 import org.jetbrains.kotlin.fir.session.*
 import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
 import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
+import org.jetbrains.kotlin.incremental.components.LookupTracker
 import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
 import org.jetbrains.kotlin.library.KotlinLibrary
 import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
@@ -113,6 +114,8 @@
     extensionRegistrars: List<FirExtensionRegistrar>,
     isCommonSource: (F) -> Boolean,
     fileBelongsToModule: (F, String) -> Boolean,
+    lookupTracker: LookupTracker?,
+    icData: KlibIcData?,
 ): List<SessionWithSources<F>> {
     return prepareSessions(
         files, configuration, rootModuleName, JsPlatforms.defaultJsPlatform, JsPlatformAnalyzerServices,
@@ -134,7 +137,8 @@
             sessionProvider,
             extensionRegistrars,
             configuration.languageVersionSettings,
-            null,
+            lookupTracker,
+            icData = icData,
             registerExtraComponents = {},
             init = sessionConfigurator,
         )
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirJsSessionFactory.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirJsSessionFactory.kt
index 75d8d64..40a96d0 100644
--- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirJsSessionFactory.kt
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirJsSessionFactory.kt
@@ -17,6 +17,7 @@
 import org.jetbrains.kotlin.fir.analysis.js.checkers.FirJsPlatformDiagnosticSuppressor
 import org.jetbrains.kotlin.fir.checkers.registerJsCheckers
 import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
+import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
 import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
 import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
 import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
@@ -35,6 +36,7 @@
         extensionRegistrars: List<FirExtensionRegistrar>,
         languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
         lookupTracker: LookupTracker?,
+        icData: KlibIcData? = null,
         registerExtraComponents: ((FirSession) -> Unit) = {},
         init: FirSessionConfigurator.() -> Unit
     ): FirSession {
@@ -52,10 +54,18 @@
             },
             registerExtraCheckers = { it.registerJsCheckers() },
             createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _, _ -> declaredMemberScope } },
-            createProviders = { _, _, symbolProvider, generatedSymbolsProvider, syntheticFunctionInterfaceProvider, dependencies ->
+            createProviders = { session, kotlinScopeProvider, symbolProvider, generatedSymbolsProvider, syntheticFunctionInterfaceProvider, dependencies ->
                 listOfNotNull(
                     symbolProvider,
                     generatedSymbolsProvider,
+                    icData?.let {
+                        KlibIcCacheBasedSymbolProvider(
+                            session,
+                            SingleModuleDataProvider(moduleData),
+                            kotlinScopeProvider,
+                            it,
+                        )
+                    },
                     syntheticFunctionInterfaceProvider,
                     *dependencies.toTypedArray(),
                 )
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt
index f6f0240..46d1dac 100644
--- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibBasedSymbolProvider.kt
@@ -5,6 +5,7 @@
 
 package org.jetbrains.kotlin.fir.session
 
+import org.jetbrains.kotlin.fir.FirModuleData
 import org.jetbrains.kotlin.fir.FirSession
 import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
 import org.jetbrains.kotlin.fir.deserialization.*
@@ -20,6 +21,7 @@
 import org.jetbrains.kotlin.name.ClassId
 import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
 import org.jetbrains.kotlin.serialization.deserialization.getClassId
 import org.jetbrains.kotlin.utils.SmartList
 import java.nio.file.Paths
@@ -30,14 +32,17 @@
     kotlinScopeProvider: FirKotlinScopeProvider,
     private val resolvedLibraries: Collection<KotlinLibrary>,
     defaultDeserializationOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library
-) : AbstractFirDeserializedSymbolProvider(
-    session, moduleDataProvider, kotlinScopeProvider, defaultDeserializationOrigin, KlibMetadataSerializerProtocol
+) : MetadataLibraryBasedSymbolProvider<KotlinLibrary>(
+    session,
+    moduleDataProvider,
+    kotlinScopeProvider,
+    defaultDeserializationOrigin
 ) {
     private val moduleHeaders by lazy {
         resolvedLibraries.associate { it to parseModuleHeader(it.moduleHeaderData) }
     }
 
-    private val fragmentNamesInLibraries: Map<String, List<KotlinLibrary>> by lazy {
+    override val fragmentNamesInLibraries: Map<String, List<KotlinLibrary>> by lazy {
         buildMap<String, SmartList<KotlinLibrary>> {
             for ((library, header) in moduleHeaders) {
                 for (fragmentName in header.packageFragmentNameList) {
@@ -48,7 +53,7 @@
         }
     }
 
-    private val knownPackagesInLibraries: Set<FqName> by lazy {
+    override val knownPackagesInLibraries: Set<FqName> by lazy {
         buildSet<FqName> {
             for ((_, header) in moduleHeaders) {
                 for (fragmentName in header.packageFragmentNameList) {
@@ -62,124 +67,12 @@
         }
     }
 
-    private val annotationDeserializer = KlibBasedAnnotationDeserializer(session)
-    private val constDeserializer = FirConstDeserializer(session, KlibMetadataSerializerProtocol)
-    private val deserializationConfiguration = CompilerDeserializationConfiguration(session.languageVersionSettings)
-    private val cachedFragments = mutableMapOf<KotlinLibrary, MutableMap<Pair<String, String>, ProtoBuf.PackageFragment>>()
-
-    private fun getPackageFragment(
-        resolvedLibrary: KotlinLibrary, packageStringName: String, packageMetadataPart: String
-    ): ProtoBuf.PackageFragment {
-        return cachedFragments.getOrPut(resolvedLibrary) {
-            mutableMapOf()
-        }.getOrPut(packageStringName to packageMetadataPart) {
-            parsePackageFragment(resolvedLibrary.packageMetadata(packageStringName, packageMetadataPart))
-        }
+    override fun moduleData(library: KotlinLibrary): FirModuleData? {
+        val libraryPath = Paths.get(library.libraryFile.path)
+        return moduleDataProvider.getModuleData(libraryPath)
     }
 
-    override fun computePackagePartsInfos(packageFqName: FqName): List<PackagePartsCacheData> {
-        val packageStringName = if (packageFqName.isRoot) "" else packageFqName.asString()
-
-        val librariesWithFragment = fragmentNamesInLibraries[packageStringName] ?: return emptyList()
-
-        return librariesWithFragment.flatMap { resolvedLibrary ->
-            resolvedLibrary.packageMetadataParts(packageStringName).mapNotNull {
-                val fragment = getPackageFragment(resolvedLibrary, packageStringName, it)
-
-                val libraryPath = Paths.get(resolvedLibrary.libraryFile.path)
-                val moduleData = moduleDataProvider.getModuleData(libraryPath) ?: return@mapNotNull null
-                val packageProto = fragment.`package`
-
-                val nameResolver = NameResolverImpl(
-                    fragment.strings,
-                    fragment.qualifiedNames,
-                )
-
-                PackagePartsCacheData(
-                    packageProto,
-                    FirDeserializationContext.createForPackage(
-                        packageFqName, packageProto, nameResolver, moduleData,
-                        annotationDeserializer,
-                        constDeserializer,
-                        createDeserializedContainerSource(resolvedLibrary, packageFqName),
-                    ),
-                )
-            }
-        }
-    }
-
-    override fun computePackageSetWithNonClassDeclarations(): Set<String> = fragmentNamesInLibraries.keys
-
-    override fun knownTopLevelClassesInPackage(packageFqName: FqName): Set<String> =
-        buildSet {
-            forEachFragmentInPackage(packageFqName) { _, fragment, nameResolver ->
-                for (classNameId in fragment.getExtension(KlibMetadataProtoBuf.className).orEmpty()) {
-                    add(nameResolver.getClassId(classNameId).shortClassName.asString())
-                }
-            }
-        }
-
-    @OptIn(SymbolInternals::class)
-    override fun extractClassMetadata(classId: ClassId, parentContext: FirDeserializationContext?): ClassMetadataFindResult? {
-        forEachFragmentInPackage(classId.packageFqName) { resolvedLibrary, fragment, nameResolver ->
-            val finder = KlibMetadataClassDataFinder(fragment, nameResolver)
-            val classProto = finder.findClassData(classId)?.classProto ?: return@forEachFragmentInPackage
-
-            val libraryPath = Paths.get(resolvedLibrary.libraryFile.path)
-            val moduleData = moduleDataProvider.getModuleData(libraryPath) ?: return null
-
-            return ClassMetadataFindResult.NoMetadata { symbol ->
-                val source = createDeserializedContainerSource(resolvedLibrary,
-
-                    classId.packageFqName
-                )
-
-                deserializeClassToSymbol(
-                    classId,
-                    classProto,
-                    symbol,
-                    nameResolver,
-                    session,
-                    moduleData,
-                    annotationDeserializer,
-                    kotlinScopeProvider,
-                    KlibMetadataSerializerProtocol,
-                    parentContext,
-                    source,
-                    origin = defaultDeserializationOrigin,
-                    deserializeNestedClass = this::getClass,
-                )
-                symbol.fir.isNewPlaceForBodyGeneration = isNewPlaceForBodyGeneration(classProto)
-            }
-        }
-
-        return null
-    }
-
-    private inline fun forEachFragmentInPackage(
-        packageFqName: FqName,
-        f: (KotlinLibrary, ProtoBuf.PackageFragment, NameResolver) -> Unit
-    ) {
-        val packageStringName = packageFqName.asString()
-
-        val librariesWithFragment = fragmentNamesInLibraries[packageStringName] ?: return
-
-        for (resolvedLibrary in librariesWithFragment) {
-            for (packageMetadataPart in resolvedLibrary.packageMetadataParts(packageStringName)) {
-
-                val fragment = getPackageFragment(resolvedLibrary, packageStringName, packageMetadataPart)
-
-                val nameResolver = NameResolverImpl(
-                    fragment.strings,
-                    fragment.qualifiedNames,
-                )
-
-                f(resolvedLibrary, fragment, nameResolver)
-            }
-        }
-    }
-
-    private fun createDeserializedContainerSource(
+    override fun createDeserializedContainerSource(
         resolvedLibrary: KotlinLibrary,
         packageFqName: FqName
     ) = KlibDeserializedContainerSource(
@@ -188,14 +81,4 @@
         deserializationConfiguration,
         packageFqName
     )
-
-    override fun isNewPlaceForBodyGeneration(classProto: ProtoBuf.Class) = false
-
-    override fun getPackage(fqName: FqName): FqName? {
-        return if (fqName in knownPackagesInLibraries) {
-            fqName
-        } else {
-            null
-        }
-    }
 }
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibIcCacheBasedSymbolProvider.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibIcCacheBasedSymbolProvider.kt
new file mode 100644
index 0000000..62b554f
--- /dev/null
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibIcCacheBasedSymbolProvider.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.fir.session
+
+
+import org.jetbrains.kotlin.fir.FirModuleData
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
+import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
+import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
+import org.jetbrains.kotlin.library.metadata.KlibDeserializedContainerSource
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
+import org.jetbrains.kotlin.utils.SmartList
+
+class KlibIcCacheBasedSymbolProvider(
+    session: FirSession,
+    moduleDataProvider: SingleModuleDataProvider,
+    kotlinScopeProvider: FirKotlinScopeProvider,
+    private val icData: KlibIcData,
+    defaultDeserializationOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library
+) : MetadataLibraryBasedSymbolProvider<KlibIcData>(
+    session,
+    moduleDataProvider,
+    kotlinScopeProvider,
+    defaultDeserializationOrigin
+) {
+    override fun moduleData(library: KlibIcData): FirModuleData {
+        return moduleDataProvider.allModuleData.single()
+    }
+
+    override val fragmentNamesInLibraries: Map<String, List<KlibIcData>> by lazy {
+        buildMap<String, SmartList<KlibIcData>> {
+            for (fragmentName in icData.packageFragmentNameList) {
+                getOrPut(fragmentName) { SmartList() }
+                    .add(icData)
+            }
+        }
+    }
+
+    override val knownPackagesInLibraries: Set<FqName> by lazy {
+        buildSet<FqName> {
+            for (fragmentName in icData.packageFragmentNameList) {
+                var curPackage = FqName(fragmentName)
+                while (!curPackage.isRoot) {
+                    add(curPackage)
+                    curPackage = curPackage.parent()
+                }
+            }
+        }
+    }
+
+    override fun createDeserializedContainerSource(resolvedLibrary: KlibIcData, packageFqName: FqName): DeserializedContainerSource {
+        return KlibDeserializedContainerSource(false, "Package '$packageFqName'", false)
+    }
+}
\ No newline at end of file
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibIcData.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibIcData.kt
new file mode 100644
index 0000000..50da41b
--- /dev/null
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/KlibIcData.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.fir.session
+
+import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
+import org.jetbrains.kotlin.library.MetadataLibrary
+import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
+import org.jetbrains.kotlin.library.metadata.parsePackageFragment
+
+class KlibIcData(incrementalData: IncrementalDataProvider) : MetadataLibrary {
+
+    private val parts: Map<String, Map<String, ByteArray>> by lazy {
+        val result = mutableMapOf<String, MutableMap<String, ByteArray>>()
+
+        incrementalData.compiledPackageParts.entries.forEach { (f, tv) ->
+            val proto = parsePackageFragment(tv.metadata)
+            val fqName = proto.getExtension(KlibMetadataProtoBuf.fqName)
+            result.getOrPut(fqName, ::mutableMapOf).put(f.name, tv.metadata)
+        }
+
+        result
+    }
+
+    val packageFragmentNameList: Collection<String>
+        get() = parts.keys
+
+    override val moduleHeaderData: ByteArray
+        get() = error("moduleHeaderData is not implemented")
+
+    override fun packageMetadataParts(fqName: String): Set<String> {
+        return parts[fqName]?.keys ?: emptySet()
+    }
+
+    override fun packageMetadata(fqName: String, partName: String): ByteArray {
+        return parts[fqName]?.get(partName) ?: error("Metadata not found for package $fqName part $partName")
+    }
+}
\ No newline at end of file
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/MetadataLibraryBasedSymbolProvider.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/MetadataLibraryBasedSymbolProvider.kt
new file mode 100644
index 0000000..059cfe4
--- /dev/null
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/MetadataLibraryBasedSymbolProvider.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2010-2021 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.fir.session
+
+import org.jetbrains.kotlin.fir.FirModuleData
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.caches.FirCache
+import org.jetbrains.kotlin.fir.caches.firCachesFactory
+import org.jetbrains.kotlin.fir.caches.getValue
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
+import org.jetbrains.kotlin.fir.deserialization.*
+import org.jetbrains.kotlin.fir.isNewPlaceForBodyGeneration
+import org.jetbrains.kotlin.fir.languageVersionSettings
+import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
+import org.jetbrains.kotlin.fir.symbols.SymbolInternals
+import org.jetbrains.kotlin.library.KotlinLibrary
+import org.jetbrains.kotlin.library.MetadataLibrary
+import org.jetbrains.kotlin.library.metadata.*
+import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
+import org.jetbrains.kotlin.metadata.ProtoBuf
+import org.jetbrains.kotlin.metadata.deserialization.NameResolver
+import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
+import org.jetbrains.kotlin.serialization.deserialization.getClassId
+import org.jetbrains.kotlin.utils.SmartList
+import java.nio.file.Paths
+
+abstract class MetadataLibraryBasedSymbolProvider<L : MetadataLibrary>(
+    session: FirSession,
+    moduleDataProvider: ModuleDataProvider,
+    kotlinScopeProvider: FirKotlinScopeProvider,
+    defaultDeserializationOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library
+) : AbstractFirDeserializedSymbolProvider(
+    session, moduleDataProvider, kotlinScopeProvider, defaultDeserializationOrigin, KlibMetadataSerializerProtocol
+) {
+    protected abstract fun moduleData(library: L): FirModuleData?
+
+    protected abstract val fragmentNamesInLibraries: Map<String, List<L>>
+
+    protected abstract val knownPackagesInLibraries: Set<FqName>
+
+    private val annotationDeserializer = KlibBasedAnnotationDeserializer(session)
+    private val constDeserializer = FirConstDeserializer(session, KlibMetadataSerializerProtocol)
+    protected val deserializationConfiguration = CompilerDeserializationConfiguration(session.languageVersionSettings)
+    private val cachedFragments = mutableMapOf<L, MutableMap<Pair<String, String>, ProtoBuf.PackageFragment>>()
+
+    private fun getPackageFragment(
+        resolvedLibrary: L, packageStringName: String, packageMetadataPart: String
+    ): ProtoBuf.PackageFragment {
+        return cachedFragments.getOrPut(resolvedLibrary) {
+            mutableMapOf()
+        }.getOrPut(packageStringName to packageMetadataPart) {
+            parsePackageFragment(resolvedLibrary.packageMetadata(packageStringName, packageMetadataPart))
+        }
+    }
+
+    override fun computePackagePartsInfos(packageFqName: FqName): List<PackagePartsCacheData> {
+        val packageStringName = if (packageFqName.isRoot) "" else packageFqName.asString()
+
+        val librariesWithFragment = fragmentNamesInLibraries[packageStringName] ?: return emptyList()
+
+        return librariesWithFragment.flatMap { resolvedLibrary ->
+            resolvedLibrary.packageMetadataParts(packageStringName).mapNotNull {
+                val fragment = getPackageFragment(resolvedLibrary, packageStringName, it)
+
+                val moduleData = moduleData(resolvedLibrary) ?: return@mapNotNull null
+                val packageProto = fragment.`package`
+
+                val nameResolver = NameResolverImpl(
+                    fragment.strings,
+                    fragment.qualifiedNames,
+                )
+
+                PackagePartsCacheData(
+                    packageProto,
+                    FirDeserializationContext.createForPackage(
+                        packageFqName, packageProto, nameResolver, moduleData,
+                        annotationDeserializer,
+                        constDeserializer,
+                        createDeserializedContainerSource(resolvedLibrary, packageFqName),
+                    ),
+                )
+            }
+        }
+    }
+
+    override fun computePackageSetWithNonClassDeclarations(): Set<String> = fragmentNamesInLibraries.keys
+
+    override fun knownTopLevelClassesInPackage(packageFqName: FqName): Set<String> =
+        buildSet {
+            forEachFragmentInPackage(packageFqName) { _, fragment, nameResolver ->
+                for (classNameId in fragment.getExtension(KlibMetadataProtoBuf.className).orEmpty()) {
+                    add(nameResolver.getClassId(classNameId).shortClassName.asString())
+                }
+            }
+        }
+
+    @OptIn(SymbolInternals::class)
+    override fun extractClassMetadata(classId: ClassId, parentContext: FirDeserializationContext?): ClassMetadataFindResult? {
+        forEachFragmentInPackage(classId.packageFqName) { resolvedLibrary, fragment, nameResolver ->
+            val finder = KlibMetadataClassDataFinder(fragment, nameResolver)
+            val classProto = finder.findClassData(classId)?.classProto ?: return@forEachFragmentInPackage
+
+            val moduleData = moduleData(resolvedLibrary) ?: return null
+
+            return ClassMetadataFindResult.NoMetadata { symbol ->
+                val source = createDeserializedContainerSource(
+                    resolvedLibrary,
+                    classId.packageFqName
+                )
+
+                deserializeClassToSymbol(
+                    classId,
+                    classProto,
+                    symbol,
+                    nameResolver,
+                    session,
+                    moduleData,
+                    annotationDeserializer,
+                    kotlinScopeProvider,
+                    KlibMetadataSerializerProtocol,
+                    parentContext,
+                    source,
+                    origin = defaultDeserializationOrigin,
+                    deserializeNestedClass = this::getClass,
+                )
+                symbol.fir.isNewPlaceForBodyGeneration = isNewPlaceForBodyGeneration(classProto)
+            }
+        }
+
+        return null
+    }
+
+    private inline fun forEachFragmentInPackage(
+        packageFqName: FqName,
+        f: (L, ProtoBuf.PackageFragment, NameResolver) -> Unit
+    ) {
+        val packageStringName = packageFqName.asString()
+
+        val librariesWithFragment = fragmentNamesInLibraries[packageStringName] ?: return
+
+        for (resolvedLibrary in librariesWithFragment) {
+            for (packageMetadataPart in resolvedLibrary.packageMetadataParts(packageStringName)) {
+
+                val fragment = getPackageFragment(resolvedLibrary, packageStringName, packageMetadataPart)
+
+                val nameResolver = NameResolverImpl(
+                    fragment.strings,
+                    fragment.qualifiedNames,
+                )
+
+                f(resolvedLibrary, fragment, nameResolver)
+            }
+        }
+    }
+
+    protected abstract fun createDeserializedContainerSource(
+        resolvedLibrary: L,
+        packageFqName: FqName
+    ): DeserializedContainerSource?
+
+    override fun isNewPlaceForBodyGeneration(classProto: ProtoBuf.Class) = false
+
+    override fun getPackage(fqName: FqName): FqName? {
+        return if (fqName in knownPackagesInLibraries) {
+            fqName
+        } else {
+            null
+        }
+    }
+}
diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementalJsKlibCompilerRunnerTest.kt b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementalJsKlibCompilerRunnerTest.kt
index a18428e..0c98f70 100644
--- a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementalJsKlibCompilerRunnerTest.kt
+++ b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/AbstractIncrementalJsKlibCompilerRunnerTest.kt
@@ -23,4 +23,13 @@
 
 abstract class AbstractIncrementalJsKlibCompilerWithScopeExpansionRunnerTest : AbstractIncrementalJsKlibCompilerRunnerTest() {
     override val scopeExpansionMode = CompileScopeExpansionMode.ALWAYS
+}
+
+abstract class AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest : AbstractIncrementalJsKlibCompilerWithScopeExpansionRunnerTest() {
+    override fun createCompilerArguments(destinationDir: File, testDir: File): K2JSCompilerArguments {
+        return super.createCompilerArguments(destinationDir, testDir).apply {
+            useK2 = true
+            languageVersion = "2.0"
+        }
+    }
 }
\ No newline at end of file
diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/IncrementalJsFirKlibCompilerWithScopeExpansionRunnerTestGenerated.java b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/IncrementalJsFirKlibCompilerWithScopeExpansionRunnerTestGenerated.java
new file mode 100644
index 0000000..9e9ba8a
--- /dev/null
+++ b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/IncrementalJsFirKlibCompilerWithScopeExpansionRunnerTestGenerated.java
@@ -0,0 +1,958 @@
+/*
+ * 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.incremental;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
+import org.jetbrains.kotlin.test.KotlinTestUtils;
+import org.jetbrains.kotlin.test.util.KtTestUtil;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateTestsKt}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@RunWith(JUnit3RunnerWithInners.class)
+public class IncrementalJsFirKlibCompilerWithScopeExpansionRunnerTestGenerated extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+    @TestMetadata("jps/jps-plugin/testData/incremental/pureKotlin")
+    @TestDataPath("$PROJECT_ROOT")
+    @RunWith(JUnit3RunnerWithInners.class)
+    public static class PureKotlin extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+        private void runTest(String testDataFilePath) throws Exception {
+            KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+        }
+
+        @TestMetadata("accessingFunctionsViaPackagePart")
+        public void testAccessingFunctionsViaPackagePart() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/accessingFunctionsViaPackagePart/");
+        }
+
+        @TestMetadata("accessingPropertiesViaField")
+        public void testAccessingPropertiesViaField() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/accessingPropertiesViaField/");
+        }
+
+        @TestMetadata("addClass")
+        public void testAddClass() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/addClass/");
+        }
+
+        @TestMetadata("addFileWithFunctionOverload")
+        public void testAddFileWithFunctionOverload() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/addFileWithFunctionOverload/");
+        }
+
+        @TestMetadata("addMemberTypeAlias")
+        public void testAddMemberTypeAlias() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/addMemberTypeAlias/");
+        }
+
+        @TestMetadata("addTopLevelTypeAlias")
+        public void testAddTopLevelTypeAlias() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/addTopLevelTypeAlias/");
+        }
+
+        public void testAllFilesPresentInPureKotlin() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/pureKotlin"), Pattern.compile("^([^\\.]+)$"), Pattern.compile("^(sealed|propertyRedeclaration|funRedeclaration|funVsConstructorOverloadConflict).*"), false);
+        }
+
+        @TestMetadata("annotations")
+        public void testAnnotations() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/annotations/");
+        }
+
+        @TestMetadata("anonymousObjectChanged")
+        public void testAnonymousObjectChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/anonymousObjectChanged/");
+        }
+
+        @TestMetadata("changeTypeImplicitlyWithCircularDependency")
+        public void testChangeTypeImplicitlyWithCircularDependency() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/changeTypeImplicitlyWithCircularDependency/");
+        }
+
+        @TestMetadata("changeTypealiasSinceK2")
+        public void testChangeTypealiasSinceK2() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/changeTypealiasSinceK2/");
+        }
+
+        @TestMetadata("changeWithRemovingUsage")
+        public void testChangeWithRemovingUsage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/changeWithRemovingUsage/");
+        }
+
+        @TestMetadata("checkConstants")
+        public void testCheckConstants() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/checkConstants/");
+        }
+
+        @TestMetadata("classInlineFunctionChanged")
+        public void testClassInlineFunctionChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/classInlineFunctionChanged/");
+        }
+
+        @TestMetadata("classObjectConstantChanged")
+        public void testClassObjectConstantChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/classObjectConstantChanged/");
+        }
+
+        @TestMetadata("classRecreated")
+        public void testClassRecreated() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/classRecreated/");
+        }
+
+        @TestMetadata("classRemoved")
+        public void testClassRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/classRemoved/");
+        }
+
+        @TestMetadata("classSignatureChanged")
+        public void testClassSignatureChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/classSignatureChanged/");
+        }
+
+        @TestMetadata("classSignatureUnchanged")
+        public void testClassSignatureUnchanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/classSignatureUnchanged/");
+        }
+
+        @TestMetadata("companionConstantChanged")
+        public void testCompanionConstantChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/companionConstantChanged/");
+        }
+
+        @TestMetadata("compilationErrorThenFixedOtherPackage")
+        public void testCompilationErrorThenFixedOtherPackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/compilationErrorThenFixedOtherPackage/");
+        }
+
+        @TestMetadata("compilationErrorThenFixedSamePackage")
+        public void testCompilationErrorThenFixedSamePackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/compilationErrorThenFixedSamePackage/");
+        }
+
+        @TestMetadata("compilationErrorThenFixedWithPhantomPart")
+        public void testCompilationErrorThenFixedWithPhantomPart() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/compilationErrorThenFixedWithPhantomPart/");
+        }
+
+        @TestMetadata("compilationErrorThenFixedWithPhantomPart2")
+        public void testCompilationErrorThenFixedWithPhantomPart2() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/compilationErrorThenFixedWithPhantomPart2/");
+        }
+
+        @TestMetadata("compilationErrorThenFixedWithPhantomPart3")
+        public void testCompilationErrorThenFixedWithPhantomPart3() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/compilationErrorThenFixedWithPhantomPart3/");
+        }
+
+        @TestMetadata("constantRemoved")
+        public void testConstantRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/constantRemoved/");
+        }
+
+        @TestMetadata("constantValueChanged")
+        public void testConstantValueChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/constantValueChanged/");
+        }
+
+        @TestMetadata("constantsUnchanged")
+        public void testConstantsUnchanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/constantsUnchanged/");
+        }
+
+        @TestMetadata("defaultArgumentInConstructorAdded")
+        public void testDefaultArgumentInConstructorAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultArgumentInConstructorAdded/");
+        }
+
+        @TestMetadata("defaultArgumentInConstructorRemoved")
+        public void testDefaultArgumentInConstructorRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultArgumentInConstructorRemoved/");
+        }
+
+        @TestMetadata("defaultValueAdded")
+        public void testDefaultValueAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultValueAdded/");
+        }
+
+        @TestMetadata("defaultValueChanged")
+        public void testDefaultValueChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultValueChanged/");
+        }
+
+        @TestMetadata("defaultValueInConstructorChanged")
+        public void testDefaultValueInConstructorChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultValueInConstructorChanged/");
+        }
+
+        @TestMetadata("defaultValueInConstructorRemoved")
+        public void testDefaultValueInConstructorRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultValueInConstructorRemoved/");
+        }
+
+        @TestMetadata("defaultValueRemoved1")
+        public void testDefaultValueRemoved1() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultValueRemoved1/");
+        }
+
+        @TestMetadata("defaultValueRemoved2")
+        public void testDefaultValueRemoved2() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/defaultValueRemoved2/");
+        }
+
+        @TestMetadata("delegatedPropertyInlineExtensionAccessor")
+        public void testDelegatedPropertyInlineExtensionAccessor() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/delegatedPropertyInlineExtensionAccessor/");
+        }
+
+        @TestMetadata("delegatedPropertyInlineMethodAccessor")
+        public void testDelegatedPropertyInlineMethodAccessor() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/delegatedPropertyInlineMethodAccessor/");
+        }
+
+        @TestMetadata("dependencyClassReferenced")
+        public void testDependencyClassReferenced() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/dependencyClassReferenced/");
+        }
+
+        @TestMetadata("fileWithConstantRemoved")
+        public void testFileWithConstantRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/fileWithConstantRemoved/");
+        }
+
+        @TestMetadata("fileWithInlineFunctionRemoved")
+        public void testFileWithInlineFunctionRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/fileWithInlineFunctionRemoved/");
+        }
+
+        @TestMetadata("filesExchangePackages")
+        public void testFilesExchangePackages() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/filesExchangePackages/");
+        }
+
+        @TestMetadata("functionBecameInline")
+        public void testFunctionBecameInline() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/functionBecameInline/");
+        }
+
+        @TestMetadata("functionReferencingClass")
+        public void testFunctionReferencingClass() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/functionReferencingClass/");
+        }
+
+        @TestMetadata("independentClasses")
+        public void testIndependentClasses() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/independentClasses/");
+        }
+
+        @TestMetadata("inlineFunctionBecomesNonInline")
+        public void testInlineFunctionBecomesNonInline() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineFunctionBecomesNonInline/");
+        }
+
+        @TestMetadata("inlineFunctionUsageAdded")
+        public void testInlineFunctionUsageAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineFunctionUsageAdded/");
+        }
+
+        @TestMetadata("inlineFunctionsCircularDependency")
+        public void testInlineFunctionsCircularDependency() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineFunctionsCircularDependency/");
+        }
+
+        @TestMetadata("inlineFunctionsUnchanged")
+        public void testInlineFunctionsUnchanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineFunctionsUnchanged/");
+        }
+
+        @TestMetadata("inlineLinesChanged")
+        public void testInlineLinesChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineLinesChanged/");
+        }
+
+        @TestMetadata("inlineModifiedWithUsage")
+        public void testInlineModifiedWithUsage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineModifiedWithUsage/");
+        }
+
+        @TestMetadata("inlinePrivateFunctionAdded")
+        public void testInlinePrivateFunctionAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlinePrivateFunctionAdded/");
+        }
+
+        @TestMetadata("inlinePropertyInClass")
+        public void testInlinePropertyInClass() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlinePropertyInClass/");
+        }
+
+        @TestMetadata("inlinePropertyOnTopLevel")
+        public void testInlinePropertyOnTopLevel() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlinePropertyOnTopLevel/");
+        }
+
+        @TestMetadata("inlineSuspendFunctionChanged")
+        public void testInlineSuspendFunctionChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineSuspendFunctionChanged/");
+        }
+
+        @TestMetadata("inlineTwoFunctionsOneChanged")
+        public void testInlineTwoFunctionsOneChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineTwoFunctionsOneChanged/");
+        }
+
+        @TestMetadata("inlineUsedWhereDeclared")
+        public void testInlineUsedWhereDeclared() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/inlineUsedWhereDeclared/");
+        }
+
+        @TestMetadata("innerClassesFromSupertypes")
+        public void testInnerClassesFromSupertypes() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/innerClassesFromSupertypes/");
+        }
+
+        @TestMetadata("internalClassChanged")
+        public void testInternalClassChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/internalClassChanged/");
+        }
+
+        @TestMetadata("internalMemberInClassChanged")
+        public void testInternalMemberInClassChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/internalMemberInClassChanged/");
+        }
+
+        @TestMetadata("internalTypealias")
+        public void testInternalTypealias() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/internalTypealias/");
+        }
+
+        @TestMetadata("internalTypealiasConstructor")
+        public void testInternalTypealiasConstructor() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/internalTypealiasConstructor/");
+        }
+
+        @TestMetadata("internalTypealiasObject")
+        public void testInternalTypealiasObject() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/internalTypealiasObject/");
+        }
+
+        @TestMetadata("localClassChanged")
+        public void testLocalClassChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/localClassChanged/");
+        }
+
+        @TestMetadata("moveClass")
+        public void testMoveClass() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/moveClass/");
+        }
+
+        @TestMetadata("moveFileWithChangingPackage")
+        public void testMoveFileWithChangingPackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/moveFileWithChangingPackage/");
+        }
+
+        @TestMetadata("moveFileWithoutChangingPackage")
+        public void testMoveFileWithoutChangingPackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/moveFileWithoutChangingPackage/");
+        }
+
+        @TestMetadata("multiplePackagesModified")
+        public void testMultiplePackagesModified() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/multiplePackagesModified/");
+        }
+
+        @TestMetadata("objectConstantChanged")
+        public void testObjectConstantChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/objectConstantChanged/");
+        }
+
+        @TestMetadata("ourClassReferenced")
+        public void testOurClassReferenced() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/ourClassReferenced/");
+        }
+
+        @TestMetadata("overloadInlined")
+        public void testOverloadInlined() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/overloadInlined/");
+        }
+
+        @TestMetadata("packageConstantChanged")
+        public void testPackageConstantChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageConstantChanged/");
+        }
+
+        @TestMetadata("packageFileAdded")
+        public void testPackageFileAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageFileAdded/");
+        }
+
+        @TestMetadata("packageFileChangedPackage")
+        public void testPackageFileChangedPackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageFileChangedPackage/");
+        }
+
+        @TestMetadata("packageFileChangedThenOtherRemoved")
+        public void testPackageFileChangedThenOtherRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageFileChangedThenOtherRemoved/");
+        }
+
+        @TestMetadata("packageFileRemoved")
+        public void testPackageFileRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageFileRemoved/");
+        }
+
+        @TestMetadata("packageFilesChangedInTurn")
+        public void testPackageFilesChangedInTurn() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageFilesChangedInTurn/");
+        }
+
+        @TestMetadata("packageInlineFunctionAccessingField")
+        public void testPackageInlineFunctionAccessingField() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageInlineFunctionAccessingField/");
+        }
+
+        @TestMetadata("packageInlineFunctionFromOurPackage")
+        public void testPackageInlineFunctionFromOurPackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageInlineFunctionFromOurPackage/");
+        }
+
+        @TestMetadata("packagePrivateOnlyChanged")
+        public void testPackagePrivateOnlyChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packagePrivateOnlyChanged/");
+        }
+
+        @TestMetadata("packageRecreated")
+        public void testPackageRecreated() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageRecreated/");
+        }
+
+        @TestMetadata("packageRecreatedAfterRenaming")
+        public void testPackageRecreatedAfterRenaming() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageRecreatedAfterRenaming/");
+        }
+
+        @TestMetadata("packageRemoved")
+        public void testPackageRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/packageRemoved/");
+        }
+
+        @TestMetadata("parameterWithDefaultValueAdded")
+        public void testParameterWithDefaultValueAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/parameterWithDefaultValueAdded/");
+        }
+
+        @TestMetadata("parameterWithDefaultValueRemoved")
+        public void testParameterWithDefaultValueRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/parameterWithDefaultValueRemoved/");
+        }
+
+        @TestMetadata("privateConstantsChanged")
+        public void testPrivateConstantsChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateConstantsChanged/");
+        }
+
+        @TestMetadata("privateMethodAdded")
+        public void testPrivateMethodAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateMethodAdded/");
+        }
+
+        @TestMetadata("privateMethodDeleted")
+        public void testPrivateMethodDeleted() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateMethodDeleted/");
+        }
+
+        @TestMetadata("privateMethodSignatureChanged")
+        public void testPrivateMethodSignatureChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateMethodSignatureChanged/");
+        }
+
+        @TestMetadata("privateSecondaryConstructorAdded")
+        public void testPrivateSecondaryConstructorAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateSecondaryConstructorAdded/");
+        }
+
+        @TestMetadata("privateSecondaryConstructorDeleted")
+        public void testPrivateSecondaryConstructorDeleted() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateSecondaryConstructorDeleted/");
+        }
+
+        @TestMetadata("privateValAccessorChanged")
+        public void testPrivateValAccessorChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateValAccessorChanged/");
+        }
+
+        @TestMetadata("privateValAdded")
+        public void testPrivateValAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateValAdded/");
+        }
+
+        @TestMetadata("privateValDeleted")
+        public void testPrivateValDeleted() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateValDeleted/");
+        }
+
+        @TestMetadata("privateValSignatureChanged")
+        public void testPrivateValSignatureChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateValSignatureChanged/");
+        }
+
+        @TestMetadata("privateVarAdded")
+        public void testPrivateVarAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateVarAdded/");
+        }
+
+        @TestMetadata("privateVarDeleted")
+        public void testPrivateVarDeleted() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateVarDeleted/");
+        }
+
+        @TestMetadata("privateVarSignatureChanged")
+        public void testPrivateVarSignatureChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/privateVarSignatureChanged/");
+        }
+
+        @TestMetadata("publicPropertyWithPrivateSetter")
+        public void testPublicPropertyWithPrivateSetter() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/publicPropertyWithPrivateSetter/");
+        }
+
+        @TestMetadata("removeAndRestoreCompanion")
+        public void testRemoveAndRestoreCompanion() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeAndRestoreCompanion/");
+        }
+
+        @TestMetadata("removeAndRestoreCompanionWithImplicitUsages")
+        public void testRemoveAndRestoreCompanionWithImplicitUsages() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeAndRestoreCompanionWithImplicitUsages/");
+        }
+
+        @TestMetadata("removeClass")
+        public void testRemoveClass() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeClass/");
+        }
+
+        @TestMetadata("removeClassInDefaultPackage")
+        public void testRemoveClassInDefaultPackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeClassInDefaultPackage/");
+        }
+
+        @TestMetadata("removeFileWithFunctionOverload")
+        public void testRemoveFileWithFunctionOverload() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeFileWithFunctionOverload/");
+        }
+
+        @TestMetadata("removeMemberTypeAlias")
+        public void testRemoveMemberTypeAlias() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeMemberTypeAlias/");
+        }
+
+        @TestMetadata("removeTopLevelTypeAlias")
+        public void testRemoveTopLevelTypeAlias() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeTopLevelTypeAlias/");
+        }
+
+        @TestMetadata("removeUnusedFile")
+        public void testRemoveUnusedFile() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/removeUnusedFile/");
+        }
+
+        @TestMetadata("renameClass")
+        public void testRenameClass() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/renameClass/");
+        }
+
+        @TestMetadata("renameFileWithClassesOnly")
+        public void testRenameFileWithClassesOnly() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/renameFileWithClassesOnly/");
+        }
+
+        @TestMetadata("renameFileWithFunctionOverload")
+        public void testRenameFileWithFunctionOverload() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/renameFileWithFunctionOverload/");
+        }
+
+        @TestMetadata("returnTypeChanged")
+        public void testReturnTypeChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/returnTypeChanged/");
+        }
+
+        @TestMetadata("secondaryConstructorInlined")
+        public void testSecondaryConstructorInlined() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/secondaryConstructorInlined/");
+        }
+
+        @TestMetadata("sequentualAddingAndDeletingOfPropertyAndUsage")
+        public void testSequentualAddingAndDeletingOfPropertyAndUsage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/sequentualAddingAndDeletingOfPropertyAndUsage/");
+        }
+
+        @TestMetadata("serializedSubClassAndChangedInterfaces")
+        public void testSerializedSubClassAndChangedInterfaces() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/serializedSubClassAndChangedInterfaces/");
+        }
+
+        @TestMetadata("simpleClassDependency")
+        public void testSimpleClassDependency() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/simpleClassDependency/");
+        }
+
+        @TestMetadata("soleFileChangesPackage")
+        public void testSoleFileChangesPackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/soleFileChangesPackage/");
+        }
+
+        @TestMetadata("subpackage")
+        public void testSubpackage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/subpackage/");
+        }
+
+        @TestMetadata("suspendWithStateMachine")
+        public void testSuspendWithStateMachine() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/suspendWithStateMachine/");
+        }
+
+        @TestMetadata("topLevelFunctionSameSignature")
+        public void testTopLevelFunctionSameSignature() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/topLevelFunctionSameSignature/");
+        }
+
+        @TestMetadata("topLevelMembersInTwoFiles")
+        public void testTopLevelMembersInTwoFiles() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/topLevelMembersInTwoFiles/");
+        }
+
+        @TestMetadata("topLevelPrivateValUsageAdded")
+        public void testTopLevelPrivateValUsageAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/topLevelPrivateValUsageAdded/");
+        }
+
+        @TestMetadata("traitClassObjectConstantChanged")
+        public void testTraitClassObjectConstantChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/traitClassObjectConstantChanged/");
+        }
+
+        @TestMetadata("valAddCustomAccessor")
+        public void testValAddCustomAccessor() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/valAddCustomAccessor/");
+        }
+
+        @TestMetadata("valRemoveCustomAccessor")
+        public void testValRemoveCustomAccessor() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/pureKotlin/valRemoveCustomAccessor/");
+        }
+    }
+
+    @TestMetadata("jps/jps-plugin/testData/incremental/classHierarchyAffected")
+    @TestDataPath("$PROJECT_ROOT")
+    @RunWith(JUnit3RunnerWithInners.class)
+    public static class ClassHierarchyAffected extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+        private void runTest(String testDataFilePath) throws Exception {
+            KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+        }
+
+        public void testAllFilesPresentInClassHierarchyAffected() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/classHierarchyAffected"), Pattern.compile("^([^\\.]+)$"), Pattern.compile("^(secondaryConstructorAdded|withIntermediateBodiesChanged|companionObjectNameChanged).*"), false);
+        }
+
+        @TestMetadata("annotationFlagRemoved")
+        public void testAnnotationFlagRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/annotationFlagRemoved/");
+        }
+
+        @TestMetadata("annotationListChanged")
+        public void testAnnotationListChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/annotationListChanged/");
+        }
+
+        @TestMetadata("bridgeGenerated")
+        public void testBridgeGenerated() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/bridgeGenerated/");
+        }
+
+        @TestMetadata("classBecameFinal")
+        public void testClassBecameFinal() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/classBecameFinal/");
+        }
+
+        @TestMetadata("classBecameInterface")
+        public void testClassBecameInterface() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/classBecameInterface/");
+        }
+
+        @TestMetadata("classBecamePrivate")
+        public void testClassBecamePrivate() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/classBecamePrivate/");
+        }
+
+        @TestMetadata("classMovedIntoOtherClass")
+        public void testClassMovedIntoOtherClass() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/classMovedIntoOtherClass/");
+        }
+
+        @TestMetadata("classRemoved")
+        public void testClassRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/classRemoved/");
+        }
+
+        @TestMetadata("classRemovedAndRestored")
+        public void testClassRemovedAndRestored() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/classRemovedAndRestored/");
+        }
+
+        @TestMetadata("companionObjectInheritedMemberChanged")
+        public void testCompanionObjectInheritedMemberChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/companionObjectInheritedMemberChanged/");
+        }
+
+        @TestMetadata("companionObjectMemberChanged")
+        public void testCompanionObjectMemberChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/companionObjectMemberChanged/");
+        }
+
+        @TestMetadata("companionObjectToSimpleObject")
+        public void testCompanionObjectToSimpleObject() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/companionObjectToSimpleObject/");
+        }
+
+        @TestMetadata("constructorVisibilityChanged")
+        public void testConstructorVisibilityChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/constructorVisibilityChanged/");
+        }
+
+        @TestMetadata("enumEntryAdded")
+        public void testEnumEntryAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/enumEntryAdded/");
+        }
+
+        @TestMetadata("enumEntryRemoved")
+        public void testEnumEntryRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/enumEntryRemoved/");
+        }
+
+        @TestMetadata("enumMemberChanged")
+        public void testEnumMemberChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/enumMemberChanged/");
+        }
+
+        @TestMetadata("flagsAndMemberInDifferentClassesChanged")
+        public void testFlagsAndMemberInDifferentClassesChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/flagsAndMemberInDifferentClassesChanged/");
+        }
+
+        @TestMetadata("flagsAndMemberInSameClassChanged")
+        public void testFlagsAndMemberInSameClassChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/flagsAndMemberInSameClassChanged/");
+        }
+
+        @TestMetadata("implcitUpcast")
+        public void testImplcitUpcast() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/implcitUpcast/");
+        }
+
+        @TestMetadata("inferredTypeArgumentChanged")
+        public void testInferredTypeArgumentChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/inferredTypeArgumentChanged/");
+        }
+
+        @TestMetadata("inferredTypeChanged")
+        public void testInferredTypeChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/inferredTypeChanged/");
+        }
+
+        @TestMetadata("interfaceAnyMethods")
+        public void testInterfaceAnyMethods() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/interfaceAnyMethods/");
+        }
+
+        @TestMetadata("lambdaParameterAffected")
+        public void testLambdaParameterAffected() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/lambdaParameterAffected/");
+        }
+
+        @TestMetadata("methodAdded")
+        public void testMethodAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/methodAdded/");
+        }
+
+        @TestMetadata("methodAnnotationAdded")
+        public void testMethodAnnotationAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/methodAnnotationAdded/");
+        }
+
+        @TestMetadata("methodNullabilityChanged")
+        public void testMethodNullabilityChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/methodNullabilityChanged/");
+        }
+
+        @TestMetadata("methodParameterWithDefaultValueAdded")
+        public void testMethodParameterWithDefaultValueAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/methodParameterWithDefaultValueAdded/");
+        }
+
+        @TestMetadata("methodRemoved")
+        public void testMethodRemoved() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/methodRemoved/");
+        }
+
+        @TestMetadata("overrideExplicit")
+        public void testOverrideExplicit() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/overrideExplicit/");
+        }
+
+        @TestMetadata("overrideImplicit")
+        public void testOverrideImplicit() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/overrideImplicit/");
+        }
+
+        @TestMetadata("propertyNullabilityChanged")
+        public void testPropertyNullabilityChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/propertyNullabilityChanged/");
+        }
+
+        @TestMetadata("sealedClassImplAdded")
+        public void testSealedClassImplAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/sealedClassImplAdded/");
+        }
+
+        @TestMetadata("sealedClassIndirectImplAdded")
+        public void testSealedClassIndirectImplAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/sealedClassIndirectImplAdded/");
+        }
+
+        @TestMetadata("sealedClassNestedImplAdded")
+        public void testSealedClassNestedImplAdded() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/sealedClassNestedImplAdded/");
+        }
+
+        @TestMetadata("starProjectionUpperBoundChanged")
+        public void testStarProjectionUpperBoundChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/starProjectionUpperBoundChanged/");
+        }
+
+        @TestMetadata("supertypesListChanged")
+        public void testSupertypesListChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/supertypesListChanged/");
+        }
+
+        @TestMetadata("typeParameterListChanged")
+        public void testTypeParameterListChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/typeParameterListChanged/");
+        }
+
+        @TestMetadata("varianceChanged")
+        public void testVarianceChanged() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/classHierarchyAffected/varianceChanged/");
+        }
+    }
+
+    @TestMetadata("jps/jps-plugin/testData/incremental/js")
+    @TestDataPath("$PROJECT_ROOT")
+    @RunWith(JUnit3RunnerWithInners.class)
+    public static class Js extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+        private void runTest(String testDataFilePath) throws Exception {
+            KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+        }
+
+        public void testAllFilesPresentInJs() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/js"), Pattern.compile("^([^\\.]+)$"), null, true);
+        }
+
+        @TestMetadata("inlineFunctionLocalDeclarationChanges")
+        public void testInlineFunctionLocalDeclarationChanges() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/js/inlineFunctionLocalDeclarationChanges/");
+        }
+
+        @TestMetadata("jps/jps-plugin/testData/incremental/js/friendsModuleDisabled")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class FriendsModuleDisabled extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+            private void runTest(String testDataFilePath) throws Exception {
+                KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+            }
+
+            public void testAllFilesPresentInFriendsModuleDisabled() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/js/friendsModuleDisabled"), Pattern.compile("^([^\\.]+)$"), null, true);
+            }
+
+            @TestMetadata("internalInlineFunctionIsChanged")
+            public void testInternalInlineFunctionIsChanged() throws Exception {
+                runTest("jps/jps-plugin/testData/incremental/js/friendsModuleDisabled/internalInlineFunctionIsChanged/");
+            }
+
+            @TestMetadata("jps/jps-plugin/testData/incremental/js/friendsModuleDisabled/internalInlineFunctionIsChanged")
+            @TestDataPath("$PROJECT_ROOT")
+            @RunWith(JUnit3RunnerWithInners.class)
+            public static class InternalInlineFunctionIsChanged extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+                private void runTest(String testDataFilePath) throws Exception {
+                    KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+                }
+
+                public void testAllFilesPresentInInternalInlineFunctionIsChanged() throws Exception {
+                    KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/js/friendsModuleDisabled/internalInlineFunctionIsChanged"), Pattern.compile("^([^\\.]+)$"), null, true);
+                }
+            }
+        }
+
+        @TestMetadata("jps/jps-plugin/testData/incremental/js/inlineFunctionLocalDeclarationChanges")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class InlineFunctionLocalDeclarationChanges extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+            private void runTest(String testDataFilePath) throws Exception {
+                KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+            }
+
+            public void testAllFilesPresentInInlineFunctionLocalDeclarationChanges() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/js/inlineFunctionLocalDeclarationChanges"), Pattern.compile("^([^\\.]+)$"), null, true);
+            }
+        }
+    }
+
+    @TestMetadata("jps/jps-plugin/testData/incremental/scopeExpansion")
+    @TestDataPath("$PROJECT_ROOT")
+    @RunWith(JUnit3RunnerWithInners.class)
+    public static class ScopeExpansion extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+        private void runTest(String testDataFilePath) throws Exception {
+            KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+        }
+
+        public void testAllFilesPresentInScopeExpansion() throws Exception {
+            KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/scopeExpansion"), Pattern.compile("^([^\\.]+)$"), Pattern.compile("^protectedBecomesPublicAccessedTroughChild.*"), true);
+        }
+
+        @TestMetadata("changeTypeAliasAndUsage")
+        public void testChangeTypeAliasAndUsage() throws Exception {
+            runTest("jps/jps-plugin/testData/incremental/scopeExpansion/changeTypeAliasAndUsage/");
+        }
+
+        @TestMetadata("jps/jps-plugin/testData/incremental/scopeExpansion/changeTypeAliasAndUsage")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class ChangeTypeAliasAndUsage extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+            private void runTest(String testDataFilePath) throws Exception {
+                KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+            }
+
+            public void testAllFilesPresentInChangeTypeAliasAndUsage() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/scopeExpansion/changeTypeAliasAndUsage"), Pattern.compile("^([^\\.]+)$"), Pattern.compile("^protectedBecomesPublicAccessedTroughChild.*"), true);
+            }
+        }
+
+        @TestMetadata("jps/jps-plugin/testData/incremental/scopeExpansion/protectedBecomesPublicAccessedTroughChild")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class ProtectedBecomesPublicAccessedTroughChild extends AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest {
+            private void runTest(String testDataFilePath) throws Exception {
+                KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+            }
+
+            public void testAllFilesPresentInProtectedBecomesPublicAccessedTroughChild() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("jps/jps-plugin/testData/incremental/scopeExpansion/protectedBecomesPublicAccessedTroughChild"), Pattern.compile("^([^\\.]+)$"), Pattern.compile("^protectedBecomesPublicAccessedTroughChild.*"), true);
+            }
+        }
+    }
+}
diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/TestFirJsSessionFactory.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/TestFirJsSessionFactory.kt
index 54101da..d06be1c 100644
--- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/TestFirJsSessionFactory.kt
+++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/TestFirJsSessionFactory.kt
@@ -64,6 +64,7 @@
             extensionRegistrars,
             languageVersionSettings,
             lookupTracker,
+            icData = null,
             registerExtraComponents,
             sessionConfigurator
         )
diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibDeserializedContainerSource.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibDeserializedContainerSource.kt
index 7b32674..e9061b4 100644
--- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibDeserializedContainerSource.kt
+++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibDeserializedContainerSource.kt
@@ -15,7 +15,7 @@
 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
 
-class KlibDeserializedContainerSource private constructor(
+class KlibDeserializedContainerSource(
     override val isPreReleaseInvisible: Boolean,
     override val presentableString: String,
     val isFromNativeInteropLibrary: Boolean
diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
index 364b75b..906bf95 100644
--- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
+++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
@@ -109,6 +109,18 @@
                 model("incremental/scopeExpansion", extension = null, excludeParentDirs = true)
             }
 
+            testClass<AbstractIncrementalJsFirKlibCompilerWithScopeExpansionRunnerTest> {
+                // IC of sealed interfaces are not supported in JS
+                // Some IC tests fail with K2
+                model("incremental/pureKotlin", extension = null, recursive = false,
+                      excludedPattern = "^(sealed|propertyRedeclaration|funRedeclaration|funVsConstructorOverloadConflict).*")
+                model("incremental/classHierarchyAffected", extension = null, recursive = false,
+                      excludedPattern = "^(secondaryConstructorAdded|withIntermediateBodiesChanged|companionObjectNameChanged).*")
+                model("incremental/js", extension = null, excludeParentDirs = true)
+                model("incremental/scopeExpansion", extension = null, excludeParentDirs = true,
+                      excludedPattern = "^protectedBecomesPublicAccessedTroughChild.*")
+            }
+
             testClass<AbstractIncrementalJsCompilerRunnerWithFriendModulesDisabledTest> {
                 model("incremental/js/friendsModuleDisabled", extension = null, recursive = false)
             }
diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt
index 1cdf250..eed473c 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt
+++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt
@@ -63,7 +63,9 @@
             libraries = libraries,
             friendLibraries = friendLibraries,
             messageCollector = messageCollector,
-            diagnosticsReporter = diagnosticsReporter
+            diagnosticsReporter = diagnosticsReporter,
+            incrementalDataProvider = null,
+            lookupTracker = null,
         )
 
         if (outputs != null) {
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt
index c4e0dbc..bb0ecc8 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsPartialLinkageTestCase.kt
@@ -210,7 +210,9 @@
             libraries = regularDependencies,
             friendLibraries = friendDependencies,
             messageCollector = messageCollector,
-            diagnosticsReporter = diagnosticsReporter
+            diagnosticsReporter = diagnosticsReporter,
+            incrementalDataProvider = null,
+            lookupTracker = null
         )
 
         if (outputs != null) {