Skip to content
This repository was archived by the owner on Oct 8, 2024. It is now read-only.

Commit 416ade1

Browse files
committed
README.md and something..
1 parent 5290c75 commit 416ade1

File tree

6 files changed

+205
-29
lines changed

6 files changed

+205
-29
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,34 @@ interface Foo {
156156
> [!note]
157157
> If `SuspendReversal.markJvmSynthetic = true`,
158158
> then `@JvmSynthetic` must (or is strongly recommended) be added to the suspend function.
159+
160+
161+
## Cautions
162+
163+
1. The processor will only handle the **abstract suspend** function.
164+
165+
2. In Java, functions with a return value of `Unit` are treated as `CompletableFuture<Void?>`
166+
167+
3. Will copy the annotations `@kotlin.Throws` and `@kotlin.jvm.Throws`.
168+
169+
4. Will **roughly** calculate whether the generated function needs to be inherited or not.
170+
171+
e.g.
172+
```kotlin
173+
interface Foo {
174+
suspend fun run()
175+
fun runBlocking() { /*...*/ }
176+
}
177+
178+
// Generated 👇
179+
180+
interface JBlockingFoo : Foo {
181+
override fun runBlocking() // Will be marked `override`
182+
suspend fun run() {
183+
runBlocking()
184+
}
185+
}
186+
```
187+
188+
> [!warning]
189+
> The judgment is very rough and not very reliable.

annotations/src/commonMain/kotlin/love/forte/suspendreversal/annotations/SuspendReversal.kt

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,69 @@ package love.forte.suspendreversal.annotations
77
@Target(AnnotationTarget.CLASS)
88
@Retention(AnnotationRetention.SOURCE)
99
public annotation class SuspendReversal(
10-
val javaBlocking: Boolean = true,
11-
val javaAsync: Boolean = true,
10+
val jBlocking: Boolean = true,
11+
val jBlockingClassNamePrefix: String = "JBlocking",
12+
val jBlockingClassNameSuffix: String = "",
13+
val jAsync: Boolean = true,
14+
val jAsyncClassNamePrefix: String = "JAsync",
15+
val jAsyncClassNameSuffix: String = "",
1216
val jsAsync: Boolean = true,
17+
val jsAsyncClassNamePrefix: String = "JsAsync",
18+
val jsAsyncClassNameSuffix: String = "",
1319
val markJvmSynthetic: Boolean = true,
1420
// todo more options..?
15-
)
21+
) {
22+
23+
// TODO
24+
@Target(AnnotationTarget.FUNCTION)
25+
@Retention(AnnotationRetention.SOURCE)
26+
public annotation class JBlocking(
27+
/**
28+
* 生成函数的基础名称,如果为空则为当前函数名。
29+
* 最终生成的函数名为 [baseName] + [suffix]。
30+
*/
31+
val baseName: String = "",
32+
33+
/**
34+
* [baseName] 名称基础上追加的名称后缀。
35+
*/
36+
val suffix: String = "Blocking",
37+
val asProperty: Boolean = false,
38+
)
39+
40+
// TODO
41+
@Target(AnnotationTarget.FUNCTION)
42+
@Retention(AnnotationRetention.SOURCE)
43+
public annotation class JAsync(
44+
/**
45+
* 生成函数的基础名称,如果为空则为当前函数名。
46+
* 最终生成的函数名为 [baseName] + [suffix]。
47+
*/
48+
val baseName: String = "",
49+
50+
/**
51+
* [baseName] 名称基础上追加的名称后缀。
52+
*/
53+
val suffix: String = "Async",
54+
val asProperty: Boolean = false,
55+
)
56+
57+
// TODO
58+
@Target(AnnotationTarget.FUNCTION)
59+
@Retention(AnnotationRetention.SOURCE)
60+
public annotation class JsAsync(
61+
/**
62+
* 生成函数的基础名称,如果为空则为当前函数名。
63+
* 最终生成的函数名为 [baseName] + [suffix]。
64+
*/
65+
val baseName: String = "",
66+
67+
/**
68+
* [baseName] 名称基础上追加的名称后缀。
69+
*/
70+
val suffix: String = "Async",
71+
val asProperty: Boolean = false,
72+
73+
)
74+
75+
}

