[FIR][K/N] Don't use FIR internals in FirNativeObjCOverrideInitChecker

^KT-61564
This commit is contained in:
Vladimir Sukharev
2024-01-12 12:49:09 +01:00
committed by Space Team
parent ad9f7bf90e
commit 55a41961d3
2 changed files with 51 additions and 19 deletions
@@ -18,28 +18,35 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.getSuperClassSymbolOrAny
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.NativeStandardInteropNames.objCOverrideInitClassId
object FirNativeObjCOverrideInitChecker : FirClassChecker() {
@OptIn(SymbolInternals::class)
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
val session = context.session
fun FirConstructor.overridesConstructor(other: FirConstructor): Boolean {
if (valueParameters.size != other.valueParameters.size)
fun FirClassSymbol<*>.constructors(session: FirSession): List<FirConstructorSymbol> {
val result = mutableListOf<FirConstructorSymbol>()
session.declaredMemberScope(this, memberRequiredPhase = null).processDeclaredConstructors { result += it }
return result
}
fun FirConstructorSymbol.overridesConstructor(other: FirConstructorSymbol): Boolean {
val aParams = this.valueParameterSymbols
val bParams = other.valueParameterSymbols
if (aParams.size != bParams.size)
return false
return valueParameters.zip(other.valueParameters).all { (thisParameter, otherParameter) ->
thisParameter.name == otherParameter.name && thisParameter.returnTypeRef.coneType == otherParameter.returnTypeRef.coneType
return aParams.zip(bParams).all { (thisParameter, otherParameter) ->
thisParameter.name == otherParameter.name && thisParameter.resolvedReturnType == otherParameter.resolvedReturnType
}
}
fun checkCanGenerateOverrideInit(firClass: FirClass, constructor: FirConstructor) {
val superClass = (firClass as FirRegularClass).symbol.getSuperClassSymbolOrAny(session)
val superConstructors = superClass.fir.constructors(session).filter {
constructor.overridesConstructor(it.fir)
val superConstructors = superClass.constructors(session).filter {
constructor.symbol.overridesConstructor(it)
}.toList()
val superConstructor: FirConstructorSymbol = superConstructors.singleOrNull() ?: run {
@@ -60,11 +67,11 @@ object FirNativeObjCOverrideInitChecker : FirClassChecker() {
return
}
val initMethod = superConstructor.fir.getObjCInitMethod(session, ScopeSession())!!
val initMethod = superConstructor.getObjCInitMethod(session, ScopeSession())!!
// Remove fake overrides of this init method, also check for explicit overriding:
firClass.declarations.forEach {
if (it is FirSimpleFunction && initMethod.symbol in it.getOverriddenSymbols(context) && !it.isSubstitutionOrIntersectionOverride) {
if (it is FirSimpleFunction && initMethod in it.getOverriddenSymbols(context) && !it.isSubstitutionOrIntersectionOverride) {
reporter.reportOn(
constructor.source,
FirNativeErrors.CONSTRUCTOR_OVERRIDES_ALREADY_OVERRIDDEN_OBJC_INITIALIZER,
@@ -13,12 +13,15 @@ import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
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.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.name.Name
@@ -69,18 +72,40 @@ fun FirConstructor.getObjCInitMethod(session: FirSession, scopeSession: ScopeSes
return null
}
fun FirConstructorSymbol.getObjCInitMethod(session: FirSession, scopeSession: ScopeSession): FirFunctionSymbol<*>? {
this.annotations.getAnnotationByClassId(NativeStandardInteropNames.objCConstructorClassId, session)?.let { annotation ->
val initSelector: String = annotation.constStringArgument("initSelector")
val classSymbol = containingClassLookupTag()?.toSymbol(session) as FirClassSymbol<*>
val initSelectors = mutableListOf<FirFunctionSymbol<*>>()
session.declaredMemberScope(classSymbol, memberRequiredPhase = null)
.processAllFunctions {
if (it.decodeObjCMethodAnnotation(session)?.selector == initSelector)
initSelectors.add(it)
}
return initSelectors.singleOrNull()
?: error("expected one init method for $classSymbol $initSelector, got ${initSelectors.size}")
}
return null
}
/**
* mimics FunctionDescriptor.decodeObjCMethodAnnotation()
*/
internal fun List<FirAnnotation>.decodeObjCMethodAnnotation(session: FirSession): ObjCMethodInfo? =
getAnnotationByClassId(NativeStandardInteropNames.objCMethodClassId, session)?.let {
ObjCMethodInfo(
selector = it.constStringArgument("selector"),
encoding = it.constStringArgument("encoding"),
isStret = it.constBooleanArgumentOrNull("isStret") ?: false,
directSymbol = getAnnotationByClassId(NativeStandardInteropNames.objCDirectClassId, session)?.constStringArgument("symbol"),
)
}
internal fun FirFunction.decodeObjCMethodAnnotation(session: FirSession): ObjCMethodInfo? =
annotations.getAnnotationByClassId(NativeStandardInteropNames.objCMethodClassId, session)?.let {
ObjCMethodInfo(
selector = it.constStringArgument("selector"),
encoding = it.constStringArgument("encoding"),
isStret = it.constBooleanArgumentOrNull("isStret") ?: false,
directSymbol = annotations.getAnnotationByClassId(NativeStandardInteropNames.objCDirectClassId, session)?.constStringArgument("symbol"),
)
}
annotations.decodeObjCMethodAnnotation(session)
internal fun FirFunctionSymbol<*>.decodeObjCMethodAnnotation(session: FirSession): ObjCMethodInfo? =
annotations.decodeObjCMethodAnnotation(session)
private fun FirAnnotation.constStringArgument(argumentName: String): String =