almost works
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt
index 2925216..ed32079 100644
--- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirNativeSessionFactory.kt
@@ -37,8 +37,10 @@
registerExtraComponents,
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { session, builtinsModuleData, kotlinScopeProvider ->
+ val klibBasedSymbolProvider = KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, resolvedLibraries)
listOf(
- KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, resolvedLibraries),
+ klibBasedSymbolProvider,
+ ForwardDeclarationsSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, klibBasedSymbolProvider, resolvedLibraries),
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
)
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ForwardDeclarationsSymbolProvider.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ForwardDeclarationsSymbolProvider.kt
new file mode 100644
index 0000000..37c0aef
--- /dev/null
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ForwardDeclarationsSymbolProvider.kt
@@ -0,0 +1,203 @@
+/*
+ * 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.descriptors.ClassKind
+import org.jetbrains.kotlin.descriptors.EffectiveVisibility
+import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.jetbrains.kotlin.fir.BinaryModuleData
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
+import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
+import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
+import org.jetbrains.kotlin.fir.declarations.getDeprecationsProvider
+import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
+import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
+import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
+import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
+import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
+import org.jetbrains.kotlin.fir.symbols.impl.*
+import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
+import org.jetbrains.kotlin.fir.types.constructClassType
+import org.jetbrains.kotlin.library.exportForwardDeclarations
+import org.jetbrains.kotlin.library.isInterop
+import org.jetbrains.kotlin.library.metadata.impl.ExportedForwardDeclarationChecker
+import org.jetbrains.kotlin.library.metadata.impl.ForwardDeclarationsFqNames
+import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
+import org.jetbrains.kotlin.library.packageFqName
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.utils.SmartList
+
+class ForwardDeclarationsSymbolProvider(
+ session: FirSession,
+ moduleDataProvider: ModuleDataProvider,
+ private val kotlinScopeProvider: FirKotlinScopeProvider,
+ val delegate: KlibBasedSymbolProvider,
+ private val resolvedLibraries: Collection<KotlinResolvedLibrary>,
+) : FirSymbolProvider(session) {
+
+ private class InteropLibraryInfo(
+ val library: KotlinResolvedLibrary,
+ val mainPackageName: FqName,
+ val exportedForwardDeclarationsByName: Map<String, FqName>,
+ )
+
+ private val forwardDeclarationsModuleData = BinaryModuleData.createDependencyModuleData(
+ Name.special("<forward declarations>"),
+ moduleDataProvider.platform,
+ moduleDataProvider.analyzerServices,
+ ).apply {
+ bindSession(session)
+ }
+
+ private val interopLibrariesByPackageName: Map<String, List<InteropLibraryInfo>> by lazy {
+ // FIXME: more granularly lazy?
+ buildMap<String, SmartList<InteropLibraryInfo>> {
+ for (resolvedLibrary in resolvedLibraries) {
+ val library = resolvedLibrary.library
+ if (!library.isInterop) continue
+
+ val mainPackageFqName = library.packageFqName?. let{ FqName(it) }
+ ?: error("Inconsistent manifest: interop library ${library.libraryName} should have `package` specified")
+ val exportedForwardDeclarations = library.exportForwardDeclarations.map { FqName(it) }.associateBy { it.shortName().asString() }
+
+ getOrPut(mainPackageFqName.asString() /* FIXME */) { SmartList() }.add(
+ InteropLibraryInfo(
+ resolvedLibrary, mainPackageFqName, exportedForwardDeclarations
+ )
+ )
+ }
+ }
+ }
+
+ override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
+ val packageStringName = classId.packageFqName.asString()
+
+ if (packageStringName in ExportedForwardDeclarationChecker.values().map { it.fqName.asString() }) {
+ // FIXME: this would probably lead to class being deserialized twice (with two different symbols).
+ return getForwardDeclarationClassLikeSymbolByClassId(classId)
+ }
+
+ for (interopLibraryInfo in interopLibrariesByPackageName[packageStringName].orEmpty()) {
+ val exportedForwardDeclarationPackage =
+ interopLibraryInfo.exportedForwardDeclarationsByName[classId.outermostClassId.shortClassName.asString()]?.parent() ?: continue
+
+ val exportedForwardDeclarationClassId = ClassId(exportedForwardDeclarationPackage, classId.relativeClassName, classId.isLocal)
+
+ // FIXME: can directly use specialized *cnames.* impl.
+ return getClassLikeSymbolByClassId(exportedForwardDeclarationClassId)
+ }
+
+ return null
+ }
+
+ private fun getForwardDeclarationClassLikeSymbolByClassId(
+ classId: ClassId
+ ): FirClassLikeSymbol<*>? {
+ val packageStringName = classId.packageFqName.asString()
+// val checker = ExportedForwardDeclarationChecker.values().single { it.fqName.asString() == packageStringName }
+ interopLibrariesByPackageName.values.flatten().forEach { interopLibraryInfo ->
+ // FIXME: check if the library has this classifier first, by using classifierNames.
+ // FIXME: use only this specific library
+ // FIXME: check kind and supertype
+ val newClassId = ClassId(interopLibraryInfo.mainPackageName, classId.relativeClassName, classId.isLocal)
+ delegate.getClassLikeSymbolByClassId(newClassId)?.let {
+ return it
+ }
+ }
+
+ val superClassFqName: String
+ val classKind: ClassKind
+
+ when (FqName(packageStringName)) {
+ ForwardDeclarationsFqNames.cNamesStructs -> {
+ classKind = ClassKind.CLASS
+ superClassFqName = "kotlinx.cinterop.COpaque"
+ }
+ ForwardDeclarationsFqNames.objCNamesClasses -> {
+ classKind = ClassKind.CLASS
+ superClassFqName = "kotlinx.cinterop.ObjCObjectBase"
+ }
+ ForwardDeclarationsFqNames.objCNamesProtocols -> {
+ classKind = ClassKind.INTERFACE
+ superClassFqName = "kotlinx.cinterop.ObjCObject"
+ }
+ else -> error(classId)
+ }
+
+ if (classId.isNestedClass) return null
+
+ val symbol = FirRegularClassSymbol(classId)
+ val modality = Modality.FINAL
+ val visibility = Visibilities.Public
+ val status = FirResolvedDeclarationStatusImpl(
+ visibility,
+ modality,
+ EffectiveVisibility.Public
+ ).apply {
+ isExpect = false // FIXME: copy from descriptors
+ isActual = false
+ isCompanion = false
+ isInner = false
+ isData = false
+ isInline = false
+ isExternal = false
+ isFun = false
+ }
+
+ buildRegularClass {
+ this.moduleData = forwardDeclarationsModuleData
+ this.origin = FirDeclarationOrigin.Library
+ name = classId.shortClassName
+ this.status = status
+ this.classKind = classKind
+ this.scopeProvider = kotlinScopeProvider // FIXME
+ this.symbol = symbol
+
+ resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
+
+ superTypeRefs += buildResolvedTypeRef {
+ type = ConeClassLikeLookupTagImpl(ClassId.topLevel(FqName(superClassFqName)))
+ .constructClassType(emptyArray(), isNullable = false)
+ }
+
+ }.apply {
+// versionRequirementsTable = context.versionRequirementTable
+
+// sourceElement = containerSource
+
+ replaceDeprecationsProvider(getDeprecationsProvider(session))
+
+// classProto.getExtensionOrNull(JvmProtoBuf.classModuleName)?.let { idx ->
+// moduleName = nameResolver.getString(idx)
+// }
+ }
+ return symbol
+ }
+
+ @FirSymbolProviderInternals
+ override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
+ }
+
+ @FirSymbolProviderInternals
+ override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
+ }
+
+ @FirSymbolProviderInternals
+ override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
+ }
+
+ override fun getPackage(fqName: FqName): FqName? {
+ if (fqName.asString() in interopLibrariesByPackageName) return fqName
+ if (fqName in setOf(ForwardDeclarationsFqNames.cNamesStructs, ForwardDeclarationsFqNames.objCNamesClasses, ForwardDeclarationsFqNames.objCNamesProtocols)) {
+ return fqName
+ }
+ return null
+ }
+}
\ No newline at end of file
diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataDeserializedPackageFragmentsFactoryImpl.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataDeserializedPackageFragmentsFactoryImpl.kt
index 84754ea..b739cb0 100644
--- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataDeserializedPackageFragmentsFactoryImpl.kt
+++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibMetadataDeserializedPackageFragmentsFactoryImpl.kt
@@ -132,7 +132,7 @@
}
/**
- * The package fragment that redirects all requests for classifier lookup to its targets.
+ * The package fragment that redirects all requests for classifier lookup to its targets: cnames.* -> proper package.
*/
class ClassifierAliasingPackageFragmentDescriptor(
targets: List<KlibMetadataPackageFragment>,
diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt
index 14f4110..b12f9b0 100644
--- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt
+++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/impl/KlibResolvedModuleDescriptorsFactoryImpl.kt
@@ -227,11 +227,11 @@
internal val cInterop = FqName("kotlinx.cinterop")
private val cNames = FqName("cnames")
- internal val cNamesStructs = cNames.child(Name.identifier("structs"))
+ val cNamesStructs = cNames.child(Name.identifier("structs"))
private val objCNames = FqName("objcnames")
- internal val objCNamesClasses = objCNames.child(Name.identifier("classes"))
- internal val objCNamesProtocols = objCNames.child(Name.identifier("protocols"))
+ val objCNamesClasses = objCNames.child(Name.identifier("classes"))
+ val objCNamesProtocols = objCNames.child(Name.identifier("protocols"))
val syntheticPackages = setOf(cNames, objCNames)
}