Skip to content
Closed
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
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
# 0.5.0
> Published 11 December 2024

### Features 🎉
* Update Service Descriptors Generation by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/227
* Kotlin 2.1.0 by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/244
* Added basic CheckedTypeAnnotation impl with compiler plugin check by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/240
* Strict mode by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/243

### Breaking Changes 🔴
* Api naming by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/236
* Update Service Descriptors Generation by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/227
* Added basic CheckedTypeAnnotation impl with compiler plugin check by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/240

### Deprecations ⚠️
* Api naming by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/236
* Strict mode by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/243

### Infra 🚧
* Update the project structure to work with kotlin-master by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/234
* Fixed version formatting with ENV vars by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/235
* Fix Kotlin master compilation by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/245
* Opt-out from annotations type safety analysis by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/246

### Other Changes 🧹
* Added test for non-serializable params by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/237
* Updated descriptor to use `RpcType` instead of `KType` directly by @Mr3zee in https://github.com/Kotlin/kotlinx-rpc/pull/239

**Full Changelog**: https://github.com/Kotlin/kotlinx-rpc/compare/0.4.0...0.5.0

# 0.4.0
> Published 5 November 2024

Expand Down
9 changes: 5 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
/*
* 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 org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import util.configureApiValidation
import util.configureNpm
import util.configureProjectReport
import util.libs
import util.configureProjectReport
import util.configureNpm
import util.configureApiValidation

plugins {
alias(libs.plugins.serialization) apply false
alias(libs.plugins.kotlinx.rpc) apply false
alias(libs.plugins.conventions.kover)
alias(libs.plugins.protobuf) apply false
alias(libs.plugins.conventions.gradle.doctor)
alias(libs.plugins.atomicfu)
id("build-util")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ internal class RpcIrContext(
getRpcIrClassSymbol("RpcServiceDescriptor", "descriptor")
}

val grpcServiceDescriptor by lazy {
getIrClassSymbol("kotlinx.rpc.grpc.descriptor", "GrpcServiceDescriptor")
}

val grpcDelegate by lazy {
getIrClassSymbol("kotlinx.rpc.grpc.descriptor", "GrpcDelegate")
}

val rpcType by lazy {
getRpcIrClassSymbol("RpcType", "descriptor")
}
Expand Down Expand Up @@ -262,6 +270,10 @@ internal class RpcIrContext(
rpcServiceDescriptor.namedProperty("fqName")
}

val grpcServiceDescriptorDelegate by lazy {
grpcServiceDescriptor.namedProperty("delegate")
}

private fun IrClassSymbol.namedProperty(name: String): IrPropertySymbol {
return owner.properties.single { it.name.asString() == name }.symbol
}
Expand All @@ -276,7 +288,7 @@ internal class RpcIrContext(
return getIrClassSymbol("kotlinx.rpc$suffix", name)
}

private fun getIrClassSymbol(packageName: String, name: String): IrClassSymbol {
fun getIrClassSymbol(packageName: String, name: String): IrClassSymbol {
return versionSpecificApi.referenceClass(pluginContext, packageName, name)
?: error("Unable to find symbol. Package: $packageName, name: $name")
}
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.codegen.extension
Expand All @@ -9,14 +9,17 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer

internal class RpcIrServiceProcessor(
@Suppress("unused")
private val logger: MessageCollector,
) : IrElementTransformer<RpcIrContext> {
override fun visitClass(declaration: IrClass, data: RpcIrContext): IrStatement {
if (declaration.hasAnnotation(RpcClassId.rpcAnnotation)) {
if ((declaration.hasAnnotation(RpcClassId.rpcAnnotation)
|| declaration.hasAnnotation(RpcClassId.grpcAnnotation)) && declaration.isInterface
) {
processService(declaration, data)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ private object Descriptor {
const val CREATE_INSTANCE = "createInstance"
}

private object GrpcDescriptor {
const val DELEGATE = "delegate"
}

@Suppress("detekt.LargeClass", "detekt.TooManyFunctions")
internal class RpcStubGenerator(
private val declaration: ServiceDeclaration,
Expand Down Expand Up @@ -123,7 +127,10 @@ internal class RpcStubGenerator(

clientProperty()

coroutineContextProperty()
// not for gRPC
if (!declaration.isGrpc) {
coroutineContextProperty()
}

declaration.fields.forEach {
rpcFlowField(it)
Expand Down Expand Up @@ -550,7 +557,15 @@ internal class RpcStubGenerator(
overriddenSymbols = listOf(method.function.symbol)

body = irBuilder(symbol).irBlockBody {
+irReturn(
val call = if (declaration.isGrpc) {
irRpcMethodClientCall(
method = method,
functionThisReceiver = functionThisReceiver,
isMethodObject = isMethodObject,
methodClass = methodClass,
arguments = arguments,
)
} else {
irCall(
callee = ctx.functions.scopedClientCall,
type = method.function.returnType,
Expand Down Expand Up @@ -600,7 +615,9 @@ internal class RpcStubGenerator(

putValueArgument(1, lambda)
}
)
}

+irReturn(call)
}
}
}
Expand Down Expand Up @@ -868,7 +885,10 @@ internal class RpcStubGenerator(
stubCompanionObjectThisReceiver = thisReceiver
?: error("Stub companion object expected to have thisReceiver: ${name.asString()}")

superTypes = listOf(ctx.rpcServiceDescriptor.typeWith(declaration.serviceType))
superTypes = listOfNotNull(
ctx.rpcServiceDescriptor.typeWith(declaration.serviceType),
if (declaration.isGrpc) ctx.grpcServiceDescriptor.typeWith(declaration.serviceType) else null,
)

generateCompanionObjectConstructor()

Expand Down Expand Up @@ -901,6 +921,10 @@ internal class RpcStubGenerator(
generateCreateInstanceFunction()

generateGetFieldsFunction()

if (declaration.isGrpc) {
generateGrpcDelegateProperty()
}
}

/**
Expand Down Expand Up @@ -1488,6 +1512,43 @@ internal class RpcStubGenerator(
}
}

/**
* override val delegate: GrpcDelegate = MyServiceDelegate
*/
private fun IrClass.generateGrpcDelegateProperty() {
addProperty {
name = Name.identifier(GrpcDescriptor.DELEGATE)
visibility = DescriptorVisibilities.PUBLIC
}.apply {
overriddenSymbols = listOf(ctx.properties.grpcServiceDescriptorDelegate)

addBackingFieldUtil {
visibility = DescriptorVisibilities.PRIVATE
type = ctx.grpcDelegate.defaultType
vsApi { isFinalVS = true }
}.apply {
initializer = factory.createExpressionBody(
IrGetObjectValueImpl(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
type = ctx.grpcDelegate.defaultType,
symbol = ctx.getIrClassSymbol(
declaration.service.packageFqName?.asString()
?: error("Expected package name fro service ${declaration.service.name}"),
"${declaration.service.name.asString()}Delegate",
),
)
)
}

addDefaultGetter(this@generateGrpcDelegateProperty, ctx.irBuiltIns) {
visibility = DescriptorVisibilities.PUBLIC
overriddenSymbols = listOf(ctx.properties.grpcServiceDescriptorDelegate.owner.getterOrFail.symbol)
}
}
}


