[K2/N] KT-56030: Support Objective-C overloading by param names only
Merge-request: KT-MR-8901 Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
c957a0b43b
commit
b9633375b4
+11
-5
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.ManglerChecker
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
|
||||
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
|
||||
import org.jetbrains.kotlin.backend.konan.driver.phases.Fir2IrOutput
|
||||
@@ -18,16 +19,15 @@ import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentTypeTransformer
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrPluginContext
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrVisibilityConverter
|
||||
import org.jetbrains.kotlin.fir.backend.*
|
||||
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
|
||||
import org.jetbrains.kotlin.fir.pipeline.convertToIrAndActualize
|
||||
import org.jetbrains.kotlin.fir.signaturer.Ir2FirManglerAdapter
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
|
||||
@@ -74,10 +74,17 @@ internal fun PhaseContext.fir2Ir(
|
||||
linkViaSignatures = false,
|
||||
signatureComposerCreator = null,
|
||||
irMangler = KonanManglerIr,
|
||||
firManglerCreator = { FirNativeKotlinMangler() },
|
||||
visibilityConverter = Fir2IrVisibilityConverter.Default,
|
||||
diagnosticReporter = diagnosticsReporter,
|
||||
languageVersionSettings = configuration.languageVersionSettings,
|
||||
kotlinBuiltIns = builtInsModule ?: DefaultBuiltIns.Instance,
|
||||
fir2IrResultPostCompute = {
|
||||
// it's important to compare manglers before actualization, since IR will be actualized, while FIR won't
|
||||
irModuleFragment.acceptVoid(
|
||||
ManglerChecker(KonanManglerIr, Ir2FirManglerAdapter(FirNativeKotlinMangler()), needsChecking = ManglerChecker.hasMetadata)
|
||||
)
|
||||
}
|
||||
).also {
|
||||
(it.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = librariesDescriptors }
|
||||
}
|
||||
@@ -86,7 +93,6 @@ internal fun PhaseContext.fir2Ir(
|
||||
}
|
||||
|
||||
val symbols = createKonanSymbols(irModuleFragment, components, pluginContext)
|
||||
// TODO KT-55580 Invoke CopyDefaultValuesToActualPhase, same as PsiToir phase does.
|
||||
|
||||
val renderDiagnosticNames = configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
|
||||
FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(diagnosticsReporter, messageCollector, renderDiagnosticNames)
|
||||
|
||||
+7
-5
@@ -10,20 +10,19 @@ import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.common.prepareNativeSessions
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||
import org.jetbrains.kotlin.fir.BinaryModuleData
|
||||
import org.jetbrains.kotlin.fir.DependencyListForCliModule
|
||||
import org.jetbrains.kotlin.fir.FirModuleCapabilities
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||
import org.jetbrains.kotlin.fir.pipeline.FirResult
|
||||
import org.jetbrains.kotlin.fir.pipeline.buildResolveAndCheckFir
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.ImplicitIntegerCoercionModuleCapability
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.library.isInterop
|
||||
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||
import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
|
||||
|
||||
@OptIn(SessionConfiguration::class)
|
||||
internal fun PhaseContext.firFrontend(input: KotlinCoreEnvironment): FirOutput {
|
||||
val configuration = input.configuration
|
||||
val messageCollector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
@@ -56,7 +55,10 @@ internal fun PhaseContext.firFrontend(input: KotlinCoreEnvironment): FirOutput {
|
||||
|
||||
val sessionsWithSources = prepareNativeSessions(
|
||||
ktFiles, configuration, mainModuleName, resolvedLibraries, dependencyList,
|
||||
extensionRegistrars, isCommonSourceForPsi, fileBelongsToModuleForPsi
|
||||
extensionRegistrars, isCommonSourceForPsi, fileBelongsToModuleForPsi,
|
||||
registerExtraComponents = {
|
||||
it.register(FirOverrideChecker::class, FirNativeOverrideChecker(it))
|
||||
},
|
||||
)
|
||||
|
||||
val outputs = sessionsWithSources.map { (session, sources) ->
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinExportChecker
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinMangleComputer
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleMode
|
||||
import org.jetbrains.kotlin.backend.common.serialization.mangle.SpecialDeclarationType
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.backend.FirBasedKotlinMangler
|
||||
import org.jetbrains.kotlin.fir.backend.FirExportCheckerVisitor
|
||||
import org.jetbrains.kotlin.fir.backend.FirMangleComputer
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.toSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class FirNativeKotlinMangler : FirBasedKotlinMangler() {
|
||||
override fun getMangleComputer(mode: MangleMode, compatibleMode: Boolean): KotlinMangleComputer<FirDeclaration> {
|
||||
return FirNativeKotlinMangleComputer(StringBuilder(256), mode)
|
||||
}
|
||||
|
||||
override fun getExportChecker(compatibleMode: Boolean): KotlinExportChecker<FirDeclaration> = FirNativeExportCheckerVisitor()
|
||||
|
||||
override fun FirDeclaration.isExported(compatibleMode: Boolean): Boolean =
|
||||
getExportChecker(compatibleMode).check(this, SpecialDeclarationType.REGULAR)
|
||||
}
|
||||
|
||||
class FirNativeExportCheckerVisitor : FirExportCheckerVisitor() {
|
||||
/**
|
||||
* mimics AbstractKonanDescriptorMangler::DeclarationDescriptor.isPlatformSpecificExport()
|
||||
*/
|
||||
override fun FirDeclaration.isPlatformSpecificExported(): Boolean {
|
||||
fun List<FirAnnotation>.hasAnnotation(fqName: FqName) = hasAnnotation(ClassId.topLevel(fqName), moduleData.session)
|
||||
|
||||
if (this is FirCallableDeclaration && isSubstitutionOrIntersectionOverride)
|
||||
return false
|
||||
|
||||
if (annotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
|
||||
// Treat any `@SymbolName` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(KonanFqNames.gcUnsafeCall)) {
|
||||
// Treat any `@GCUnsafeCall` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
|
||||
// Treat any `@ExportForCppRuntime` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(RuntimeNames.cnameAnnotation)) {
|
||||
// Treat `@CName` declaration as exported.
|
||||
return true
|
||||
}
|
||||
if (annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class FirNativeKotlinMangleComputer(
|
||||
builder: StringBuilder,
|
||||
mode: MangleMode,
|
||||
) : FirMangleComputer(builder, mode) {
|
||||
override fun copy(newMode: MangleMode): FirNativeKotlinMangleComputer =
|
||||
FirNativeKotlinMangleComputer(builder, newMode)
|
||||
|
||||
/**
|
||||
* mimics FunctionDescriptor.platformSpecificFunctionName()
|
||||
*/
|
||||
override fun FirFunction.platformSpecificFunctionName(): String? {
|
||||
val session = moduleData.session
|
||||
val scopeSession = ScopeSession()
|
||||
getInitMethodIfObjCConstructor(session, scopeSession)
|
||||
?.getObjCMethodInfoFromOverriddenFunctions(session, scopeSession)
|
||||
?.let {
|
||||
return buildString {
|
||||
receiverParameter?.let {
|
||||
append(it.getTypeName(session))
|
||||
append(".")
|
||||
}
|
||||
|
||||
append("objc:")
|
||||
append(it.selector)
|
||||
if ((this@platformSpecificFunctionName is FirConstructor) && isObjCConstructor(session)) append("#Constructor")
|
||||
|
||||
if (this@platformSpecificFunctionName is FirPropertyAccessor) {
|
||||
append("#Accessor")
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun FirFunction.specialValueParamPrefix(param: FirValueParameter): String {
|
||||
val session = moduleData.session
|
||||
return if (this.hasObjCMethodAnnotation(session) || this.hasObjCFactoryAnnotation(session) || this.isObjCClassMethod(session))
|
||||
"${param.name}:"
|
||||
else
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirReceiverParameter.getTypeName(session: FirSession): String {
|
||||
return when (val symbol = typeRef.coneType.toSymbol(session)) {
|
||||
is FirClassLikeSymbol -> symbol.classId.shortClassName.asString()
|
||||
is FirTypeParameterSymbol -> symbol.name.asString()
|
||||
else -> error("Unexpected symbol class: ${symbol?.javaClass?.name}")
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker
|
||||
|
||||
class FirNativeOverrideChecker(private val session: FirSession) : FirOverrideChecker {
|
||||
private val standardOverrideChecker = FirStandardOverrideChecker(session)
|
||||
|
||||
override fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean =
|
||||
overrideCandidate.isPlatformOverriddenFunction(session, baseDeclaration)
|
||||
?: standardOverrideChecker.isOverriddenFunction(overrideCandidate, baseDeclaration)
|
||||
|
||||
override fun isOverriddenProperty(overrideCandidate: FirCallableDeclaration, baseDeclaration: FirProperty): Boolean =
|
||||
overrideCandidate.isPlatformOverriddenProperty(baseDeclaration)
|
||||
?: standardOverrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||
|
||||
// FIXME KT-57640: Revise the necessity of platform-specific property overridability handling
|
||||
private fun FirCallableDeclaration.isPlatformOverriddenProperty(baseDeclaration: FirProperty): Boolean? {
|
||||
if (this !is FirProperty || name != baseDeclaration.name) {
|
||||
return null
|
||||
}
|
||||
if (this.isExternalObjCClassProperty(session) && baseDeclaration.isExternalObjCClassProperty(session))
|
||||
return true
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* mimics ObjCOverridabilityCondition.isOverridable
|
||||
*/
|
||||
private fun FirSimpleFunction.isPlatformOverriddenFunction(session: FirSession, baseDeclaration: FirSimpleFunction): Boolean? {
|
||||
if (this.name != baseDeclaration.name) {
|
||||
return null
|
||||
}
|
||||
val superInfo = baseDeclaration.decodeObjCMethodAnnotation(session) ?: return null
|
||||
val subInfo = decodeObjCMethodAnnotation(session)
|
||||
return if (subInfo != null) {
|
||||
// Overriding Objective-C method by Objective-C method in interop stubs.
|
||||
// Don't even check method signatures, so this check is weaker than the standard one
|
||||
superInfo.selector == subInfo.selector
|
||||
} else {
|
||||
// Overriding Objective-C method by Kotlin method.
|
||||
if (!parameterNamesMatch(this, baseDeclaration)) false else null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mimics ObjCInteropKt.parameterNamesMatch
|
||||
*/
|
||||
private fun parameterNamesMatch(first: FirSimpleFunction, second: FirSimpleFunction): Boolean {
|
||||
// The original Objective-C method selector is represented as
|
||||
// function name and parameter names (except first).
|
||||
|
||||
if (first.valueParameters.size != second.valueParameters.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
first.valueParameters.forEachIndexed { index, parameter ->
|
||||
if (index > 0 && parameter.name != second.valueParameters[index].name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.getContainingClass
|
||||
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.processAllFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.scopeForClass
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
private val objCDirectClassId = ClassId.topLevel(objCDirectFqName)
|
||||
private val objCMethodClassId = ClassId.topLevel(objCMethodFqName)
|
||||
private val objCObjectClassId = ClassId.topLevel(objCObjectFqName)
|
||||
private val objCFactoryClassId = ClassId.topLevel(objCFactoryFqName)
|
||||
private val objCConstructorClassId = ClassId.topLevel(objCConstructorFqName)
|
||||
private val externalObjCClassClassId = ClassId.topLevel(externalObjCClassFqName)
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
internal fun FirFunction.getObjCMethodInfoFromOverriddenFunctions(session: FirSession, scopeSession: ScopeSession): ObjCMethodInfo? {
|
||||
decodeObjCMethodAnnotation(session)?.let {
|
||||
return it
|
||||
}
|
||||
// recursively find ObjCMethod annotation in getDirectOverriddenFunctions() (same as `overriddenDescriptors` in K1)
|
||||
return when (val symbol = this.symbol) {
|
||||
is FirNamedFunctionSymbol -> {
|
||||
val firClassSymbol = containingClassLookupTag()?.toSymbol(session) as FirClassSymbol<*>?
|
||||
firClassSymbol?.let {
|
||||
val unsubstitutedScope = it.unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = false, memberRequiredPhase = null)
|
||||
// call of `processFunctionsByName()` is needed only for necessary side-effect before `getDirectOverriddenFunctions` call
|
||||
unsubstitutedScope.processFunctionsByName(symbol.name) {}
|
||||
unsubstitutedScope.getDirectOverriddenFunctions(symbol).firstNotNullOfOrNull {
|
||||
it.fir.getObjCMethodInfoFromOverriddenFunctions(session, scopeSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mimics ConstructorDescriptor.getObjCInitMethod()
|
||||
*/
|
||||
@OptIn(SymbolInternals::class)
|
||||
private fun FirConstructor.getObjCInitMethod(session: FirSession, scopeSession: ScopeSession): FirFunction? {
|
||||
this.annotations.getAnnotationByClassId(objCConstructorClassId, session)?.let { annotation ->
|
||||
val initSelector: String = annotation.constStringArgument("initSelector")
|
||||
val classSymbol = containingClassLookupTag()?.toSymbol(session) as FirClassSymbol<*>
|
||||
val initSelectors = mutableListOf<FirFunction>()
|
||||
classSymbol.fir.scopeForClass(ConeSubstitutor.Empty, session, scopeSession, classSymbol.toLookupTag(), memberRequiredPhase = null)
|
||||
.processAllFunctions {
|
||||
if (it.fir.decodeObjCMethodAnnotation(session)?.selector == initSelector)
|
||||
initSelectors.add(it.fir)
|
||||
}
|
||||
return initSelectors.singleOrNull()
|
||||
?: error("expected one init method for $classSymbol $initSelector, got ${initSelectors.size}")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* mimics FunctionDescriptor.decodeObjCMethodAnnotation()
|
||||
*/
|
||||
internal fun FirFunction.decodeObjCMethodAnnotation(session: FirSession): ObjCMethodInfo? =
|
||||
annotations.getAnnotationByClassId(objCMethodClassId, session)?.let {
|
||||
ObjCMethodInfo(
|
||||
selector = it.constStringArgument("selector"),
|
||||
encoding = it.constStringArgument("encoding"),
|
||||
isStret = it.constBooleanArgumentOrNull("isStret") ?: false,
|
||||
directSymbol = annotations.getAnnotationByClassId(objCDirectClassId, session)?.constStringArgument("symbol"),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun FirAnnotation.constStringArgument(argumentName: String): String =
|
||||
constArgument(argumentName) as? String ?: error("Expected string constant value of argument '$argumentName' at annotation $this")
|
||||
|
||||
private fun FirAnnotation.constBooleanArgumentOrNull(argumentName: String): Boolean? =
|
||||
constArgument(argumentName) as Boolean?
|
||||
|
||||
private fun FirAnnotation.constArgument(argumentName: String) =
|
||||
(argumentMapping.mapping[Name.identifier(argumentName)] as? FirConstExpression<*>)?.value
|
||||
|
||||
internal fun FirFunction.hasObjCFactoryAnnotation(session: FirSession) = this.annotations.hasAnnotation(objCFactoryClassId, session)
|
||||
|
||||
internal fun FirFunction.hasObjCMethodAnnotation(session: FirSession) = this.annotations.hasAnnotation(objCMethodClassId, session)
|
||||
|
||||
/**
|
||||
* almost mimics FunctionDescriptor.isObjCClassMethod(), apart from `it.isObjCClass()` changed to `it.symbol.isObjCClass(session)` for simplicity
|
||||
*/
|
||||
internal fun FirFunction.isObjCClassMethod(session: FirSession) =
|
||||
getContainingClass(session).let { it is FirClass && it.symbol.isObjCClass(session) }
|
||||
|
||||
/**
|
||||
* mimics ConstructorDescriptor.isObjCConstructor()
|
||||
*/
|
||||
internal fun FirConstructor.isObjCConstructor(session: FirSession) =
|
||||
this.annotations.hasAnnotation(objCConstructorClassId, session)
|
||||
|
||||
/**
|
||||
* mimics IrClass.isObjCClass()
|
||||
*/
|
||||
private fun FirClassSymbol<*>.isObjCClass(session: FirSession) = classId.packageFqName != interopPackageName &&
|
||||
selfOrAnySuperClass(session) {
|
||||
it.classId == objCObjectClassId
|
||||
}
|
||||
|
||||
/**
|
||||
* almost mimics `IrClass.selfOrAnySuperClass()` apart from using of classsymbol instead of class itself, to use `classId.toSymbol()`
|
||||
*/
|
||||
private fun FirClassSymbol<*>.selfOrAnySuperClass(session: FirSession, pred: (FirClassSymbol<*>) -> Boolean): Boolean =
|
||||
DFS.ifAny(
|
||||
listOf(this),
|
||||
{ current -> current.resolvedSuperTypes.mapNotNull { it.classId?.toSymbol(session) as? FirClassSymbol } },
|
||||
pred
|
||||
)
|
||||
|
||||
internal fun FirFunction.getInitMethodIfObjCConstructor(session: FirSession, scopeSession: ScopeSession): FirFunction? =
|
||||
if (this is FirConstructor && isObjCConstructor(session))
|
||||
getObjCInitMethod(session, scopeSession)
|
||||
else
|
||||
this
|
||||
|
||||
internal fun FirProperty.isExternalObjCClassProperty(session: FirSession) =
|
||||
(getContainingClassSymbol(session) as? FirClassSymbol)?.isExternalObjCClass(session) == true
|
||||
|
||||
internal fun FirClassSymbol<*>.isExternalObjCClass(session: FirSession): Boolean =
|
||||
isObjCClass(session) &&
|
||||
parentsWithSelf(session).filterIsInstance<FirClass>().any {
|
||||
it.hasAnnotation(externalObjCClassClassId, session)
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
fun FirClassSymbol<*>.parentsWithSelf(session: FirSession): Sequence<FirClassLikeDeclaration> {
|
||||
return generateSequence<FirClassLikeDeclaration>(fir) { it.getContainingDeclaration(session) }
|
||||
}
|
||||
+8
-17
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBasedClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getPublicSignature
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -30,21 +29,15 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
|
||||
internal val interopPackageName = InteropFqNames.packageName
|
||||
internal val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject"))
|
||||
internal val objCObjectIdSignature = getTopLevelPublicSignature(objCObjectFqName)
|
||||
private val objCClassFqName = interopPackageName.child(Name.identifier("ObjCClass"))
|
||||
private val objCClassIdSignature = getTopLevelPublicSignature(objCClassFqName)
|
||||
private val objCProtocolFqName = interopPackageName.child(Name.identifier("ObjCProtocol"))
|
||||
private val objCProtocolIdSignature = getTopLevelPublicSignature(objCProtocolFqName)
|
||||
internal val externalObjCClassFqName = interopPackageName.child(Name.identifier("ExternalObjCClass"))
|
||||
private val objCMethodFqName = interopPackageName.child(Name.identifier("ObjCMethod"))
|
||||
private val objCDirectFqName = interopPackageName.child(Name.identifier("ObjCDirect"))
|
||||
private val objCConstructorFqName = FqName("kotlinx.cinterop.ObjCConstructor")
|
||||
private val objCFactoryFqName = interopPackageName.child(Name.identifier("ObjCFactory"))
|
||||
internal val objCDirectFqName = interopPackageName.child(Name.identifier("ObjCDirect"))
|
||||
internal val objCMethodFqName = interopPackageName.child(Name.identifier("ObjCMethod"))
|
||||
internal val objCConstructorFqName = FqName("kotlinx.cinterop.ObjCConstructor")
|
||||
internal val objCFactoryFqName = interopPackageName.child(Name.identifier("ObjCFactory"))
|
||||
private val objcnamesForwardDeclarationsPackageName = Name.identifier("objcnames")
|
||||
|
||||
private fun getTopLevelPublicSignature(fqName: FqName): IdSignature.CommonSignature =
|
||||
getPublicSignature(fqName.parent(), fqName.shortName().asString())
|
||||
|
||||
fun ClassDescriptor.isObjCClass(): Boolean =
|
||||
this.containingDeclaration.fqNameSafe != interopPackageName &&
|
||||
this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } // TODO: this is not cheap. Cache me!
|
||||
@@ -59,7 +52,7 @@ private fun IrClass.selfOrAnySuperClass(pred: (IrClass) -> Boolean): Boolean {
|
||||
}
|
||||
|
||||
internal fun IrClass.isObjCClass() = this.packageFqName != interopPackageName &&
|
||||
selfOrAnySuperClass { objCObjectIdSignature == it.symbol.signature }
|
||||
selfOrAnySuperClass { it.hasEqualFqName(objCObjectFqName) }
|
||||
|
||||
fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() &&
|
||||
this.parentsWithSelf.filterIsInstance<ClassDescriptor>().any {
|
||||
@@ -78,10 +71,10 @@ fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().a
|
||||
}
|
||||
|
||||
fun IrClass.isObjCMetaClass(): Boolean = selfOrAnySuperClass {
|
||||
objCClassIdSignature == it.symbol.signature
|
||||
it.hasEqualFqName(objCClassFqName)
|
||||
}
|
||||
|
||||
fun IrClass.isObjCProtocolClass(): Boolean = objCProtocolIdSignature == symbol.signature
|
||||
fun IrClass.isObjCProtocolClass(): Boolean = hasEqualFqName(objCProtocolFqName)
|
||||
|
||||
fun ClassDescriptor.isObjCProtocolClass(): Boolean =
|
||||
this.fqNameSafe == objCProtocolFqName
|
||||
@@ -123,9 +116,7 @@ private fun FunctionDescriptor.decodeObjCMethodAnnotation(): ObjCMethodInfo? {
|
||||
selector = it.getStringValue("selector"),
|
||||
encoding = it.getStringValue("encoding"),
|
||||
isStret = it.getArgumentValueOrNull<Boolean>("isStret") ?: false,
|
||||
directSymbol = this.annotations.findAnnotation(objCDirectFqName)?.let {
|
||||
it.getStringValue("symbol")
|
||||
},
|
||||
directSymbol = this.annotations.findAnnotation(objCDirectFqName)?.getStringValue("symbol"),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4917,7 +4917,7 @@ standaloneTest("interop_opengl_teapot") {
|
||||
|
||||
if (PlatformInfo.isAppleTarget(project)) {
|
||||
interopTest("interop_objc_smoke") {
|
||||
enabled = !isNoopGC && !isK2(project) // KT-56030
|
||||
enabled = !isNoopGC
|
||||
source = "interop/objc/smoke.kt"
|
||||
interop = 'objcSmoke'
|
||||
doBeforeBuild {
|
||||
@@ -4968,7 +4968,7 @@ if (PlatformInfo.isAppleTarget(project)) {
|
||||
}
|
||||
|
||||
interopTestMultifile("interop_objc_tests") {
|
||||
disabled = isK2(project) // KT-55909
|
||||
disabled = isK2(project) // KT-57504
|
||||
source = "interop/objc/tests/"
|
||||
interop = 'objcTests'
|
||||
flags = ['-tr', '-e', 'main']
|
||||
@@ -5259,8 +5259,7 @@ if (PlatformInfo.isAppleTarget(project)) {
|
||||
|
||||
standaloneTest("interop_kt55653") {
|
||||
// Test depends on macOS-specific AppKit
|
||||
enabled = (project.testTarget == 'macos_x64' || project.testTarget == 'macos_arm64' || project.testTarget == null) &&
|
||||
!isK2(project) // KT-56030
|
||||
enabled = (project.testTarget == 'macos_x64' || project.testTarget == 'macos_arm64' || project.testTarget == null)
|
||||
source = "interop/objc/kt55653/main.kt"
|
||||
useGoldenData = true
|
||||
UtilsKt.dependsOnPlatformLibs(it)
|
||||
|
||||
Reference in New Issue
Block a user