Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrMutableAnnotationContainer
import org.jetbrains.kotlin.ir.declarations.IrParameterKind
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
Expand Down Expand Up @@ -119,7 +120,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import java.lang.reflect.Field
import java.util.function.Predicate
import org.jetbrains.kotlin.ir.declarations.IrParameterKind
import java.util.concurrent.ThreadLocalRandom

// Somehow addSetter was removed from the IrProperty in https://github.com/JetBrains/kotlin/commit/d1dc938a5d7331ba43fcbb8ce53c3e17ef76a22a#diff-2726c3747ace0a1c93ad82365cf3ff18L114
// Remove this extension when this will be re-introduced? see https://kotlinlang.slack.com/archives/C7L3JB43G/p1600888883006300
Expand Down Expand Up @@ -203,30 +204,48 @@ val ClassDescriptor.isBaseRealmObject: Boolean
val realmObjectTypes: Set<Name> = setOf(REALM_OBJECT, EMBEDDED_REALM_OBJECT)
val realmObjectClassIds = realmObjectTypes.map { name -> ClassId(PACKAGE_TYPES, name) }

private val firIsBaseRealmObjectRecursionGuard = ThreadLocal.withInitial { mutableSetOf<FirClassSymbol<*>>() }

// This is the K2 equivalent of our PSI hack to determine if a symbol has a RealmObject base class.
// There is currently no way to determine this within the resolved type system and there is
// probably no such option around the corner.
// https://kotlinlang.slack.com/archives/C03PK0PE257/p1694599154558669
@OptIn(SymbolInternals::class)
val FirClassSymbol<*>.isBaseRealmObject: Boolean
get() = this.classKind == ClassKind.CLASS &&
this.fir.superTypeRefs.any { typeRef ->
when (typeRef) {
// In SUPERTYPES stage
is FirUserTypeRef -> {
typeRef.qualifier.last().name in realmObjectTypes &&
// Disregard constructor invocations as that means that it is a Realm Java class
!(
typeRef.source?.run { treeStructure.getParent(lighterASTNode) }
?.tokenType?.let { it == KtStubElementTypes.CONSTRUCTOR_CALLEE }
?: false
)
get() {
// Prevent StackOverflowError from recursive calls during FIR type resolution.
val processingSet = firIsBaseRealmObjectRecursionGuard.get()
if (processingSet.contains(this)) {
// Recursive call detected for this symbol, break the cycle.
// It's safer to return false here to prevent a StackOverflowError.
// The "true" status might be determined by a non-recursive path if one exists.
return false
}

processingSet.add(this)
try {
return this.classKind == ClassKind.CLASS &&
this.fir.superTypeRefs.any { typeRef ->
when (typeRef) {
// In SUPERTYPES stage
is FirUserTypeRef -> {
typeRef.qualifier.last().name in realmObjectTypes &&
// Disregard constructor invocations as that means that it is a Realm Java class
!(
typeRef.source?.run { treeStructure.getParent(lighterASTNode) }
?.tokenType?.let { it == KtStubElementTypes.CONSTRUCTOR_CALLEE }
?: false
)
}
// After SUPERTYPES stage
is FirResolvedTypeRef -> typeRef.coneType.classId in realmObjectClassIds
else -> false
}
}
// After SUPERTYPES stage
is FirResolvedTypeRef -> typeRef.coneType.classId in realmObjectClassIds
else -> false
}
} finally {
processingSet.remove(this)
}
}

// JetBrains already have a method `fun IrAnnotationContainer.hasAnnotation(symbol: IrClassSymbol)`
// It is unclear exactly what the difference is and how to get a ClassSymbol from a ClassId,
Expand Down