// Associated object annotation works on JS, WASM, and Native platforms.
// See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/find-associated-object.html
private fun addAssociatedObjectAnnotationIfPossible() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

package kotlinx.rpc.codegen.extension

import kotlinx.rpc.codegen.common.RpcClassId
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.kotlinFqName

class ServiceDeclaration(
Expand All @@ -18,6 +20,7 @@ class ServiceDeclaration(
val methods: List<Method>,
val fields: List<FlowField>,
) {
val isGrpc = service.hasAnnotation(RpcClassId.grpcAnnotation)
val fqName = service.kotlinFqName.asString()

val serviceType = service.defaultType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.name.Name
object RpcClassId {
val remoteServiceInterface = ClassId(FqName("kotlinx.rpc"), Name.identifier("RemoteService"))
val rpcAnnotation = ClassId(FqName("kotlinx.rpc.annotations"), Name.identifier("Rpc"))
val grpcAnnotation = ClassId(FqName("kotlinx.rpc.grpc.annotations"), Name.identifier("Grpc"))
val checkedTypeAnnotation = ClassId(FqName("kotlinx.rpc.annotations"), Name.identifier("CheckedTypeAnnotation"))

val serializableAnnotation = ClassId(FqName("kotlinx.serialization"), Name.identifier("Serializable"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey

internal class RpcGeneratedStubKey(
val isGrpc: Boolean,
private val serviceName: Name,
val functions: List<FirFunctionSymbol<*>>,
) : GeneratedDeclarationKey() {
Expand All @@ -25,6 +26,7 @@ internal val FirBasedSymbol<*>.generatedRpcServiceStubKey: RpcGeneratedStubKey?
(origin as? FirDeclarationOrigin.Plugin)?.key as? RpcGeneratedStubKey

internal class RpcGeneratedRpcMethodClassKey(
val isGrpc: Boolean,
val rpcMethod: FirFunctionSymbol<*>,
) : GeneratedDeclarationKey() {
val isObject = rpcMethod.valueParameterSymbols.isEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class FirRpcAdditionalCheckers(
) : FirAdditionalCheckersExtension(session) {
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
register(FirRpcPredicates.rpc)
register(FirRpcPredicates.grpc)
register(FirRpcPredicates.checkedAnnotationMeta)
}

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.codegen
Expand All @@ -12,6 +12,14 @@ object FirRpcPredicates {
annotated(RpcClassId.rpcAnnotation.asSingleFqName()) // @Rpc
}

internal val rpcMeta = DeclarationPredicate.create {
metaAnnotated(RpcClassId.rpcAnnotation.asSingleFqName(), includeItself = true)
}

internal val grpc = DeclarationPredicate.create {
annotated(RpcClassId.grpcAnnotation.asSingleFqName()) // @Grpc
}

internal val checkedAnnotationMeta = DeclarationPredicate.create {
metaAnnotated(RpcClassId.checkedTypeAnnotation.asSingleFqName(), includeItself = false)
}
Expand Down
Loading