Skip to content

Commit 386bbcc

Browse files
committed
Added minor checks for @Rpc services
1 parent ba377da commit 386bbcc

File tree

6 files changed

+155
-38
lines changed

6 files changed

+155
-38
lines changed

compiler-plugin/compiler-plugin-k2/src/main/core/kotlinx/rpc/codegen/checkers/FirRpcCheckers.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class FirRpcDeclarationCheckers(ctx: FirCheckersContext) : DeclarationCheckers()
1717
override val regularClassCheckers: Set<FirRegularClassChecker> = setOfNotNull(
1818
FirRpcAnnotationChecker(ctx),
1919
if (ctx.serializationIsPresent) FirRpcStrictModeClassChecker(ctx) else null,
20+
FirRpcServiceDeclarationChecker(ctx),
2021
)
2122

2223
override val classCheckers: Set<FirClassChecker> = setOf(
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.rpc.codegen.checkers
6+
7+
import kotlinx.rpc.codegen.FirCheckersContext
8+
import kotlinx.rpc.codegen.FirRpcPredicates
9+
import kotlinx.rpc.codegen.checkers.diagnostics.FirRpcDiagnostics
10+
import kotlinx.rpc.codegen.common.RpcClassId
11+
import kotlinx.rpc.codegen.vsApi
12+
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
13+
import org.jetbrains.kotlin.diagnostics.reportOn
14+
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
15+
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
16+
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
17+
import org.jetbrains.kotlin.fir.declarations.FirClass
18+
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
19+
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
20+
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
21+
import org.jetbrains.kotlin.fir.types.coneType
22+
23+
class FirRpcServiceDeclarationChecker(
24+
@Suppress("unused")
25+
private val ctx: FirCheckersContext,
26+
) : FirClassChecker(MppCheckerKind.Common) {
27+
override fun check(
28+
declaration: FirClass,
29+
context: CheckerContext,
30+
reporter: DiagnosticReporter,
31+
) {
32+
if (!context.session.predicateBasedProvider.matches(FirRpcPredicates.rpc, declaration)) {
33+
return
34+
}
35+
36+
if (declaration.typeParameters.isNotEmpty()) {
37+
reporter.reportOn(
38+
source = declaration.source,
39+
factory = FirRpcDiagnostics.TYPE_PARAMETERS_IN_RPC_INTERFACE,
40+
context = context,
41+
)
42+
}
43+
44+
declaration.declarations.filterIsInstance<FirSimpleFunction>().onEach { function ->
45+
if (function.typeParameters.isNotEmpty()) {
46+
reporter.reportOn(
47+
source = function.source,
48+
factory = FirRpcDiagnostics.TYPE_PARAMETERS_IN_RPC_FUNCTION,
49+
context = context,
50+
)
51+
}
52+
53+
val returnType = vsApi { function.returnTypeRef.coneType.toClassSymbolVS(context.session) }
54+
?: return@onEach
55+
56+
if (returnType.classId != RpcClassId.flow && !function.isSuspend) {
57+
reporter.reportOn(
58+
source = function.source,
59+
factory = FirRpcDiagnostics.NON_SUSPENDING_REQUEST_WITHOUT_STREAMING_RETURN_TYPE,
60+
context = context,
61+
)
62+
}
63+
}
64+
.groupBy { it.name }
65+
.filter { (_, list) -> list.size > 1 }
66+
.forEach { name, functions ->
67+
functions.forEach { function ->
68+
reporter.reportOn(
69+
source = function.source,
70+
factory = FirRpcDiagnostics.AD_HOC_POLYMORPHISM_IN_RPC_SERVICE,
71+
a = functions.size,
72+
b = name,
73+
context = context,
74+
)
75+
}
76+
}
77+
}
78+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:Suppress("unused")
6+
7+
package kotlinx.rpc.codegen.checkers.diagnostics
8+
9+
import kotlinx.rpc.codegen.StrictMode
10+
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0
11+
import org.jetbrains.kotlin.diagnostics.Severity
12+
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
13+
import org.jetbrains.kotlin.utils.DummyDelegate
14+
import kotlin.properties.ReadOnlyProperty
15+
import kotlin.reflect.KClass
16+
import kotlin.reflect.KProperty
17+
18+
inline fun <reified T> modded0(mode: StrictMode): DiagnosticFactory0DelegateProviderOnNull {
19+
return DiagnosticFactory0DelegateProviderOnNull(mode, T::class)
20+
}
21+
22+
class DiagnosticFactory0DelegateProviderOnNull(
23+
private val mode: StrictMode,
24+
private val psiType: KClass<*>,
25+
) {
26+
operator fun provideDelegate(
27+
@Suppress("unused")
28+
thisRef: Any?,
29+
prop: KProperty<*>,
30+
): ReadOnlyProperty<Any?, KtDiagnosticFactory0?> {
31+
val severity = when (mode) {
32+
StrictMode.ERROR -> Severity.ERROR
33+
StrictMode.WARNING -> Severity.WARNING
34+
StrictMode.NONE -> null
35+
} ?: return DummyDelegate(null)
36+
37+
return DummyDelegate(
38+
KtDiagnosticFactory0(
39+
name = prop.name,
40+
severity = severity,
41+
defaultPositioningStrategy = SourceElementPositioningStrategies.DEFAULT,
42+
psiType = psiType,
43+
),
44+
)
45+
}
46+
}

compiler-plugin/compiler-plugin-k2/src/main/core/kotlinx/rpc/codegen/checkers/diagnostics/FirRpcDiagnostics.kt

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,27 @@
44

55
package kotlinx.rpc.codegen.checkers.diagnostics
66

7-
import kotlinx.rpc.codegen.StrictMode
87
import kotlinx.rpc.codegen.StrictModeAggregator
98
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
10-
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0
11-
import org.jetbrains.kotlin.diagnostics.Severity
129
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
1310
import org.jetbrains.kotlin.diagnostics.error0
1411
import org.jetbrains.kotlin.diagnostics.error1
12+
import org.jetbrains.kotlin.diagnostics.error2
1513
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
1614
import org.jetbrains.kotlin.diagnostics.warning0
1715
import org.jetbrains.kotlin.fir.types.ConeKotlinType
16+
import org.jetbrains.kotlin.name.Name
1817
import org.jetbrains.kotlin.psi.KtAnnotationEntry
19-
import org.jetbrains.kotlin.utils.DummyDelegate
20-
import kotlin.properties.ReadOnlyProperty
21-
import kotlin.reflect.KClass
22-
import kotlin.reflect.KProperty
2318

2419
object FirRpcDiagnostics {
2520
val MISSING_RPC_ANNOTATION by error0<KtAnnotationEntry>()
2621
val MISSING_SERIALIZATION_MODULE by warning0<KtAnnotationEntry>()
2722
val WRONG_RPC_ANNOTATION_TARGET by error0<KtAnnotationEntry>()
2823
val CHECKED_ANNOTATION_VIOLATION by error1<KtAnnotationEntry, ConeKotlinType>()
24+
val NON_SUSPENDING_REQUEST_WITHOUT_STREAMING_RETURN_TYPE by error0<PsiElement>()
25+
val AD_HOC_POLYMORPHISM_IN_RPC_SERVICE by error2<PsiElement, Int, Name>()
26+
val TYPE_PARAMETERS_IN_RPC_FUNCTION by error0<PsiElement>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
27+
val TYPE_PARAMETERS_IN_RPC_INTERFACE by error0<PsiElement>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
2928

3029
init {
3130
RootDiagnosticRendererFactory.registerFactory(RpcDiagnosticRendererFactory)
@@ -46,33 +45,3 @@ class FirRpcStrictModeDiagnostics(val modes: StrictModeAggregator) {
4645
RootDiagnosticRendererFactory.registerFactory(RpcStrictModeDiagnosticRendererFactory(this))
4746
}
4847
}
49-
50-
private inline fun <reified T> modded0(mode: StrictMode): DiagnosticFactory0DelegateProviderOnNull {
51-
return DiagnosticFactory0DelegateProviderOnNull(mode, T::class)
52-
}
53-
54-
class DiagnosticFactory0DelegateProviderOnNull(
55-
private val mode: StrictMode,
56-
private val psiType: KClass<*>,
57-
) {
58-
operator fun provideDelegate(
59-
@Suppress("unused")
60-
thisRef: Any?,
61-
prop: KProperty<*>,
62-
): ReadOnlyProperty<Any?, KtDiagnosticFactory0?> {
63-
val severity = when (mode) {
64-
StrictMode.ERROR -> Severity.ERROR
65-
StrictMode.WARNING -> Severity.WARNING
66-
StrictMode.NONE -> null
67-
} ?: return DummyDelegate(null)
68-
69-
return DummyDelegate(
70-
KtDiagnosticFactory0(
71-
name = prop.name,
72-
severity = severity,
73-
defaultPositioningStrategy = SourceElementPositioningStrategies.DEFAULT,
74-
psiType = psiType,
75-
),
76-
)
77-
}
78-
}

compiler-plugin/compiler-plugin-k2/src/main/core/kotlinx/rpc/codegen/checkers/diagnostics/RpcDiagnosticRendererFactory.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import kotlinx.rpc.codegen.StrictMode
88
import kotlinx.rpc.codegen.StrictModeAggregator
99
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
1010
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
11+
import org.jetbrains.kotlin.diagnostics.rendering.Renderer
1112
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers
1213

1314
object RpcDiagnosticRendererFactory : BaseDiagnosticRendererFactory() {
@@ -37,6 +38,28 @@ object RpcDiagnosticRendererFactory : BaseDiagnosticRendererFactory() {
3738
"must be annotated with {0} or an annotation annotated with {0}.",
3839
rendererA = FirDiagnosticRenderers.RENDER_TYPE,
3940
)
41+
42+
put(
43+
factory = FirRpcDiagnostics.NON_SUSPENDING_REQUEST_WITHOUT_STREAMING_RETURN_TYPE,
44+
message = "Non suspending request function is not allowed for functions that doesn't return Flow.",
45+
)
46+
47+
put(
48+
factory = FirRpcDiagnostics.AD_HOC_POLYMORPHISM_IN_RPC_SERVICE,
49+
message = "Ad-hoc polymorphism is not allowed in @Rpc services. Found {0} '{1}' functions.",
50+
rendererA = Renderer { it.toString() },
51+
rendererB = Renderer { it.asString() },
52+
)
53+
54+
put(
55+
factory = FirRpcDiagnostics.TYPE_PARAMETERS_IN_RPC_FUNCTION,
56+
message = "Type parameters are not allowed in Rpc functions.",
57+
)
58+
59+
put(
60+
factory = FirRpcDiagnostics.TYPE_PARAMETERS_IN_RPC_INTERFACE,
61+
message = "Type parameters are not allowed in @Rpc interfaces.",
62+
)
4063
}
4164
}
4265

tests/compiler-plugin-tests/src/test/kotlin/kotlinx/rpc/codegen/test/services/ExtensionRegistrarConfigurator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class ExtensionRegistrarConfigurator(testServices: TestServices) : EnvironmentCo
2323

2424
override fun CompilerPluginRegistrar.ExtensionStorage.registerCompilerExtensions(
2525
module: TestModule,
26-
configuration: CompilerConfiguration
26+
configuration: CompilerConfiguration,
2727
) {
2828
val strictMode = module.directives[RpcDirectives.RPC_STRICT_MODE]
2929
if (strictMode.isNotEmpty()) {

0 commit comments

Comments
 (0)