From f5c8b3437938fcda7b2fc6cf448c64d122f23fe4 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Mon, 22 Sep 2025 12:42:50 +0200 Subject: [PATCH] Supported deprecated options --- .../src/commonTest/proto/options.proto | 26 +++++++++++++++++++ .../gen/core/AModelToKotlinCommonGenerator.kt | 1 - .../rpc/protoc/gen/core/CodeGenerator.kt | 24 +++++++++++++++++ .../rpc/protoc/gen/core/codeRequestToModel.kt | 10 +++++++ .../rpc/protoc/gen/core/model/model.kt | 8 ++++++ .../grpc/ModelToGrpcKotlinCommonGenerator.kt | 4 ++- .../ModelToProtobufKotlinCommonGenerator.kt | 15 ++++++----- 7 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 grpc/grpc-core/src/commonTest/proto/options.proto diff --git a/grpc/grpc-core/src/commonTest/proto/options.proto b/grpc/grpc-core/src/commonTest/proto/options.proto new file mode 100644 index 000000000..7cedc83bc --- /dev/null +++ b/grpc/grpc-core/src/commonTest/proto/options.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +message Options { + option deprecated = true; + string old = 1 [deprecated = true]; + oneof oneof { + string first = 2 [deprecated = true]; + } + map map = 3 [deprecated = true]; + repeated string list = 4 [deprecated = true]; +} + +enum OptionsEnum { + option deprecated = true; + option allow_alias = true; + + SOME = 0 [deprecated = true]; + SOME_2 = 0 [deprecated = true]; +} + +service SomeService { + option deprecated = true; + rpc SomeMethod(Options) returns (Options) { + option deprecated = true; + } +} diff --git a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt index 07ed5ae24..7723d76b6 100644 --- a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt +++ b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/AModelToKotlinCommonGenerator.kt @@ -11,7 +11,6 @@ import kotlinx.rpc.protoc.gen.core.model.FqName import kotlinx.rpc.protoc.gen.core.model.MessageDeclaration import kotlinx.rpc.protoc.gen.core.model.Model import kotlinx.rpc.protoc.gen.core.model.fullName -import org.slf4j.Logger const val RPC_INTERNAL_PACKAGE_SUFFIX = "_rpc_internal" const val MSG_INTERNAL_SUFFIX = "Internal" diff --git a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/CodeGenerator.kt b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/CodeGenerator.kt index cfd63296b..6108076a2 100644 --- a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/CodeGenerator.kt +++ b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/CodeGenerator.kt @@ -2,6 +2,8 @@ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ +@file:Suppress("DuplicatedCode") + package kotlinx.rpc.protoc.gen.core @DslMarker @@ -176,6 +178,7 @@ open class CodeGenerator( modifiers: String = "", contextReceiver: String = "", annotations: List = emptyList(), + deprecation: DeprecationLevel? = null, type: String, propertyInitializer: PropertyInitializer = PropertyInitializer.PLAIN, value: String = "", @@ -187,6 +190,7 @@ open class CodeGenerator( for (annotation in annotations) { addLine(annotation) } + addDeprecation(deprecation) val modifiersString = (if (modifiers.isEmpty()) "" else "$modifiers ").withVisibility() val contextString = if (contextReceiver.isEmpty()) "" else "$contextReceiver." @@ -218,6 +222,7 @@ open class CodeGenerator( args: String = "", contextReceiver: String = "", annotations: List = emptyList(), + deprecation: DeprecationLevel? = null, returnType: String, block: (CodeGenerator.() -> Unit)? = null, ) { @@ -225,6 +230,8 @@ open class CodeGenerator( for (annotation in annotations) { addLine(annotation) } + addDeprecation(deprecation) + val modifiersString = (if (modifiers.isEmpty()) "" else "$modifiers ").withVisibility() val contextString = if (contextReceiver.isEmpty()) "" else "$contextReceiver." val returnTypeString = if (returnType.isEmpty() || returnType == "Unit") "" else ": $returnType" @@ -243,6 +250,7 @@ open class CodeGenerator( modifiers: String = "", superTypes: List = emptyList(), annotations: List = emptyList(), + deprecation: DeprecationLevel? = null, declarationType: DeclarationType = DeclarationType.Class, block: (CodeGenerator.() -> Unit)? = null, ) { @@ -253,6 +261,7 @@ open class CodeGenerator( constructorArgs = emptyList(), superTypes = superTypes, annotations = annotations, + deprecation = deprecation, declarationType = declarationType, block = block, ) @@ -266,6 +275,7 @@ open class CodeGenerator( constructorArgs: List = emptyList(), superTypes: List = emptyList(), annotations: List = emptyList(), + deprecation: DeprecationLevel? = null, declarationType: DeclarationType = DeclarationType.Class, block: (CodeGenerator.() -> Unit)? = null, ) { @@ -276,6 +286,7 @@ open class CodeGenerator( constructorArgs = constructorArgs.map { it to null }, superTypes = superTypes, annotations = annotations, + deprecation = deprecation, declarationType = declarationType, block = block, ) @@ -289,6 +300,7 @@ open class CodeGenerator( constructorArgs: List> = emptyList(), superTypes: List = emptyList(), annotations: List = emptyList(), + deprecation: DeprecationLevel? = null, declarationType: DeclarationType = DeclarationType.Class, block: (CodeGenerator.() -> Unit)? = null, ) { @@ -296,6 +308,7 @@ open class CodeGenerator( for (annotation in annotations) { addLine(annotation) } + addDeprecation(deprecation) val modifiersString = (if (modifiers.isEmpty()) "" else "$modifiers ").withVisibility() @@ -437,6 +450,17 @@ open class CodeGenerator( } } + private fun addDeprecation(deprecation: DeprecationLevel?) { + if (deprecation != null) { + val value = if (deprecation != DeprecationLevel.WARNING) { + "@Deprecated(\"This declaration is deprecated in .proto file\", DeprecationLevel.$deprecation)" + } else { + "@Deprecated(\"This declaration is deprecated in .proto file\")" + } + addLine(value) + } + } + @Suppress("PrivatePropertyName") private val ONE_INDENT = " ".repeat(config.indentSize) } diff --git a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/codeRequestToModel.kt b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/codeRequestToModel.kt index 5f890fb77..3b4787634 100644 --- a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/codeRequestToModel.kt +++ b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/codeRequestToModel.kt @@ -17,6 +17,7 @@ import kotlinx.rpc.protoc.gen.core.model.MethodDeclaration import kotlinx.rpc.protoc.gen.core.model.Model import kotlinx.rpc.protoc.gen.core.model.OneOfDeclaration import kotlinx.rpc.protoc.gen.core.model.ServiceDeclaration +import kotlin.Boolean import kotlin.collections.plus private val nameCache = mutableMapOf() @@ -127,6 +128,7 @@ private fun Descriptors.FileDescriptor.toModel(): FileDeclaration = cached { (comments + Paths.editionsCommentPath).get(), (comments + Paths.packageCommentPath).get() ), + deprecated = options.deprecated, dec = this, ) } @@ -156,6 +158,7 @@ private fun Descriptors.Descriptor.toModel(comments: Comments?): MessageDeclarat type = FieldType.OneOf(it), doc = it.doc, dec = it.variants.first().dec, + deprecated = options.deprecated, ) } @@ -169,6 +172,7 @@ private fun Descriptors.Descriptor.toModel(comments: Comments?): MessageDeclarat nestedDeclarations = nestedTypes.map { it.toModel(comments + Paths.messageMessageCommentPath + it.index) }, doc = comments.get(), dec = this, + deprecated = options.deprecated, ) } @@ -180,6 +184,7 @@ private fun Descriptors.FieldDescriptor.toModel(comments: Comments, presenceIdx: presenceIdx = presenceIdx, doc = comments.get(), dec = this, + deprecated = options.deprecated, ) } @@ -219,6 +224,7 @@ private fun Descriptors.EnumDescriptor.toModel(comments: Comments?): EnumDeclara aliases = aliases, doc = comments.get(), dec = this, + deprecated = options.deprecated, ) } @@ -227,6 +233,7 @@ private fun Descriptors.EnumValueDescriptor.toModel(comments: Comments): EnumDec name = fqName(), doc = comments.get(), dec = this, + deprecated = options.deprecated, ) } @@ -237,6 +244,7 @@ private fun Descriptors.EnumValueDescriptor.toAliasModel(enumComments: Comments, original = original, doc = enumComments.get(), dec = this, + deprecated = options.deprecated, ) } @@ -246,6 +254,7 @@ private fun Descriptors.ServiceDescriptor.toModel(comments: Comments): ServiceDe methods = methods.map { it.toModel(comments + Paths.serviceMethodCommentPath + it.index) }, dec = this, doc = comments.get(), + deprecated = options.deprecated, ) } @@ -256,6 +265,7 @@ private fun Descriptors.MethodDescriptor.toModel(comments: Comments): MethodDecl outputType = lazy { outputType.toModel(null) }, dec = this, doc = comments.get(), + deprecated = options.deprecated, ) } diff --git a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/model/model.kt b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/model/model.kt index 07933ae67..0354f4536 100644 --- a/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/model/model.kt +++ b/protoc-gen/common/src/main/kotlin/kotlinx/rpc/protoc/gen/core/model/model.kt @@ -20,6 +20,7 @@ data class FileDeclaration( val serviceDeclarations: List, val doc: List, val dec: Descriptors.FileDescriptor, + val deprecated: Boolean, ) data class MessageDeclaration( @@ -31,6 +32,7 @@ data class MessageDeclaration( val nestedDeclarations: List, val doc: Comment?, val dec: Descriptors.Descriptor, + val deprecated: Boolean, ) { val isMapEntry = dec.options.mapEntry val isUserFacing = !isMapEntry @@ -49,6 +51,7 @@ data class EnumDeclaration( val aliases: List, val doc: Comment?, val dec: Descriptors.EnumDescriptor, + val deprecated: Boolean, ) { fun defaultEntry(): Entry { @@ -63,6 +66,7 @@ data class EnumDeclaration( val name: FqName, val doc: Comment?, val dec: Descriptors.EnumValueDescriptor, + val deprecated: Boolean, ) data class Alias( @@ -70,6 +74,7 @@ data class EnumDeclaration( val original: Entry, val doc: Comment?, val dec: Descriptors.EnumValueDescriptor, + val deprecated: Boolean, ) } @@ -85,6 +90,7 @@ data class FieldDeclaration( val type: FieldType, val doc: Comment?, val dec: Descriptors.FieldDescriptor, + val deprecated: Boolean, // defines the index in the presenceMask of the Message. // this cannot be the number, as only fields with hasPresence == true are part of the presenceMask val presenceIdx: Int? = null, @@ -111,6 +117,7 @@ data class ServiceDeclaration( val methods: List, val dec: Descriptors.ServiceDescriptor, val doc: Comment?, + val deprecated: Boolean, ) data class MethodDeclaration( @@ -119,5 +126,6 @@ data class MethodDeclaration( val outputType: Lazy, val dec: Descriptors.MethodDescriptor, val doc: Comment?, + val deprecated: Boolean, ) diff --git a/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt b/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt index 6acf1e4e2..e66a782bd 100644 --- a/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt +++ b/protoc-gen/grpc/src/main/kotlin/kotlinx/rpc/protoc/gen/grpc/ModelToGrpcKotlinCommonGenerator.kt @@ -36,7 +36,8 @@ class ModelToGrpcKotlinCommonGenerator( name = service.name.simpleName, comment = service.doc, declarationType = CodeGenerator.DeclarationType.Interface, - annotations = listOf("@kotlinx.rpc.grpc.annotations.Grpc$annotationParams") + annotations = listOf("@kotlinx.rpc.grpc.annotations.Grpc$annotationParams"), + deprecation = if (service.deprecated) DeprecationLevel.WARNING else null, ) { service.methods.forEach { method -> val inputType = method.inputType @@ -53,6 +54,7 @@ class ModelToGrpcKotlinCommonGenerator( modifiers = if (method.dec.isServerStreaming) "" else "suspend", args = "message: ${inputType.value.name.safeFullName().wrapInFlowIf(method.dec.isClientStreaming)}", annotations = annotations, + deprecation = if (method.deprecated) DeprecationLevel.WARNING else null, returnType = outputType.value.name.safeFullName().wrapInFlowIf(method.dec.isServerStreaming), ) } diff --git a/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt b/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt index fd1c9404e..a05260ab8 100644 --- a/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt +++ b/protoc-gen/protobuf/src/main/kotlin/kotlinx/rpc/protoc/gen/ModelToProtobufKotlinCommonGenerator.kt @@ -80,7 +80,8 @@ class ModelToProtobufKotlinCommonGenerator( name = declaration.name.simpleName, comment = declaration.doc, declarationType = CodeGenerator.DeclarationType.Interface, - annotations = annotations + annotations = annotations, + deprecation = if (declaration.deprecated) DeprecationLevel.WARNING else null, ) { declaration.actualFields.forEachIndexed { i, field -> property( @@ -88,6 +89,7 @@ class ModelToProtobufKotlinCommonGenerator( comment = field.doc, type = field.typeFqName(), needsNewLineAfterDeclaration = i == declaration.actualFields.lastIndex, + deprecation = if (field.deprecated) DeprecationLevel.WARNING else null, ) } @@ -300,7 +302,7 @@ class ModelToProtobufKotlinCommonGenerator( } private fun CodeGenerator.generateMessageDecoder(declaration: MessageDeclaration) { - var args = "msg: ${declaration.internalClassFullName()}, decoder: $PB_PKG.WireDecoder"; + var args = "msg: ${declaration.internalClassFullName()}, decoder: $PB_PKG.WireDecoder" if (declaration.isGroup) { args += ", startGroup: $PB_PKG.KTag" } @@ -406,8 +408,6 @@ class ModelToProtobufKotlinCommonGenerator( } is FieldType.Message -> { - val msg = fieldType.dec.value - whenCase("tag.fieldNr == ${field.number} && tag.wireType == $PB_PKG.WireType.${fieldType.wireType.name}") { if (field.presenceIdx != null) { // check if the current sub message object was already set, if not, set a new one @@ -995,6 +995,7 @@ class ModelToProtobufKotlinCommonGenerator( constructorArgs = listOf("val value: ${variant.typeFqName()}"), annotations = listOf("@JvmInline"), superTypes = listOf(interfaceName), + deprecation = if (variant.deprecated) DeprecationLevel.WARNING else null, ) additionalPublicImports.add("kotlin.jvm.JvmInline") @@ -1003,9 +1004,7 @@ class ModelToProtobufKotlinCommonGenerator( } private fun CodeGenerator.generatePublicEnum(declaration: EnumDeclaration) { - val className = declaration.name.simpleName - val entriesSorted = declaration.originalEntries.sortedBy { it.dec.number } clazz( @@ -1013,14 +1012,15 @@ class ModelToProtobufKotlinCommonGenerator( comment = declaration.doc, modifiers = "sealed", constructorArgs = listOf("open val number: Int"), + deprecation = if (declaration.deprecated) DeprecationLevel.WARNING else null, ) { - declaration.originalEntries.forEach { variant -> clazz( name = variant.name.simpleName, comment = variant.doc, declarationType = CodeGenerator.DeclarationType.Object, superTypes = listOf("$className(number = ${variant.dec.number})"), + deprecation = if (variant.deprecated) DeprecationLevel.WARNING else null, ) } @@ -1042,6 +1042,7 @@ class ModelToProtobufKotlinCommonGenerator( type = className, propertyInitializer = CodeGenerator.PropertyInitializer.GETTER, value = alias.original.name.simpleName, + deprecation = if (alias.deprecated) DeprecationLevel.WARNING else null, ) }