processor/src/main/kotlin/love/forte/suspendreversal/processor/ProcessJs.kt

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,22 @@ internal fun resolveJs(
1919
typeParameterResolver: TypeParameterResolver,
2020
superClassName: TypeName,
2121
) {
22+
val nearestAnnotation = symbol.nearestAnnotation
2223
val asyncTypeBuilder: TypeSpec.Builder? = generateReversalTypeSpecBuilder(
2324
typeParameterResolver = typeParameterResolver,
2425
superClassName = superClassName,
2526
environment = environment,
2627
symbol = symbol,
27-
isEnabled = symbol.nearestAnnotation.jsAsync,
28-
classNamePrefix = "JsAsync"
28+
isEnabled = nearestAnnotation.jsAsync,
29+
classNamePrefix = nearestAnnotation.jsAsyncClassNamePrefix,
30+
classNameSuffix = nearestAnnotation.jsAsyncClassNameSuffix
2931
)
3032

3133
// all suspend abstract fun
3234
symbol.declaration.declarations
3335
.filterIsInstance<KSFunctionDeclaration>()
3436
.filter { it.isAbstract && Modifier.SUSPEND in it.modifiers }
3537
.forEach { abstractSuspendFunction ->
36-
environment.logger.info("abstractSuspendFunction: $abstractSuspendFunction")
3738
if (asyncTypeBuilder != null) {
3839
val (asyncFun, overriddenFun) = generateAsyncFunctions(
3940
symbol,
@@ -53,6 +54,9 @@ private fun generateAsyncFunctions(
5354
typeParameterResolver: TypeParameterResolver,
5455
abstractSuspendFunction: KSFunctionDeclaration
5556
): GeneratedReversalFunctions {
57+
val abstractSuspendFunctionName = abstractSuspendFunction.simpleName.asString()
58+
val funName = abstractSuspendFunctionName + "Async"
59+
5660
val funcParameterResolver = abstractSuspendFunction.typeParameters.toTypeParameterResolver(typeParameterResolver)
5761

5862
val modifiers = abstractSuspendFunction.modifiers.mapNotNull { it.toKModifier() }
@@ -71,14 +75,24 @@ private fun generateAsyncFunctions(
7175
).build()
7276
}
7377

74-
val abstractSuspendFunctionName = abstractSuspendFunction.simpleName.asString()
75-
val abstractAsyncFunction = FunSpec.builder(abstractSuspendFunctionName + "Async").apply {
78+
val override = shouldOverride(
79+
annotationInfo.declaration,
80+
funName,
81+
abstractSuspendFunction.extensionReceiver,
82+
abstractSuspendFunction.parameters
83+
)
84+
85+
86+
val abstractAsyncFunction = FunSpec.builder(funName).apply {
7687
// doc
7788
addKdoc("Async reversal function for [%N]", abstractSuspendFunctionName)
7889

7990
val modifiers0 = modifiers.toMutableSet()
8091
modifiers0.remove(KModifier.SUSPEND)
8192
modifiers0.add(KModifier.ABSTRACT)
93+
if (override) {
94+
modifiers0.add(KModifier.OVERRIDE)
95+
}
8296

8397
addModifiers(modifiers0)
8498
addTypeVariables(typeVariables)

processor/src/main/kotlin/love/forte/suspendreversal/processor/ProcessJvm.kt

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,32 @@ internal fun resolveJvm(
1919
typeParameterResolver: TypeParameterResolver,
2020
superClassName: TypeName,
2121
) {
22+
val nearestAnnotation = symbol.nearestAnnotation
2223
val blockingTypeBuilder: TypeSpec.Builder? = generateReversalTypeSpecBuilder(
2324
typeParameterResolver = typeParameterResolver,
2425
superClassName = superClassName,
2526
environment = environment,
2627
symbol = symbol,
27-
isEnabled = symbol.nearestAnnotation.javaBlocking,
28-
classNamePrefix = "JBlocking"
28+
isEnabled = nearestAnnotation.jBlocking,
29+
classNamePrefix = nearestAnnotation.jBlockingClassNamePrefix,
30+
classNameSuffix = nearestAnnotation.jBlockingClassNameSuffix
2931
)
3032

3133
val asyncTypeBuilder: TypeSpec.Builder? = generateReversalTypeSpecBuilder(
3234
typeParameterResolver = typeParameterResolver,
3335
superClassName = superClassName,
3436
environment = environment,
3537
symbol = symbol,
36-
isEnabled = symbol.nearestAnnotation.javaAsync,
37-
classNamePrefix = "JAsync"
38+
isEnabled = nearestAnnotation.jAsync,
39+
classNamePrefix = nearestAnnotation.jAsyncClassNamePrefix,
40+
classNameSuffix = nearestAnnotation.jAsyncClassNameSuffix,
3841
)
3942

4043
// all suspend abstract fun
4144
symbol.declaration.declarations
4245
.filterIsInstance<KSFunctionDeclaration>()
4346
.filter { it.isAbstract && Modifier.SUSPEND in it.modifiers }
4447
.forEach { abstractSuspendFunction ->
45-
environment.logger.info("abstractSuspendFunction: $abstractSuspendFunction")
4648
if (blockingTypeBuilder != null) {
4749
val (blockingFun, overriddenFun) = generateBlockingFunctions(
4850
symbol,
@@ -74,6 +76,8 @@ private fun generateBlockingFunctions(
7476
typeParameterResolver: TypeParameterResolver,
7577
abstractSuspendFunction: KSFunctionDeclaration
7678
): GeneratedReversalFunctions {
79+
val abstractSuspendFunctionName = abstractSuspendFunction.simpleName.asString()
80+
val funName = abstractSuspendFunctionName + "Blocking" // TODO from annotation
7781
val funcParameterResolver = abstractSuspendFunction.typeParameters.toTypeParameterResolver(typeParameterResolver)
7882

7983
val modifiers = abstractSuspendFunction.modifiers.mapNotNull { it.toKModifier() }
@@ -93,14 +97,27 @@ private fun generateBlockingFunctions(
9397
).build()
9498
}
9599

96-
val abstractSuspendFunctionName = abstractSuspendFunction.simpleName.asString()
97-
val abstractBlockingFunction = FunSpec.builder(abstractSuspendFunctionName + "Blocking").apply {
100+
val override = shouldOverride(
101+
annotationInfo.declaration,
102+
funName,
103+
abstractSuspendFunction.extensionReceiver,
104+
abstractSuspendFunction.parameters
105+
)
106+
107+
val abstractBlockingFunction = FunSpec.builder(funName).apply {
98108
// doc
99-
addKdoc("Blocking reversal function for [%N]\n\n @see %N", abstractSuspendFunctionName, abstractSuspendFunctionName)
109+
addKdoc(
110+
"Blocking reversal function for [%N]\n\n @see %N",
111+
abstractSuspendFunctionName,
112+
abstractSuspendFunctionName
113+
)
100114

101115
val modifiers0 = modifiers.toMutableSet()
102116
modifiers0.remove(KModifier.SUSPEND)
103117
modifiers0.add(KModifier.ABSTRACT)
118+
if (override) {
119+
modifiers0.add(KModifier.OVERRIDE)
120+
}
104121

105122
addModifiers(modifiers0)
106123
addTypeVariables(typeVariables)
@@ -160,6 +177,8 @@ private fun generateAsyncFunctions(
160177
typeParameterResolver: TypeParameterResolver,
161178
abstractSuspendFunction: KSFunctionDeclaration
162179
): GeneratedReversalFunctions {
180+
val abstractSuspendFunctionName = abstractSuspendFunction.simpleName.asString()
181+
val funName = abstractSuspendFunctionName + "Async"
163182
val funcParameterResolver = abstractSuspendFunction.typeParameters.toTypeParameterResolver(typeParameterResolver)
164183

165184
val modifiers = abstractSuspendFunction.modifiers.mapNotNull { it.toKModifier() }
@@ -177,16 +196,27 @@ private fun generateAsyncFunctions(
177196
modifiers = modifiers0
178197
).build()
179198
}
199+
val override = shouldOverride(
200+
annotationInfo.declaration,
201+
funName,
202+
abstractSuspendFunction.extensionReceiver,
203+
abstractSuspendFunction.parameters
204+
)
180205

181-
val abstractSuspendFunctionName = abstractSuspendFunction.simpleName.asString()
182-
val abstractAsyncFunction = FunSpec.builder(abstractSuspendFunctionName + "Async").apply {
206+
val abstractAsyncFunction = FunSpec.builder(funName).apply {
183207
// doc
184-
addKdoc("Async reversal function for [%N]\n\n @see %N", abstractSuspendFunctionName, abstractSuspendFunctionName)
208+
addKdoc(
209+
"Async reversal function for [%N]\n\n @see %N",
210+
abstractSuspendFunctionName,
211+
abstractSuspendFunctionName
212+
)
185213

186214
val modifiers0 = modifiers.toMutableSet()
187215
modifiers0.remove(KModifier.SUSPEND)
188216
modifiers0.add(KModifier.ABSTRACT)
189-
217+
if (override) {
218+
modifiers0.add(KModifier.OVERRIDE)
219+
}
190220

191221
addModifiers(modifiers0)
192222
addTypeVariables(typeVariables)

processor/src/main/kotlin/love/forte/suspendreversal/processor/SuspendInterfaceReversalProcessor.kt

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package love.forte.suspendreversal.processor
22

3-
import com.google.devtools.ksp.KspExperimental
4-
import com.google.devtools.ksp.getAnnotationsByType
5-
import com.google.devtools.ksp.isAbstract
3+
import com.google.devtools.ksp.*
64
import com.google.devtools.ksp.processing.*
75
import com.google.devtools.ksp.symbol.*
86
import com.squareup.kotlinpoet.*
@@ -180,16 +178,17 @@ internal fun generateReversalTypeSpecBuilder(
180178
symbol: AnnotationAndClassDeclaration,
181179
isEnabled: Boolean,
182180
classNamePrefix: String,
181+
classNameSuffix: String,
183182
): TypeSpec.Builder? {
184183
val declaration = symbol.declaration
185184
val declarationName = declaration.simpleName.asString()
186185

187186
val builder: TypeSpec.Builder = if (isEnabled) {
188187
when (declaration.classKind) {
189188
ClassKind.CLASS -> {
190-
environment.logger.info("CLASS declaration: $declaration")
189+
val className = classNamePrefix + declaration.simpleName.asString() + classNameSuffix
191190

192-
TypeSpec.classBuilder(classNamePrefix + declaration.simpleName.asString())
191+
TypeSpec.classBuilder(className)
193192
.apply {
194193
superclass(superClassName)
195194
// build primary constructor
@@ -241,7 +240,8 @@ internal fun generateReversalTypeSpecBuilder(
241240
"""
242241
Generated suspend reversal type for [%N].
243242
@see %N
244-
""".trimIndent(), declarationName, declarationName)
243+
""".trimIndent(), declarationName, declarationName
244+
)
245245

246246

247247
return builder
@@ -252,14 +252,18 @@ internal data class GeneratedReversalFunctions(
252252
val overriddenSuspendFunction: FunSpec
253253
)
254254

255-
internal fun KSType.resolveClassDeclarationToClassName(): ClassName? {
255+
internal fun KSType.resolveClassDeclaration(): KSClassDeclaration? {
256256
return when (val declaration = declaration) {
257-
is KSClassDeclaration -> declaration.toClassName()
258-
is KSTypeAlias -> declaration.type.resolve().resolveClassDeclarationToClassName()
257+
is KSClassDeclaration -> declaration
258+
is KSTypeAlias -> declaration.findActualType()
259259
else -> return null
260260
}
261261
}
262262

263+
internal fun KSType.resolveClassDeclarationToClassName(): ClassName? {
264+
return resolveClassDeclaration()?.toClassName()
265+
}
266+
263267
/**
264268
* 需要添加(拷贝)的注解们
265269
* - [JvmThrowsClassName]
@@ -276,3 +280,37 @@ internal fun resolveIncludeAnnotations(builder: FunSpec.Builder, source: KSFunct
276280
}
277281

278282
}
283+
284+
/**
285+
* 粗略的判断是否需要标记继承
286+
*/
287+
internal fun shouldOverride(
288+
declaration: KSClassDeclaration,
289+
name: String,
290+
extensionReceiver: KSTypeReference?,
291+
params: List<KSValueParameter>
292+
): Boolean {
293+
return declaration.getAllFunctions().any { func ->
294+
if (func.simpleName.asString() != name) {
295+
return@any false
296+
}
297+
298+
val funcReceiver = func.extensionReceiver
299+
if (funcReceiver != extensionReceiver) return@any false
300+
val funParams = func.parameters
301+
if (funParams.size != params.size) return@any false
302+
303+
for ((index, funParam) in funParams.withIndex()) {
304+
val param = params[index]
305+
if (param.type == funParam.type) continue
306+
307+
val funParamClassDecl = funParam.type.resolve().resolveClassDeclaration()
308+
val paramClassDecl = param.type.resolve().resolveClassDeclaration()
309+
310+
// skip.
311+
if (funParamClassDecl == null || paramClassDecl == null) return false
312+
}
313+
314+
return true
315+
}
316+
}

samples/simple-sample2/src/commonMain/kotlin/pk1/pk2/Foo.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ abstract class S2<T, out R, in I, V : Number>(val name: String) {
4343
@JvmSynthetic
4444
@Throws(Exception::class)
4545
abstract suspend fun run()
46+
47+
open fun runBlocking() {}
48+
4649
@JvmSynthetic
4750
abstract suspend fun get(): String
4851
}

0 commit comments

Comments
 (0)