@@ -22,6 +22,10 @@ import io.realm.kotlin.compiler.ClassIds.EMBEDDED_OBJECT_INTERFACE
22
22
import io.realm.kotlin.compiler.ClassIds.KOTLIN_COLLECTIONS_LISTOF
23
23
import io.realm.kotlin.compiler.ClassIds.PERSISTED_NAME_ANNOTATION
24
24
import io.realm.kotlin.compiler.ClassIds.REALM_OBJECT_INTERFACE
25
+ import io.realm.kotlin.compiler.FqNames.PACKAGE_TYPES
26
+ import io.realm.kotlin.compiler.Names.ASYMMETRIC_REALM_OBJECT
27
+ import io.realm.kotlin.compiler.Names.EMBEDDED_REALM_OBJECT
28
+ import io.realm.kotlin.compiler.Names.REALM_OBJECT
25
29
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
26
30
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
27
31
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocationWithRange
@@ -30,9 +34,15 @@ import org.jetbrains.kotlin.com.intellij.openapi.util.text.StringUtil
30
34
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
31
35
import org.jetbrains.kotlin.com.intellij.psi.PsiElementVisitor
32
36
import org.jetbrains.kotlin.descriptors.ClassDescriptor
37
+ import org.jetbrains.kotlin.descriptors.ClassKind
33
38
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
34
39
import org.jetbrains.kotlin.descriptors.Modality
35
40
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
41
+ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
42
+ import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
43
+ import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
44
+ import org.jetbrains.kotlin.fir.types.FirUserTypeRef
45
+ import org.jetbrains.kotlin.fir.types.classId
36
46
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
37
47
import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder
38
48
import org.jetbrains.kotlin.ir.builders.IrBlockBuilder
@@ -105,6 +115,7 @@ import org.jetbrains.kotlin.name.CallableId
105
115
import org.jetbrains.kotlin.name.ClassId
106
116
import org.jetbrains.kotlin.name.FqName
107
117
import org.jetbrains.kotlin.name.Name
118
+ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
108
119
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes.SUPER_TYPE_LIST
109
120
import org.jetbrains.kotlin.resolve.DescriptorUtils
110
121
import org.jetbrains.kotlin.types.KotlinType
@@ -141,10 +152,9 @@ val anyRealmObjectInterfacesFqNames = realmObjectInterfaceFqNames + realmEmbedde
141
152
142
153
fun IrType.classIdOrFail (): ClassId = getClass()?.classId ? : error(" Can't get classId of ${render()} " )
143
154
144
- inline fun ClassDescriptor.hasInterfacePsi (interfaces : Set <String >): Boolean {
145
- // Using PSI to find super types to avoid cyclic reference (see https://github.com/realm/realm-kotlin/issues/339)
155
+ inline fun PsiElement.hasInterface (interfaces : Set <String >): Boolean {
146
156
var hasRealmObjectAsSuperType = false
147
- this .findPsi()?. acceptChildren(object : PsiElementVisitor () {
157
+ this .acceptChildren(object : PsiElementVisitor () {
148
158
override fun visitElement (element : PsiElement ) {
149
159
if (element.node.elementType == SUPER_TYPE_LIST ) {
150
160
// Check supertypes for classes with Embbeded/RealmObject as generics and remove
@@ -169,6 +179,10 @@ inline fun ClassDescriptor.hasInterfacePsi(interfaces: Set<String>): Boolean {
169
179
170
180
return hasRealmObjectAsSuperType
171
181
}
182
+ inline fun ClassDescriptor.hasInterfacePsi (interfaces : Set <String >): Boolean {
183
+ // Using PSI to find super types to avoid cyclic reference (see https://github.com/realm/realm-kotlin/issues/339)
184
+ return this .findPsi()?.hasInterface(interfaces) ? : false
185
+ }
172
186
173
187
// Do to the way PSI works, it can be a bit tricky to uniquely identify when the Realm Kotlin
174
188
// RealmObject interface is used. For that reason, once we have determined a match for RealmObject,
@@ -186,6 +200,34 @@ val ClassDescriptor.isEmbeddedRealmObject: Boolean
186
200
val ClassDescriptor .isBaseRealmObject: Boolean
187
201
get() = this .hasInterfacePsi(realmObjectPsiNames + embeddedRealmObjectPsiNames + asymmetricRealmObjectPsiNames) && ! this .hasInterfacePsi(realmJavaObjectPsiNames)
188
202
203
+ val realmObjectTypes: Set <Name > = setOf (REALM_OBJECT , EMBEDDED_REALM_OBJECT , ASYMMETRIC_REALM_OBJECT )
204
+ val realmObjectClassIds = realmObjectTypes.map { name -> ClassId (PACKAGE_TYPES , name) }
205
+
206
+ // This is the K2 equivalent of our PSI hack to determine if a symbol has a RealmObject base class.
207
+ // There is currently no way to determine this within the resolved type system and there is
208
+ // probably no such option around the corner.
209
+ // https://kotlinlang.slack.com/archives/C03PK0PE257/p1694599154558669
210
+ @OptIn(SymbolInternals ::class )
211
+ val FirClassSymbol <* >.isBaseRealmObject: Boolean
212
+ get() = this .classKind == ClassKind .CLASS &&
213
+ this .fir.superTypeRefs.any { typeRef ->
214
+ when (typeRef) {
215
+ // In SUPERTYPES stage
216
+ is FirUserTypeRef -> {
217
+ typeRef.qualifier.last().name in realmObjectTypes &&
218
+ // Disregard constructor invocations as that means that it is a Realm Java class
219
+ ! (
220
+ typeRef.source?.run { treeStructure.getParent(lighterASTNode) }
221
+ ?.tokenType?.let { it == KtStubElementTypes .CONSTRUCTOR_CALLEE }
222
+ ? : false
223
+ )
224
+ }
225
+ // After SUPERTYPES stage
226
+ is FirResolvedTypeRef -> typeRef.type.classId in realmObjectClassIds
227
+ else -> false
228
+ }
229
+ }
230
+
189
231
// JetBrains already have a method `fun IrAnnotationContainer.hasAnnotation(symbol: IrClassSymbol)`
190
232
// It is unclear exactly what the difference is and how to get a ClassSymbol from a ClassId,
191
233
// so for now just work around it.
0 commit comments