4
4
5
5
package kotlinx.rpc.codegen
6
6
7
- import kotlinx.rpc.codegen.common.ClassDeclarations
7
+ import kotlinx.rpc.codegen.common.RpcClassId
8
8
import kotlinx.rpc.codegen.common.RpcNames
9
9
import kotlinx.rpc.codegen.common.rpcMethodClassName
10
10
import kotlinx.rpc.codegen.common.rpcMethodName
@@ -19,9 +19,7 @@ import org.jetbrains.kotlin.fir.FirSession
19
19
import org.jetbrains.kotlin.fir.declarations.FirFunction
20
20
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
21
21
import org.jetbrains.kotlin.fir.declarations.utils.visibility
22
- import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
23
- import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
24
- import org.jetbrains.kotlin.fir.extensions.NestedClassGenerationContext
22
+ import org.jetbrains.kotlin.fir.extensions.*
25
23
import org.jetbrains.kotlin.fir.moduleData
26
24
import org.jetbrains.kotlin.fir.plugin.*
27
25
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -44,22 +42,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackage
44
42
*
45
43
* ## General idea
46
44
*
47
- * [getNestedClassifiersNames] should return a set of [Name]s to generate for.
48
- * For these names [generateNestedClassLikeDeclaration] can generate some nested classes,
49
- * which is what we need.
50
- *
51
- * But the catch is that we cannot say for sure, if we need to generate a class
52
- * while in [getNestedClassifiersNames], but if we do not return anything
53
- * [generateNestedClassLikeDeclaration] will not be called.
54
- * We need to generate a class if only the current declaration is an RPC interface
55
- * (inherits kotlinx.rpc.RPC). There is no resolved supertypes in [getNestedClassifiersNames],
56
- * But, if the potentially generated class is not referenced anywhere,
57
- * then [generateNestedClassLikeDeclaration] will already have supertypes resolved,
58
- * so we can use this info to check the actual supertypes for RPC interface.
59
- *
60
- * So we always return a class name that may be generated.
61
- * And then, in [generateNestedClassLikeDeclaration] we do the actual check with the resolved supertypes
62
- * and generate a class if needed, otherwise returning null.
45
+ * Detect `@Rpc` annotation - generate stub classes.
63
46
*
64
47
* ## Usage of kotlinx.serialization plugin
65
48
*
@@ -68,38 +51,38 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackage
68
51
* We generate classes that are marked `@Serializable`.
69
52
* In that case, the serialization plugin will not be able to pick up those classes and process them accordingly.
70
53
*
71
- * That's why we have an instance of this plugin, which we call only on our generated classes - [serializationExtension]
54
+ * That is why we have an instance of this plugin, which we call only on our generated classes - [serializationExtension]
72
55
*
73
56
* Not all the methods that we would like to call are public, so we access them via reflection:
74
57
* - [generateCompanionDeclaration]
75
58
* - [generateSerializerImplClass]
76
59
*
77
60
* This is basically copying the behavior of the actual plugin but isolated only for our generated classes.
78
61
*/
79
- class FirRPCServiceGenerator (
62
+ class FirRpcServiceGenerator (
80
63
session : FirSession ,
81
64
@Suppress(" unused" )
82
65
private val logger : MessageCollector ,
83
66
) : FirDeclarationGenerationExtension(session) {
84
67
private val serializationExtension = SerializationFirResolveExtension (session)
85
68
private val isJvmOrMetadata = ! session.moduleData.platform.run { isJs() || isWasm() || isNative() }
86
69
70
+ override fun FirDeclarationPredicateRegistrar.registerPredicates () {
71
+ register(FirRpcPredicates .rpc)
72
+ }
73
+
87
74
/* *
88
75
* Generates nested classifiers.
89
76
*
90
77
* They can be of three kinds:
91
78
* - Nested Service Stub class.
92
79
* In that case [classSymbol] will not have any RPC-generated [FirClassSymbol.origin].
93
- * Rge only check we do - is we check that the declaration is an interface,
94
- * and return [RpcNames.SERVICE_STUB_NAME].
95
- * We cannot be sure if the declaration is actually an RPC service,
96
- * because superTypes are not resolved during that stage.
97
- * We postpone this check until [generateNestedClassLikeDeclaration].
80
+ * The only check we do - presence of the `@Rpc` annotation and return [RpcNames.SERVICE_STUB_NAME].
98
81
*
99
82
* - Companion object of the service stub and method classes.
100
83
* If we generate this companion object, we will have [FirClassSymbol.origin]
101
84
* of [classSymbol] be set to [RPCGeneratedStubKey],
102
- * because we are inside the previously generated service stub class.
85
+ * because we're inside the previously generated service stub class.
103
86
* The same goes for method classes too.
104
87
* So we return [SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT]
105
88
* and a list of method class names.
@@ -141,7 +124,7 @@ class FirRPCServiceGenerator(
141
124
SpecialNames .DEFAULT_NAME_FOR_COMPANION_OBJECT
142
125
}
143
126
144
- classSymbol.isInterface -> {
127
+ classSymbol.isInterface && session.predicateBasedProvider.matches( FirRpcPredicates .rpc, classSymbol) -> {
145
128
setOf (RpcNames .SERVICE_STUB_NAME )
146
129
}
147
130
@@ -158,7 +141,7 @@ class FirRPCServiceGenerator(
158
141
override fun generateNestedClassLikeDeclaration (
159
142
owner : FirClassSymbol <* >,
160
143
name : Name ,
161
- context : NestedClassGenerationContext
144
+ context : NestedClassGenerationContext ,
162
145
): FirClassLikeSymbol <* >? {
163
146
val rpcServiceStubKey = owner.generatedRpcServiceStubKey
164
147
return when {
@@ -214,7 +197,7 @@ class FirRPCServiceGenerator(
214
197
modality = Modality .FINAL
215
198
}
216
199
217
- rpcMethodClass.addAnnotation(ClassDeclarations .serializableAnnotation, session)
200
+ rpcMethodClass.addAnnotation(RpcClassId .serializableAnnotation, session)
218
201
219
202
/* *
220
203
* Required to pass isSerializableObjectAndNeedsFactory check
@@ -264,18 +247,10 @@ class FirRPCServiceGenerator(
264
247
}
265
248
266
249
/* *
267
- * Checks whether the [owner] class is actually an RPC service
268
- * (the supertypes are resolved at this stage,
269
- * as the [RpcNames.SERVICE_STUB_NAME] is not references anywhere)
270
- *
271
- * If the [owner] is an RPC service - generates its service stub.
250
+ * Generates [owner]'s service stub.
272
251
* Scrapes the functions from the [owner] to generate method classes.
273
252
*/
274
253
private fun generateRpcServiceStubClass (owner : FirClassSymbol <* >): FirRegularClassSymbol ? {
275
- owner.resolvedSuperTypes.find {
276
- it.classId == ClassDeclarations .rpcInterface
277
- } ? : return null
278
-
279
254
@OptIn(SymbolInternals ::class )
280
255
val functions = owner.fir.declarations
281
256
.filterIsInstance<FirFunction >()
@@ -306,7 +281,7 @@ class FirRPCServiceGenerator(
306
281
}
307
282
308
283
/* *
309
- * If the method does not have any parameters, it is an object,
284
+ * If the method doesn't have any parameters, it is an object,
310
285
* and its only callable names are constructor, and the ones provided by the [serializationExtension].
311
286
* Otherwise, the callable names are the names of the method parameters and the constructor.
312
287
*/
@@ -322,7 +297,7 @@ class FirRPCServiceGenerator(
322
297
rpcMethodClassKey.rpcMethod.valueParameterSymbols.map { it.name }.toSet()
323
298
} + SpecialNames .INIT
324
299
325
- // ^ init is necessary either way, as serialization does not add it for a serializable object
300
+ // ^ init is necessary either way, as serialization doesn't add it for a serializable object
326
301
}
327
302
328
303
override fun generateConstructors (context : MemberGenerationContext ): List <FirConstructorSymbol > {
@@ -361,7 +336,7 @@ class FirRPCServiceGenerator(
361
336
362
337
override fun generateProperties (
363
338
callableId : CallableId ,
364
- context : MemberGenerationContext ?
339
+ context : MemberGenerationContext ? ,
365
340
): List <FirPropertySymbol > {
366
341
context ? : return emptyList()
367
342
@@ -399,14 +374,14 @@ class FirRPCServiceGenerator(
399
374
returnType = valueParam.resolvedReturnType,
400
375
).apply {
401
376
if (valueParam.resolvedReturnType.requiresContextual()) {
402
- addAnnotation(ClassDeclarations .contextualAnnotation, session)
377
+ addAnnotation(RpcClassId .contextualAnnotation, session)
403
378
}
404
379
}.symbol.let (::listOf)
405
380
}
406
381
407
382
private fun ConeKotlinType.requiresContextual (): Boolean {
408
383
return when (classId) {
409
- ClassDeclarations .flow, ClassDeclarations .sharedFlow, ClassDeclarations .stateFlow -> true
384
+ RpcClassId .flow, RpcClassId .sharedFlow, RpcClassId .stateFlow -> true
410
385
else -> false
411
386
}
412
387
}
@@ -416,7 +391,7 @@ class FirRPCServiceGenerator(
416
391
*/
417
392
override fun generateFunctions (
418
393
callableId : CallableId ,
419
- context : MemberGenerationContext ?
394
+ context : MemberGenerationContext ? ,
420
395
): List <FirNamedFunctionSymbol > {
421
396
val owner = context?.owner ? : return emptyList()
422
397
0 commit comments