Skip to content
Merged
Show file tree
Hide file tree
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 @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.dumpKotlinLike
import org.jetbrains.kotlin.ir.util.hasDefaultValue

/**
* This class scans user declared RPC service
Expand All @@ -35,7 +36,7 @@ internal object RpcDeclarationScanner {
function = declaration,
arguments = ctx.versionSpecificApi.run {
declaration.valueParametersVS().memoryOptimizedMap { param ->
ServiceDeclaration.Method.Argument(param, param.type)
ServiceDeclaration.Method.Argument(param, param.type, param.hasDefaultValue())
}
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ internal class RpcStubGenerator(
values {
+stringConst(parameter.value.name.asString())
+irRpcTypeCall(parameter.type)
+booleanConst(parameter.isOptional)
+irListOfAnnotations(parameter.value)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ServiceDeclaration(
class Argument(
val value: IrValueParameter,
val type: IrType,
val isOptional: Boolean,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ object FirRpcStrictModeClassChecker {
} memoryOptimizedPlus (function.resolvedReturnTypeRef.source to function.resolvedReturnTypeRef)

types.forEach { (source, symbol) ->
checkSerializableTypes<FirClassLikeSymbol<*>>(
checkSerializableTypes(
context = context,
typeRef = symbol,
serializablePropertiesProvider = serializablePropertiesProvider,
Expand All @@ -96,8 +96,6 @@ object FirRpcStrictModeClassChecker {
}
}
}

symbol
}
}

Expand All @@ -106,34 +104,36 @@ object FirRpcStrictModeClassChecker {
}
}

private fun <ContextElement> checkSerializableTypes(
private fun checkSerializableTypes(
context: CheckerContext,
typeRef: FirTypeRef,
serializablePropertiesProvider: FirSerializablePropertiesProvider,
parentContext: List<ContextElement> = emptyList(),
checker: (FirClassLikeSymbol<*>, List<ContextElement>) -> ContextElement?,
parentContext: List<FirClassLikeSymbol<*>> = emptyList(),
checker: (FirClassLikeSymbol<*>, List<FirClassLikeSymbol<*>>) -> Unit,
) {
val symbol = typeRef.toClassLikeSymbol(context.session) ?: return
val newElement = checker(symbol, parentContext)
val nextContext = if (newElement != null) {
parentContext memoryOptimizedPlus newElement
} else {
parentContext
}

checker(symbol, parentContext)

if (symbol !is FirClassSymbol<*>) {
return
}

val extracted = extractArgumentsTypeRefAndSource(typeRef)
val nextContext = parentContext memoryOptimizedPlus symbol

if (symbol in parentContext && symbol.typeParameterSymbols.isEmpty()) {
return
}

val typeParameters = extractArgumentsTypeRefAndSource(typeRef)
.orEmpty()
.withIndex()
.associate { (i, refSource) ->
symbol.typeParameterSymbols[i].toConeType() to refSource.typeRef
}

val flowProps: List<FirTypeRef> = if (symbol.classId == RpcClassId.flow) {
listOf(extracted.values.toList()[0]!!)
listOf(typeParameters.values.toList()[0]!!)
} else {
emptyList()
}
Expand All @@ -144,7 +144,7 @@ object FirRpcStrictModeClassChecker {
if (resolvedTypeRef.toClassLikeSymbol(context.session) != null) {
resolvedTypeRef
} else {
extracted[property.resolvedReturnType]
typeParameters[property.resolvedReturnType]
}
}.memoryOptimizedPlus(flowProps)
.forEach { symbol ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotated
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNameReferenceExpression

// ###########################################################################
// ### BIG WARNING, LISTEN CLOSELY! ###
Expand All @@ -25,8 +26,8 @@ import org.jetbrains.kotlin.psi.KtElement
// ###########################################################################

object FirRpcDiagnostics : RpcKtDiagnosticsContainer() {
val WRONG_RPC_ANNOTATION_TARGET by error1<KtAnnotated, ConeKotlinType>()
val CHECKED_ANNOTATION_VIOLATION by error3<KtAnnotated, Int, ConeKotlinType, FirBasedSymbol<*>>()
val WRONG_RPC_ANNOTATION_TARGET by error1<KtElement, ConeKotlinType>()
val CHECKED_ANNOTATION_VIOLATION by error3<KtElement, Int, ConeKotlinType, FirBasedSymbol<*>>()
val NON_SUSPENDING_REQUEST_WITHOUT_STREAMING_RETURN_TYPE by error0<KtElement>()
val AD_HOC_POLYMORPHISM_IN_RPC_SERVICE by error2<KtElement, Int, Name>()
val TYPE_PARAMETERS_IN_RPC_FUNCTION by error0<KtElement>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
Expand Down
2 changes: 1 addition & 1 deletion compiler-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ org.gradle.parallel=true
org.gradle.workers.max=8
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.configureondemand=true
#org.gradle.configureondemand=true // breaks compiler tests

org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public sealed interface RpcInvokator<@Rpc T : Any> {
public interface RpcParameter {
public val name: String
public val type: RpcType
public val isOptional: Boolean

/**
* List of annotations with target [AnnotationTarget.VALUE_PARAMETER].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class RpcCallableDefault<@Rpc T : Any>(
public class RpcParameterDefault(
override val name: String,
override val type: RpcType,
override val isOptional: Boolean,
override val annotations: List<Annotation>,
) : RpcParameter

Expand Down
2 changes: 1 addition & 1 deletion dokka-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ org.gradle.parallel=true
org.gradle.workers.max=8
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.configureondemand=true
#org.gradle.configureondemand=true // breaks compiler tests

org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

import io.gitlab.arturbosch.detekt.Detekt
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

@file:OptIn(ExperimentalAbiValidation::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,6 @@ fun RepositoryHandler.configureLocalDevRepository() {
}
}

val sonatypeRepositoryUri: String?
get() {
val repositoryId: String = project.getSensitiveProperty("libs.repository.id")
?.takeIf { it.isNotBlank() }
?: return null

return "https://oss.sonatype.org/service/local/staging/deployByRepositoryId/$repositoryId"
}

fun configureEmptyJavadocArtifact(): TaskProvider<Jar?> {
val javadocJar by project.tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
Expand Down
2 changes: 1 addition & 1 deletion gradle-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ org.gradle.parallel=true
org.gradle.workers.max=8
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.configureondemand=true
#org.gradle.configureondemand=true // breaks compiler tests

org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ org.gradle.parallel=true
org.gradle.workers.max=8
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.configureondemand=true
#org.gradle.configureondemand=true // breaks compiler tests

org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.rpc.krpc.internal
Expand All @@ -15,6 +15,7 @@ import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.*
import kotlinx.serialization.modules.SerializersModule
import kotlin.reflect.KType
import kotlin.reflect.KTypeParameter

@OptIn(ExperimentalSerializationApi::class)
internal fun SerializersModule.buildContextualInternal(type: KType): KSerializer<Any?>? {
Expand Down Expand Up @@ -113,7 +114,7 @@ public class CallableParametersSerializer(
elementName = param.name,
descriptor = callableSerializers[i].descriptor,
annotations = param.type.annotations,
isOptional = param.type.kType.isMarkedNullable,
isOptional = param.isOptional,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ interface KrpcTestService {
suspend fun doubleGenericParams(arg1: List<List<String>>)
suspend fun mapParams(arg1: Map<String, Map<Int, List<String>>>)
suspend fun customType(arg1: TestClass): TestClass
suspend fun nullable(arg1: String?): TestClass?
suspend fun nullableParam(arg1: String?): String
suspend fun nullableReturn(returnNull: Boolean): TestClass?
suspend fun variance(arg2: TestList<in TestClass>, arg3: TestList2<TestClass>): TestList<out TestClass>?

suspend fun nonSerializableClass(localDate: LocalDate): LocalDate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,12 @@ class KrpcTestServiceBackend : KrpcTestService {
return arg1
}

override suspend fun nullable(arg1: String?): TestClass? {
return if (arg1 == null) null else TestClass()
override suspend fun nullableParam(arg1: String?): String {
return arg1 ?: "null"
}

override suspend fun nullableReturn(returnNull: Boolean): TestClass? {
return if (returnNull) null else TestClass()
}

override suspend fun variance(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,21 @@ abstract class KrpcTransportTestBase {
}

@Test
open fun nullable() = runTest {
val result = client.nullable("test")
assertEquals(TestClass(), result)
open fun nullableParameter() = runTest {
val result = client.nullableParam("test")
assertEquals("test", result)

val result2 = client.nullableParam(null)
assertEquals("null", result2)
}

@Test
open fun nullableReturn() = runTest {
val result = client.nullableReturn(returnNull = true)
assertEquals(null, result)

val result2 = client.nullable(null)
assertEquals(null, result2)
val result2 = client.nullableReturn(returnNull = false)
assertEquals(TestClass(), result2)
}

@Test
Expand Down Expand Up @@ -345,7 +354,7 @@ abstract class KrpcTransportTestBase {
@Test
open fun testNullables() = runTest {
assertEquals(1, client.nullableInt(1))
assertNull(client.nullable(null))
assertNull(client.nullableReturn(returnNull = true))
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ProtoBufLocalTransportTest : LocalTransportTest() {

// 'null' is not supported in ProtoBuf
@Test
override fun nullable(): TestResult = runTest { }
override fun nullableReturn(): TestResult = runTest { }

@Test
override fun testByteArraySerialization(): TestResult = runTest { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,37 @@ FILE: b.kt

public final fun copy(flow1: R|kotlinx/coroutines/flow/Flow<kotlin/Int>| = this@R|/MultiFlow|.R|/MultiFlow.flow1|, flow2: R|kotlinx/coroutines/flow/Flow<kotlin/Int>| = this@R|/MultiFlow|.R|/MultiFlow.flow2|, flow3: R|kotlinx/coroutines/flow/Flow<kotlin/Int>| = this@R|/MultiFlow|.R|/MultiFlow.flow3|): R|MultiFlow|

}
public final data class ComplexFilter : R|kotlin/Any| {
public constructor(a: R|SimpleFilter?|, b: R|ComplexFilter?|): R|ComplexFilter| {
super<R|kotlin/Any|>()
}

public final val a: R|SimpleFilter?| = R|<local>/a|
public get(): R|SimpleFilter?|

public final val b: R|ComplexFilter?| = R|<local>/b|
public get(): R|ComplexFilter?|

public final operator fun component1(): R|SimpleFilter?|

public final operator fun component2(): R|ComplexFilter?|

public final fun copy(a: R|SimpleFilter?| = this@R|/ComplexFilter|.R|/ComplexFilter.a|, b: R|ComplexFilter?| = this@R|/ComplexFilter|.R|/ComplexFilter.b|): R|ComplexFilter|

}
public final data class SimpleFilter : R|kotlin/Any| {
public constructor(text: R|kotlin/String|): R|SimpleFilter| {
super<R|kotlin/Any|>()
}

public final val text: R|kotlin/String| = R|<local>/text|
public get(): R|kotlin/String|

public final operator fun component1(): R|kotlin/String|

public final fun copy(text: R|kotlin/String| = this@R|/SimpleFilter|.R|/SimpleFilter.text|): R|SimpleFilter|

}
@R|kotlinx/rpc/annotations/Rpc|() public abstract interface MyService : R|kotlin/Any| {
public abstract val flow: R|kotlinx/coroutines/flow/Flow<kotlin/Int>|
Expand Down Expand Up @@ -105,6 +136,8 @@ FILE: b.kt

public abstract fun nonSuspendNoFlowString(): R|kotlin/String|

public abstract suspend fun complex(filter: R|ComplexFilter|): R|kotlin/String|

public final class $rpcServiceStub : R|kotlin/Any| {
public final companion object Companion : R|kotlin/Any| {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ data class MultiFlow(
val flow3: Flow<Int>,
)

data class ComplexFilter(
val a: SimpleFilter?,
val b: ComplexFilter?
)

data class SimpleFilter(val text: String)

@Rpc
interface MyService {
<!FIELD_IN_RPC_SERVICE!>val flow: Flow<Int><!>
Expand Down Expand Up @@ -57,4 +64,5 @@ interface MyService {
suspend fun clientNestedTrickyFlow(<!NESTED_STREAMING_IN_RPC_SERVICE!>inner: Wrapper<Flow<Wrapper<Flow<Int>>>><!>)
<!NON_SUSPENDING_REQUEST_WITHOUT_STREAMING_RETURN_TYPE!>fun nonSuspendNoFlow()<!>
<!NON_SUSPENDING_REQUEST_WITHOUT_STREAMING_RETURN_TYPE!>fun nonSuspendNoFlowString(): String<!>
suspend fun complex(filter: ComplexFilter): String // doesn't fail on circular dependency
}
3 changes: 2 additions & 1 deletion updateTestData.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

#
# Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
#

if [ "$#" -ne 1 ] && [ "$#" -ne 2 ]; then
Expand All @@ -23,4 +23,5 @@ set -o xtrace
:tests:compiler-plugin-tests:test \
--tests "kotlinx.rpc.codegen.test.runners.$1Generated$TEST_NAME" \
--continue \
--stacktrace \
-Pkotlin.test.update.test.data=true